blob: 21230d991e59dcaf9ef7c39f5eaa766515d471a6 [file] [log] [blame]
Mark Sleee8540632006-05-30 09:24:40 +00001#include <sys/socket.h>
2#include <netinet/in.h>
Mark Slee8d7e1f62006-06-07 06:48:56 +00003#include <errno.h>
Mark Sleee8540632006-05-30 09:24:40 +00004
5#include "transport/TSocket.h"
6#include "transport/TServerSocket.h"
7
Marc Slemko6f038a72006-08-03 18:58:09 +00008namespace facebook { namespace thrift { namespace transport {
9
Mark Sleee8540632006-05-30 09:24:40 +000010TServerSocket::TServerSocket(int port) :
11 port_(port), serverSocket_(0), acceptBacklog_(1024) {}
12
13TServerSocket::~TServerSocket() {
14 close();
15}
16
Mark Slee8d7e1f62006-06-07 06:48:56 +000017void TServerSocket::listen() {
Mark Sleee8540632006-05-30 09:24:40 +000018 serverSocket_ = socket(AF_INET, SOCK_STREAM, 0);
19 if (serverSocket_ == -1) {
Mark Slee8d7e1f62006-06-07 06:48:56 +000020 perror("TServerSocket::listen() socket");
Mark Sleee8540632006-05-30 09:24:40 +000021 close();
Mark Slee8d7e1f62006-06-07 06:48:56 +000022 throw TTransportException(TTX_NOT_OPEN, "Could not create server socket.");
Mark Sleee8540632006-05-30 09:24:40 +000023 }
24
25 // Set reusaddress to prevent 2MSL delay on accept
26 int one = 1;
27 if (-1 == setsockopt(serverSocket_, SOL_SOCKET, SO_REUSEADDR,
28 &one, sizeof(one))) {
29 perror("TServerSocket::listen() SO_REUSEADDR");
30 close();
Mark Slee8d7e1f62006-06-07 06:48:56 +000031 throw TTransportException(TTX_NOT_OPEN, "Could not set SO_REUSEADDR");
Mark Sleee8540632006-05-30 09:24:40 +000032 }
33
34 // Turn linger off, don't want to block on calls to close
35 struct linger ling = {0, 0};
36 if (-1 == setsockopt(serverSocket_, SOL_SOCKET, SO_LINGER,
37 &ling, sizeof(ling))) {
Mark Sleee8540632006-05-30 09:24:40 +000038 close();
Mark Slee8d7e1f62006-06-07 06:48:56 +000039 perror("TServerSocket::listen() SO_LINGER");
40 throw TTransportException(TTX_NOT_OPEN, "Could not set SO_LINGER");
Mark Sleee8540632006-05-30 09:24:40 +000041 }
42
43 // Bind to a port
44 struct sockaddr_in addr;
45 memset(&addr, 0, sizeof(addr));
46 addr.sin_family = AF_INET;
47 addr.sin_port = htons(port_);
48 addr.sin_addr.s_addr = INADDR_ANY;
49 if (-1 == bind(serverSocket_, (struct sockaddr *)&addr, sizeof(addr))) {
50 char errbuf[1024];
51 sprintf(errbuf, "TServerSocket::listen() BIND %d", port_);
52 perror(errbuf);
53 close();
Mark Slee8d7e1f62006-06-07 06:48:56 +000054 throw TTransportException(TTX_NOT_OPEN, "Could not bind");
Mark Sleee8540632006-05-30 09:24:40 +000055 }
56
57 // Call listen
58 if (-1 == ::listen(serverSocket_, acceptBacklog_)) {
59 perror("TServerSocket::listen() LISTEN");
60 close();
Mark Slee8d7e1f62006-06-07 06:48:56 +000061 throw TTransportException(TTX_NOT_OPEN, "Could not listen");
Mark Sleee8540632006-05-30 09:24:40 +000062 }
63
64 // The socket is now listening!
Mark Sleee8540632006-05-30 09:24:40 +000065}
66
Mark Slee8d7e1f62006-06-07 06:48:56 +000067TTransport* TServerSocket::acceptImpl() {
Mark Sleee8540632006-05-30 09:24:40 +000068 if (serverSocket_ <= 0) {
Mark Slee8d7e1f62006-06-07 06:48:56 +000069 throw TTransportException(TTX_NOT_OPEN, "TServerSocket not listening");
Mark Sleee8540632006-05-30 09:24:40 +000070 }
71
72 struct sockaddr_in clientAddress;
73 int size = sizeof(clientAddress);
74 int clientSocket = ::accept(serverSocket_,
75 (struct sockaddr *) &clientAddress,
76 (socklen_t *) &size);
77
78 if (clientSocket <= 0) {
79 perror("TServerSocket::accept()");
Mark Slee8d7e1f62006-06-07 06:48:56 +000080 throw TTransportException(TTX_UNKNOWN, "ERROR:" + errno);
Mark Sleee8540632006-05-30 09:24:40 +000081 }
82
83 return new TSocket(clientSocket);
84}
85
86void TServerSocket::close() {
87 if (serverSocket_ > 0) {
88 shutdown(serverSocket_, SHUT_RDWR);
89 ::close(serverSocket_);
90 }
91 serverSocket_ = 0;
92}
Marc Slemko6f038a72006-08-03 18:58:09 +000093
94}}} // facebook::thrift::transport