blob: c4a7f7c22076c8c8a5e157e63078c4d7e2747d55 [file] [log] [blame]
David Reissea2cba82009-03-30 21:35:00 +00001/*
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 */
Mark Slee9f0c6512007-02-28 23:58:26 +000019
Roger Meier2fa9c312011-09-05 19:15:53 +000020#ifdef HAVE_CONFIG_H
21#include <config.h>
22#endif
David Reissc88eb8c2008-06-11 01:18:54 +000023#include <cstring>
David Reiss08d2f112009-05-21 02:28:36 +000024#include <sys/types.h>
Roger Meier2fa9c312011-09-05 19:15:53 +000025#ifdef HAVE_SYS_SOCKET_H
Mark Sleee8540632006-05-30 09:24:40 +000026#include <sys/socket.h>
Roger Meier2fa9c312011-09-05 19:15:53 +000027#endif
28#ifdef HAVE_SYS_UN_H
Bryan Duxburya18364a2010-09-28 14:36:07 +000029#include <sys/un.h>
Roger Meier2fa9c312011-09-05 19:15:53 +000030#endif
31#ifdef HAVE_SYS_POLL_H
David Reiss1677ac92008-04-08 06:26:27 +000032#include <sys/poll.h>
Roger Meier2fa9c312011-09-05 19:15:53 +000033#endif
34#ifdef HAVE_NETINET_IN_H
Mark Sleee8540632006-05-30 09:24:40 +000035#include <netinet/in.h>
Mark Slee29050782006-09-29 00:12:30 +000036#include <netinet/tcp.h>
Roger Meier2fa9c312011-09-05 19:15:53 +000037#endif
38#ifdef HAVE_NETDB_H
Mark Slee6d56eb92007-07-06 22:28:15 +000039#include <netdb.h>
Roger Meier2fa9c312011-09-05 19:15:53 +000040#endif
Mark Sleea5a783f2007-03-02 19:41:08 +000041#include <fcntl.h>
Mark Slee8d7e1f62006-06-07 06:48:56 +000042#include <errno.h>
Roger Meier2fa9c312011-09-05 19:15:53 +000043#ifdef HAVE_UNISTD_H
David Reiss5105b2e2009-05-21 02:28:27 +000044#include <unistd.h>
Roger Meier2fa9c312011-09-05 19:15:53 +000045#endif
Mark Sleee8540632006-05-30 09:24:40 +000046
Marc Slemkod42a2c22006-08-10 03:30:18 +000047#include "TSocket.h"
48#include "TServerSocket.h"
Marc Slemko16698852006-08-04 03:16:10 +000049#include <boost/shared_ptr.hpp>
Mark Sleee8540632006-05-30 09:24:40 +000050
David Reiss9b903442009-10-21 05:51:28 +000051#ifndef AF_LOCAL
52#define AF_LOCAL AF_UNIX
53#endif
54
Roger Meier84e4a3c2011-09-16 20:58:44 +000055#ifndef SOCKOPT_CAST_T
56# ifndef _WIN32
57# define SOCKOPT_CAST_T void
58# else
59# define SOCKOPT_CAST_T char
60# endif // _WIN32
61#endif
62
63template<class T>
64inline const SOCKOPT_CAST_T* const_cast_sockopt(const T* v) {
65 return reinterpret_cast<const SOCKOPT_CAST_T*>(v);
66}
67
68template<class T>
69inline SOCKOPT_CAST_T* cast_sockopt(T* v) {
70 return reinterpret_cast<SOCKOPT_CAST_T*>(v);
71}
72
T Jake Lucianib5e62212009-01-31 22:36:20 +000073namespace apache { namespace thrift { namespace transport {
Marc Slemko6f038a72006-08-03 18:58:09 +000074
Martin Kraemere6c4fa62007-07-09 19:08:25 +000075using namespace std;
David Reissd4a269c2007-08-23 02:37:19 +000076using boost::shared_ptr;
Marc Slemko16698852006-08-04 03:16:10 +000077
Mark Sleee8540632006-05-30 09:24:40 +000078TServerSocket::TServerSocket(int port) :
Mark Slee29050782006-09-29 00:12:30 +000079 port_(port),
Martin Kraemeree341cb2007-02-05 21:40:38 +000080 serverSocket_(-1),
Mark Slee29050782006-09-29 00:12:30 +000081 acceptBacklog_(1024),
82 sendTimeout_(0),
Mark Sleea5a783f2007-03-02 19:41:08 +000083 recvTimeout_(0),
Jake Farrell32e7b2c2011-09-14 06:19:10 +000084 accTimeout_(-1),
boz1ea81ce2007-05-14 23:04:33 +000085 retryLimit_(0),
86 retryDelay_(0),
Christopher Piro9cc63b52008-03-21 00:40:42 +000087 tcpSendBuffer_(0),
88 tcpRecvBuffer_(0),
Mark Slee561b5362007-03-09 19:26:29 +000089 intSock1_(-1),
90 intSock2_(-1) {}
Mark Slee29050782006-09-29 00:12:30 +000091
92TServerSocket::TServerSocket(int port, int sendTimeout, int recvTimeout) :
93 port_(port),
Martin Kraemeree341cb2007-02-05 21:40:38 +000094 serverSocket_(-1),
Mark Slee29050782006-09-29 00:12:30 +000095 acceptBacklog_(1024),
96 sendTimeout_(sendTimeout),
Mark Sleea5a783f2007-03-02 19:41:08 +000097 recvTimeout_(recvTimeout),
Jake Farrell32e7b2c2011-09-14 06:19:10 +000098 accTimeout_(-1),
boz1ea81ce2007-05-14 23:04:33 +000099 retryLimit_(0),
100 retryDelay_(0),
Christopher Piro9cc63b52008-03-21 00:40:42 +0000101 tcpSendBuffer_(0),
102 tcpRecvBuffer_(0),
Mark Slee561b5362007-03-09 19:26:29 +0000103 intSock1_(-1),
104 intSock2_(-1) {}
Mark Sleee8540632006-05-30 09:24:40 +0000105
Bryan Duxburya18364a2010-09-28 14:36:07 +0000106TServerSocket::TServerSocket(string path) :
107 port_(0),
108 path_(path),
109 serverSocket_(-1),
110 acceptBacklog_(1024),
111 sendTimeout_(0),
112 recvTimeout_(0),
Roger Meier17b84692011-11-04 11:55:49 +0000113 accTimeout_(-1),
Bryan Duxburya18364a2010-09-28 14:36:07 +0000114 retryLimit_(0),
115 retryDelay_(0),
116 tcpSendBuffer_(0),
117 tcpRecvBuffer_(0),
118 intSock1_(-1),
119 intSock2_(-1) {}
120
Mark Sleee8540632006-05-30 09:24:40 +0000121TServerSocket::~TServerSocket() {
122 close();
123}
124
Mark Slee29050782006-09-29 00:12:30 +0000125void TServerSocket::setSendTimeout(int sendTimeout) {
126 sendTimeout_ = sendTimeout;
127}
128
129void TServerSocket::setRecvTimeout(int recvTimeout) {
130 recvTimeout_ = recvTimeout;
131}
132
Jake Farrell32e7b2c2011-09-14 06:19:10 +0000133void TServerSocket::setAcceptTimeout(int accTimeout) {
134 accTimeout_ = accTimeout;
135}
136
boz1ea81ce2007-05-14 23:04:33 +0000137void TServerSocket::setRetryLimit(int retryLimit) {
138 retryLimit_ = retryLimit;
139}
140
141void TServerSocket::setRetryDelay(int retryDelay) {
142 retryDelay_ = retryDelay;
143}
144
Christopher Piro9cc63b52008-03-21 00:40:42 +0000145void TServerSocket::setTcpSendBuffer(int tcpSendBuffer) {
146 tcpSendBuffer_ = tcpSendBuffer;
147}
148
149void TServerSocket::setTcpRecvBuffer(int tcpRecvBuffer) {
150 tcpRecvBuffer_ = tcpRecvBuffer;
151}
152
Mark Slee8d7e1f62006-06-07 06:48:56 +0000153void TServerSocket::listen() {
Mark Slee561b5362007-03-09 19:26:29 +0000154 int sv[2];
155 if (-1 == socketpair(AF_LOCAL, SOCK_STREAM, 0, sv)) {
David Reiss01e55c12008-07-13 22:18:51 +0000156 GlobalOutput.perror("TServerSocket::listen() socketpair() ", errno);
Mark Slee561b5362007-03-09 19:26:29 +0000157 intSock1_ = -1;
158 intSock2_ = -1;
159 } else {
Mark Sleee02385b2007-06-09 01:21:16 +0000160 intSock1_ = sv[1];
161 intSock2_ = sv[0];
Mark Slee561b5362007-03-09 19:26:29 +0000162 }
163
Mark Slee6d56eb92007-07-06 22:28:15 +0000164 struct addrinfo hints, *res, *res0;
165 int error;
166 char port[sizeof("65536") + 1];
David Reissc88eb8c2008-06-11 01:18:54 +0000167 std::memset(&hints, 0, sizeof(hints));
Mark Slee6d56eb92007-07-06 22:28:15 +0000168 hints.ai_family = PF_UNSPEC;
169 hints.ai_socktype = SOCK_STREAM;
Mark Slee256bdc42007-11-27 08:42:19 +0000170 hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
Mark Slee6d56eb92007-07-06 22:28:15 +0000171 sprintf(port, "%d", port_);
172
173 // Wildcard address
174 error = getaddrinfo(NULL, port, &hints, &res0);
175 if (error) {
David Reiss01e55c12008-07-13 22:18:51 +0000176 GlobalOutput.printf("getaddrinfo %d: %s", error, gai_strerror(error));
Mark Slee6d56eb92007-07-06 22:28:15 +0000177 close();
178 throw TTransportException(TTransportException::NOT_OPEN, "Could not resolve host for server socket.");
179 }
180
181 // Pick the ipv6 address first since ipv4 addresses can be mapped
182 // into ipv6 space.
183 for (res = res0; res; res = res->ai_next) {
184 if (res->ai_family == AF_INET6 || res->ai_next == NULL)
185 break;
186 }
Mark Slee256bdc42007-11-27 08:42:19 +0000187
Bryan Duxburya18364a2010-09-28 14:36:07 +0000188 if (! path_.empty()) {
189 serverSocket_ = socket(PF_UNIX, SOCK_STREAM, IPPROTO_IP);
190 } else {
191 serverSocket_ = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
192 }
193
Mark Sleee8540632006-05-30 09:24:40 +0000194 if (serverSocket_ == -1) {
David Reiss9b209552008-04-08 06:26:05 +0000195 int errno_copy = errno;
David Reiss01e55c12008-07-13 22:18:51 +0000196 GlobalOutput.perror("TServerSocket::listen() socket() ", errno_copy);
Mark Sleee8540632006-05-30 09:24:40 +0000197 close();
David Reiss9b209552008-04-08 06:26:05 +0000198 throw TTransportException(TTransportException::NOT_OPEN, "Could not create server socket.", errno_copy);
Mark Sleee8540632006-05-30 09:24:40 +0000199 }
200
201 // Set reusaddress to prevent 2MSL delay on accept
202 int one = 1;
203 if (-1 == setsockopt(serverSocket_, SOL_SOCKET, SO_REUSEADDR,
Roger Meier84e4a3c2011-09-16 20:58:44 +0000204 cast_sockopt(&one), sizeof(one))) {
David Reiss9b209552008-04-08 06:26:05 +0000205 int errno_copy = errno;
David Reiss01e55c12008-07-13 22:18:51 +0000206 GlobalOutput.perror("TServerSocket::listen() setsockopt() SO_REUSEADDR ", errno_copy);
Mark Sleee8540632006-05-30 09:24:40 +0000207 close();
David Reiss9b209552008-04-08 06:26:05 +0000208 throw TTransportException(TTransportException::NOT_OPEN, "Could not set SO_REUSEADDR", errno_copy);
Mark Sleee8540632006-05-30 09:24:40 +0000209 }
210
Christopher Piro9cc63b52008-03-21 00:40:42 +0000211 // Set TCP buffer sizes
212 if (tcpSendBuffer_ > 0) {
213 if (-1 == setsockopt(serverSocket_, SOL_SOCKET, SO_SNDBUF,
Roger Meier84e4a3c2011-09-16 20:58:44 +0000214 cast_sockopt(&tcpSendBuffer_), sizeof(tcpSendBuffer_))) {
David Reiss9b209552008-04-08 06:26:05 +0000215 int errno_copy = errno;
David Reiss01e55c12008-07-13 22:18:51 +0000216 GlobalOutput.perror("TServerSocket::listen() setsockopt() SO_SNDBUF ", errno_copy);
Christopher Piro9cc63b52008-03-21 00:40:42 +0000217 close();
David Reiss9b209552008-04-08 06:26:05 +0000218 throw TTransportException(TTransportException::NOT_OPEN, "Could not set SO_SNDBUF", errno_copy);
Christopher Piro9cc63b52008-03-21 00:40:42 +0000219 }
220 }
221
222 if (tcpRecvBuffer_ > 0) {
223 if (-1 == setsockopt(serverSocket_, SOL_SOCKET, SO_RCVBUF,
Roger Meier84e4a3c2011-09-16 20:58:44 +0000224 cast_sockopt(&tcpRecvBuffer_), sizeof(tcpRecvBuffer_))) {
David Reiss9b209552008-04-08 06:26:05 +0000225 int errno_copy = errno;
David Reiss01e55c12008-07-13 22:18:51 +0000226 GlobalOutput.perror("TServerSocket::listen() setsockopt() SO_RCVBUF ", errno_copy);
Christopher Piro9cc63b52008-03-21 00:40:42 +0000227 close();
David Reiss9b209552008-04-08 06:26:05 +0000228 throw TTransportException(TTransportException::NOT_OPEN, "Could not set SO_RCVBUF", errno_copy);
Christopher Piro9cc63b52008-03-21 00:40:42 +0000229 }
230 }
231
Mark Slee29050782006-09-29 00:12:30 +0000232 // Defer accept
233 #ifdef TCP_DEFER_ACCEPT
234 if (-1 == setsockopt(serverSocket_, SOL_SOCKET, TCP_DEFER_ACCEPT,
235 &one, sizeof(one))) {
David Reiss9b209552008-04-08 06:26:05 +0000236 int errno_copy = errno;
David Reiss01e55c12008-07-13 22:18:51 +0000237 GlobalOutput.perror("TServerSocket::listen() setsockopt() TCP_DEFER_ACCEPT ", errno_copy);
Mark Slee29050782006-09-29 00:12:30 +0000238 close();
David Reiss9b209552008-04-08 06:26:05 +0000239 throw TTransportException(TTransportException::NOT_OPEN, "Could not set TCP_DEFER_ACCEPT", errno_copy);
Mark Slee29050782006-09-29 00:12:30 +0000240 }
241 #endif // #ifdef TCP_DEFER_ACCEPT
242
David Reiss13aea462008-06-10 22:56:04 +0000243 #ifdef IPV6_V6ONLY
Roger Meier18f10502011-06-04 08:57:43 +0000244 if (res->ai_family == AF_INET6 && path_.empty()) {
David Reisseee98be2010-03-09 05:20:10 +0000245 int zero = 0;
246 if (-1 == setsockopt(serverSocket_, IPPROTO_IPV6, IPV6_V6ONLY,
Roger Meier84e4a3c2011-09-16 20:58:44 +0000247 cast_sockopt(&zero), sizeof(zero))) {
David Reisseee98be2010-03-09 05:20:10 +0000248 GlobalOutput.perror("TServerSocket::listen() IPV6_V6ONLY ", errno);
249 }
David Reiss13aea462008-06-10 22:56:04 +0000250 }
251 #endif // #ifdef IPV6_V6ONLY
252
Mark Sleee8540632006-05-30 09:24:40 +0000253 // Turn linger off, don't want to block on calls to close
254 struct linger ling = {0, 0};
255 if (-1 == setsockopt(serverSocket_, SOL_SOCKET, SO_LINGER,
Roger Meier84e4a3c2011-09-16 20:58:44 +0000256 cast_sockopt(&ling), sizeof(ling))) {
David Reiss9b209552008-04-08 06:26:05 +0000257 int errno_copy = errno;
David Reiss01e55c12008-07-13 22:18:51 +0000258 GlobalOutput.perror("TServerSocket::listen() setsockopt() SO_LINGER ", errno_copy);
Mark Sleee8540632006-05-30 09:24:40 +0000259 close();
David Reiss9b209552008-04-08 06:26:05 +0000260 throw TTransportException(TTransportException::NOT_OPEN, "Could not set SO_LINGER", errno_copy);
Mark Sleee8540632006-05-30 09:24:40 +0000261 }
262
Bryan Duxburya18364a2010-09-28 14:36:07 +0000263 // Unix Sockets do not need that
264 if (path_.empty()) {
265 // TCP Nodelay, speed over bandwidth
266 if (-1 == setsockopt(serverSocket_, IPPROTO_TCP, TCP_NODELAY,
Roger Meier84e4a3c2011-09-16 20:58:44 +0000267 cast_sockopt(&one), sizeof(one))) {
Bryan Duxburya18364a2010-09-28 14:36:07 +0000268 int errno_copy = errno;
269 GlobalOutput.perror("TServerSocket::listen() setsockopt() TCP_NODELAY ", errno_copy);
270 close();
271 throw TTransportException(TTransportException::NOT_OPEN, "Could not set TCP_NODELAY", errno_copy);
272 }
Mark Slee29050782006-09-29 00:12:30 +0000273 }
274
Mark Sleea5a783f2007-03-02 19:41:08 +0000275 // Set NONBLOCK on the accept socket
276 int flags = fcntl(serverSocket_, F_GETFL, 0);
277 if (flags == -1) {
David Reiss9b209552008-04-08 06:26:05 +0000278 int errno_copy = errno;
David Reiss01e55c12008-07-13 22:18:51 +0000279 GlobalOutput.perror("TServerSocket::listen() fcntl() F_GETFL ", errno_copy);
David Reiss9b209552008-04-08 06:26:05 +0000280 throw TTransportException(TTransportException::NOT_OPEN, "fcntl() failed", errno_copy);
Mark Sleea5a783f2007-03-02 19:41:08 +0000281 }
Mark Slee561b5362007-03-09 19:26:29 +0000282
Mark Sleea5a783f2007-03-02 19:41:08 +0000283 if (-1 == fcntl(serverSocket_, F_SETFL, flags | O_NONBLOCK)) {
David Reiss9b209552008-04-08 06:26:05 +0000284 int errno_copy = errno;
David Reiss01e55c12008-07-13 22:18:51 +0000285 GlobalOutput.perror("TServerSocket::listen() fcntl() O_NONBLOCK ", errno_copy);
David Reiss9b209552008-04-08 06:26:05 +0000286 throw TTransportException(TTransportException::NOT_OPEN, "fcntl() failed", errno_copy);
Mark Sleea5a783f2007-03-02 19:41:08 +0000287 }
288
boz1ea81ce2007-05-14 23:04:33 +0000289 // prepare the port information
Mark Slee256bdc42007-11-27 08:42:19 +0000290 // we may want to try to bind more than once, since SO_REUSEADDR doesn't
boz1ea81ce2007-05-14 23:04:33 +0000291 // always seem to work. The client can configure the retry variables.
292 int retries = 0;
Bryan Duxburya18364a2010-09-28 14:36:07 +0000293
294 if (! path_.empty()) {
Roger Meier84e4a3c2011-09-16 20:58:44 +0000295
296#ifndef _WIN32
297
Bryan Duxburya18364a2010-09-28 14:36:07 +0000298 // Unix Domain Socket
299 struct sockaddr_un address;
300 socklen_t len;
301
302 if (path_.length() > sizeof(address.sun_path)) {
303 int errno_copy = errno;
304 GlobalOutput.perror("TSocket::listen() Unix Domain socket path too long", errno_copy);
305 throw TTransportException(TTransportException::NOT_OPEN, " Unix Domain socket path too long");
boz1ea81ce2007-05-14 23:04:33 +0000306 }
307
Bryan Duxburya18364a2010-09-28 14:36:07 +0000308 address.sun_family = AF_UNIX;
Roger Meierd11ca5a2010-10-18 08:22:57 +0000309 snprintf(address.sun_path, sizeof(address.sun_path), "%s", path_.c_str());
Bryan Duxburya18364a2010-09-28 14:36:07 +0000310 len = sizeof(address);
boz1ea81ce2007-05-14 23:04:33 +0000311
Bryan Duxburya18364a2010-09-28 14:36:07 +0000312 do {
313 if (0 == bind(serverSocket_, (struct sockaddr *) &address, len)) {
314 break;
315 }
316 // use short circuit evaluation here to only sleep if we need to
317 } while ((retries++ < retryLimit_) && (sleep(retryDelay_) == 0));
318 } else {
319 do {
320 if (0 == bind(serverSocket_, res->ai_addr, res->ai_addrlen)) {
321 break;
322 }
323 // use short circuit evaluation here to only sleep if we need to
324 } while ((retries++ < retryLimit_) && (sleep(retryDelay_) == 0));
325
326 // free addrinfo
327 freeaddrinfo(res0);
Roger Meier84e4a3c2011-09-16 20:58:44 +0000328
329#else
330 GlobalOutput.perror("TSocket::open() Unix Domain socket path not supported on windows", -99);
331 throw TTransportException(TTransportException::NOT_OPEN, " Unix Domain socket path not supported");
332#endif
333
Bryan Duxburya18364a2010-09-28 14:36:07 +0000334 }
Mark Slee256bdc42007-11-27 08:42:19 +0000335
boz1ea81ce2007-05-14 23:04:33 +0000336 // throw an error if we failed to bind properly
337 if (retries > retryLimit_) {
Mark Sleee8540632006-05-30 09:24:40 +0000338 char errbuf[1024];
Bryan Duxburya18364a2010-09-28 14:36:07 +0000339 if (! path_.empty()) {
340 sprintf(errbuf, "TServerSocket::listen() PATH %s", path_.c_str());
341 }
342 else {
343 sprintf(errbuf, "TServerSocket::listen() BIND %d", port_);
344 }
boz6ded7752007-06-05 22:41:18 +0000345 GlobalOutput(errbuf);
Mark Sleee8540632006-05-30 09:24:40 +0000346 close();
Mark Sleef9831082007-02-20 20:59:21 +0000347 throw TTransportException(TTransportException::NOT_OPEN, "Could not bind");
Mark Sleee8540632006-05-30 09:24:40 +0000348 }
349
350 // Call listen
351 if (-1 == ::listen(serverSocket_, acceptBacklog_)) {
David Reiss9b209552008-04-08 06:26:05 +0000352 int errno_copy = errno;
David Reiss01e55c12008-07-13 22:18:51 +0000353 GlobalOutput.perror("TServerSocket::listen() listen() ", errno_copy);
Mark Sleee8540632006-05-30 09:24:40 +0000354 close();
David Reiss9b209552008-04-08 06:26:05 +0000355 throw TTransportException(TTransportException::NOT_OPEN, "Could not listen", errno_copy);
Mark Sleee8540632006-05-30 09:24:40 +0000356 }
357
358 // The socket is now listening!
Mark Sleee8540632006-05-30 09:24:40 +0000359}
360
Marc Slemko16698852006-08-04 03:16:10 +0000361shared_ptr<TTransport> TServerSocket::acceptImpl() {
Martin Kraemer10640d82007-02-03 01:59:12 +0000362 if (serverSocket_ < 0) {
Mark Sleef9831082007-02-20 20:59:21 +0000363 throw TTransportException(TTransportException::NOT_OPEN, "TServerSocket not listening");
Mark Sleee8540632006-05-30 09:24:40 +0000364 }
365
David Reiss1677ac92008-04-08 06:26:27 +0000366 struct pollfd fds[2];
Mark Sleea5a783f2007-03-02 19:41:08 +0000367
Aditya Agarwal7859a572007-05-31 01:33:07 +0000368 int maxEintrs = 5;
369 int numEintrs = 0;
370
Mark Sleea5a783f2007-03-02 19:41:08 +0000371 while (true) {
David Reissc88eb8c2008-06-11 01:18:54 +0000372 std::memset(fds, 0 , sizeof(fds));
David Reiss1677ac92008-04-08 06:26:27 +0000373 fds[0].fd = serverSocket_;
374 fds[0].events = POLLIN;
Mark Slee561b5362007-03-09 19:26:29 +0000375 if (intSock2_ >= 0) {
David Reiss1677ac92008-04-08 06:26:27 +0000376 fds[1].fd = intSock2_;
David Reiss2724c7a2008-04-18 17:48:03 +0000377 fds[1].events = POLLIN;
Mark Sleea5a783f2007-03-02 19:41:08 +0000378 }
Jake Farrell32e7b2c2011-09-14 06:19:10 +0000379 /*
380 TODO: if EINTR is received, we'll restart the timeout.
381 To be accurate, we need to fix this in the future.
382 */
383 int ret = poll(fds, 2, accTimeout_);
Mark Sleea5a783f2007-03-02 19:41:08 +0000384
Mark Slee561b5362007-03-09 19:26:29 +0000385 if (ret < 0) {
Aditya Agarwal7859a572007-05-31 01:33:07 +0000386 // error cases
bozf83c9db2007-05-31 23:38:37 +0000387 if (errno == EINTR && (numEintrs++ < maxEintrs)) {
Mark Slee256bdc42007-11-27 08:42:19 +0000388 // EINTR needs to be handled manually and we can tolerate
Aditya Agarwal7859a572007-05-31 01:33:07 +0000389 // a certain number
390 continue;
391 }
David Reiss9b209552008-04-08 06:26:05 +0000392 int errno_copy = errno;
David Reiss01e55c12008-07-13 22:18:51 +0000393 GlobalOutput.perror("TServerSocket::acceptImpl() poll() ", errno_copy);
David Reiss9b209552008-04-08 06:26:05 +0000394 throw TTransportException(TTransportException::UNKNOWN, "Unknown", errno_copy);
Mark Slee561b5362007-03-09 19:26:29 +0000395 } else if (ret > 0) {
396 // Check for an interrupt signal
David Reiss1677ac92008-04-08 06:26:27 +0000397 if (intSock2_ >= 0 && (fds[1].revents & POLLIN)) {
Mark Slee561b5362007-03-09 19:26:29 +0000398 int8_t buf;
Roger Meier84e4a3c2011-09-16 20:58:44 +0000399 if (-1 == recv(intSock2_, cast_sockopt(&buf), sizeof(int8_t), 0)) {
David Reiss01e55c12008-07-13 22:18:51 +0000400 GlobalOutput.perror("TServerSocket::acceptImpl() recv() interrupt ", errno);
Mark Slee561b5362007-03-09 19:26:29 +0000401 }
402 throw TTransportException(TTransportException::INTERRUPTED);
403 }
David Reiss9b209552008-04-08 06:26:05 +0000404
Mark Slee561b5362007-03-09 19:26:29 +0000405 // Check for the actual server socket being ready
David Reiss1677ac92008-04-08 06:26:27 +0000406 if (fds[0].revents & POLLIN) {
Mark Slee561b5362007-03-09 19:26:29 +0000407 break;
408 }
409 } else {
David Reiss1677ac92008-04-08 06:26:27 +0000410 GlobalOutput("TServerSocket::acceptImpl() poll 0");
Mark Slee256bdc42007-11-27 08:42:19 +0000411 throw TTransportException(TTransportException::UNKNOWN);
Mark Sleea5a783f2007-03-02 19:41:08 +0000412 }
413 }
414
Mark Slee6d56eb92007-07-06 22:28:15 +0000415 struct sockaddr_storage clientAddress;
Mark Sleee8540632006-05-30 09:24:40 +0000416 int size = sizeof(clientAddress);
417 int clientSocket = ::accept(serverSocket_,
418 (struct sockaddr *) &clientAddress,
419 (socklen_t *) &size);
Mark Slee256bdc42007-11-27 08:42:19 +0000420
Martin Kraemeree341cb2007-02-05 21:40:38 +0000421 if (clientSocket < 0) {
David Reissbc3dddb2007-08-22 23:20:24 +0000422 int errno_copy = errno;
David Reiss01e55c12008-07-13 22:18:51 +0000423 GlobalOutput.perror("TServerSocket::acceptImpl() ::accept() ", errno_copy);
David Reissbc3dddb2007-08-22 23:20:24 +0000424 throw TTransportException(TTransportException::UNKNOWN, "accept()", errno_copy);
Mark Sleee8540632006-05-30 09:24:40 +0000425 }
Mark Sleea5a783f2007-03-02 19:41:08 +0000426
427 // Make sure client socket is blocking
428 int flags = fcntl(clientSocket, F_GETFL, 0);
429 if (flags == -1) {
David Reissbc3dddb2007-08-22 23:20:24 +0000430 int errno_copy = errno;
David Reiss01e55c12008-07-13 22:18:51 +0000431 GlobalOutput.perror("TServerSocket::acceptImpl() fcntl() F_GETFL ", errno_copy);
David Reissbc3dddb2007-08-22 23:20:24 +0000432 throw TTransportException(TTransportException::UNKNOWN, "fcntl(F_GETFL)", errno_copy);
Mark Sleea5a783f2007-03-02 19:41:08 +0000433 }
David Reiss9b209552008-04-08 06:26:05 +0000434
Mark Sleea5a783f2007-03-02 19:41:08 +0000435 if (-1 == fcntl(clientSocket, F_SETFL, flags & ~O_NONBLOCK)) {
David Reissbc3dddb2007-08-22 23:20:24 +0000436 int errno_copy = errno;
David Reiss01e55c12008-07-13 22:18:51 +0000437 GlobalOutput.perror("TServerSocket::acceptImpl() fcntl() F_SETFL ~O_NONBLOCK ", errno_copy);
David Reissbc3dddb2007-08-22 23:20:24 +0000438 throw TTransportException(TTransportException::UNKNOWN, "fcntl(F_SETFL)", errno_copy);
Mark Sleea5a783f2007-03-02 19:41:08 +0000439 }
Mark Slee256bdc42007-11-27 08:42:19 +0000440
Bryan Duxburycd9aea12011-02-22 18:12:06 +0000441 shared_ptr<TSocket> client = createSocket(clientSocket);
Mark Slee29050782006-09-29 00:12:30 +0000442 if (sendTimeout_ > 0) {
443 client->setSendTimeout(sendTimeout_);
444 }
445 if (recvTimeout_ > 0) {
446 client->setRecvTimeout(recvTimeout_);
Mark Sleea5a783f2007-03-02 19:41:08 +0000447 }
David Reiss23248712010-10-06 17:10:08 +0000448 client->setCachedAddress((sockaddr*) &clientAddress, size);
449
Mark Slee29050782006-09-29 00:12:30 +0000450 return client;
Mark Sleee8540632006-05-30 09:24:40 +0000451}
452
Bryan Duxburycd9aea12011-02-22 18:12:06 +0000453shared_ptr<TSocket> TServerSocket::createSocket(int clientSocket) {
454 return shared_ptr<TSocket>(new TSocket(clientSocket));
455}
456
Mark Slee561b5362007-03-09 19:26:29 +0000457void TServerSocket::interrupt() {
458 if (intSock1_ >= 0) {
459 int8_t byte = 0;
Roger Meier84e4a3c2011-09-16 20:58:44 +0000460 if (-1 == send(intSock1_, cast_sockopt(&byte), sizeof(int8_t), 0)) {
David Reiss01e55c12008-07-13 22:18:51 +0000461 GlobalOutput.perror("TServerSocket::interrupt() send() ", errno);
Mark Slee561b5362007-03-09 19:26:29 +0000462 }
463 }
464}
465
Mark Sleee8540632006-05-30 09:24:40 +0000466void TServerSocket::close() {
Martin Kraemeree341cb2007-02-05 21:40:38 +0000467 if (serverSocket_ >= 0) {
Roger Meier84e4a3c2011-09-16 20:58:44 +0000468
469#ifdef _WIN32
470 shutdown(serverSocket_, SD_BOTH);
471 ::closesocket(serverSocket_);
472#else
473 shutdown(serverSocket_, SHUT_RDWR);
474 ::close(serverSocket_);
475#endif
476
Mark Sleee8540632006-05-30 09:24:40 +0000477 }
Mark Slee561b5362007-03-09 19:26:29 +0000478 if (intSock1_ >= 0) {
Roger Meier84e4a3c2011-09-16 20:58:44 +0000479 ::close(intSock1_);
Mark Slee561b5362007-03-09 19:26:29 +0000480 }
481 if (intSock2_ >= 0) {
482 ::close(intSock2_);
483 }
Martin Kraemeree341cb2007-02-05 21:40:38 +0000484 serverSocket_ = -1;
Mark Slee561b5362007-03-09 19:26:29 +0000485 intSock1_ = -1;
486 intSock2_ = -1;
Mark Sleee8540632006-05-30 09:24:40 +0000487}
Marc Slemko6f038a72006-08-03 18:58:09 +0000488
T Jake Lucianib5e62212009-01-31 22:36:20 +0000489}}} // apache::thrift::transport