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 = {};
91 if (isdigit(_host[0])) {
92 if (0 == inet_aton(_host.c_str(), &sin.sin_addr)) {
93 throw BESInternalError(
string(
"Invalid host ip address ") + _host, __FILE__, __LINE__);
96 if ((address = inet_addr(_host.c_str())) == -1) {
97 string err(
"Invalid host ip address ");
101 sin.sin_addr.s_addr = address;
103 sin.sin_family = AF_INET;
106 if ((ph = gethostbyname(_host.c_str())) == NULL) {
108 case HOST_NOT_FOUND: {
109 string err(
"No such host ");
115 err += _host +
" is busy, try again later";
119 string err(
"DNS error for host ");
124 string err(
"No IP address for host ");
134 sin.sin_family = ph->h_addrtype;
135 for (
char **p = ph->h_addr_list; *p != NULL; p++) {
137 (void) memcpy(&in.s_addr, *p,
sizeof(in.s_addr));
138 memcpy((
char*) &sin.sin_addr, (
char*) &in,
sizeof(in));
143 sin.sin_port = htons(_portVal);
144 pProtoEnt = getprotobyname(
"tcp");
146 string err(
"Error retreiving tcp protocol information");
151 int descript = socket(AF_INET, SOCK_STREAM, pProtoEnt->p_proto);
153 if (descript == -1) {
154 throw BESInternalError(
string(
"getting socket descriptor: ") + strerror(errno), __FILE__, __LINE__);
161 holder = fcntl(_socket, F_GETFL, NULL);
162 holder = holder | O_NONBLOCK;
163 int status = fcntl(_socket, F_SETFL, holder);
165 throw BESInternalError(
string(
"Could not reset socket to blocking mode: ") + strerror(errno), __FILE__, __LINE__);
168 setTcpRecvBufferSize();
169 setTcpSendBufferSize();
171 int res = ::connect(descript, (
struct sockaddr*) &sin,
sizeof(sin));
174 if (errno == EINPROGRESS) {
177 struct timeval timeout;
184 FD_SET(_socket, &write_fd);
186 if (select(maxfd + 1, NULL, &write_fd, NULL, &timeout) < 0) {
189 holder = fcntl(_socket, F_GETFL, NULL);
190 holder = holder & (~O_NONBLOCK);
191 int status = fcntl(_socket, F_SETFL, holder);
193 throw BESInternalError(
string(
"Could not reset socket to blocking mode: ") + strerror(errno), __FILE__, __LINE__);
196 throw BESInternalError(
string(
"selecting sockets: ") + strerror(errno), __FILE__, __LINE__);
205 int status = getsockopt(_socket, SOL_SOCKET, SO_ERROR, (
void*) &valopt, &lon);
207 throw BESInternalError(
string(
"Could not check socket status: ") + strerror(errno), __FILE__, __LINE__);
212 holder = fcntl(_socket, F_GETFL, NULL);
213 holder = holder & (~O_NONBLOCK);
214 int status = fcntl(_socket, F_SETFL, holder);
216 throw BESInternalError(
string(
"Could not reset socket to blocking mode: ") + strerror(errno), __FILE__, __LINE__);
220 "Server may be down or you may be trying on the wrong port", __FILE__, __LINE__);
225 holder = fcntl(_socket, F_GETFL, NULL);
226 holder = holder & (~O_NONBLOCK);
227 int status = fcntl(_socket, F_SETFL, holder);
229 throw BESInternalError(
string(
"Could not reset socket to blocking mode: ") + strerror(errno), __FILE__, __LINE__);
238 holder = fcntl(_socket, F_GETFL, NULL);
239 holder = holder & (~O_NONBLOCK);
240 int status = fcntl(_socket, F_SETFL, holder);
242 throw BESInternalError(
string(
"Could not reset socket to blocking mode: ") + strerror(errno), __FILE__, __LINE__);
245 throw BESInternalError(
string(
"socket connect: ") + strerror(errno), __FILE__, __LINE__);
253 holder = fcntl(_socket, F_GETFL, NULL);
254 holder = holder & (~O_NONBLOCK);
255 int status = fcntl(_socket, F_SETFL, holder);
257 throw BESInternalError(
string(
"Could not reset socket to blocking mode: ") + strerror(errno), __FILE__, __LINE__);
264 void TcpSocket::listen()
267 string err(
"Socket is already connected");
272 string err(
"Socket is already listening");
276 struct sockaddr_in server = {};
277 server.sin_family = AF_INET;
279 if (!_host.empty()) {
280 int status = inet_pton(AF_INET, _host.c_str(), &server.sin_addr.s_addr);
282 throw BESInternalError(
"Error using IP address: " + _host, __FILE__, __LINE__);
285 server.sin_addr.s_addr = INADDR_ANY;
288 BESDEBUG(
"ppt",
"Checking /etc/services for port " << _portVal << endl);
289 struct servent *sir = getservbyport(htons(_portVal), 0);
291 std::ostringstream error_oss;
292 error_oss << endl <<
"CONFIGURATION ERROR: The requested port (" << _portVal
293 <<
") appears in the system services list. ";
294 error_oss <<
"Port " << _portVal <<
" is assigned to the service '" << sir->s_name << (string)
"'";
296 if (sir->s_aliases[0] != 0) {
297 error_oss <<
" which may also be known as: ";
298 for (
int i = 0; sir->s_aliases[i] != 0; i++) {
299 if (i > 0) error_oss <<
" or ";
301 error_oss << sir->s_aliases[i];
310 server.sin_port = htons(_portVal);
311 _socket = socket(AF_INET, SOCK_STREAM, 0);
314 if (setsockopt(_socket, SOL_SOCKET, SO_REUSEADDR, (
char*)&on,
sizeof(on))) {
315 std::ostringstream errMsg;
316 errMsg << endl <<
"ERROR: Failed to set SO_REUSEADDR on TCP socket";
317 const char* error_info = strerror(errno);
318 if (error_info) errMsg <<
". Msg:: " << error_info;
323 BESDEBUG(
"besdaemon",
"About to bind to port: " << _portVal <<
" in process: " << getpid() << endl);
325 if (bind(_socket, (
struct sockaddr*) &server,
sizeof server) != -1) {
326 int length =
sizeof(server);
327 #ifdef _GETSOCKNAME_USES_SOCKLEN_T 328 if (getsockname(_socket, (
struct sockaddr *) &server, (socklen_t *) &length) == -1) {
330 if( getsockname( _socket, (
struct sockaddr *)&server, &length ) == -1 ) {
332 string error(
"getting socket name");
333 const char* error_info = strerror(errno);
334 if (error_info) error +=
" " + (string) error_info;
340 setTcpRecvBufferSize();
341 setTcpSendBufferSize();
343 if (::listen(_socket, 5) == 0) {
347 string error(
"could not listen TCP socket");
348 const char* error_info = strerror(errno);
349 if (error_info) error +=
" " + (string) error_info;
354 std::ostringstream error_msg;
355 error_msg << endl <<
"ERROR: Failed to bind TCP socket: " << _portVal;
356 const char* error_info = strerror(errno);
357 if (error_info) error_msg <<
": " << error_info;
363 std::ostringstream error_oss;
364 error_oss << endl <<
"ERROR: Failed to create socket for port " << _portVal << endl;
365 const char *error_info = strerror(errno);
366 if (error_info) error_oss <<
" " << (string) error_info;
389 void TcpSocket::setTcpRecvBufferSize()
391 if (!_haveRecvBufferSize) {
402 if (setit ==
"Yes" || setit ==
"yes" || setit ==
"Yes") {
406 istringstream sizestrm(sizestr);
407 unsigned int sizenum = 0;
410 string err =
"Socket Recv Size malformed: " + sizestr;
415 int err = setsockopt(_socket, SOL_SOCKET, SO_RCVBUF, (
char *) &sizenum, (socklen_t)
sizeof(sizenum));
418 char *serr = strerror(myerrno);
419 string err =
"Failed to set the socket receive buffer size: ";
423 err +=
"unknow error occurred";
427 BESDEBUG(
"ppt",
"Tcp receive buffer size set to " << (
unsigned long)sizenum << endl);
450 void TcpSocket::setTcpSendBufferSize()
463 if (setit ==
"Yes" || setit ==
"yes" || setit ==
"Yes") {
472 istringstream sizestrm(sizestr);
473 unsigned int sizenum = 0;
476 string err =
"Socket Send Size malformed: " + sizestr;
481 int err = setsockopt(_socket, SOL_SOCKET, SO_SNDBUF, (
char *) &sizenum, (socklen_t)
sizeof(sizenum));
484 char *serr = strerror(myerrno);
485 string err =
"Failed to set the socket send buffer size: ";
489 err +=
"unknow error occurred";
493 BESDEBUG(
"ppt",
"Tcp send buffer size set to " << (
unsigned long)sizenum << endl);
507 if (!_haveRecvBufferSize) {
509 unsigned int sizenum = 0;
510 socklen_t sizelen =
sizeof(sizenum);
511 int err = getsockopt(_socket, SOL_SOCKET, SO_RCVBUF, (
char *) &sizenum, (socklen_t *) &sizelen);
514 char *serr = strerror(myerrno);
515 string err =
"Failed to get the socket receive buffer size: ";
519 err +=
"unknow error occurred";
523 BESDEBUG(
"ppt",
"Tcp receive buffer size is " << (
unsigned long)sizenum << endl);
525 _haveRecvBufferSize =
true;
526 _recvBufferSize = sizenum;
528 return _recvBufferSize;
541 if (!_haveSendBufferSize) {
543 unsigned int sizenum = 0;
544 socklen_t sizelen =
sizeof(sizenum);
545 int err = getsockopt(_socket, SOL_SOCKET, SO_SNDBUF, (
char *) &sizenum, (socklen_t *) &sizelen);
548 char *serr = strerror(myerrno);
549 string err =
"Failed to get the socket send buffer size: ";
553 err +=
"unknow error occurred";
557 BESDEBUG(
"ppt",
"Tcp send buffer size is " << (
unsigned long)sizenum << endl);
559 _haveSendBufferSize =
true;
560 _sendBufferSize = sizenum;
562 return _sendBufferSize;
573 struct request_info req;
574 request_init( &req, RQ_DAEMON,
"besdaemon", RQ_FILE,
575 getSocketDescriptor(), 0 );
578 if( STR_EQ( eval_hostname(), paranoid ) && hosts_access() )
595 strm << BESIndent::LMarg <<
"TcpSocket::dump - (" << (
void *)
this <<
")" << endl;
597 strm << BESIndent::LMarg <<
"host: " << _host << endl;
598 strm << BESIndent::LMarg <<
"port: " << _portVal << endl;
599 strm << BESIndent::LMarg <<
"have recv buffer size: " << _haveRecvBufferSize << endl;
600 strm << BESIndent::LMarg <<
"recv buffer size: " << _recvBufferSize << endl;
601 strm << BESIndent::LMarg <<
"have send buffer size: " << _haveSendBufferSize << endl;
602 strm << BESIndent::LMarg <<
"send buffer size: " << _sendBufferSize << endl;
604 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
Abstract exception class for the BES with basic string message.
virtual unsigned int getSendBufferSize()
get the tcp send buffer size using getsockopt
void get_value(const string &s, string &val, bool &found)
Retrieve the value of a given key, if set.
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
static BESKeys * TheKeys()
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