head 1.4; access; symbols; locks; strict; comment @# @; 1.4 date 2002.09.07.01.50.40; author curt; state Exp; branches; next 1.3; 1.3 date 2002.08.31.19.01.57; author curt; state Exp; branches; next 1.2; 1.2 date 2002.08.31.18.54.04; author curt; state Exp; branches; next 1.1; 1.1 date 2002.02.15.17.22.00; author curt; state Exp; branches; next ; desc @@ 1.4 log @Updated doxygen docs. @ text @
Main Page Class Hierarchy Compound List File List Compound Members File Members

# sg_socket.cxx

    00001 // sg_socket.cxx -- Socket I/O routines
    00002 //
    00003 // Written by Curtis Olson, started November 1999.
    00004 // Modified by Bernie Bright <bbright@@bigpond.net.au>, May 2002.
    00005 //
    00006 // Copyright (C) 1999  Curtis L. Olson - curt@@flightgear.org
    00007 //
    00008 // This program is free software; you can redistribute it and/or
    00009 // modify it under the terms of the GNU General Public License as
    00010 // published by the Free Software Foundation; either version 2 of the
    00011 // License, or (at your option) any later version.
    00012 //
    00013 // This program is distributed in the hope that it will be useful, but
    00014 // WITHOUT ANY WARRANTY; without even the implied warranty of
    00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00016 // General Public License for more details.
    00017 //
    00018 // You should have received a copy of the GNU General Public License
    00019 // along with this program; if not, write to the Free Software
    00020 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
    00021 //
    00022 // $Id: sg_socket.cxx,v 1.15 2002/05/15 19:21:54 curt Exp $
    00023
    00024
    00025 #include <simgear/compiler.h>
    00026
    00027 #if defined( sgi )
    00028 #include <strings.h>
    00029 #endif
    00030
    00031 #include <simgear/debug/logstream.hxx>
    00032
    00033 #include "sg_socket.hxx"
    00034
    00035 bool SGSocket::init = false;
    00036
    00037 SGSocket::SGSocket( const string& host, const string& port_,
    00038                     const string& style ) :
    00039     hostname(host),
    00040     port_str(port_),
    00041     save_len(0),
    00042     client(0),
    00043     is_tcp(false),
    00044     is_server(false),
    00045     first_read(false)
    00046 {
    00047     if (!init)
    00048     {
    00049         netInit(NULL, NULL);    // plib-1.4.2 compatible
    00050         init = true;
    00051     }
    00052
    00053     if ( style == "tcp" )
    00054     {
    00055         is_tcp = true;
    00056     }
    00057     else if ( style != (string)"udp" )
    00058     {
    00059         SG_LOG( SG_IO, SG_ALERT,
    00060                 "Error: SGSocket() unknown style = " << style );
    00061     }
    00062
    00063     set_type( sgSocketType );
    00064 }
    00065
    00066
    00067 SGSocket::~SGSocket()
    00068 {
    00069     this->close();
    00070 }
    00071
    00072
    00073 bool
    00074 SGSocket::make_server_socket()
    00075 {
    00076     if (!sock.open( is_tcp ))
    00077     {
    00078         SG_LOG( SG_IO, SG_ALERT,
    00079                 "Error: socket() failed in make_server_socket()" );
    00080         return false;
    00081     }
    00082
    00083     if (sock.bind( "", port ) < 0)
    00084     {
    00085         SG_LOG( SG_IO, SG_ALERT,
    00086                 "Error: bind() failed in make_server_socket()" );
    00087         sock.close();
    00088         return false;
    00089     }
    00090
    00091     return true;
    00092 }
    00093
    00094
    00095 bool
    00096 SGSocket::make_client_socket()
    00097 {
    00098     if (!sock.open( is_tcp ))
    00099     {
    00100         SG_LOG( SG_IO, SG_ALERT,
    00101                 "Error: socket() failed in make_client_socket()" );
    00102         return false;
    00103     }
    00104
    00105     if (sock.connect( hostname.c_str(), port ) < 0)
    00106     {
    00107         SG_LOG( SG_IO, SG_ALERT,
    00108                 "Error: connect() failed in make_client_socket()" );
    00109         sock.close();
    00110         return false;
    00111     }
    00112
    00113     return true;
    00114 }
    00115
    00116 // If specified as a server (in direction for now) open the master
    00117 // listening socket.  If specified as a client (out direction), open a
    00118 // connection to a server.
    00119 bool
    00120 SGSocket::open( SGProtocolDir direction )
    00121 {
    00122     set_dir( direction );
    00123
    00124     is_server = is_tcp &&
    00125         (direction == SG_IO_IN || direction == SG_IO_BI);
    00126
    00127     if ( port_str == "" || port_str == "any" ) {
    00128         port = 0;
    00129     } else {
    00130         port = atoi( port_str.c_str() );
    00131     }
    00132
    00133     if (direction == SG_IO_IN)
    00134     {
    00135         // this means server for now
    00136
    00137         // Setup socket to listen on.  Set "port" before making this
    00138         // call.  A port of "0" indicates that we want to let the os
    00139         // pick any available port.
    00140         if (!make_server_socket())
    00141         {
    00142             SG_LOG( SG_IO, SG_ALERT, "SG_IO_IN socket creation failed" );
    00143             return false;
    00144         }
    00145
    00146         if ( !is_tcp )
    00147         {
    00148             // Non-blocking UDP
    00149             nonblock();
    00150         }
    00151         else
    00152         {
    00153             // Blocking TCP
    00154             // Specify the maximum length of the connection queue
    00155             sock.listen( SG_MAX_SOCKET_QUEUE );
    00156         }
    00157
    00158     }
    00159     else if (direction == SG_IO_OUT)
    00160     {
    00161         // this means client for now
    00162
    00163         if (!make_client_socket())
    00164         {
    00165             SG_LOG( SG_IO, SG_ALERT, "SG_IO_OUT socket creation failed" );
    00166             return false;
    00167         }
    00168
    00169         if ( !is_tcp )
    00170         {
    00171             // Non-blocking UDP
    00172             nonblock();
    00173         }
    00174     }
    00175     else if (direction == SG_IO_BI && is_tcp)
    00176     {
    00177         // this means server for TCP sockets
    00178
    00179         // Setup socket to listen on.  Set "port" before making this
    00180         // call.  A port of "0" indicates that we want to let the os
    00181         // pick any available port.
    00182         if (!make_server_socket())
    00183         {
    00184             SG_LOG( SG_IO, SG_ALERT, "SG_IO_BI socket creation failed" );
    00185             return false;
    00186         }
    00187         // Blocking TCP
    00188         // Specify the maximum length of the connection queue
    00189         sock.listen( SG_MAX_SOCKET_QUEUE );
    00190     }
    00191     else
    00192     {
    00193         SG_LOG( SG_IO, SG_ALERT,
    00194                 "Error:  bidirection mode not available for UDP sockets." );
    00195         return false;
    00196     }
    00197
    00198     first_read = false;
    00199
    00200     return true;
    00201 }
    00202
    00203
    00204 // read data from socket (server)
    00205 // read a block of data of specified size
    00206 int
    00207 SGSocket::read( char *buf, int length )
    00208 {
    00209     if (sock.getHandle() == -1 &&
    00210         (client == 0 || client->getHandle() == -1))
    00211     {
    00212         return 0;
    00213     }
    00214
    00215     // test for any input available on sock (returning immediately, even if
    00216     // nothing)
    00217     int result = poll();
    00218
    00219     if (result > 0)
    00220     {
    00221         result = sock.recv( buf, length );
    00222
    00223         if ( result != length )
    00224         {
    00225             SG_LOG( SG_IO, SG_INFO,
    00226                     "Warning: read() not enough bytes." );
    00227         }
    00228     }
    00229
    00230     return result;
    00231 }
    00232
    00233
    00234 // read a line of data, length is max size of input buffer
    00235 int
    00236 SGSocket::readline( char *buf, int length )
    00237 {
    00238     if (sock.getHandle() == -1 &&
    00239         (client == 0 || client->getHandle() == -1))
    00240     {
    00241         return 0;
    00242     }
    00243
    00244     // test for any input read on sock (returning immediately, even if
    00245     // nothing)
    00246     int result = this->poll();
    00247
    00248     if (result > 0)
    00249     {
    00250         // read a chunk, keep in the save buffer until we have the
    00251         // requested amount read
    00252
    00253         if (is_tcp)
    00254         {
    00255             char *buf_ptr = save_buf + save_len;
    00256             result = client->recv( buf_ptr, SG_IO_MAX_MSG_SIZE - save_len );
    00257
    00258             if ( result > 0 )
    00259             {
    00260                 first_read = true;
    00261             }
    00262
    00263             save_len += result;
    00264
    00265             // Try and detect that the remote end died.  This
    00266             // could cause problems so if you see connections
    00267             // dropping for unexplained reasons, LOOK HERE!
    00268             if (result == 0 && save_len == 0 && first_read == true)
    00269             {
    00270                 SG_LOG( SG_IO, SG_ALERT,
    00271                         "Connection closed by foreign host." );
    00272                 delete client;
    00273                 client = 0;
    00274             }
    00275         }
    00276         else
    00277         {
    00278             char *buf_ptr = save_buf + save_len;
    00279             result = sock.recv( buf_ptr, SG_IO_MAX_MSG_SIZE - save_len );
    00280             save_len += result;
    00281         }
    00282     }
    00283
    00284     // look for the end of line in save_buf
    00285     int i;
    00286     for ( i = 0; i < save_len && save_buf[i] != '\n'; ++i )
    00287         ;
    00288     if ( save_buf[i] == '\n' ) {
    00289         result = i + 1;
    00290     } else {
    00291         // no end of line yet
    00292         return 0;
    00293     }
    00294
    00295     // we found an end of line
    00296
    00297     // copy to external buffer
    00298     strncpy( buf, save_buf, result );
    00299     buf[result] = '\0';
    00300
    00301     // shift save buffer
    00302     //memmove( save_buf+, save_buf+, ? );
    00303     for ( i = result; i < save_len; ++i ) {
    00304         save_buf[ i - result ] = save_buf[i];
    00305     }
    00306     save_len -= result;
    00307
    00308     return result;
    00309 }
    00310
    00311
    00312 // write data to socket (client)
    00313 int
    00314 SGSocket::write( const char *buf, const int length )
    00315 {
    00316     netSocket* s = client == 0 ? &sock : client;
    00317     if (s->getHandle() == -1)
    00318     {
    00319         return 0;
    00320     }
    00321
    00322     bool error_condition = false;
    00323
    00324     if ( s->send( buf, length ) < 0 )
    00325     {
    00326         SG_LOG( SG_IO, SG_ALERT, "Error writing to socket: " << port );
    00327         error_condition = true;
    00328     }
    00329
    00330     if ( error_condition ) {
    00331         return 0;
    00332     }
    00333
    00334     return length;
    00335 }
    00336
    00337
    00338 // write null terminated string to socket (server)
    00339 int
    00340 SGSocket::writestring( const char *str )
    00341 {
    00342     int length = strlen( str );
    00343     return this->write( str, length );
    00344 }
    00345
    00346
    00347 // close the port
    00348 bool
    00349 SGSocket::close()
    00350 {
    00351     delete client;
    00352     client = 0;
    00353
    00354     sock.close();
    00355     return true;
    00356 }
    00357
    00358
    00359 // configure the socket as non-blocking
    00360 bool
    00361 SGSocket::nonblock()
    00362 {
    00363     if (sock.getHandle() == -1) {
    00364         return false;
    00365     }
    00366
    00367     sock.setBlocking( false );
    00368     return true;
    00369 }
    00370
    00371 int
    00372 SGSocket::poll()
    00373 {
    00374     netSocket* readers[2];
    00375
    00376     readers[0] = client != 0 ? client : &sock;
    00377     readers[1] = 0;
    00378
    00379     netSocket* writers[1];
    00380     writers[0] = 0;
    00381
    00382     int result = netSocket::select( readers, writers, 0 );
    00383
    00384     if (result > 0 && is_server && client == 0)
    00385     {
    00386         // Accept a new client connection
    00387         netAddress addr;
    00388         int new_fd = sock.accept( &addr );
    00389         SG_LOG( SG_IO, SG_INFO, "Accepted connection from "
    00390                 << addr.getHost() << ":" << addr.getPort() );
    00391         client = new netSocket();
    00392         client->setHandle( new_fd );
    00393         return 0;
    00394     }
    00395
    00396     return result;
    00397 }

@ 1.3 log @Oops, try again. @ text @d406 1 a406 1