View Javadoc
1   /*
2    * Copyright 2016 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.channel.epoll;
17  
18  import io.netty.channel.ChannelException;
19  import io.netty.channel.DefaultFileRegion;
20  import io.netty.channel.unix.NativeInetAddress;
21  import io.netty.channel.unix.PeerCredentials;
22  import io.netty.channel.unix.Socket;
23  import io.netty.channel.socket.InternetProtocolFamily;
24  import io.netty.util.internal.PlatformDependent;
25  import io.netty.util.internal.SocketUtils;
26  import io.netty.util.internal.UnstableApi;
27  
28  import java.io.IOException;
29  import java.net.InetAddress;
30  import java.net.Inet6Address;
31  import java.net.NetworkInterface;
32  import java.net.UnknownHostException;
33  import java.util.Enumeration;
34  
35  import static io.netty.channel.unix.Errors.ioResult;
36  
37  /**
38   * A socket which provides access Linux native methods.
39   */
40  @UnstableApi
41  public final class LinuxSocket extends Socket {
42      static final InetAddress INET6_ANY = unsafeInetAddrByName("::");
43      private static final InetAddress INET_ANY = unsafeInetAddrByName("0.0.0.0");
44      private static final long MAX_UINT32_T = 0xFFFFFFFFL;
45  
46      LinuxSocket(int fd) {
47          super(fd);
48      }
49  
50      InternetProtocolFamily family() {
51          return ipv6 ? InternetProtocolFamily.IPv6 : InternetProtocolFamily.IPv4;
52      }
53  
54      int sendmmsg(NativeDatagramPacketArray.NativeDatagramPacket[] msgs,
55                                 int offset, int len) throws IOException {
56          return Native.sendmmsg(intValue(), ipv6, msgs, offset, len);
57      }
58  
59      int recvmmsg(NativeDatagramPacketArray.NativeDatagramPacket[] msgs,
60                   int offset, int len) throws IOException {
61          return Native.recvmmsg(intValue(), ipv6, msgs, offset, len);
62      }
63  
64      int recvmsg(NativeDatagramPacketArray.NativeDatagramPacket msg) throws IOException {
65          return Native.recvmsg(intValue(), ipv6, msg);
66      }
67  
68      void setTimeToLive(int ttl) throws IOException {
69          setTimeToLive(intValue(), ttl);
70      }
71  
72      void setInterface(InetAddress address) throws IOException {
73          final NativeInetAddress a = NativeInetAddress.newInstance(address);
74          setInterface(intValue(), ipv6, a.address(), a.scopeId(), interfaceIndex(address));
75      }
76  
77      void setNetworkInterface(NetworkInterface netInterface) throws IOException {
78          InetAddress address = deriveInetAddress(netInterface, family() == InternetProtocolFamily.IPv6);
79          if (address.equals(family() == InternetProtocolFamily.IPv4 ? INET_ANY : INET6_ANY)) {
80              throw new IOException("NetworkInterface does not support " + family());
81          }
82          final NativeInetAddress nativeAddress = NativeInetAddress.newInstance(address);
83          setInterface(intValue(), ipv6, nativeAddress.address(), nativeAddress.scopeId(), interfaceIndex(netInterface));
84      }
85  
86      InetAddress getInterface() throws IOException {
87          NetworkInterface inf = getNetworkInterface();
88          if (inf != null) {
89              Enumeration<InetAddress> addresses = SocketUtils.addressesFromNetworkInterface(inf);
90              if (addresses.hasMoreElements()) {
91                  return addresses.nextElement();
92              }
93          }
94          return null;
95      }
96  
97      NetworkInterface getNetworkInterface() throws IOException {
98          int ret = getInterface(intValue(), ipv6);
99          if (ipv6) {
100             return PlatformDependent.javaVersion() >= 7 ? NetworkInterface.getByIndex(ret) : null;
101         }
102         InetAddress address = inetAddress(ret);
103         return address != null ? NetworkInterface.getByInetAddress(address) : null;
104     }
105 
106     private static InetAddress inetAddress(int value) {
107         byte[] var1 = {
108                 (byte) (value >>> 24 & 255),
109                 (byte) (value >>> 16 & 255),
110                 (byte) (value >>> 8 & 255),
111                 (byte) (value & 255)
112         };
113 
114         try {
115             return InetAddress.getByAddress(var1);
116         } catch (UnknownHostException ignore) {
117             return null;
118         }
119     }
120 
121     void joinGroup(InetAddress group, NetworkInterface netInterface, InetAddress source) throws IOException {
122         final NativeInetAddress g = NativeInetAddress.newInstance(group);
123         final boolean isIpv6 = group instanceof Inet6Address;
124         final NativeInetAddress i = NativeInetAddress.newInstance(deriveInetAddress(netInterface, isIpv6));
125         if (source != null) {
126             if (source.getClass() != group.getClass()) {
127                 throw new IllegalArgumentException("Source address is different type to group");
128             }
129             final NativeInetAddress s = NativeInetAddress.newInstance(source);
130             joinSsmGroup(intValue(), ipv6 && isIpv6, g.address(), i.address(),
131                     g.scopeId(), interfaceIndex(netInterface), s.address());
132         } else {
133             joinGroup(intValue(), ipv6 && isIpv6, g.address(), i.address(), g.scopeId(), interfaceIndex(netInterface));
134         }
135     }
136 
137     void leaveGroup(InetAddress group, NetworkInterface netInterface, InetAddress source) throws IOException {
138         final NativeInetAddress g = NativeInetAddress.newInstance(group);
139         final boolean isIpv6 = group instanceof Inet6Address;
140         final NativeInetAddress i = NativeInetAddress.newInstance(deriveInetAddress(netInterface, isIpv6));
141         if (source != null) {
142             if (source.getClass() != group.getClass()) {
143                 throw new IllegalArgumentException("Source address is different type to group");
144             }
145             final NativeInetAddress s = NativeInetAddress.newInstance(source);
146             leaveSsmGroup(intValue(), ipv6 && isIpv6, g.address(), i.address(),
147                     g.scopeId(), interfaceIndex(netInterface), s.address());
148         } else {
149             leaveGroup(intValue(), ipv6 && isIpv6, g.address(), i.address(), g.scopeId(), interfaceIndex(netInterface));
150         }
151     }
152 
153     private static int interfaceIndex(NetworkInterface networkInterface) {
154         return PlatformDependent.javaVersion() >= 7 ? networkInterface.getIndex() : -1;
155     }
156 
157     private static int interfaceIndex(InetAddress address) throws IOException {
158         if (PlatformDependent.javaVersion() >= 7) {
159             NetworkInterface iface = NetworkInterface.getByInetAddress(address);
160             if (iface != null) {
161                 return iface.getIndex();
162             }
163         }
164         return -1;
165     }
166 
167     void setTcpDeferAccept(int deferAccept) throws IOException {
168         setTcpDeferAccept(intValue(), deferAccept);
169     }
170 
171     void setTcpQuickAck(boolean quickAck) throws IOException {
172         setTcpQuickAck(intValue(), quickAck ? 1 : 0);
173     }
174 
175     void setTcpCork(boolean tcpCork) throws IOException {
176         setTcpCork(intValue(), tcpCork ? 1 : 0);
177     }
178 
179     void setSoBusyPoll(int loopMicros) throws IOException {
180         setSoBusyPoll(intValue(), loopMicros);
181     }
182 
183     void setTcpNotSentLowAt(long tcpNotSentLowAt) throws IOException {
184         if (tcpNotSentLowAt < 0 || tcpNotSentLowAt > MAX_UINT32_T) {
185             throw new IllegalArgumentException("tcpNotSentLowAt must be a uint32_t");
186         }
187         setTcpNotSentLowAt(intValue(), (int) tcpNotSentLowAt);
188     }
189 
190     void setTcpFastOpen(int tcpFastopenBacklog) throws IOException {
191         setTcpFastOpen(intValue(), tcpFastopenBacklog);
192     }
193 
194     void setTcpKeepIdle(int seconds) throws IOException {
195         setTcpKeepIdle(intValue(), seconds);
196     }
197 
198     void setTcpKeepIntvl(int seconds) throws IOException {
199         setTcpKeepIntvl(intValue(), seconds);
200     }
201 
202     void setTcpKeepCnt(int probes) throws IOException {
203         setTcpKeepCnt(intValue(), probes);
204     }
205 
206     void setTcpUserTimeout(int milliseconds) throws IOException {
207         setTcpUserTimeout(intValue(), milliseconds);
208     }
209 
210     void setIpFreeBind(boolean enabled) throws IOException {
211         setIpFreeBind(intValue(), enabled ? 1 : 0);
212     }
213 
214     void setIpTransparent(boolean enabled) throws IOException {
215         setIpTransparent(intValue(), enabled ? 1 : 0);
216     }
217 
218     void setIpRecvOrigDestAddr(boolean enabled) throws IOException {
219         setIpRecvOrigDestAddr(intValue(), enabled ? 1 : 0);
220     }
221 
222     int getTimeToLive() throws IOException {
223         return getTimeToLive(intValue());
224     }
225 
226     void getTcpInfo(EpollTcpInfo info) throws IOException {
227         getTcpInfo(intValue(), info.info);
228     }
229 
230     void setTcpMd5Sig(InetAddress address, byte[] key) throws IOException {
231         final NativeInetAddress a = NativeInetAddress.newInstance(address);
232         setTcpMd5Sig(intValue(), ipv6, a.address(), a.scopeId(), key);
233     }
234 
235     boolean isTcpCork() throws IOException  {
236         return isTcpCork(intValue()) != 0;
237     }
238 
239     int getSoBusyPoll() throws IOException  {
240         return getSoBusyPoll(intValue());
241     }
242 
243     int getTcpDeferAccept() throws IOException {
244         return getTcpDeferAccept(intValue());
245     }
246 
247     boolean isTcpQuickAck() throws IOException {
248         return isTcpQuickAck(intValue()) != 0;
249     }
250 
251     long getTcpNotSentLowAt() throws IOException {
252         return getTcpNotSentLowAt(intValue()) & MAX_UINT32_T;
253     }
254 
255     int getTcpKeepIdle() throws IOException {
256         return getTcpKeepIdle(intValue());
257     }
258 
259     int getTcpKeepIntvl() throws IOException {
260         return getTcpKeepIntvl(intValue());
261     }
262 
263     int getTcpKeepCnt() throws IOException {
264         return getTcpKeepCnt(intValue());
265     }
266 
267     int getTcpUserTimeout() throws IOException {
268         return getTcpUserTimeout(intValue());
269     }
270 
271     boolean isIpFreeBind() throws IOException {
272         return isIpFreeBind(intValue()) != 0;
273     }
274 
275     boolean isIpTransparent() throws IOException {
276         return isIpTransparent(intValue()) != 0;
277     }
278 
279     boolean isIpRecvOrigDestAddr() throws IOException {
280         return isIpRecvOrigDestAddr(intValue()) != 0;
281     }
282 
283     PeerCredentials getPeerCredentials() throws IOException {
284         return getPeerCredentials(intValue());
285     }
286 
287     boolean isLoopbackModeDisabled() throws IOException {
288         return getIpMulticastLoop(intValue(), ipv6) == 0;
289     }
290 
291     void setLoopbackModeDisabled(boolean loopbackModeDisabled) throws IOException {
292         setIpMulticastLoop(intValue(), ipv6, loopbackModeDisabled ? 0 : 1);
293     }
294 
295     boolean isUdpGro() throws IOException {
296         return isUdpGro(intValue()) != 0;
297     }
298 
299     void setUdpGro(boolean gro) throws IOException {
300         setUdpGro(intValue(), gro ? 1 : 0);
301     }
302 
303     long sendFile(DefaultFileRegion src, long baseOffset, long offset, long length) throws IOException {
304         // Open the file-region as it may be created via the lazy constructor. This is needed as we directly access
305         // the FileChannel field via JNI.
306         src.open();
307 
308         long res = sendFile(intValue(), src, baseOffset, offset, length);
309         if (res >= 0) {
310             return res;
311         }
312         return ioResult("sendfile", (int) res);
313     }
314 
315     private static InetAddress deriveInetAddress(NetworkInterface netInterface, boolean ipv6) {
316         final InetAddress ipAny = ipv6 ? INET6_ANY : INET_ANY;
317         if (netInterface != null) {
318             final Enumeration<InetAddress> ias = netInterface.getInetAddresses();
319             while (ias.hasMoreElements()) {
320                 final InetAddress ia = ias.nextElement();
321                 final boolean isV6 = ia instanceof Inet6Address;
322                 if (isV6 == ipv6) {
323                     return ia;
324                 }
325             }
326         }
327         return ipAny;
328     }
329 
330     public static LinuxSocket newSocketStream(boolean ipv6) {
331         return new LinuxSocket(newSocketStream0(ipv6));
332     }
333 
334     public static LinuxSocket newSocketStream(InternetProtocolFamily protocol) {
335         return new LinuxSocket(newSocketStream0(protocol));
336     }
337 
338     public static LinuxSocket newSocketStream() {
339         return newSocketStream(isIPv6Preferred());
340     }
341 
342     public static LinuxSocket newSocketDgram(boolean ipv6) {
343         return new LinuxSocket(newSocketDgram0(ipv6));
344     }
345 
346     public static LinuxSocket newSocketDgram(InternetProtocolFamily family) {
347         return new LinuxSocket(newSocketDgram0(family));
348     }
349 
350     public static LinuxSocket newSocketDgram() {
351         return newSocketDgram(isIPv6Preferred());
352     }
353 
354     public static LinuxSocket newSocketDomain() {
355         return new LinuxSocket(newSocketDomain0());
356     }
357 
358     public static LinuxSocket newSocketDomainDgram() {
359         return new LinuxSocket(newSocketDomainDgram0());
360     }
361 
362     private static InetAddress unsafeInetAddrByName(String inetName) {
363         try {
364             return InetAddress.getByName(inetName);
365         } catch (UnknownHostException uhe) {
366             throw new ChannelException(uhe);
367         }
368     }
369 
370     private static native void joinGroup(int fd, boolean ipv6, byte[] group, byte[] interfaceAddress,
371                                          int scopeId, int interfaceIndex) throws IOException;
372     private static native void joinSsmGroup(int fd, boolean ipv6, byte[] group, byte[] interfaceAddress,
373                                             int scopeId, int interfaceIndex, byte[] source) throws IOException;
374     private static native void leaveGroup(int fd, boolean ipv6, byte[] group, byte[] interfaceAddress,
375                                           int scopeId, int interfaceIndex) throws IOException;
376     private static native void leaveSsmGroup(int fd, boolean ipv6, byte[] group, byte[] interfaceAddress,
377                                              int scopeId, int interfaceIndex, byte[] source) throws IOException;
378     private static native long sendFile(int socketFd, DefaultFileRegion src, long baseOffset,
379                                         long offset, long length) throws IOException;
380 
381     private static native int getTcpDeferAccept(int fd) throws IOException;
382     private static native int isTcpQuickAck(int fd) throws IOException;
383     private static native int isTcpCork(int fd) throws IOException;
384     private static native int getSoBusyPoll(int fd) throws IOException;
385     private static native int getTcpNotSentLowAt(int fd) throws IOException;
386     private static native int getTcpKeepIdle(int fd) throws IOException;
387     private static native int getTcpKeepIntvl(int fd) throws IOException;
388     private static native int getTcpKeepCnt(int fd) throws IOException;
389     private static native int getTcpUserTimeout(int fd) throws IOException;
390     private static native int getTimeToLive(int fd) throws IOException;
391     private static native int isIpFreeBind(int fd) throws IOException;
392     private static native int isIpTransparent(int fd) throws IOException;
393     private static native int isIpRecvOrigDestAddr(int fd) throws IOException;
394     private static native void getTcpInfo(int fd, long[] array) throws IOException;
395     private static native PeerCredentials getPeerCredentials(int fd) throws IOException;
396 
397     private static native void setTcpDeferAccept(int fd, int deferAccept) throws IOException;
398     private static native void setTcpQuickAck(int fd, int quickAck) throws IOException;
399     private static native void setTcpCork(int fd, int tcpCork) throws IOException;
400     private static native void setSoBusyPoll(int fd, int loopMicros) throws IOException;
401     private static native void setTcpNotSentLowAt(int fd, int tcpNotSentLowAt) throws IOException;
402     private static native void setTcpFastOpen(int fd, int tcpFastopenBacklog) throws IOException;
403     private static native void setTcpKeepIdle(int fd, int seconds) throws IOException;
404     private static native void setTcpKeepIntvl(int fd, int seconds) throws IOException;
405     private static native void setTcpKeepCnt(int fd, int probes) throws IOException;
406     private static native void setTcpUserTimeout(int fd, int milliseconds)throws IOException;
407     private static native void setIpFreeBind(int fd, int freeBind) throws IOException;
408     private static native void setIpTransparent(int fd, int transparent) throws IOException;
409     private static native void setIpRecvOrigDestAddr(int fd, int transparent) throws IOException;
410     private static native void setTcpMd5Sig(
411             int fd, boolean ipv6, byte[] address, int scopeId, byte[] key) throws IOException;
412     private static native void setInterface(
413             int fd, boolean ipv6, byte[] interfaceAddress, int scopeId, int networkInterfaceIndex) throws IOException;
414     private static native int getInterface(int fd, boolean ipv6);
415     private static native int getIpMulticastLoop(int fd, boolean ipv6) throws IOException;
416     private static native void setIpMulticastLoop(int fd, boolean ipv6, int enabled) throws IOException;
417     private static native void setTimeToLive(int fd, int ttl) throws IOException;
418     private static native int isUdpGro(int fd) throws IOException;
419     private static native void setUdpGro(int fd, int gro) throws IOException;
420 }