blob: 1cf4a320447e1762441ce64b01c559d2faae724d [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
8TServerSocket::TServerSocket(int port) :
9 port_(port), serverSocket_(0), acceptBacklog_(1024) {}
10
11TServerSocket::~TServerSocket() {
12 close();
13}
14
Mark Slee8d7e1f62006-06-07 06:48:56 +000015void TServerSocket::listen() {
Mark Sleee8540632006-05-30 09:24:40 +000016 serverSocket_ = socket(AF_INET, SOCK_STREAM, 0);
17 if (serverSocket_ == -1) {
Mark Slee8d7e1f62006-06-07 06:48:56 +000018 perror("TServerSocket::listen() socket");
Mark Sleee8540632006-05-30 09:24:40 +000019 close();
Mark Slee8d7e1f62006-06-07 06:48:56 +000020 throw TTransportException(TTX_NOT_OPEN, "Could not create server socket.");
Mark Sleee8540632006-05-30 09:24:40 +000021 }
22
23 // Set reusaddress to prevent 2MSL delay on accept
24 int one = 1;
25 if (-1 == setsockopt(serverSocket_, SOL_SOCKET, SO_REUSEADDR,
26 &one, sizeof(one))) {
27 perror("TServerSocket::listen() SO_REUSEADDR");
28 close();
Mark Slee8d7e1f62006-06-07 06:48:56 +000029 throw TTransportException(TTX_NOT_OPEN, "Could not set SO_REUSEADDR");
Mark Sleee8540632006-05-30 09:24:40 +000030 }
31
32 // Turn linger off, don't want to block on calls to close
33 struct linger ling = {0, 0};
34 if (-1 == setsockopt(serverSocket_, SOL_SOCKET, SO_LINGER,
35 &ling, sizeof(ling))) {
Mark Sleee8540632006-05-30 09:24:40 +000036 close();
Mark Slee8d7e1f62006-06-07 06:48:56 +000037 perror("TServerSocket::listen() SO_LINGER");
38 throw TTransportException(TTX_NOT_OPEN, "Could not set SO_LINGER");
Mark Sleee8540632006-05-30 09:24:40 +000039 }
40
41 // Bind to a port
42 struct sockaddr_in addr;
43 memset(&addr, 0, sizeof(addr));
44 addr.sin_family = AF_INET;
45 addr.sin_port = htons(port_);
46 addr.sin_addr.s_addr = INADDR_ANY;
47 if (-1 == bind(serverSocket_, (struct sockaddr *)&addr, sizeof(addr))) {
48 char errbuf[1024];
49 sprintf(errbuf, "TServerSocket::listen() BIND %d", port_);
50 perror(errbuf);
51 close();
Mark Slee8d7e1f62006-06-07 06:48:56 +000052 throw TTransportException(TTX_NOT_OPEN, "Could not bind");
Mark Sleee8540632006-05-30 09:24:40 +000053 }
54
55 // Call listen
56 if (-1 == ::listen(serverSocket_, acceptBacklog_)) {
57 perror("TServerSocket::listen() LISTEN");
58 close();
Mark Slee8d7e1f62006-06-07 06:48:56 +000059 throw TTransportException(TTX_NOT_OPEN, "Could not listen");
Mark Sleee8540632006-05-30 09:24:40 +000060 }
61
62 // The socket is now listening!
Mark Sleee8540632006-05-30 09:24:40 +000063}
64
Mark Slee8d7e1f62006-06-07 06:48:56 +000065TTransport* TServerSocket::acceptImpl() {
Mark Sleee8540632006-05-30 09:24:40 +000066 if (serverSocket_ <= 0) {
Mark Slee8d7e1f62006-06-07 06:48:56 +000067 throw TTransportException(TTX_NOT_OPEN, "TServerSocket not listening");
Mark Sleee8540632006-05-30 09:24:40 +000068 }
69
70 struct sockaddr_in clientAddress;
71 int size = sizeof(clientAddress);
72 int clientSocket = ::accept(serverSocket_,
73 (struct sockaddr *) &clientAddress,
74 (socklen_t *) &size);
75
76 if (clientSocket <= 0) {
77 perror("TServerSocket::accept()");
Mark Slee8d7e1f62006-06-07 06:48:56 +000078 throw TTransportException(TTX_UNKNOWN, "ERROR:" + errno);
Mark Sleee8540632006-05-30 09:24:40 +000079 }
80
81 return new TSocket(clientSocket);
82}
83
84void TServerSocket::close() {
85 if (serverSocket_ > 0) {
86 shutdown(serverSocket_, SHUT_RDWR);
87 ::close(serverSocket_);
88 }
89 serverSocket_ = 0;
90}