36 #include <sys/types.h>
37 #include <sys/socket.h>
40 #include <sys/select.h>
43 #include <netinet/in.h>
44 #include <arpa/inet.h>
47 #include <netinet/tcp.h>
62 #include <arpa/inet.h>
64 #include "TcpSocket.h"
65 #include "SocketConfig.h"
66 #include "TheBESKeys.h"
68 #include "BESInternalError.h"
69 #include "BESInternalFatalError.h"
73 #define prolog string("TcpSocket::").append(__func__).append("() - ")
75 void TcpSocket::connect()
78 string err(
"Socket is already listening");
83 string err(
"Socket is already connected");
87 if (_host ==
"") _host =
"localhost";
89 struct protoent *pProtoEnt;
90 struct sockaddr_in sin;
95 if (isdigit(_host[0])) {
96 if (0 == inet_aton(_host.c_str(), &sin.sin_addr)) {
97 throw BESInternalError(
string(
"Invalid host ip address ") + _host, __FILE__, __LINE__);
100 if ((address = inet_addr(_host.c_str())) == -1) {
101 string err(
"Invalid host ip address ");
105 sin.sin_addr.s_addr = address;
107 sin.sin_family = AF_INET;
110 if ((ph = gethostbyname(_host.c_str())) == NULL) {
112 case HOST_NOT_FOUND: {
113 string err(
"No such host ");
119 err += _host +
" is busy, try again later";
123 string err(
"DNS error for host ");
128 string err(
"No IP address for host ");
138 sin.sin_family = ph->h_addrtype;
139 for (
char **p = ph->h_addr_list; *p != NULL; p++) {
141 (void) memcpy(&in.s_addr, *p,
sizeof(in.s_addr));
142 memcpy((
char*) &sin.sin_addr, (
char*) &in,
sizeof(in));
147 sin.sin_port = htons(_portVal);
148 pProtoEnt = getprotobyname(
"tcp");
150 string err(
"Error retreiving tcp protocol information");
155 int descript = socket(AF_INET, SOCK_STREAM, pProtoEnt->p_proto);
157 if (descript == -1) {
158 throw BESInternalError(
string(
"getting socket descriptor: ") + strerror(errno), __FILE__, __LINE__);
165 holder = fcntl(_socket, F_GETFL, NULL);
166 holder = holder | O_NONBLOCK;
167 int status = fcntl(_socket, F_SETFL, holder);
169 throw BESInternalError(
string(
"Could not reset socket to blocking mode: ") + strerror(errno), __FILE__, __LINE__);
172 setTcpRecvBufferSize();
173 setTcpSendBufferSize();
175 int res = ::connect(descript, (
struct sockaddr*) &sin,
sizeof(sin));
178 if (errno == EINPROGRESS) {
181 struct timeval timeout;
188 FD_SET(_socket, &write_fd);
190 if (select(maxfd + 1, NULL, &write_fd, NULL, &timeout) < 0) {
193 holder = fcntl(_socket, F_GETFL, NULL);
194 holder = holder & (~O_NONBLOCK);
195 int status = fcntl(_socket, F_SETFL, holder);
197 throw BESInternalError(
string(
"Could not reset socket to blocking mode: ") + strerror(errno), __FILE__, __LINE__);
200 throw BESInternalError(
string(
"selecting sockets: ") + strerror(errno), __FILE__, __LINE__);
209 int status = getsockopt(_socket, SOL_SOCKET, SO_ERROR, (
void*) &valopt, &lon);
211 throw BESInternalError(
string(
"Could not check socket status: ") + strerror(errno), __FILE__, __LINE__);
216 holder = fcntl(_socket, F_GETFL, NULL);
217 holder = holder & (~O_NONBLOCK);
218 int status = fcntl(_socket, F_SETFL, holder);
220 throw BESInternalError(
string(
"Could not reset socket to blocking mode: ") + strerror(errno), __FILE__, __LINE__);
224 "Server may be down or you may be trying on the wrong port", __FILE__, __LINE__);
229 holder = fcntl(_socket, F_GETFL, NULL);
230 holder = holder & (~O_NONBLOCK);
231 int status = fcntl(_socket, F_SETFL, holder);
233 throw BESInternalError(
string(
"Could not reset socket to blocking mode: ") + strerror(errno), __FILE__, __LINE__);
242 holder = fcntl(_socket, F_GETFL, NULL);
243 holder = holder & (~O_NONBLOCK);
244 int status = fcntl(_socket, F_SETFL, holder);
246 throw BESInternalError(
string(
"Could not reset socket to blocking mode: ") + strerror(errno), __FILE__, __LINE__);
249 throw BESInternalError(
string(
"socket connect: ") + strerror(errno), __FILE__, __LINE__);
257 holder = fcntl(_socket, F_GETFL, NULL);
258 holder = holder & (~O_NONBLOCK);
259 int status = fcntl(_socket, F_SETFL, holder);
261 throw BESInternalError(
string(
"Could not reset socket to blocking mode: ") + strerror(errno), __FILE__, __LINE__);
268 void TcpSocket::listen()
271 string err(
"Socket is already connected");
276 string err(
"Socket is already listening");
280 struct sockaddr_in server;
281 server.sin_family = AF_INET;
283 if (!_host.empty()) {
284 int status = inet_pton(AF_INET, _host.c_str(), &server.sin_addr.s_addr);
286 throw BESInternalError(
"Error using IP address: " + _host, __FILE__, __LINE__);
289 server.sin_addr.s_addr = INADDR_ANY;
292 BESDEBUG(MODULE, prolog <<
"Checking /etc/services for port " << _portVal << endl);
293 struct servent *sir = getservbyport(htons(_portVal), 0);
295 std::ostringstream error_oss;
296 error_oss << endl <<
"CONFIGURATION ERROR: The requested port (" << _portVal
297 <<
") appears in the system services list. ";
298 error_oss <<
"Port " << _portVal <<
" is assigned to the service '" << sir->s_name << (string)
"'";
300 if (sir->s_aliases[0] != 0) {
301 error_oss <<
" which may also be known as: ";
302 for (
int i = 0; sir->s_aliases[i] != 0; i++) {
303 if (i > 0) error_oss <<
" or ";
305 error_oss << sir->s_aliases[i];
314 server.sin_port = htons(_portVal);
315 _socket = socket(AF_INET, SOCK_STREAM, 0);
318 if (setsockopt(_socket, SOL_SOCKET, SO_REUSEADDR, (
char*)&on,
sizeof(on))) {
319 std::ostringstream errMsg;
320 errMsg << endl <<
"ERROR: Failed to set SO_REUSEADDR on TCP socket";
321 const char* error_info = strerror(errno);
322 if (error_info) errMsg <<
". Msg:: " << error_info;
327 BESDEBUG(MODULE, prolog <<
"About to bind to port: " << _portVal <<
" in process: " << getpid() << endl);
329 if (::bind(_socket, (
struct sockaddr*) &server,
sizeof server) != -1) {
330 int length =
sizeof(server);
331 #ifdef _GETSOCKNAME_USES_SOCKLEN_T
332 if (getsockname(_socket, (
struct sockaddr *) &server, (socklen_t *) &length) == -1) {
334 if( getsockname( _socket, (
struct sockaddr *)&server, &length ) == -1 ) {
336 string error(
"getting socket name");
337 const char* error_info = strerror(errno);
338 if (error_info) error +=
" " + (string) error_info;
344 setTcpRecvBufferSize();
345 setTcpSendBufferSize();
347 if (::listen(_socket, 5) == 0) {
351 string error(
"could not listen TCP socket");
352 const char* error_info = strerror(errno);
353 if (error_info) error +=
" " + (string) error_info;
358 std::ostringstream error_msg;
359 error_msg << endl <<
"ERROR: Failed to bind TCP socket: " << _portVal;
360 const char* error_info = strerror(errno);
361 if (error_info) error_msg <<
": " << error_info;
367 std::ostringstream error_oss;
368 error_oss << endl <<
"ERROR: Failed to create socket for port " << _portVal << endl;
369 const char *error_info = strerror(errno);
370 if (error_info) error_oss <<
" " << (string) error_info;
393 void TcpSocket::setTcpRecvBufferSize()
395 if (!_haveRecvBufferSize) {
406 if (setit ==
"Yes" || setit ==
"yes" || setit ==
"Yes") {
410 istringstream sizestrm(sizestr);
411 unsigned int sizenum = 0;
414 string err =
"Socket Recv Size malformed: " + sizestr;
419 int err = setsockopt(_socket, SOL_SOCKET, SO_RCVBUF, (
char *) &sizenum, (socklen_t)
sizeof(sizenum));
422 char *serr = strerror(myerrno);
423 string err =
"Failed to set the socket receive buffer size: ";
427 err +=
"unknow error occurred";
431 BESDEBUG(MODULE, prolog <<
"Tcp receive buffer size set to " << (
unsigned long)sizenum << endl);
454 void TcpSocket::setTcpSendBufferSize()
467 if (setit ==
"Yes" || setit ==
"yes" || setit ==
"Yes") {
476 istringstream sizestrm(sizestr);
477 unsigned int sizenum = 0;
480 string err =
"Socket Send Size malformed: " + sizestr;
485 int err = setsockopt(_socket, SOL_SOCKET, SO_SNDBUF, (
char *) &sizenum, (socklen_t)
sizeof(sizenum));
488 char *serr = strerror(myerrno);
489 string err =
"Failed to set the socket send buffer size: ";
493 err +=
"unknow error occurred";
497 BESDEBUG(MODULE, prolog <<
"Tcp send buffer size set to " << (
unsigned long)sizenum << endl);
511 if (!_haveRecvBufferSize) {
513 unsigned int sizenum = 0;
514 socklen_t sizelen =
sizeof(sizenum);
515 int err = getsockopt(_socket, SOL_SOCKET, SO_RCVBUF, (
char *) &sizenum, (socklen_t *) &sizelen);
518 char *serr = strerror(myerrno);
519 string err =
"Failed to get the socket receive buffer size: ";
523 err +=
"unknow error occurred";
527 BESDEBUG(MODULE, prolog <<
"Tcp receive buffer size is " << (
unsigned long)sizenum << endl);
529 _haveRecvBufferSize =
true;
530 _recvBufferSize = sizenum;
532 return _recvBufferSize;
545 if (!_haveSendBufferSize) {
547 unsigned int sizenum = 0;
548 socklen_t sizelen =
sizeof(sizenum);
549 int err = getsockopt(_socket, SOL_SOCKET, SO_SNDBUF, (
char *) &sizenum, (socklen_t *) &sizelen);
552 char *serr = strerror(myerrno);
553 string err =
"Failed to get the socket send buffer size: ";
557 err +=
"unknow error occurred";
561 BESDEBUG(MODULE, prolog <<
"Tcp send buffer size is " << (
unsigned long)sizenum << endl);
563 _haveSendBufferSize =
true;
564 _sendBufferSize = sizenum;
566 return _sendBufferSize;
577 struct request_info req;
578 request_init( &req, RQ_DAEMON,
"besdaemon", RQ_FILE,
579 getSocketDescriptor(), 0 );
582 if( STR_EQ( eval_hostname(), paranoid ) && hosts_access() )
599 strm << BESIndent::LMarg <<
"TcpSocket::dump - (" << (
void *)
this <<
")" << endl;
601 strm << BESIndent::LMarg <<
"host: " << _host << endl;
602 strm << BESIndent::LMarg <<
"port: " << _portVal << endl;
603 strm << BESIndent::LMarg <<
"have recv buffer size: " << _haveRecvBufferSize << endl;
604 strm << BESIndent::LMarg <<
"recv buffer size: " << _recvBufferSize << endl;
605 strm << BESIndent::LMarg <<
"have send buffer size: " << _haveSendBufferSize << endl;
606 strm << BESIndent::LMarg <<
"send buffer size: " << _sendBufferSize << endl;
608 BESIndent::UnIndent();
Abstract exception class for the BES with basic string message.
virtual int get_line()
get the line number where the exception was thrown
virtual std::string get_file()
get the file name where the exception was thrown
virtual std::string get_message()
get the error message for this exception
exception thrown if internal error encountered
exception thrown if an internal error is found and is fatal to the BES
virtual void dump(std::ostream &strm) const
dumps information about this object
virtual unsigned int getRecvBufferSize()
get the tcp receive buffer size using getsockopt
virtual unsigned int getSendBufferSize()
get the tcp send buffer size using getsockopt
virtual bool allowConnection()
is there any wrapper code for unix sockets
virtual void dump(std::ostream &strm) const
dumps information about this object
void get_value(const std::string &s, std::string &val, bool &found)
Retrieve the value of a given key, if set.
static TheBESKeys * TheKeys()