X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fio%2Fsg_socket.cxx;h=905639b91d2c01f437dbe9a01d2b9827246f5658;hb=a66d1ad8552e910adb72d442177e2c9f21660857;hp=4340135726e91323993c1f3891a82b64efa6621e;hpb=453a53b37212f16c4ddc79d068f3c878cae29959;p=simgear.git diff --git a/simgear/io/sg_socket.cxx b/simgear/io/sg_socket.cxx index 43401357..905639b9 100644 --- a/simgear/io/sg_socket.cxx +++ b/simgear/io/sg_socket.cxx @@ -50,7 +50,7 @@ SGSocket::SGSocket( const string& host, const string& port, { #if defined(_MSC_VER) if (!wsock_init && !wsastartup()) { - FG_LOG( FG_IO, FG_ALERT, "Winsock not available"); + SG_LOG( SG_IO, SG_ALERT, "Winsock not available"); } #endif @@ -60,7 +60,7 @@ SGSocket::SGSocket( const string& host, const string& port, sock_style = SOCK_STREAM; } else { sock_style = SOCK_DGRAM; - FG_LOG( FG_IO, FG_ALERT, + SG_LOG( SG_IO, SG_ALERT, "Error: SGSocket() unknown style = " << style ); } @@ -84,7 +84,7 @@ SGSocket::SocketType SGSocket::make_server_socket () { // Create the socket. sock = socket (PF_INET, sock_style, 0); if (sock == INVALID_SOCKET) { - FG_LOG( FG_IO, FG_ALERT, + SG_LOG( SG_IO, SG_ALERT, "Error: socket() failed in make_server_socket()" ); return INVALID_SOCKET; } @@ -95,7 +95,7 @@ SGSocket::SocketType SGSocket::make_server_socket () { name.sin_port = htons(port); // set port to zero to let system pick name.sin_addr.s_addr = htonl (INADDR_ANY); if (bind (sock, (struct sockaddr *) &name, sizeof (name)) != 0) { - FG_LOG( FG_IO, FG_ALERT, + SG_LOG( SG_IO, SG_ALERT, "Error: bind() failed in make_server_socket()" ); return INVALID_SOCKET; } @@ -103,7 +103,7 @@ SGSocket::SocketType SGSocket::make_server_socket () { // Find the assigned port number length = sizeof(struct sockaddr_in); if ( getsockname(sock, (struct sockaddr *) &name, &length) ) { - FG_LOG( FG_IO, FG_ALERT, + SG_LOG( SG_IO, SG_ALERT, "Error: getsockname() failed in make_server_socket()" ); return INVALID_SOCKET; } @@ -117,12 +117,12 @@ SGSocket::SocketType SGSocket::make_client_socket () { struct sockaddr_in name; struct hostent *hp; - FG_LOG( FG_IO, FG_INFO, "Make client socket()" ); + SG_LOG( SG_IO, SG_INFO, "Make client socket()" ); // Create the socket. sock = socket (PF_INET, sock_style, 0); if (sock == INVALID_SOCKET) { - FG_LOG( FG_IO, FG_ALERT, + SG_LOG( SG_IO, SG_ALERT, "Error: socket() failed in make_server_socket()" ); return INVALID_SOCKET; } @@ -132,6 +132,10 @@ SGSocket::SocketType SGSocket::make_client_socket () { // get the hosts official name/info hp = gethostbyname( hostname.c_str() ); + if (hp == NULL) { + SG_LOG( SG_IO, SG_ALERT, "Error: hostname lookup failed" ); + return INVALID_SOCKET; + } // Connect this socket to the host and the port specified on the // command line @@ -146,7 +150,7 @@ SGSocket::SocketType SGSocket::make_client_socket () { sizeof(struct sockaddr_in)) != 0 ) { closesocket(sock); - FG_LOG( FG_IO, FG_ALERT, + SG_LOG( SG_IO, SG_ALERT, "Error: connect() failed in make_client_socket()" ); return INVALID_SOCKET; } @@ -158,7 +162,7 @@ SGSocket::SocketType SGSocket::make_client_socket () { // Wrapper functions size_t SGSocket::readsocket( int fd, void *buf, size_t count ) { #if defined(_MSC_VER) - return ::recv( fd, buf, count, 0 ); + return ::recv( fd, (char *)buf, count, 0 ); #else return ::read( fd, buf, count ); #endif @@ -166,7 +170,7 @@ size_t SGSocket::readsocket( int fd, void *buf, size_t count ) { size_t SGSocket::writesocket( int fd, const void *buf, size_t count ) { #if defined(_MSC_VER) - return ::send( fd, buf, count, 0 ); + return ::send( fd, (const char*)buf, count, 0 ); #else return ::write( fd, buf, count ); #endif @@ -182,7 +186,9 @@ int SGSocket::closesocket( int fd ) { // If specified as a server (in direction for now) open the master // listening socket. If specified as a client (out direction), open a // connection to a server. -bool SGSocket::open( SGProtocolDir dir ) { +bool SGSocket::open( const SGProtocolDir d ) { + set_dir( d ); + if ( port_str == "" || port_str == "any" ) { port = 0; } else { @@ -191,16 +197,19 @@ bool SGSocket::open( SGProtocolDir dir ) { // client_connections.clear(); - if ( dir == SG_IO_IN ) { + if ( get_dir() == SG_IO_IN ) { // this means server for now // Setup socket to listen on. Set "port" before making this // call. A port of "0" indicates that we want to let the os // pick any available port. sock = make_server_socket(); - // TODO: check for error. + if ( sock == INVALID_SOCKET ) { + SG_LOG( SG_IO, SG_ALERT, "socket creation failed" ); + return false; + } - FG_LOG( FG_IO, FG_INFO, "socket is connected to port = " << port ); + SG_LOG( SG_IO, SG_INFO, "socket is connected to port = " << port ); if ( sock_style == SOCK_DGRAM ) { // Non-blocking UDP @@ -211,28 +220,46 @@ bool SGSocket::open( SGProtocolDir dir ) { listen( sock, SG_MAX_SOCKET_QUEUE ); } - } else if ( dir == SG_IO_OUT ) { + } else if ( get_dir() == SG_IO_OUT ) { // this means client for now sock = make_client_socket(); - // TODO: check for error. + // TODO: check for error. if ( sock_style == SOCK_DGRAM ) { // Non-blocking UDP nonblock(); } + } else if ( get_dir() == SG_IO_BI && sock_style == SOCK_STREAM ) { + // this means server for TCP sockets + + // Setup socket to listen on. Set "port" before making this + // call. A port of "0" indicates that we want to let the os + // pick any available port. + sock = make_server_socket(); + // TODO: check for error. + + SG_LOG( SG_IO, SG_INFO, "socket is connected to port = " << port ); + + // Blocking TCP + // Specify the maximum length of the connection queue + listen( sock, SG_MAX_SOCKET_QUEUE ); } else { - FG_LOG( FG_IO, FG_ALERT, - "Error: bidirection mode not available yet for sockets." ); + SG_LOG( SG_IO, SG_ALERT, + "Error: bidirection mode not available for UDP sockets." ); return false; } if ( sock < 0 ) { - FG_LOG( FG_IO, FG_ALERT, "Error opening socket: " << hostname + SG_LOG( SG_IO, SG_ALERT, "Error opening socket: " << hostname << ":" << port ); return false; } + // extra SOCK_STREAM stuff + msgsock = INVALID_SOCKET; + first_read = false; + return true; } @@ -240,8 +267,11 @@ bool SGSocket::open( SGProtocolDir dir ) { // read data from socket (server) // read a block of data of specified size int SGSocket::read( char *buf, int length ) { - int result = 0; + if ( sock == INVALID_SOCKET ) { + return 0; + } + int result = 0; // check for potential input fd_set ready; FD_ZERO(&ready); @@ -255,9 +285,22 @@ int SGSocket::read( char *buf, int length ) { select(32, &ready, 0, 0, &tv); if ( FD_ISSET(sock, &ready) ) { - result = readsocket( sock, buf, length ); + // cout << "data ready" << endl; + + if ( sock_style == SOCK_STREAM ) { + if ( msgsock == INVALID_SOCKET ) { + msgsock = accept(sock, 0, 0); + closesocket(sock); + sock = msgsock; + } else { + result = readsocket( sock, buf, length ); + } + } else { + result = readsocket( sock, buf, length ); + } + if ( result != length ) { - FG_LOG( FG_IO, FG_INFO, + SG_LOG( SG_IO, SG_INFO, "Warning: read() not enough bytes." ); } } @@ -268,7 +311,11 @@ int SGSocket::read( char *buf, int length ) { // read a line of data, length is max size of input buffer int SGSocket::readline( char *buf, int length ) { - int result = 0; + if ( sock == INVALID_SOCKET ) { + return 0; + } + + // cout << "sock = " << sock << endl; // check for potential input fd_set ready; @@ -280,19 +327,55 @@ int SGSocket::readline( char *buf, int length ) { // test for any input read on sock (returning immediately, even if // nothing) - int rc = select(32, &ready, 0, 0, &tv); - // FG_LOG( FG_IO, FG_DEBUG, "select returned " << rc ); + int result = select(32, &ready, 0, 0, &tv); + // cout << "result = " << result << endl; if ( FD_ISSET(sock, &ready) ) { + // cout << "fd change state\n"; // read a chunk, keep in the save buffer until we have the // requested amount read - char *buf_ptr = save_buf + save_len; - result = readsocket( sock, buf_ptr, SG_IO_MAX_MSG_SIZE - save_len ); - save_len += result; + if ( sock_style == SOCK_STREAM ) { + // cout << "sock_stream\n"; + if ( msgsock == INVALID_SOCKET ) { + // cout << "msgsock == invalid\n"; + msgsock = accept(sock, 0, 0); + closesocket(sock); + sock = msgsock; + } else { + // cout << "ready to read\n"; + char *buf_ptr = save_buf + save_len; + result = readsocket( sock, buf_ptr, SG_IO_MAX_MSG_SIZE + - save_len ); + // cout << "read result = " << result << endl; + + if ( result > 0 ) { + first_read = true; + } + + save_len += result; + + // Try and detect that the remote end died. This + // could cause problems so if you see connections + // dropping for unexplained reasons, LOOK HERE! + if ( result == 0 && save_len == 0 && first_read == true ) { + SG_LOG( SG_IO, SG_ALERT, + "Connection closed by foreign host." ); + closesocket(sock); + open( get_dir() ); + } + } + } else { + char *buf_ptr = save_buf + save_len; + result = readsocket( sock, buf_ptr, SG_IO_MAX_MSG_SIZE - save_len ); + save_len += result; + } + // cout << "current read = " << buf_ptr << endl; // cout << "current save_buf = " << save_buf << endl; // cout << "save_len = " << save_len << endl; + } else { + // cout << "no data ready\n"; } // look for the end of line in save_buf @@ -325,11 +408,15 @@ int SGSocket::readline( char *buf, int length ) { // write data to socket (client) -int SGSocket::write( char *buf, int length ) { +int SGSocket::write( const char *buf, const int length ) { + if ( sock == INVALID_SOCKET ) { + return 0; + } + bool error_condition = false; if ( writesocket(sock, buf, length) < 0 ) { - FG_LOG( FG_IO, FG_ALERT, "Error writing to socket: " << port ); + SG_LOG( SG_IO, SG_ALERT, "Error writing to socket: " << port ); error_condition = true; } @@ -350,7 +437,7 @@ int SGSocket::write( char *buf, int length ) { if ( FD_ISSET(sock, &ready) ) { int msgsock = accept(sock, 0, 0); if ( msgsock < 0 ) { - FG_LOG( FG_IO, FG_ALERT, + SG_LOG( SG_IO, SG_ALERT, "Error: accept() failed in write()" ); return 0; } else { @@ -358,7 +445,7 @@ int SGSocket::write( char *buf, int length ) { } } - FG_LOG( FG_IO, FG_INFO, "Client connections = " << + SG_LOG( SG_IO, SG_INFO, "Client connections = " << client_connections.size() ); for ( int i = 0; i < (int)client_connections.size(); ++i ) { int msgsock = client_connections[i]; @@ -369,7 +456,7 @@ int SGSocket::write( char *buf, int length ) { // write the interesting data to the socket if ( writesocket(msgsock, buf, length) == SOCKET_ERROR ) { - FG_LOG( FG_IO, FG_ALERT, "Error writing to socket: " << port ); + SG_LOG( SG_IO, SG_ALERT, "Error writing to socket: " << port ); error_condition = true; } else { #ifdef _POSIX_SYNCHRONIZED_IO @@ -390,7 +477,11 @@ int SGSocket::write( char *buf, int length ) { // write null terminated string to socket (server) -int SGSocket::writestring( char *str ) { +int SGSocket::writestring( const char *str ) { + if ( sock == INVALID_SOCKET ) { + return 0; + } + int length = strlen( str ); return write( str, length ); } @@ -398,12 +489,9 @@ int SGSocket::writestring( char *str ) { // close the port bool SGSocket::close() { -#if 0 - for ( int i = 0; i < (int)client_connections.size(); ++i ) { - int msgsock = client_connections[i]; - closesocket( msgsock ); + if ( sock == INVALID_SOCKET ) { + return 0; } -#endif closesocket( sock ); return true; @@ -412,11 +500,15 @@ bool SGSocket::close() { // configure the socket as non-blocking bool SGSocket::nonblock() { + if ( sock == INVALID_SOCKET ) { + return 0; + } + #if defined(_MSC_VER) u_long arg = 1; if (ioctlsocket( sock, FIONBIO, &arg ) != 0) { int error_code = WSAGetLastError(); - FG_LOG( FG_IO, FG_ALERT, + SG_LOG( SG_IO, SG_ALERT, "Error " << error_code << ": unable to set non-blocking mode" ); return false; @@ -441,14 +533,14 @@ SGSocket::wsastartup() { int err = WSAStartup( wVersionRequested, &wsaData ); if (err != 0) { - FG_LOG( FG_IO, FG_ALERT, "Error: Couldn't load winsock" ); + SG_LOG( SG_IO, SG_ALERT, "Error: Couldn't load winsock" ); return false; } #if 0 if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 ) { - FG_LOG( FG_IO, FG_ALERT, "Couldn't load a suitable winsock"); + SG_LOG( SG_IO, SG_ALERT, "Couldn't load a suitable winsock"); WSACleanup( ); return false; }