View Javadoc
1   /*
2    * Copyright 2015 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.ChannelConfig;
20  import io.netty.channel.ChannelMetadata;
21  import io.netty.channel.ChannelOutboundBuffer;
22  import io.netty.channel.ChannelPipeline;
23  import io.netty.channel.ChannelPromise;
24  import io.netty.channel.EventLoop;
25  import io.netty.channel.ServerChannel;
26  
27  import java.net.InetSocketAddress;
28  import java.net.SocketAddress;
29  
30  public abstract class AbstractEpollServerChannel extends AbstractEpollChannel implements ServerChannel {
31      private static final ChannelMetadata METADATA = new ChannelMetadata(false, 16);
32  
33      protected AbstractEpollServerChannel(int fd) {
34          this(new LinuxSocket(fd), false);
35      }
36  
37      AbstractEpollServerChannel(LinuxSocket fd) {
38          this(fd, isSoErrorZero(fd));
39      }
40  
41      AbstractEpollServerChannel(LinuxSocket fd, boolean active) {
42          super(null, fd, Native.EPOLLIN, active);
43      }
44  
45      @Override
46      public ChannelMetadata metadata() {
47          return METADATA;
48      }
49  
50      @Override
51      protected boolean isCompatible(EventLoop loop) {
52          return loop instanceof EpollEventLoop;
53      }
54  
55      @Override
56      protected InetSocketAddress remoteAddress0() {
57          return null;
58      }
59  
60      @Override
61      protected AbstractEpollUnsafe newUnsafe() {
62          return new EpollServerSocketUnsafe();
63      }
64  
65      @Override
66      protected void doWrite(ChannelOutboundBuffer in) throws Exception {
67          throw new UnsupportedOperationException();
68      }
69  
70      @Override
71      protected Object filterOutboundMessage(Object msg) throws Exception {
72          throw new UnsupportedOperationException();
73      }
74  
75      abstract Channel newChildChannel(int fd, byte[] remote, int offset, int len) throws Exception;
76  
77      final class EpollServerSocketUnsafe extends AbstractEpollUnsafe {
78          // Will hold the remote address after accept(...) was successful.
79          // We need 24 bytes for the address as maximum + 1 byte for storing the length.
80          // So use 26 bytes as it's a power of two.
81          private final byte[] acceptedAddress = new byte[26];
82  
83          @Override
84          public void connect(SocketAddress socketAddress, SocketAddress socketAddress2, ChannelPromise channelPromise) {
85              // Connect not supported by ServerChannel implementations
86              channelPromise.setFailure(new UnsupportedOperationException());
87          }
88  
89          @Override
90          void epollInReady() {
91              assert eventLoop().inEventLoop();
92              final ChannelConfig config = config();
93              if (shouldBreakEpollInReady(config)) {
94                  clearEpollIn0();
95                  return;
96              }
97              final EpollRecvByteAllocatorHandle allocHandle = recvBufAllocHandle();
98              allocHandle.edgeTriggered(isFlagSet(Native.EPOLLET));
99  
100             final ChannelPipeline pipeline = pipeline();
101             allocHandle.reset(config);
102             allocHandle.attemptedBytesRead(1);
103             epollInBefore();
104 
105             Throwable exception = null;
106             try {
107                 try {
108                     do {
109                         // lastBytesRead represents the fd. We use lastBytesRead because it must be set so that the
110                         // EpollRecvByteAllocatorHandle knows if it should try to read again or not when autoRead is
111                         // enabled.
112                         allocHandle.lastBytesRead(socket.accept(acceptedAddress));
113                         if (allocHandle.lastBytesRead() == -1) {
114                             // this means everything was handled for now
115                             break;
116                         }
117                         allocHandle.incMessagesRead(1);
118 
119                         readPending = false;
120                         pipeline.fireChannelRead(newChildChannel(allocHandle.lastBytesRead(), acceptedAddress, 1,
121                                                                  acceptedAddress[0]));
122                     } while (allocHandle.continueReading());
123                 } catch (Throwable t) {
124                     exception = t;
125                 }
126                 allocHandle.readComplete();
127                 pipeline.fireChannelReadComplete();
128 
129                 if (exception != null) {
130                     pipeline.fireExceptionCaught(exception);
131                 }
132             } finally {
133                 epollInFinally(config);
134             }
135         }
136     }
137 
138     @Override
139     protected boolean doConnect(SocketAddress remoteAddress, SocketAddress localAddress) throws Exception {
140         throw new UnsupportedOperationException();
141     }
142 }