blob: e4d7c02283fdc7e1e4a59b129c5e2c9e03232d17 [file] [log] [blame]
Mark Slee9f0c6512007-02-28 23:58:26 +00001// Copyright (c) 2006- Facebook
2// Distributed under the Thrift Software License
3//
4// See accompanying file LICENSE or visit the Thrift site at:
5// http://developers.facebook.com/thrift/
6
Mark Sleee8540632006-05-30 09:24:40 +00007#include <sys/socket.h>
8#include <netinet/in.h>
Mark Slee29050782006-09-29 00:12:30 +00009#include <netinet/tcp.h>
Mark Slee8d7e1f62006-06-07 06:48:56 +000010#include <errno.h>
Mark Sleee8540632006-05-30 09:24:40 +000011
Marc Slemkod42a2c22006-08-10 03:30:18 +000012#include "TSocket.h"
13#include "TServerSocket.h"
Marc Slemko16698852006-08-04 03:16:10 +000014#include <boost/shared_ptr.hpp>
Mark Sleee8540632006-05-30 09:24:40 +000015
Marc Slemko6f038a72006-08-03 18:58:09 +000016namespace facebook { namespace thrift { namespace transport {
17
Marc Slemko16698852006-08-04 03:16:10 +000018using namespace boost;
19
Mark Sleee8540632006-05-30 09:24:40 +000020TServerSocket::TServerSocket(int port) :
Mark Slee29050782006-09-29 00:12:30 +000021 port_(port),
Martin Kraemeree341cb2007-02-05 21:40:38 +000022 serverSocket_(-1),
Mark Slee29050782006-09-29 00:12:30 +000023 acceptBacklog_(1024),
24 sendTimeout_(0),
25 recvTimeout_(0) {}
26
27TServerSocket::TServerSocket(int port, int sendTimeout, int recvTimeout) :
28 port_(port),
Martin Kraemeree341cb2007-02-05 21:40:38 +000029 serverSocket_(-1),
Mark Slee29050782006-09-29 00:12:30 +000030 acceptBacklog_(1024),
31 sendTimeout_(sendTimeout),
32 recvTimeout_(recvTimeout) {}
Mark Sleee8540632006-05-30 09:24:40 +000033
34TServerSocket::~TServerSocket() {
35 close();
36}
37
Mark Slee29050782006-09-29 00:12:30 +000038void TServerSocket::setSendTimeout(int sendTimeout) {
39 sendTimeout_ = sendTimeout;
40}
41
42void TServerSocket::setRecvTimeout(int recvTimeout) {
43 recvTimeout_ = recvTimeout;
44}
45
Mark Slee8d7e1f62006-06-07 06:48:56 +000046void TServerSocket::listen() {
Mark Sleee8540632006-05-30 09:24:40 +000047 serverSocket_ = socket(AF_INET, SOCK_STREAM, 0);
48 if (serverSocket_ == -1) {
Mark Slee8d7e1f62006-06-07 06:48:56 +000049 perror("TServerSocket::listen() socket");
Mark Sleee8540632006-05-30 09:24:40 +000050 close();
Mark Sleef9831082007-02-20 20:59:21 +000051 throw TTransportException(TTransportException::NOT_OPEN, "Could not create server socket.");
Mark Sleee8540632006-05-30 09:24:40 +000052 }
53
54 // Set reusaddress to prevent 2MSL delay on accept
55 int one = 1;
56 if (-1 == setsockopt(serverSocket_, SOL_SOCKET, SO_REUSEADDR,
57 &one, sizeof(one))) {
58 perror("TServerSocket::listen() SO_REUSEADDR");
59 close();
Mark Sleef9831082007-02-20 20:59:21 +000060 throw TTransportException(TTransportException::NOT_OPEN, "Could not set SO_REUSEADDR");
Mark Sleee8540632006-05-30 09:24:40 +000061 }
62
Mark Slee29050782006-09-29 00:12:30 +000063 // Defer accept
64 #ifdef TCP_DEFER_ACCEPT
65 if (-1 == setsockopt(serverSocket_, SOL_SOCKET, TCP_DEFER_ACCEPT,
66 &one, sizeof(one))) {
67 perror("TServerSocket::listen() TCP_DEFER_ACCEPT");
68 close();
Mark Sleef9831082007-02-20 20:59:21 +000069 throw TTransportException(TTransportException::NOT_OPEN, "Could not set TCP_DEFER_ACCEPT");
Mark Slee29050782006-09-29 00:12:30 +000070 }
71 #endif // #ifdef TCP_DEFER_ACCEPT
72
Mark Sleee8540632006-05-30 09:24:40 +000073 // Turn linger off, don't want to block on calls to close
74 struct linger ling = {0, 0};
75 if (-1 == setsockopt(serverSocket_, SOL_SOCKET, SO_LINGER,
76 &ling, sizeof(ling))) {
Mark Sleee8540632006-05-30 09:24:40 +000077 close();
Mark Slee8d7e1f62006-06-07 06:48:56 +000078 perror("TServerSocket::listen() SO_LINGER");
Mark Sleef9831082007-02-20 20:59:21 +000079 throw TTransportException(TTransportException::NOT_OPEN, "Could not set SO_LINGER");
Mark Sleee8540632006-05-30 09:24:40 +000080 }
81
Mark Slee29050782006-09-29 00:12:30 +000082 // TCP Nodelay, speed over bandwidth
83 if (-1 == setsockopt(serverSocket_, IPPROTO_TCP, TCP_NODELAY,
84 &one, sizeof(one))) {
85 close();
86 perror("setsockopt TCP_NODELAY");
Mark Sleef9831082007-02-20 20:59:21 +000087 throw TTransportException(TTransportException::NOT_OPEN, "Could not set TCP_NODELAY");
Mark Slee29050782006-09-29 00:12:30 +000088 }
89
Mark Sleee8540632006-05-30 09:24:40 +000090 // Bind to a port
91 struct sockaddr_in addr;
92 memset(&addr, 0, sizeof(addr));
93 addr.sin_family = AF_INET;
94 addr.sin_port = htons(port_);
95 addr.sin_addr.s_addr = INADDR_ANY;
96 if (-1 == bind(serverSocket_, (struct sockaddr *)&addr, sizeof(addr))) {
97 char errbuf[1024];
98 sprintf(errbuf, "TServerSocket::listen() BIND %d", port_);
99 perror(errbuf);
100 close();
Mark Sleef9831082007-02-20 20:59:21 +0000101 throw TTransportException(TTransportException::NOT_OPEN, "Could not bind");
Mark Sleee8540632006-05-30 09:24:40 +0000102 }
103
104 // Call listen
105 if (-1 == ::listen(serverSocket_, acceptBacklog_)) {
106 perror("TServerSocket::listen() LISTEN");
107 close();
Mark Sleef9831082007-02-20 20:59:21 +0000108 throw TTransportException(TTransportException::NOT_OPEN, "Could not listen");
Mark Sleee8540632006-05-30 09:24:40 +0000109 }
110
111 // The socket is now listening!
Mark Sleee8540632006-05-30 09:24:40 +0000112}
113
Marc Slemko16698852006-08-04 03:16:10 +0000114shared_ptr<TTransport> TServerSocket::acceptImpl() {
Martin Kraemer10640d82007-02-03 01:59:12 +0000115 if (serverSocket_ < 0) {
Mark Sleef9831082007-02-20 20:59:21 +0000116 throw TTransportException(TTransportException::NOT_OPEN, "TServerSocket not listening");
Mark Sleee8540632006-05-30 09:24:40 +0000117 }
118
119 struct sockaddr_in clientAddress;
120 int size = sizeof(clientAddress);
121 int clientSocket = ::accept(serverSocket_,
122 (struct sockaddr *) &clientAddress,
123 (socklen_t *) &size);
124
Martin Kraemeree341cb2007-02-05 21:40:38 +0000125 if (clientSocket < 0) {
Mark Sleee8540632006-05-30 09:24:40 +0000126 perror("TServerSocket::accept()");
Mark Sleef9831082007-02-20 20:59:21 +0000127 throw TTransportException(TTransportException::UNKNOWN, "ERROR:" + errno);
Mark Sleee8540632006-05-30 09:24:40 +0000128 }
Martin Kraemer10640d82007-02-03 01:59:12 +0000129
Mark Slee29050782006-09-29 00:12:30 +0000130 shared_ptr<TSocket> client(new TSocket(clientSocket));
131 if (sendTimeout_ > 0) {
132 client->setSendTimeout(sendTimeout_);
133 }
134 if (recvTimeout_ > 0) {
135 client->setRecvTimeout(recvTimeout_);
136 }
137 return client;
Mark Sleee8540632006-05-30 09:24:40 +0000138}
139
140void TServerSocket::close() {
Martin Kraemeree341cb2007-02-05 21:40:38 +0000141 if (serverSocket_ >= 0) {
Mark Sleee8540632006-05-30 09:24:40 +0000142 shutdown(serverSocket_, SHUT_RDWR);
143 ::close(serverSocket_);
144 }
Martin Kraemeree341cb2007-02-05 21:40:38 +0000145 serverSocket_ = -1;
Mark Sleee8540632006-05-30 09:24:40 +0000146}
Marc Slemko6f038a72006-08-03 18:58:09 +0000147
148}}} // facebook::thrift::transport