View Javadoc
1   /*
2    * Copyright 2014 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    *   http://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.Channel;
19  import io.netty.channel.ChannelFuture;
20  import io.netty.channel.ChannelPromise;
21  import io.netty.channel.EventLoop;
22  import io.netty.channel.socket.ServerSocketChannel;
23  import io.netty.channel.socket.SocketChannel;
24  import io.netty.channel.unix.FileDescriptor;
25  import io.netty.util.concurrent.GlobalEventExecutor;
26  import io.netty.util.internal.OneTimeTask;
27  
28  import java.net.InetSocketAddress;
29  import java.net.SocketAddress;
30  import java.util.concurrent.Executor;
31  
32  /**
33   * {@link SocketChannel} implementation that uses linux EPOLL Edge-Triggered Mode for
34   * maximal performance.
35   */
36  public final class EpollSocketChannel extends AbstractEpollStreamChannel implements SocketChannel {
37  
38      private final EpollSocketChannelConfig config;
39  
40      private volatile InetSocketAddress local;
41      private volatile InetSocketAddress remote;
42  
43      EpollSocketChannel(Channel parent, int fd, InetSocketAddress remote) {
44          super(parent, fd);
45          config = new EpollSocketChannelConfig(this);
46          // Directly cache the remote and local addresses
47          // See https://github.com/netty/netty/issues/2359
48          this.remote = remote;
49          local = Native.localAddress(fd);
50      }
51  
52      public EpollSocketChannel() {
53          super(Native.socketStreamFd());
54          config = new EpollSocketChannelConfig(this);
55      }
56  
57      /**
58       * Creates a new {@link EpollSocketChannel} from an existing {@link FileDescriptor}.
59       */
60      public EpollSocketChannel(FileDescriptor fd) {
61          super(fd);
62          config = new EpollSocketChannelConfig(this);
63  
64          // As we create an EpollSocketChannel from a FileDescriptor we should try to obtain the remote and local
65          // address from it. This is needed as the FileDescriptor may be bound/connected already.
66          remote = Native.remoteAddress(fd.intValue());
67          local = Native.localAddress(fd.intValue());
68      }
69  
70      /**
71       * Returns the {@code TCP_INFO} for the current socket. See <a href="http://linux.die.net/man/7/tcp">man 7 tcp</a>.
72       */
73      public EpollTcpInfo tcpInfo() {
74          return tcpInfo(new EpollTcpInfo());
75      }
76  
77      /**
78       * Updates and returns the {@code TCP_INFO} for the current socket.
79       * See <a href="http://linux.die.net/man/7/tcp">man 7 tcp</a>.
80       */
81      public EpollTcpInfo tcpInfo(EpollTcpInfo info) {
82          Native.tcpInfo(fd().intValue(), info);
83          return info;
84      }
85  
86      @Override
87      public InetSocketAddress remoteAddress() {
88          return (InetSocketAddress) super.remoteAddress();
89      }
90  
91      @Override
92      public InetSocketAddress localAddress() {
93          return (InetSocketAddress) super.localAddress();
94      }
95  
96      @Override
97      protected SocketAddress localAddress0() {
98          return local;
99      }
100 
101     @Override
102     protected SocketAddress remoteAddress0() {
103         if (remote == null) {
104             // Remote address not know, try to get it now.
105             InetSocketAddress address = Native.remoteAddress(fd().intValue());
106             if (address != null) {
107                 remote = address;
108             }
109             return address;
110         }
111         return remote;
112     }
113 
114     @Override
115     protected void doBind(SocketAddress local) throws Exception {
116         InetSocketAddress localAddress = (InetSocketAddress) local;
117         int fd = fd().intValue();
118         Native.bind(fd, localAddress);
119         this.local = Native.localAddress(fd);
120     }
121 
122     @Override
123     public EpollSocketChannelConfig config() {
124         return config;
125     }
126 
127     @Override
128     public boolean isInputShutdown() {
129         return isInputShutdown0();
130     }
131 
132     @Override
133     public boolean isOutputShutdown() {
134         return isOutputShutdown0();
135     }
136 
137     @Override
138     public ChannelFuture shutdownOutput() {
139         return shutdownOutput(newPromise());
140     }
141 
142     @Override
143     public ChannelFuture shutdownOutput(final ChannelPromise promise) {
144         Executor closeExecutor = ((EpollSocketChannelUnsafe) unsafe()).closeExecutor();
145         if (closeExecutor != null) {
146             closeExecutor.execute(new OneTimeTask() {
147                 @Override
148                 public void run() {
149                     shutdownOutput0(promise);
150                 }
151             });
152         } else {
153             EventLoop loop = eventLoop();
154             if (loop.inEventLoop()) {
155                 shutdownOutput0(promise);
156             } else {
157                 loop.execute(new OneTimeTask() {
158                     @Override
159                     public void run() {
160                         shutdownOutput0(promise);
161                     }
162                 });
163             }
164         }
165         return promise;
166     }
167 
168     @Override
169     public ServerSocketChannel parent() {
170         return (ServerSocketChannel) super.parent();
171     }
172 
173     @Override
174     protected AbstractEpollUnsafe newUnsafe() {
175         return new EpollSocketChannelUnsafe();
176     }
177 
178     @Override
179     protected boolean doConnect(SocketAddress remoteAddress, SocketAddress localAddress) throws Exception {
180         if (localAddress != null) {
181             checkResolvable((InetSocketAddress) localAddress);
182         }
183         checkResolvable((InetSocketAddress) remoteAddress);
184         if (super.doConnect(remoteAddress, localAddress)) {
185             int fd = fd().intValue();
186             local = Native.localAddress(fd);
187             remote = (InetSocketAddress) remoteAddress;
188             return true;
189         }
190         return false;
191     }
192 
193     private final class EpollSocketChannelUnsafe extends EpollStreamUnsafe {
194         @Override
195         protected Executor closeExecutor() {
196             if (config().getSoLinger() > 0) {
197                 return GlobalEventExecutor.INSTANCE;
198             }
199             return null;
200         }
201     }
202 }