From 59991393caa63499898526fed6f0145302f00755 Mon Sep 17 00:00:00 2001 From: curt Date: Mon, 12 Nov 2001 04:47:58 +0000 Subject: [PATCH] plib/net based udp client/server sockets. --- simgear/io/Makefile.am | 4 +- simgear/io/iochannel.hxx | 1 + simgear/io/sg_socket_udp.cxx | 202 +++++++++++++++++++++++++++++++++++ simgear/io/sg_socket_udp.hxx | 138 ++++++++++++++++++++++++ 4 files changed, 344 insertions(+), 1 deletion(-) create mode 100644 simgear/io/sg_socket_udp.cxx create mode 100644 simgear/io/sg_socket_udp.hxx diff --git a/simgear/io/Makefile.am b/simgear/io/Makefile.am index 70dbab83..558c7b8c 100644 --- a/simgear/io/Makefile.am +++ b/simgear/io/Makefile.am @@ -9,6 +9,7 @@ include_HEADERS = \ sg_file.hxx \ sg_serial.hxx \ sg_socket.hxx + sg_socket_udp.hxx libsgio_a_SOURCES = \ iochannel.cxx \ @@ -16,7 +17,8 @@ libsgio_a_SOURCES = \ sg_binobj.cxx \ sg_file.cxx \ sg_serial.cxx \ - sg_socket.cxx + sg_socket.cxx \ + sg_socket_udp.cxx INCLUDES += -I$(top_srcdir) diff --git a/simgear/io/iochannel.hxx b/simgear/io/iochannel.hxx index 76a8fb24..ee43aa64 100644 --- a/simgear/io/iochannel.hxx +++ b/simgear/io/iochannel.hxx @@ -158,6 +158,7 @@ public: inline void set_dir( const SGProtocolDir d ) { dir = d; } inline SGProtocolDir get_dir() const { return dir; } inline bool isvalid() const { return valid; } + inline void set_valid( const bool v ) { valid = v; } }; diff --git a/simgear/io/sg_socket_udp.cxx b/simgear/io/sg_socket_udp.cxx new file mode 100644 index 00000000..d3f17041 --- /dev/null +++ b/simgear/io/sg_socket_udp.cxx @@ -0,0 +1,202 @@ +// sg_socket.cxx -- Socket I/O routines +// +// Written by Curtis Olson, started November 1999. +// +// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + + +#include + +#if defined( sgi ) +#include +#endif + +#include + +#include "sg_socket_udp.hxx" + + +SGSocketUDP::SGSocketUDP( const string& host, const string& port ) : + hostname(host), + port_str(port), + save_len(0) +{ + set_valid( false ); +} + + +SGSocketUDP::~SGSocketUDP() { +} + + +// 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 SGSocketUDP::open( const SGProtocolDir d ) { + set_dir( d ); + + if ( ! sock.open( false ) ) { // open a UDP socket + SG_LOG( SG_IO, SG_ALERT, "error opening socket" ); + return false; + } + + if ( port_str == "" || port_str == "any" ) { + port = 0; + } else { + port = atoi( port_str.c_str() ); + } + + // client_connections.clear(); + + if ( get_dir() == SG_IO_IN ) { + // this means server + + // bind ... + if ( sock.bind( hostname.c_str(), port ) == -1 ) { + SG_LOG( SG_IO, SG_ALERT, "error binding to port" << port_str ); + return false; + } + } else if ( get_dir() == SG_IO_OUT ) { + // this means client + + // connect ... + if ( sock.connect( hostname.c_str(), port ) == -1 ) { + SG_LOG( SG_IO, SG_ALERT, + "error connecting to " << hostname << port_str ); + return false; + } + } else { + SG_LOG( SG_IO, SG_ALERT, + "Error: bidirection mode not available for UDP sockets." ); + return false; + } + + set_valid( true ); + + return true; +} + + +// read data from socket (server) +// read a block of data of specified size +int SGSocketUDP::read( char *buf, int length ) { + if ( ! isvalid() ) { + return 0; + } + + int result; + + if ( (result = sock.recv(buf, SG_IO_MAX_MSG_SIZE, 0)) >= 0 ) { + buf[result] = '\0'; + // printf("msg received = %s\n", buf); + } + + return result; +} + + +// read a line of data, length is max size of input buffer +int SGSocketUDP::readline( char *buf, int length ) { + if ( ! isvalid() ) { + return 0; + } + + // cout << "sock = " << sock << endl; + + char *buf_ptr = save_buf + save_len; + int result = sock.recv(buf_ptr, SG_IO_MAX_MSG_SIZE, 0); + // printf("msg received = %s\n", buf); + save_len += result; + + // look for the end of line in save_buf + int i; + for ( i = 0; i < save_len && save_buf[i] != '\n'; ++i ); + if ( save_buf[i] == '\n' ) { + result = i + 1; + } else { + // no end of line yet + // cout << "no eol found" << endl; + return 0; + } + // cout << "line length = " << result << endl; + + // we found an end of line + + // copy to external buffer + strncpy( buf, save_buf, result ); + buf[result] = '\0'; + // cout << "sg_socket line = " << buf << endl; + + // shift save buffer + for ( i = result; i < save_len; ++i ) { + save_buf[ i - result ] = save_buf[i]; + } + save_len -= result; + + return result; +} + + +// write data to socket (client) +int SGSocketUDP::write( const char *buf, const int length ) { + if ( ! isvalid() ) { + return 0; + } + + bool error_condition = false; + + if ( sock.send( buf, length, 0 ) < 0 ) { + SG_LOG( SG_IO, SG_ALERT, "Error writing to socket: " << port ); + error_condition = true; + return 0; + } + + return length; +} + + +// write null terminated string to socket (server) +int SGSocketUDP::writestring( const char *str ) { + if ( !isvalid() ) { + return 0; + } + + int length = strlen( str ); + return write( str, length ); +} + + +// close the port +bool SGSocketUDP::close() { + if ( !isvalid() ) { + return 0; + } + + sock.close(); + + return true; +} + + +// configure the socket as non-blocking +bool SGSocketUDP::setBlocking( bool value ) { + sock.setBlocking( value ); + + return true; +} diff --git a/simgear/io/sg_socket_udp.hxx b/simgear/io/sg_socket_udp.hxx new file mode 100644 index 00000000..bb413fa3 --- /dev/null +++ b/simgear/io/sg_socket_udp.hxx @@ -0,0 +1,138 @@ +/** + * \file sg_socket_udp.hxx + * UDP Socket I/O routines. + */ + +// Written by Curtis Olson, started November 2001. +// +// Copyright (C) 2001 Curtis L. Olson - curt@flightgear.org +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + + +#ifndef _SG_SOCKET_UDP_HXX +#define _SG_SOCKET_UDP_HXX + + +#ifndef __cplusplus +# error This library requires C++ +#endif + +#include + +#include + +#include STL_STRING + +#include +#include + +SG_USING_STD(string); + +/** + * A UDP socket I/O class based on SGIOChannel and plib/net. + */ +class SGSocketUDP : public SGIOChannel { + +private: + + netSocket sock; + + string hostname; + string port_str; + + char save_buf[ 2 * SG_IO_MAX_MSG_SIZE ]; + int save_len; + + short unsigned int port; + +public: + + /** + * Create an instance of SGSocketUDP. + * + * When calling the constructor you need to provide a host name, and a + * port number. The convention used by the + * SGSocketUDP class is that the server side listens and the client + * side sends. For a server socket, the host name should be + * empty. For a server, the port number is optional, if you do not + * specify a port, the system will assign one. For a client + * socket, you need to specify both a destination host and + * destination port. + * + * UDP sockets are a lower level protocol than TCP sockets and are + * "connectionless" in the sense that either client or server can + * exist, or not exist, startup, quit, etc. in any order and + * whenever both ends are alive, the communication succeeds. With + * UDP sockets, the server end just sits and listens for incoming + * packets from anywhere. The client end sends it's message and + * forgets about it. It doesn't care if there isn't even a server + * out there listening and all the packets are getting + * lost. Although systems/networks usually do a pretty good job + * (statistically) of getting your UDP packets to their + * destination, there is no guarantee that any particular packet + * will make it. But, because of this low level implementation and + * lack of error checking, UDP packets are much faster and + * efficient. UDP packets are good for sending positional + * information to synchronize two applications. In this case, you + * want the information to arrive as quickly as possible, and if + * you lose a packet, you'd rather get new updated information + * rather than have the system waste time resending a packet that + * is becoming older and older with every retry. + * @param host name of host if direction is SG_IO_OUT or SG_IO_BI + * @param port port number if we care to choose one. + * @param style specify "udp" or "tcp" */ + SGSocketUDP( const string& host, const string& port ); + + /** Destructor */ + ~SGSocketUDP(); + + // 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 open( const SGProtocolDir d ); + + // read data from socket + int read( char *buf, int length ); + + // read data from socket + int readline( char *buf, int length ); + + // write data to a socket + int write( const char *buf, const int length ); + + // write null terminated string to a socket + int writestring( const char *str ); + + // close file + bool close(); + + /** + * Set blocking true or false + * @return success/failure + */ + bool setBlocking( bool value ); + + /** @return the remote host name */ + inline string get_hostname() const { return hostname; } + + /** @return the port number (in string form) */ + inline string get_port_str() const { return port_str; } +}; + + +#endif // _SG_SOCKET_UDP_HXX -- 2.39.5