1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  *   http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 package org.apache.thrift.transport;
21 
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
24 
25 import java.io.IOException;
26 import java.net.InetSocketAddress;
27 import java.net.ServerSocket;
28 import java.net.Socket;
29 import java.net.SocketException;
30 
31 /**
32  * Wrapper around ServerSocket for Thrift.
33  *
34  */
35 public class TServerSocket extends TServerTransport {
36 
37   private static final Logger LOGGER = LoggerFactory.getLogger(TServerSocket.class.getName());
38 
39   /**
40    * Underlying ServerSocket object
41    */
42   private ServerSocket serverSocket_ = null;
43 
44   /**
45    * Timeout for client sockets from accept
46    */
47   private int clientTimeout_ = 0;
48 
49   public static class ServerSocketTransportArgs extends AbstractServerTransportArgs<ServerSocketTransportArgs> {
50     ServerSocket serverSocket;
51 
serverSocket(ServerSocket serverSocket)52     public ServerSocketTransportArgs serverSocket(ServerSocket serverSocket) {
53       this.serverSocket = serverSocket;
54       return this;
55     }
56   }
57 
58   /**
59    * Creates a server socket from underlying socket object
60    */
TServerSocket(ServerSocket serverSocket)61   public TServerSocket(ServerSocket serverSocket) throws TTransportException {
62     this(serverSocket, 0);
63   }
64 
65   /**
66    * Creates a server socket from underlying socket object
67    */
TServerSocket(ServerSocket serverSocket, int clientTimeout)68   public TServerSocket(ServerSocket serverSocket, int clientTimeout) throws TTransportException {
69     this(new ServerSocketTransportArgs().serverSocket(serverSocket).clientTimeout(clientTimeout));
70   }
71 
72   /**
73    * Creates just a port listening server socket
74    */
TServerSocket(int port)75   public TServerSocket(int port) throws TTransportException {
76     this(port, 0);
77   }
78 
79   /**
80    * Creates just a port listening server socket
81    */
TServerSocket(int port, int clientTimeout)82   public TServerSocket(int port, int clientTimeout) throws TTransportException {
83     this(new InetSocketAddress(port), clientTimeout);
84   }
85 
TServerSocket(InetSocketAddress bindAddr)86   public TServerSocket(InetSocketAddress bindAddr) throws TTransportException {
87     this(bindAddr, 0);
88   }
89 
TServerSocket(InetSocketAddress bindAddr, int clientTimeout)90   public TServerSocket(InetSocketAddress bindAddr, int clientTimeout) throws TTransportException {
91     this(new ServerSocketTransportArgs().bindAddr(bindAddr).clientTimeout(clientTimeout));
92   }
93 
TServerSocket(ServerSocketTransportArgs args)94   public TServerSocket(ServerSocketTransportArgs args) throws TTransportException {
95     clientTimeout_ = args.clientTimeout;
96     if (args.serverSocket != null) {
97       this.serverSocket_ = args.serverSocket;
98       return;
99     }
100     try {
101       // Make server socket
102       serverSocket_ = new ServerSocket();
103       // Prevent 2MSL delay problem on server restarts
104       serverSocket_.setReuseAddress(true);
105       // Bind to listening port
106       serverSocket_.bind(args.bindAddr, args.backlog);
107     } catch (IOException ioe) {
108       close();
109       throw new TTransportException("Could not create ServerSocket on address " + args.bindAddr.toString() + ".", ioe);
110     }
111   }
112 
listen()113   public void listen() throws TTransportException {
114     // Make sure to block on accept
115     if (serverSocket_ != null) {
116       try {
117         serverSocket_.setSoTimeout(0);
118       } catch (SocketException sx) {
119         LOGGER.error("Could not set socket timeout.", sx);
120       }
121     }
122   }
123 
124   @Override
accept()125   public TSocket accept() throws TTransportException {
126     if (serverSocket_ == null) {
127       throw new TTransportException(TTransportException.NOT_OPEN, "No underlying server socket.");
128     }
129     Socket result;
130     try {
131       result = serverSocket_.accept();
132     } catch (Exception e) {
133       throw new TTransportException(e);
134     }
135     if (result == null) {
136       throw new TTransportException("Blocking server's accept() may not return NULL");
137     }
138     TSocket socket = new TSocket(result);
139     socket.setTimeout(clientTimeout_);
140     return socket;
141   }
142 
close()143   public void close() {
144     if (serverSocket_ != null) {
145       try {
146         serverSocket_.close();
147       } catch (IOException iox) {
148         LOGGER.warn("Could not close server socket.", iox);
149       }
150       serverSocket_ = null;
151     }
152   }
153 
interrupt()154   public void interrupt() {
155     // The thread-safeness of this is dubious, but Java documentation suggests
156     // that it is safe to do this from a different thread context
157     close();
158   }
159 
getServerSocket()160   public ServerSocket getServerSocket() {
161     return serverSocket_;
162   }
163 }
164