34 #include <sys/types.h> 35 #include <sys/socket.h> 38 #include <sys/select.h> 41 #include <netinet/in.h> 42 #include <arpa/inet.h> 45 #include <netinet/tcp.h> 60 #include <arpa/inet.h> 64 using std::istringstream;
66 #include "TcpSocket.h" 67 #include "SocketConfig.h" 68 #include "TheBESKeys.h" 70 #include "BESInternalError.h" 71 #include "BESInternalFatalError.h" 73 void TcpSocket::connect()
76 string err(
"Socket is already listening");
81 string err(
"Socket is already connected");
85 if (_host ==
"") _host =
"localhost";
87 struct protoent *pProtoEnt;
88 struct sockaddr_in sin = {};
93 if (isdigit(_host[0])) {
94 if (0 == inet_aton(_host.c_str(), &sin.sin_addr)) {
95 throw BESInternalError(
string(
"Invalid host ip address ") + _host, __FILE__, __LINE__);
98 if ((address = inet_addr(_host.c_str())) == -1) {
99 string err(
"Invalid host ip address ");
103 sin.sin_addr.s_addr = address;
105 sin.sin_family = AF_INET;
108 if ((ph = gethostbyname(_host.c_str())) == NULL) {
110 case HOST_NOT_FOUND: {
111 string err(
"No such host ");
117 err += _host +
" is busy, try again later";
121 string err(
"DNS error for host ");
126 string err(
"No IP address for host ");
136 sin.sin_family = ph->h_addrtype;
137 for (
char **p = ph->h_addr_list; *p != NULL; p++) {
139 (void) memcpy(&in.s_addr, *p,
sizeof(in.s_addr));
140 memcpy((
char*) &sin.sin_addr, (
char*) &in,
sizeof(in));
145 sin.sin_port = htons(_portVal);
146 pProtoEnt = getprotobyname(
"tcp");
148 string err(
"Error retreiving tcp protocol information");
153 int descript = socket(AF_INET, SOCK_STREAM, pProtoEnt->p_proto);
155 if (descript == -1) {
156 throw BESInternalError(
string(
"getting socket descriptor: ") + strerror(errno), __FILE__, __LINE__);
163 holder = fcntl(_socket, F_GETFL, NULL);
164 holder = holder | O_NONBLOCK;
165 int status = fcntl(_socket, F_SETFL, holder);
167 throw BESInternalError(
string(
"Could not reset socket to blocking mode: ") + strerror(errno), __FILE__, __LINE__);
170 setTcpRecvBufferSize();
171 setTcpSendBufferSize();
173 int res = ::connect(descript, (
struct sockaddr*) &sin,
sizeof(sin));
176 if (errno == EINPROGRESS) {
179 struct timeval timeout;
186 FD_SET(_socket, &write_fd);
188 if (select(maxfd + 1, NULL, &write_fd, NULL, &timeout) < 0) {
191 holder = fcntl(_socket, F_GETFL, NULL);
192 holder = holder & (~O_NONBLOCK);
193 int status = fcntl(_socket, F_SETFL, holder);
195 throw BESInternalError(
string(
"Could not reset socket to blocking mode: ") + strerror(errno), __FILE__, __LINE__);
198 throw BESInternalError(
string(
"selecting sockets: ") + strerror(errno), __FILE__, __LINE__);
207 int status = getsockopt(_socket, SOL_SOCKET, SO_ERROR, (
void*) &valopt, &lon);
209 throw BESInternalError(
string(
"Could not check socket status: ") + strerror(errno), __FILE__, __LINE__);
214 holder = fcntl(_socket, F_GETFL, NULL);
215 holder = holder & (~O_NONBLOCK);
216 int status = fcntl(_socket, F_SETFL, holder);
218 throw BESInternalError(
string(
"Could not reset socket to blocking mode: ") + strerror(errno), __FILE__, __LINE__);
222 "Server may be down or you may be trying on the wrong port", __FILE__, __LINE__);
227 holder = fcntl(_socket, F_GETFL, NULL);
228 holder = holder & (~O_NONBLOCK);
229 int status = fcntl(_socket, F_SETFL, holder);
231 throw BESInternalError(
string(
"Could not reset socket to blocking mode: ") + strerror(errno), __FILE__, __LINE__);
240 holder = fcntl(_socket, F_GETFL, NULL);
241 holder = holder & (~O_NONBLOCK);
242 int status = fcntl(_socket, F_SETFL, holder);
244 throw BESInternalError(
string(
"Could not reset socket to blocking mode: ") + strerror(errno), __FILE__, __LINE__);
247 throw BESInternalError(
string(
"socket connect: ") + strerror(errno), __FILE__, __LINE__);
255 holder = fcntl(_socket, F_GETFL, NULL);
256 holder = holder & (~O_NONBLOCK);
257 int status = fcntl(_socket, F_SETFL, holder);
259 throw BESInternalError(
string(
"Could not reset socket to blocking mode: ") + strerror(errno), __FILE__, __LINE__);
266 void TcpSocket::listen()
269 string err(
"Socket is already connected");
274 string err(
"Socket is already listening");
278 struct sockaddr_in server = {};
279 server.sin_family = AF_INET;
281 if (!_host.empty()) {
282 int status = inet_pton(AF_INET, _host.c_str(), &server.sin_addr.s_addr);
284 throw BESInternalError(
"Error using IP address: " + _host, __FILE__, __LINE__);
287 server.sin_addr.s_addr = INADDR_ANY;
290 BESDEBUG(
"ppt",
"Checking /etc/services for port " << _portVal << endl);
291 struct servent *sir = getservbyport(htons(_portVal), 0);
293 std::ostringstream error_oss;
294 error_oss << endl <<
"CONFIGURATION ERROR: The requested port (" << _portVal
295 <<
") appears in the system services list. ";
296 error_oss <<
"Port " << _portVal <<
" is assigned to the service '" << sir->s_name << (string)
"'";
298 if (sir->s_aliases[0] != 0) {
299 error_oss <<
" which may also be known as: ";
300 for (
int i = 0; sir->s_aliases[i] != 0; i++) {
301 if (i > 0) error_oss <<
" or ";
303 error_oss << sir->s_aliases[i];
312 server.sin_port = htons(_portVal);
313 _socket = socket(AF_INET, SOCK_STREAM, 0);
316 if (setsockopt(_socket, SOL_SOCKET, SO_REUSEADDR, (
char*)&on,
sizeof(on))) {
317 std::ostringstream errMsg;
318 errMsg << endl <<
"ERROR: Failed to set SO_REUSEADDR on TCP socket";
319 const char* error_info = strerror(errno);
320 if (error_info) errMsg <<
". Msg:: " << error_info;
325 BESDEBUG(
"besdaemon",
"About to bind to port: " << _portVal <<
" in process: " << getpid() << endl);
327 if (bind(_socket, (
struct sockaddr*) &server,
sizeof server) != -1) {
328 int length =
sizeof(server);
329 #ifdef _GETSOCKNAME_USES_SOCKLEN_T 330 if (getsockname(_socket, (
struct sockaddr *) &server, (socklen_t *) &length) == -1) {
332 if( getsockname( _socket, (
struct sockaddr *)&server, &length ) == -1 ) {
334 string error(
"getting socket name");
335 const char* error_info = strerror(errno);
336 if (error_info) error +=
" " + (string) error_info;
342 setTcpRecvBufferSize();
343 setTcpSendBufferSize();
345 if (::listen(_socket, 5) == 0) {
349 string error(
"could not listen TCP socket");
350 const char* error_info = strerror(errno);
351 if (error_info) error +=
" " + (string) error_info;
356 std::ostringstream error_msg;
357 error_msg << endl <<
"ERROR: Failed to bind TCP socket: " << _portVal;
358 const char* error_info = strerror(errno);
359 if (error_info) error_msg <<
": " << error_info;
365 std::ostringstream error_oss;
366 error_oss << endl <<
"ERROR: Failed to create socket for port " << _portVal << endl;
367 const char *error_info = strerror(errno);
368 if (error_info) error_oss <<
" " << (string) error_info;
391 void TcpSocket::setTcpRecvBufferSize()
393 if (!_haveRecvBufferSize) {
404 if (setit ==
"Yes" || setit ==
"yes" || setit ==
"Yes") {
408 istringstream sizestrm(sizestr);
409 unsigned int sizenum = 0;
412 string err =
"Socket Recv Size malformed: " + sizestr;
417 int err = setsockopt(_socket, SOL_SOCKET, SO_RCVBUF, (
char *) &sizenum, (socklen_t)
sizeof(sizenum));
420 char *serr = strerror(myerrno);
421 string err =
"Failed to set the socket receive buffer size: ";
425 err +=
"unknow error occurred";
429 BESDEBUG(
"ppt",
"Tcp receive buffer size set to " << (
unsigned long)sizenum << endl);
452 void TcpSocket::setTcpSendBufferSize()
465 if (setit ==
"Yes" || setit ==
"yes" || setit ==
"Yes") {
474 istringstream sizestrm(sizestr);
475 unsigned int sizenum = 0;
478 string err =
"Socket Send Size malformed: " + sizestr;
483 int err = setsockopt(_socket, SOL_SOCKET, SO_SNDBUF, (
char *) &sizenum, (socklen_t)
sizeof(sizenum));
486 char *serr = strerror(myerrno);
487 string err =
"Failed to set the socket send buffer size: ";
491 err +=
"unknow error occurred";
495 BESDEBUG(
"ppt",
"Tcp send buffer size set to " << (
unsigned long)sizenum << endl);
509 if (!_haveRecvBufferSize) {
511 unsigned int sizenum = 0;
512 socklen_t sizelen =
sizeof(sizenum);
513 int err = getsockopt(_socket, SOL_SOCKET, SO_RCVBUF, (
char *) &sizenum, (socklen_t *) &sizelen);
516 char *serr = strerror(myerrno);
517 string err =
"Failed to get the socket receive buffer size: ";
521 err +=
"unknow error occurred";
525 BESDEBUG(
"ppt",
"Tcp receive buffer size is " << (
unsigned long)sizenum << endl);
527 _haveRecvBufferSize =
true;
528 _recvBufferSize = sizenum;
530 return _recvBufferSize;
543 if (!_haveSendBufferSize) {
545 unsigned int sizenum = 0;
546 socklen_t sizelen =
sizeof(sizenum);
547 int err = getsockopt(_socket, SOL_SOCKET, SO_SNDBUF, (
char *) &sizenum, (socklen_t *) &sizelen);
550 char *serr = strerror(myerrno);
551 string err =
"Failed to get the socket send buffer size: ";
555 err +=
"unknow error occurred";
559 BESDEBUG(
"ppt",
"Tcp send buffer size is " << (
unsigned long)sizenum << endl);
561 _haveSendBufferSize =
true;
562 _sendBufferSize = sizenum;
564 return _sendBufferSize;
575 struct request_info req;
576 request_init( &req, RQ_DAEMON,
"besdaemon", RQ_FILE,
577 getSocketDescriptor(), 0 );
580 if( STR_EQ( eval_hostname(), paranoid ) && hosts_access() )
597 strm << BESIndent::LMarg <<
"TcpSocket::dump - (" << (
void *)
this <<
")" << endl;
599 strm << BESIndent::LMarg <<
"host: " << _host << endl;
600 strm << BESIndent::LMarg <<
"port: " << _portVal << endl;
601 strm << BESIndent::LMarg <<
"have recv buffer size: " << _haveRecvBufferSize << endl;
602 strm << BESIndent::LMarg <<
"recv buffer size: " << _recvBufferSize << endl;
603 strm << BESIndent::LMarg <<
"have send buffer size: " << _haveSendBufferSize << endl;
604 strm << BESIndent::LMarg <<
"send buffer size: " << _sendBufferSize << endl;
606 BESIndent::UnIndent();
virtual unsigned int getRecvBufferSize()
get the tcp receive buffer size using getsockopt
exception thrown if an internal error is found and is fatal to the BES
exception thrown if inernal error encountered
virtual std::string get_message()
get the error message for this exception
void get_value(const string &s, string &val, bool &found)
Retrieve the value of a given key, if set.
Abstract exception class for the BES with basic string message.
static TheBESKeys * TheKeys()
virtual unsigned int getSendBufferSize()
get the tcp send buffer size using getsockopt
virtual std::string get_file()
get the file name where the exception was thrown
virtual void dump(ostream &strm) const
dumps information about this object
virtual void dump(std::ostream &strm) const
dumps information about this object
virtual bool allowConnection()
is there any wrapper code for unix sockets
virtual int get_line()
get the line number where the exception was thrown