blob: f9f3e7fa0d452e20a22806d06e4402473e2dc081 [file] [log] [blame]
Mark Sleee8540632006-05-30 09:24:40 +00001#include <sys/socket.h>
2#include <netinet/in.h>
Mark Slee29050782006-09-29 00:12:30 +00003#include <netinet/tcp.h>
Mark Slee8d7e1f62006-06-07 06:48:56 +00004#include <errno.h>
Mark Sleee8540632006-05-30 09:24:40 +00005
Marc Slemkod42a2c22006-08-10 03:30:18 +00006#include "TSocket.h"
7#include "TServerSocket.h"
Marc Slemko16698852006-08-04 03:16:10 +00008#include <boost/shared_ptr.hpp>
Mark Sleee8540632006-05-30 09:24:40 +00009
Marc Slemko6f038a72006-08-03 18:58:09 +000010namespace facebook { namespace thrift { namespace transport {
11
Marc Slemko16698852006-08-04 03:16:10 +000012using namespace boost;
13
Mark Sleee8540632006-05-30 09:24:40 +000014TServerSocket::TServerSocket(int port) :
Mark Slee29050782006-09-29 00:12:30 +000015 port_(port),
16 serverSocket_(0),
17 acceptBacklog_(1024),
18 sendTimeout_(0),
19 recvTimeout_(0) {}
20
21TServerSocket::TServerSocket(int port, int sendTimeout, int recvTimeout) :
22 port_(port),
23 serverSocket_(0),
24 acceptBacklog_(1024),
25 sendTimeout_(sendTimeout),
26 recvTimeout_(recvTimeout) {}
Mark Sleee8540632006-05-30 09:24:40 +000027
28TServerSocket::~TServerSocket() {
29 close();
30}
31
Mark Slee29050782006-09-29 00:12:30 +000032void TServerSocket::setSendTimeout(int sendTimeout) {
33 sendTimeout_ = sendTimeout;
34}
35
36void TServerSocket::setRecvTimeout(int recvTimeout) {
37 recvTimeout_ = recvTimeout;
38}
39
Mark Slee8d7e1f62006-06-07 06:48:56 +000040void TServerSocket::listen() {
Mark Sleee8540632006-05-30 09:24:40 +000041 serverSocket_ = socket(AF_INET, SOCK_STREAM, 0);
42 if (serverSocket_ == -1) {
Mark Slee8d7e1f62006-06-07 06:48:56 +000043 perror("TServerSocket::listen() socket");
Mark Sleee8540632006-05-30 09:24:40 +000044 close();
Mark Slee8d7e1f62006-06-07 06:48:56 +000045 throw TTransportException(TTX_NOT_OPEN, "Could not create server socket.");
Mark Sleee8540632006-05-30 09:24:40 +000046 }
47
48 // Set reusaddress to prevent 2MSL delay on accept
49 int one = 1;
50 if (-1 == setsockopt(serverSocket_, SOL_SOCKET, SO_REUSEADDR,
51 &one, sizeof(one))) {
52 perror("TServerSocket::listen() SO_REUSEADDR");
53 close();
Mark Slee8d7e1f62006-06-07 06:48:56 +000054 throw TTransportException(TTX_NOT_OPEN, "Could not set SO_REUSEADDR");
Mark Sleee8540632006-05-30 09:24:40 +000055 }
56
Mark Slee29050782006-09-29 00:12:30 +000057 // Defer accept
58 #ifdef TCP_DEFER_ACCEPT
59 if (-1 == setsockopt(serverSocket_, SOL_SOCKET, TCP_DEFER_ACCEPT,
60 &one, sizeof(one))) {
61 perror("TServerSocket::listen() TCP_DEFER_ACCEPT");
62 close();
63 throw TTransportException(TTX_NOT_OPEN, "Could not set TCP_DEFER_ACCEPT");
64 }
65 #endif // #ifdef TCP_DEFER_ACCEPT
66
Mark Sleee8540632006-05-30 09:24:40 +000067 // Turn linger off, don't want to block on calls to close
68 struct linger ling = {0, 0};
69 if (-1 == setsockopt(serverSocket_, SOL_SOCKET, SO_LINGER,
70 &ling, sizeof(ling))) {
Mark Sleee8540632006-05-30 09:24:40 +000071 close();
Mark Slee8d7e1f62006-06-07 06:48:56 +000072 perror("TServerSocket::listen() SO_LINGER");
73 throw TTransportException(TTX_NOT_OPEN, "Could not set SO_LINGER");
Mark Sleee8540632006-05-30 09:24:40 +000074 }
75
Mark Slee29050782006-09-29 00:12:30 +000076 // TCP Nodelay, speed over bandwidth
77 if (-1 == setsockopt(serverSocket_, IPPROTO_TCP, TCP_NODELAY,
78 &one, sizeof(one))) {
79 close();
80 perror("setsockopt TCP_NODELAY");
81 throw TTransportException(TTX_NOT_OPEN, "Could not set TCP_NODELAY");
82 }
83
Mark Sleee8540632006-05-30 09:24:40 +000084 // Bind to a port
85 struct sockaddr_in addr;
86 memset(&addr, 0, sizeof(addr));
87 addr.sin_family = AF_INET;
88 addr.sin_port = htons(port_);
89 addr.sin_addr.s_addr = INADDR_ANY;
90 if (-1 == bind(serverSocket_, (struct sockaddr *)&addr, sizeof(addr))) {
91 char errbuf[1024];
92 sprintf(errbuf, "TServerSocket::listen() BIND %d", port_);
93 perror(errbuf);
94 close();
Mark Slee8d7e1f62006-06-07 06:48:56 +000095 throw TTransportException(TTX_NOT_OPEN, "Could not bind");
Mark Sleee8540632006-05-30 09:24:40 +000096 }
97
98 // Call listen
99 if (-1 == ::listen(serverSocket_, acceptBacklog_)) {
100 perror("TServerSocket::listen() LISTEN");
101 close();
Mark Slee8d7e1f62006-06-07 06:48:56 +0000102 throw TTransportException(TTX_NOT_OPEN, "Could not listen");
Mark Sleee8540632006-05-30 09:24:40 +0000103 }
104
105 // The socket is now listening!
Mark Sleee8540632006-05-30 09:24:40 +0000106}
107
Marc Slemko16698852006-08-04 03:16:10 +0000108shared_ptr<TTransport> TServerSocket::acceptImpl() {
Martin Kraemer10640d82007-02-03 01:59:12 +0000109 if (serverSocket_ < 0) {
Mark Slee8d7e1f62006-06-07 06:48:56 +0000110 throw TTransportException(TTX_NOT_OPEN, "TServerSocket not listening");
Mark Sleee8540632006-05-30 09:24:40 +0000111 }
112
113 struct sockaddr_in clientAddress;
114 int size = sizeof(clientAddress);
115 int clientSocket = ::accept(serverSocket_,
116 (struct sockaddr *) &clientAddress,
117 (socklen_t *) &size);
118
119 if (clientSocket <= 0) {
120 perror("TServerSocket::accept()");
Mark Slee8d7e1f62006-06-07 06:48:56 +0000121 throw TTransportException(TTX_UNKNOWN, "ERROR:" + errno);
Mark Sleee8540632006-05-30 09:24:40 +0000122 }
Martin Kraemer10640d82007-02-03 01:59:12 +0000123
Mark Slee29050782006-09-29 00:12:30 +0000124 shared_ptr<TSocket> client(new TSocket(clientSocket));
125 if (sendTimeout_ > 0) {
126 client->setSendTimeout(sendTimeout_);
127 }
128 if (recvTimeout_ > 0) {
129 client->setRecvTimeout(recvTimeout_);
130 }
131 return client;
Mark Sleee8540632006-05-30 09:24:40 +0000132}
133
134void TServerSocket::close() {
135 if (serverSocket_ > 0) {
136 shutdown(serverSocket_, SHUT_RDWR);
137 ::close(serverSocket_);
138 }
139 serverSocket_ = 0;
140}
Marc Slemko6f038a72006-08-03 18:58:09 +0000141
142}}} // facebook::thrift::transport