37#include <sys/socket.h>
40#include <sys/select.h>
43#include <netinet/in.h>
47#include <netinet/tcp.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("() - ")
75void TcpSocket::connect()
78 string err(
"Socket is already listening");
83 string err(
"Socket is already connected");
87 if (_host.empty()) _host =
"localhost";
89 struct protoent *pProtoEnt;
90 struct sockaddr_in sin{};
92 if (isdigit(_host[0])) {
93 if (0 == inet_aton(_host.c_str(), &sin.sin_addr)) {
94 throw BESInternalError(
string(
"Invalid host ip address ") + _host, __FILE__, __LINE__);
97 sin.sin_family = AF_INET;
101 if ((ph = gethostbyname(_host.c_str())) ==
nullptr) {
103 case HOST_NOT_FOUND: {
104 string err(
"No such host ");
110 err += _host +
" is busy, try again later";
114 string err(
"DNS error for host ");
119 string err(
"No IP address for host ");
129 sin.sin_family = ph->h_addrtype;
130 for (
char **p = ph->h_addr_list; *p != NULL; p++) {
132 (void) memcpy(&in.s_addr, *p,
sizeof(in.s_addr));
133 memcpy((
char*) &sin.sin_addr, (
char*) &in,
sizeof(in));
138 sin.sin_port = htons(_portVal);
139 pProtoEnt = getprotobyname(
"tcp");
141 string err(
"Error retreiving tcp protocol information");
146 int descript = socket(AF_INET, SOCK_STREAM, pProtoEnt->p_proto);
148 if (descript == -1) {
149 throw BESInternalError(
string(
"getting socket descriptor: ") + strerror(errno), __FILE__, __LINE__);
156 holder = fcntl(_socket, F_GETFL, NULL);
157 holder = holder | O_NONBLOCK;
158 int status = fcntl(_socket, F_SETFL, holder);
160 throw BESInternalError(
string(
"Could not reset socket to blocking mode: ") + strerror(errno), __FILE__, __LINE__);
163 setTcpRecvBufferSize();
164 setTcpSendBufferSize();
166 int res = ::connect(descript, (
struct sockaddr*) &sin,
sizeof(sin));
169 if (errno == EINPROGRESS) {
172 struct timeval timeout;
179 FD_SET(_socket, &write_fd);
181 if (select(maxfd + 1, NULL, &write_fd, NULL, &timeout) < 0) {
184 holder = fcntl(_socket, F_GETFL, NULL);
185 holder = holder & (~O_NONBLOCK);
186 int status = fcntl(_socket, F_SETFL, holder);
188 throw BESInternalError(
string(
"Could not reset socket to blocking mode: ") + strerror(errno), __FILE__, __LINE__);
191 throw BESInternalError(
string(
"selecting sockets: ") + strerror(errno), __FILE__, __LINE__);
200 int status = getsockopt(_socket, SOL_SOCKET, SO_ERROR, (
void*) &valopt, &lon);
202 throw BESInternalError(
string(
"Could not check socket status: ") + strerror(errno), __FILE__, __LINE__);
207 holder = fcntl(_socket, F_GETFL, NULL);
208 holder = holder & (~O_NONBLOCK);
209 int status = fcntl(_socket, F_SETFL, holder);
211 throw BESInternalError(
string(
"Could not reset socket to blocking mode: ") + strerror(errno), __FILE__, __LINE__);
215 "Server may be down or you may be trying on the wrong port", __FILE__, __LINE__);
220 holder = fcntl(_socket, F_GETFL, NULL);
221 holder = holder & (~O_NONBLOCK);
222 int status = fcntl(_socket, F_SETFL, holder);
224 throw BESInternalError(
string(
"Could not reset socket to blocking mode: ") + strerror(errno), __FILE__, __LINE__);
233 holder = fcntl(_socket, F_GETFL, NULL);
234 holder = holder & (~O_NONBLOCK);
235 int status = fcntl(_socket, F_SETFL, holder);
237 throw BESInternalError(
string(
"Could not reset socket to blocking mode: ") + strerror(errno), __FILE__, __LINE__);
240 throw BESInternalError(
string(
"socket connect: ") + strerror(errno), __FILE__, __LINE__);
248 holder = fcntl(_socket, F_GETFL, NULL);
249 holder = holder & (~O_NONBLOCK);
250 int status = fcntl(_socket, F_SETFL, holder);
252 throw BESInternalError(
string(
"Could not reset socket to blocking mode: ") + strerror(errno), __FILE__, __LINE__);
259void TcpSocket::listen()
262 string err(
"Socket is already connected");
267 string err(
"Socket is already listening");
271 struct sockaddr_in server;
272 server.sin_family = AF_INET;
274 if (!_host.empty()) {
275 int status = inet_pton(AF_INET, _host.c_str(), &server.sin_addr.s_addr);
277 throw BESInternalError(
"Error using IP address: " + _host, __FILE__, __LINE__);
280 server.sin_addr.s_addr = INADDR_ANY;
283 BESDEBUG(MODULE, prolog <<
"Checking /etc/services for port " << _portVal << endl);
284 struct servent *sir = getservbyport(htons(_portVal), 0);
286 std::ostringstream error_oss;
287 error_oss << endl <<
"CONFIGURATION ERROR: The requested port (" << _portVal
288 <<
") appears in the system services list. ";
289 error_oss <<
"Port " << _portVal <<
" is assigned to the service '" << sir->s_name << (string)
"'";
291 if (sir->s_aliases[0] != 0) {
292 error_oss <<
" which may also be known as: ";
293 for (
int i = 0; sir->s_aliases[i] != 0; i++) {
294 if (i > 0) error_oss <<
" or ";
296 error_oss << sir->s_aliases[i];
305 server.sin_port = htons(_portVal);
306 _socket = socket(AF_INET, SOCK_STREAM, 0);
309 if (setsockopt(_socket, SOL_SOCKET, SO_REUSEADDR, (
char*)&on,
sizeof(on))) {
310 std::ostringstream errMsg;
311 errMsg << endl <<
"ERROR: Failed to set SO_REUSEADDR on TCP socket";
312 const char* error_info = strerror(errno);
313 if (error_info) errMsg <<
". Msg:: " << error_info;
318 BESDEBUG(MODULE, prolog <<
"About to bind to port: " << _portVal <<
" in process: " << getpid() << endl);
320 if (::bind(_socket, (
struct sockaddr*) &server,
sizeof server) != -1) {
321 int length =
sizeof(server);
322#ifdef _GETSOCKNAME_USES_SOCKLEN_T
323 if (getsockname(_socket, (
struct sockaddr *) &server, (socklen_t *) &length) == -1) {
325 if( getsockname( _socket, (
struct sockaddr *)&server, &length ) == -1 ) {
327 string error(
"getting socket name");
328 const char* error_info = strerror(errno);
329 if (error_info) error +=
" " + (string) error_info;
335 setTcpRecvBufferSize();
336 setTcpSendBufferSize();
338 if (::listen(_socket, 5) == 0) {
342 string error(
"could not listen TCP socket");
343 const char* error_info = strerror(errno);
344 if (error_info) error +=
" " + (string) error_info;
349 std::ostringstream error_msg;
350 error_msg << endl <<
"ERROR: Failed to bind TCP socket: " << _portVal;
351 const char* error_info = strerror(errno);
352 if (error_info) error_msg <<
": " << error_info;
358 std::ostringstream error_oss;
359 error_oss << endl <<
"ERROR: Failed to create socket for port " << _portVal << endl;
360 const char *error_info = strerror(errno);
361 if (error_info) error_oss <<
" " << (string) error_info;
384void TcpSocket::setTcpRecvBufferSize()
386 if (!_haveRecvBufferSize) {
397 if (setit ==
"Yes" || setit ==
"yes" || setit ==
"Yes") {
401 istringstream sizestrm(sizestr);
402 unsigned int sizenum = 0;
405 string err =
"Socket Recv Size malformed: " + sizestr;
410 int err = setsockopt(_socket, SOL_SOCKET, SO_RCVBUF, (
char *) &sizenum, (socklen_t)
sizeof(sizenum));
413 char *serr = strerror(myerrno);
414 string err =
"Failed to set the socket receive buffer size: ";
418 err +=
"unknow error occurred";
422 BESDEBUG(MODULE, prolog <<
"Tcp receive buffer size set to " << (
unsigned long)sizenum << endl);
445void TcpSocket::setTcpSendBufferSize()
458 if (setit ==
"Yes" || setit ==
"yes" || setit ==
"Yes") {
467 istringstream sizestrm(sizestr);
468 unsigned int sizenum = 0;
471 string err =
"Socket Send Size malformed: " + sizestr;
476 int err = setsockopt(_socket, SOL_SOCKET, SO_SNDBUF, (
char *) &sizenum, (socklen_t)
sizeof(sizenum));
479 char *serr = strerror(myerrno);
480 string err =
"Failed to set the socket send buffer size: ";
484 err +=
"unknow error occurred";
488 BESDEBUG(MODULE, prolog <<
"Tcp send buffer size set to " << (
unsigned long)sizenum << endl);
502 if (!_haveRecvBufferSize) {
504 unsigned int sizenum = 0;
505 socklen_t sizelen =
sizeof(sizenum);
506 int err = getsockopt(_socket, SOL_SOCKET, SO_RCVBUF, (
char *) &sizenum, (socklen_t *) &sizelen);
509 char *serr = strerror(myerrno);
510 string err =
"Failed to get the socket receive buffer size: ";
514 err +=
"unknow error occurred";
518 BESDEBUG(MODULE, prolog <<
"Tcp receive buffer size is " << (
unsigned long)sizenum << endl);
520 _haveRecvBufferSize =
true;
521 _recvBufferSize = sizenum;
523 return _recvBufferSize;
536 if (!_haveSendBufferSize) {
538 unsigned int sizenum = 0;
539 socklen_t sizelen =
sizeof(sizenum);
540 int err = getsockopt(_socket, SOL_SOCKET, SO_SNDBUF, (
char *) &sizenum, (socklen_t *) &sizelen);
543 char *serr = strerror(myerrno);
544 string err =
"Failed to get the socket send buffer size: ";
548 err +=
"unknow error occurred";
552 BESDEBUG(MODULE, prolog <<
"Tcp send buffer size is " << (
unsigned long)sizenum << endl);
554 _haveSendBufferSize =
true;
555 _sendBufferSize = sizenum;
557 return _sendBufferSize;
568 struct request_info req;
569 request_init( &req, RQ_DAEMON,
"besdaemon", RQ_FILE,
570 getSocketDescriptor(), 0 );
573 if( STR_EQ( eval_hostname(), paranoid ) && hosts_access() )
590 strm << BESIndent::LMarg <<
"TcpSocket::dump - (" << (
void *)
this <<
")" << endl;
592 strm << BESIndent::LMarg <<
"host: " << _host << endl;
593 strm << BESIndent::LMarg <<
"port: " << _portVal << endl;
594 strm << BESIndent::LMarg <<
"have recv buffer size: " << _haveRecvBufferSize << endl;
595 strm << BESIndent::LMarg <<
"recv buffer size: " << _recvBufferSize << endl;
596 strm << BESIndent::LMarg <<
"have send buffer size: " << _haveSendBufferSize << endl;
597 strm << BESIndent::LMarg <<
"send buffer size: " << _sendBufferSize << endl;
599 BESIndent::UnIndent();
Base exception class for the BES with basic string message.
unsigned int get_line() const
get the line number where the exception was thrown
std::string get_file() const
get the file name where the exception was thrown
std::string get_message() const
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()