]> git.mxchange.org Git - simgear.git/blobdiff - simgear/io/sg_socket.cxx
Check for valid hostname lookup in sg_socket.cxx.
[simgear.git] / simgear / io / sg_socket.cxx
index 6336e76b4dce5d8678015fd2660eb97b161dc491..905639b91d2c01f437dbe9a01d2b9827246f5658 100644 (file)
@@ -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,7 +220,7 @@ 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();
@@ -221,7 +230,7 @@ bool SGSocket::open( SGProtocolDir dir ) {
            // Non-blocking UDP
            nonblock();
        }
-    } else if ( dir == SG_IO_BI && sock_style == SOCK_STREAM ) {
+    } 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
@@ -230,23 +239,27 @@ bool SGSocket::open( SGProtocolDir dir ) {
        sock = make_server_socket();
        // TODO: check for error.
 
-       FG_LOG( FG_IO, FG_INFO, "socket is connected to port = " << port );
+       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, 
+       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;
 }
 
@@ -254,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);
@@ -269,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." );
        }
     }
@@ -282,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;
@@ -294,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
@@ -339,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;
     }
 
@@ -364,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 {
@@ -372,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];
@@ -383,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
@@ -404,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 );
 }
@@ -412,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;
@@ -426,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;
@@ -455,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;
     }