1 // sg_socket.cxx -- Socket I/O routines
3 // Written by Curtis Olson, started November 1999.
5 // Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include <simgear/compiler.h>
26 #if !defined(_MSC_VER)
27 # include <sys/time.h> // select()
28 # include <sys/types.h> // socket(), bind(), select(), accept()
29 # include <sys/socket.h> // socket(), bind(), listen(), accept()
30 # include <netinet/in.h> // struct sockaddr_in
31 # include <netdb.h> // gethostbyname()
32 # include <unistd.h> // select(), fsync()/fdatasync(), fcntl()
33 # include <fcntl.h> // fcntl()
40 #include <simgear/debug/logstream.hxx>
42 #include "sg_socket.hxx"
45 SGSocket::SGSocket( const string& host, const string& port,
46 const string& style ) :
52 if (!wsock_init && !wsastartup()) {
53 SG_LOG( SG_IO, SG_ALERT, "Winsock not available");
57 if ( style == "udp" ) {
58 sock_style = SOCK_DGRAM;
59 } else if ( style == "tcp" ) {
60 sock_style = SOCK_STREAM;
62 sock_style = SOCK_DGRAM;
63 SG_LOG( SG_IO, SG_ALERT,
64 "Error: SGSocket() unknown style = " << style );
67 set_type( sgSocketType );
71 SGSocket::~SGSocket() {
75 SGSocket::SocketType SGSocket::make_server_socket () {
76 struct sockaddr_in name;
78 #if defined( __CYGWIN__ ) || defined( __CYGWIN32__ ) || defined( sgi ) || defined( _MSC_VER )
85 sock = socket (PF_INET, sock_style, 0);
86 if (sock == INVALID_SOCKET) {
87 SG_LOG( SG_IO, SG_ALERT,
88 "Error: socket() failed in make_server_socket()" );
89 return INVALID_SOCKET;
92 // Give the socket a name.
93 name.sin_family = AF_INET;
94 name.sin_addr.s_addr = INADDR_ANY;
95 name.sin_port = htons(port); // set port to zero to let system pick
96 name.sin_addr.s_addr = htonl (INADDR_ANY);
97 if (bind (sock, (struct sockaddr *) &name, sizeof (name)) != 0) {
98 SG_LOG( SG_IO, SG_ALERT,
99 "Error: bind() failed in make_server_socket()" );
100 return INVALID_SOCKET;
103 // Find the assigned port number
104 length = sizeof(struct sockaddr_in);
105 if ( getsockname(sock, (struct sockaddr *) &name, &length) ) {
106 SG_LOG( SG_IO, SG_ALERT,
107 "Error: getsockname() failed in make_server_socket()" );
108 return INVALID_SOCKET;
110 port = ntohs(name.sin_port);
116 SGSocket::SocketType SGSocket::make_client_socket () {
117 struct sockaddr_in name;
120 SG_LOG( SG_IO, SG_INFO, "Make client socket()" );
122 // Create the socket.
123 sock = socket (PF_INET, sock_style, 0);
124 if (sock == INVALID_SOCKET) {
125 SG_LOG( SG_IO, SG_ALERT,
126 "Error: socket() failed in make_server_socket()" );
127 return INVALID_SOCKET;
130 // specify address family
131 name.sin_family = AF_INET;
133 // get the hosts official name/info
134 hp = gethostbyname( hostname.c_str() );
136 SG_LOG( SG_IO, SG_ALERT, "Error: hostname lookup failed" );
137 return INVALID_SOCKET;
140 // Connect this socket to the host and the port specified on the
142 #if defined( __CYGWIN__ ) || defined( __CYGWIN32__ )
143 bcopy(hp->h_addr, (char *)(&(name.sin_addr.s_addr)), hp->h_length);
145 bcopy(hp->h_addr, &(name.sin_addr.s_addr), hp->h_length);
147 name.sin_port = htons(port);
149 if ( connect(sock, (struct sockaddr *) &name,
150 sizeof(struct sockaddr_in)) != 0 )
153 SG_LOG( SG_IO, SG_ALERT,
154 "Error: connect() failed in make_client_socket()" );
155 return INVALID_SOCKET;
163 size_t SGSocket::readsocket( int fd, void *buf, size_t count ) {
164 #if defined(_MSC_VER)
165 return ::recv( fd, (char *)buf, count, 0 );
167 return ::read( fd, buf, count );
171 size_t SGSocket::writesocket( int fd, const void *buf, size_t count ) {
172 #if defined(_MSC_VER)
173 return ::send( fd, (const char*)buf, count, 0 );
175 return ::write( fd, buf, count );
179 #if !defined(_MSC_VER)
180 int SGSocket::closesocket( int fd ) {
181 return ::close( fd );
186 // If specified as a server (in direction for now) open the master
187 // listening socket. If specified as a client (out direction), open a
188 // connection to a server.
189 bool SGSocket::open( const SGProtocolDir d ) {
192 if ( port_str == "" || port_str == "any" ) {
195 port = atoi( port_str.c_str() );
198 // client_connections.clear();
200 if ( get_dir() == SG_IO_IN ) {
201 // this means server for now
203 // Setup socket to listen on. Set "port" before making this
204 // call. A port of "0" indicates that we want to let the os
205 // pick any available port.
206 sock = make_server_socket();
207 if ( sock == INVALID_SOCKET ) {
208 SG_LOG( SG_IO, SG_ALERT, "socket creation failed" );
212 SG_LOG( SG_IO, SG_INFO, "socket is connected to port = " << port );
214 if ( sock_style == SOCK_DGRAM ) {
219 // Specify the maximum length of the connection queue
220 listen( sock, SG_MAX_SOCKET_QUEUE );
223 } else if ( get_dir() == SG_IO_OUT ) {
224 // this means client for now
226 sock = make_client_socket();
227 // TODO: check for error.
229 if ( sock_style == SOCK_DGRAM ) {
233 } else if ( get_dir() == SG_IO_BI && sock_style == SOCK_STREAM ) {
234 // this means server for TCP sockets
236 // Setup socket to listen on. Set "port" before making this
237 // call. A port of "0" indicates that we want to let the os
238 // pick any available port.
239 sock = make_server_socket();
240 // TODO: check for error.
242 SG_LOG( SG_IO, SG_INFO, "socket is connected to port = " << port );
245 // Specify the maximum length of the connection queue
246 listen( sock, SG_MAX_SOCKET_QUEUE );
248 SG_LOG( SG_IO, SG_ALERT,
249 "Error: bidirection mode not available for UDP sockets." );
254 SG_LOG( SG_IO, SG_ALERT, "Error opening socket: " << hostname
259 // extra SOCK_STREAM stuff
260 msgsock = INVALID_SOCKET;
267 // read data from socket (server)
268 // read a block of data of specified size
269 int SGSocket::read( char *buf, int length ) {
270 if ( sock == INVALID_SOCKET ) {
275 // check for potential input
278 FD_SET(sock, &ready);
283 // test for any input available on sock (returning immediately, even if
285 select(32, &ready, 0, 0, &tv);
287 if ( FD_ISSET(sock, &ready) ) {
288 // cout << "data ready" << endl;
290 if ( sock_style == SOCK_STREAM ) {
291 if ( msgsock == INVALID_SOCKET ) {
292 msgsock = accept(sock, 0, 0);
296 result = readsocket( sock, buf, length );
299 result = readsocket( sock, buf, length );
302 if ( result != length ) {
303 SG_LOG( SG_IO, SG_INFO,
304 "Warning: read() not enough bytes." );
312 // read a line of data, length is max size of input buffer
313 int SGSocket::readline( char *buf, int length ) {
314 if ( sock == INVALID_SOCKET ) {
318 // cout << "sock = " << sock << endl;
320 // check for potential input
323 FD_SET(sock, &ready);
328 // test for any input read on sock (returning immediately, even if
330 int result = select(32, &ready, 0, 0, &tv);
331 // cout << "result = " << result << endl;
333 if ( FD_ISSET(sock, &ready) ) {
334 // cout << "fd change state\n";
335 // read a chunk, keep in the save buffer until we have the
336 // requested amount read
338 if ( sock_style == SOCK_STREAM ) {
339 // cout << "sock_stream\n";
340 if ( msgsock == INVALID_SOCKET ) {
341 // cout << "msgsock == invalid\n";
342 msgsock = accept(sock, 0, 0);
346 // cout << "ready to read\n";
347 char *buf_ptr = save_buf + save_len;
348 result = readsocket( sock, buf_ptr, SG_IO_MAX_MSG_SIZE
350 // cout << "read result = " << result << endl;
358 // Try and detect that the remote end died. This
359 // could cause problems so if you see connections
360 // dropping for unexplained reasons, LOOK HERE!
361 if ( result == 0 && save_len == 0 && first_read == true ) {
362 SG_LOG( SG_IO, SG_ALERT,
363 "Connection closed by foreign host." );
369 char *buf_ptr = save_buf + save_len;
370 result = readsocket( sock, buf_ptr, SG_IO_MAX_MSG_SIZE - save_len );
374 // cout << "current read = " << buf_ptr << endl;
375 // cout << "current save_buf = " << save_buf << endl;
376 // cout << "save_len = " << save_len << endl;
378 // cout << "no data ready\n";
381 // look for the end of line in save_buf
383 for ( i = 0; i < save_len && save_buf[i] != '\n'; ++i );
384 if ( save_buf[i] == '\n' ) {
387 // no end of line yet
388 // cout << "no eol found" << endl;
391 // cout << "line length = " << result << endl;
393 // we found an end of line
395 // copy to external buffer
396 strncpy( buf, save_buf, result );
398 // cout << "sg_socket line = " << buf << endl;
401 for ( i = result; i < save_len; ++i ) {
402 save_buf[ i - result ] = save_buf[i];
410 // write data to socket (client)
411 int SGSocket::write( const char *buf, const int length ) {
412 if ( sock == INVALID_SOCKET ) {
416 bool error_condition = false;
418 if ( writesocket(sock, buf, length) < 0 ) {
419 SG_LOG( SG_IO, SG_ALERT, "Error writing to socket: " << port );
420 error_condition = true;
424 // check for any new client connection requests
427 FD_SET(sock, &ready);
432 // test for any input on sock (returning immediately, even if
434 select(32, &ready, 0, 0, &tv);
436 // any new connections?
437 if ( FD_ISSET(sock, &ready) ) {
438 int msgsock = accept(sock, 0, 0);
440 SG_LOG( SG_IO, SG_ALERT,
441 "Error: accept() failed in write()" );
444 client_connections.push_back( msgsock );
448 SG_LOG( SG_IO, SG_INFO, "Client connections = " <<
449 client_connections.size() );
450 for ( int i = 0; i < (int)client_connections.size(); ++i ) {
451 int msgsock = client_connections[i];
453 // read and junk any possible incoming messages.
454 // char junk[ SG_IO_MAX_MSG_SIZE ];
455 // std::read( msgsock, junk, SG_IO_MAX_MSG_SIZE );
457 // write the interesting data to the socket
458 if ( writesocket(msgsock, buf, length) == SOCKET_ERROR ) {
459 SG_LOG( SG_IO, SG_ALERT, "Error writing to socket: " << port );
460 error_condition = true;
462 #ifdef _POSIX_SYNCHRONIZED_IO
463 // fdatasync(msgsock);
471 if ( error_condition ) {
479 // write null terminated string to socket (server)
480 int SGSocket::writestring( const char *str ) {
481 if ( sock == INVALID_SOCKET ) {
485 int length = strlen( str );
486 return write( str, length );
491 bool SGSocket::close() {
492 if ( sock == INVALID_SOCKET ) {
501 // configure the socket as non-blocking
502 bool SGSocket::nonblock() {
503 if ( sock == INVALID_SOCKET ) {
507 #if defined(_MSC_VER)
509 if (ioctlsocket( sock, FIONBIO, &arg ) != 0) {
510 int error_code = WSAGetLastError();
511 SG_LOG( SG_IO, SG_ALERT,
512 "Error " << error_code << ": unable to set non-blocking mode"
517 fcntl( sock, F_SETFL, O_NONBLOCK );
522 #if defined(_MSC_VER)
524 bool SGSocket::wsock_init = false;
527 SGSocket::wsastartup() {
528 WORD wVersionRequested;
531 //wVersionRequested = MAKEWORD( 2, 2 );
532 wVersionRequested = MAKEWORD( 1, 1 );
533 int err = WSAStartup( wVersionRequested, &wsaData );
536 SG_LOG( SG_IO, SG_ALERT, "Error: Couldn't load winsock" );
541 if ( LOBYTE( wsaData.wVersion ) != 2 ||
542 HIBYTE( wsaData.wVersion ) != 2 ) {
543 SG_LOG( SG_IO, SG_ALERT, "Couldn't load a suitable winsock");