From 22812a0aaef07c8da20b0c7e151016965e29dcff Mon Sep 17 00:00:00 2001 From: curt Date: Tue, 11 Jul 2000 18:37:49 +0000 Subject: [PATCH] Moved to SimGear. --- simgear/io/Makefile.am | 17 ++ simgear/io/iochannel.cxx | 74 ++++++++ simgear/io/iochannel.hxx | 78 ++++++++ simgear/io/sg_file.cxx | 155 ++++++++++++++++ simgear/io/sg_file.hxx | 83 +++++++++ simgear/io/sg_serial.cxx | 153 ++++++++++++++++ simgear/io/sg_serial.hxx | 90 ++++++++++ simgear/io/sg_socket.cxx | 377 +++++++++++++++++++++++++++++++++++++++ simgear/io/sg_socket.hxx | 97 ++++++++++ 9 files changed, 1124 insertions(+) create mode 100644 simgear/io/Makefile.am create mode 100644 simgear/io/iochannel.cxx create mode 100644 simgear/io/iochannel.hxx create mode 100644 simgear/io/sg_file.cxx create mode 100644 simgear/io/sg_file.hxx create mode 100644 simgear/io/sg_serial.cxx create mode 100644 simgear/io/sg_serial.hxx create mode 100644 simgear/io/sg_socket.cxx create mode 100644 simgear/io/sg_socket.hxx diff --git a/simgear/io/Makefile.am b/simgear/io/Makefile.am new file mode 100644 index 00000000..12bd629b --- /dev/null +++ b/simgear/io/Makefile.am @@ -0,0 +1,17 @@ +includedir = @includedir@/io + +lib_LIBRARIES = libsgio.a + +include_HEADERS = \ + iochannel.hxx \ + sg_file.hxx \ + sg_serial.hxx \ + sg_socket.hxx + +libsgio_a_SOURCES = \ + iochannel.cxx \ + sg_file.cxx \ + sg_serial.cxx \ + sg_socket.cxx + +INCLUDES += -I$(top_builddir) diff --git a/simgear/io/iochannel.cxx b/simgear/io/iochannel.cxx new file mode 100644 index 00000000..ab83fc09 --- /dev/null +++ b/simgear/io/iochannel.cxx @@ -0,0 +1,74 @@ +// iochannel.cxx -- High level IO channel class +// +// 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 "iochannel.hxx" +// #include "garmin.hxx" +// #include "nmea.hxx" + + +// constructor +SGIOChannel::SGIOChannel() +{ +} + + +// destructor +SGIOChannel::~SGIOChannel() +{ +} + + +// dummy configure routine +bool SGIOChannel::open( SGProtocolDir dir ) { + return false; +} + + +// dummy process routine +int SGIOChannel::read( char *buf, int length ) { + return 0; +} + + +// dummy process routine +int SGIOChannel::readline( char *buf, int length ) { + return 0; +} + + +// dummy process routine +int SGIOChannel::write( char *buf, int length ) { + return false; +} + + +// dummy process routine +int SGIOChannel::writestring( char *str ) { + return false; +} + + +// dummy close routine +bool SGIOChannel::close() { + return false; +} diff --git a/simgear/io/iochannel.hxx b/simgear/io/iochannel.hxx new file mode 100644 index 00000000..941cdc0d --- /dev/null +++ b/simgear/io/iochannel.hxx @@ -0,0 +1,78 @@ +// iochannel.hxx -- High level IO channel class +// +// 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$ + + +#ifndef _IOCHANNEL_HXX +#define _IOCHANNEL_HXX + + +#include + +// #include "protocol.hxx" + +#include STL_STRING +#include + +FG_USING_STD(vector); +FG_USING_STD(string); + + +#define SG_IO_MAX_MSG_SIZE 16384 + +enum SGProtocolDir { + SG_IO_NONE = 0, + SG_IO_IN = 1, + SG_IO_OUT = 2, + SG_IO_BI = 3 +}; + + +enum SGChannelType { + sgFileType = 0, + sgSerialType = 1, + sgSocketType = 2 +}; + +class SGIOChannel { + + SGChannelType type; + +public: + + SGIOChannel(); + virtual ~SGIOChannel(); + + virtual bool open( SGProtocolDir dir ); + virtual int read( char *buf, int length ); + virtual int readline( char *buf, int length ); + virtual int write( char *buf, int length ); + virtual int writestring( char *str ); + virtual bool close(); + + virtual void set_type( SGChannelType t ) { type = t; } + virtual SGChannelType get_type() const { return type; } +}; + + +#endif // _IOCHANNEL_HXX + + diff --git a/simgear/io/sg_file.cxx b/simgear/io/sg_file.cxx new file mode 100644 index 00000000..687a5a05 --- /dev/null +++ b/simgear/io/sg_file.cxx @@ -0,0 +1,155 @@ +// sg_file.cxx -- File 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 + +#include STL_STRING + +#ifdef _MSC_VER +# include +#endif + +#include + +#include "sg_file.hxx" + +FG_USING_STD(string); + + +SGFile::SGFile() { + set_type( sgFileType ); +} + + +SGFile::~SGFile() { +} + + +// open the file based on specified direction +bool SGFile::open( SGProtocolDir dir ) { + if ( dir == SG_IO_OUT ) { +#ifdef _MSC_VER + fp = _open( file_name.c_str(), O_WRONLY | O_CREAT | O_TRUNC, + 00666 ); +#else + fp = std::open( file_name.c_str(), O_WRONLY | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | + S_IROTH | S_IWOTH ); +#endif + } else if ( dir == SG_IO_IN ) { +#ifdef _MSC_VER + fp = _open( file_name.c_str(), O_RDONLY ); +#else + fp = std::open( file_name.c_str(), O_RDONLY ); +#endif + } else { + FG_LOG( FG_IO, FG_ALERT, + "Error: bidirection mode not available for files." ); + return false; + } + + if ( fp == -1 ) { + FG_LOG( FG_IO, FG_ALERT, "Error opening file: " << file_name ); + return false; + } + + return true; +} + + +// read a block of data of specified size +int SGFile::read( char *buf, int length ) { + // read a chunk +#ifdef _MSC_VER + int result = _read( fp, buf, length ); +#else + int result = std::read( fp, buf, length ); +#endif + + return result; +} + + +// read a line of data, length is max size of input buffer +int SGFile::readline( char *buf, int length ) { + // save our current position + int pos = lseek( fp, 0, SEEK_CUR ); + + // read a chunk +#ifdef _MSC_VER + int result = _read( fp, buf, length ); +#else + int result = std::read( fp, buf, length ); +#endif + + // find the end of line and reset position + int i; + for ( i = 0; i < result && buf[i] != '\n'; ++i ); + if ( buf[i] == '\n' ) { + result = i + 1; + } else { + result = i; + } + lseek( fp, pos + result, SEEK_SET ); + + // just in case ... + buf[ result ] = '\0'; + + return result; +} + + +// write data to a file +int SGFile::write( char *buf, int length ) { +#ifdef _MSC_VER + int result = _write( fp, buf, length ); +#else + int result = std::write( fp, buf, length ); +#endif + if ( result != length ) { + FG_LOG( FG_IO, FG_ALERT, "Error writing data: " << file_name ); + } + + return result; +} + + +// write null terminated string to a file +int SGFile::writestring( char *str ) { + int length = strlen( str ); + return write( str, length ); +} + + +// close the port +bool SGFile::close() { +#ifdef _MSC_VER + if ( _close( fp ) == -1 ) { +#else + if ( std::close( fp ) == -1 ) { +#endif + return false; + } + + return true; +} diff --git a/simgear/io/sg_file.hxx b/simgear/io/sg_file.hxx new file mode 100644 index 00000000..994cc275 --- /dev/null +++ b/simgear/io/sg_file.hxx @@ -0,0 +1,83 @@ +// sg_file.hxx -- File 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$ + + +#ifndef _SG_FILE_HXX +#define _SG_FILE_HXX + + +#ifndef __cplusplus +# error This library requires C++ +#endif + +#include + +#include + +#include // for open(), read(), write(), close() +#include // for open(), read(), write(), close() +#include // for open(), read(), write(), close() +#if !defined( _MSC_VER ) +# include // for open(), read(), write(), close() +#endif + +#include "iochannel.hxx" + +FG_USING_STD(string); + + +class SGFile : public SGIOChannel { + + string file_name; + int fp; + +public: + + SGFile(); + ~SGFile(); + + // open the file based on specified direction + bool open( SGProtocolDir dir ); + + // read a block of data of specified size + int read( char *buf, int length ); + + // read a line of data, length is max size of input buffer + int readline( char *buf, int length ); + + // write data to a file + int write( char *buf, int length ); + + // write null terminated string to a file + int writestring( char *str ); + + // close file + bool close(); + + inline string get_file_name() const { return file_name; } + inline void set_file_name( const string& fn ) { file_name = fn; } +}; + + +#endif // _SG_FILE_HXX + + diff --git a/simgear/io/sg_serial.cxx b/simgear/io/sg_serial.cxx new file mode 100644 index 00000000..2d409fb8 --- /dev/null +++ b/simgear/io/sg_serial.cxx @@ -0,0 +1,153 @@ +// sg_serial.cxx -- Serial 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 + +#include STL_STRING + +#include +#include + +#include "sg_serial.hxx" + +FG_USING_STD(string); + + +SGSerial::SGSerial() : + save_len(0) +{ + set_type( sgSerialType ); +} + + +SGSerial::~SGSerial() { +} + + +// open the serial port based on specified direction +bool SGSerial::open( SGProtocolDir dir ) { + if ( ! port.open_port( device ) ) { + FG_LOG( FG_IO, FG_ALERT, "Error opening device: " << device ); + return false; + } + + // cout << "fd = " << port.fd << endl; + + if ( ! port.set_baud( atoi( baud.c_str() ) ) ) { + FG_LOG( FG_IO, FG_ALERT, "Error setting baud: " << baud ); + return false; + } + + return true; +} + + +// Read data from port. If we don't get enough data, save what we did +// get in the save buffer and return 0. The save buffer will be +// prepended to subsequent reads until we get as much as is requested. + +int SGSerial::read( char *buf, int length ) { + int result; + + // read a chunk, keep in the save buffer until we have the + // requested amount read + + char *buf_ptr = save_buf + save_len; + result = port.read_port( buf_ptr, length - save_len ); + + if ( result + save_len == length ) { + strncpy( buf, save_buf, length ); + save_len = 0; + + return length; + } + + return 0; +} + + +// read data from port +int SGSerial::readline( char *buf, int length ) { + int result; + + // read a chunk, keep in the save buffer until we have the + // requested amount read + + char *buf_ptr = save_buf + save_len; + result = port.read_port( buf_ptr, SG_IO_MAX_MSG_SIZE - save_len ); + 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 + return 0; + } + + // we found an end of line + + // copy to external buffer + strncpy( buf, save_buf, result ); + buf[result] = '\0'; + FG_LOG( FG_IO, FG_INFO, "fg_serial line = " << buf ); + + // 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 port +int SGSerial::write( char *buf, int length ) { + int result = port.write_port( buf, length ); + + if ( result != length ) { + FG_LOG( FG_IO, FG_ALERT, "Error writing data: " << device ); + } + + return result; +} + + +// write null terminated string to port +int SGSerial::writestring( char *str ) { + int length = strlen( str ); + return write( str, length ); +} + + +// close the port +bool SGSerial::close() { + if ( ! port.close_port() ) { + return false; + } + + return true; +} diff --git a/simgear/io/sg_serial.hxx b/simgear/io/sg_serial.hxx new file mode 100644 index 00000000..ce7a7d4d --- /dev/null +++ b/simgear/io/sg_serial.hxx @@ -0,0 +1,90 @@ +// sg_serial.hxx -- Serial 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$ + + +#ifndef _SG_SERIAL_HXX +#define _SG_SERIAL_HXX + + +#ifndef __cplusplus +# error This library requires C++ +#endif + +#include + +#include + +// #ifdef FG_HAVE_STD_INCLUDES +// # include +// #else +// # include +// #endif + +#include + +#include "iochannel.hxx" + +FG_USING_STD(string); + + +class SGSerial : public SGIOChannel { + + string device; + string baud; + FGSerialPort port; + + char save_buf[ 2 * SG_IO_MAX_MSG_SIZE ]; + int save_len; + +public: + + SGSerial(); + ~SGSerial(); + + // open the serial port based on specified direction + bool open( SGProtocolDir dir ); + + // read a block of data of specified size + int read( char *buf, int length ); + + // read a line of data, length is max size of input buffer + int readline( char *buf, int length ); + + // write data to port + int write( char *buf, int length ); + + // write null terminated string to port + int writestring( char *str ); + + // close port + bool close(); + + inline string get_device() const { return device; } + inline void set_device( const string& d ) { device = d; } + inline string get_baud() const { return baud; } + inline void set_baud( const string& b ) { baud = b; } +}; + + +#endif // _SG_SERIAL_HXX + + diff --git a/simgear/io/sg_socket.cxx b/simgear/io/sg_socket.cxx new file mode 100644 index 00000000..1aadd283 --- /dev/null +++ b/simgear/io/sg_socket.cxx @@ -0,0 +1,377 @@ +// 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( _MSC_VER ) +# include // select() +# include // socket(), bind(), select(), accept() +# include // socket(), bind(), listen(), accept() +# include // struct sockaddr_in +# include // gethostbyname() +# include // select(), fsync()/fdatasync() +#else +# include // select() +# include // socket(), bind(), listen(), accept(), + // struct sockaddr_in, gethostbyname() +# include +# include +#endif + +#if defined( sgi ) +#include +#endif + +#include STL_STRING + +#include + +#include "sg_socket.hxx" + +FG_USING_STD(string); + + +SGSocket::SGSocket() : + save_len(0) +{ + set_type( sgSocketType ); +} + + +SGSocket::~SGSocket() { +} + + +int SGSocket::make_server_socket () { + struct sockaddr_in name; + +#if defined( __CYGWIN__ ) || defined( __CYGWIN32__ ) || defined( sgi ) || defined( _MSC_VER ) + int length; +#else + socklen_t length; +#endif + + // Create the socket. + sock = socket (PF_INET, SOCK_STREAM, 0); + if (sock < 0) { + FG_LOG( FG_IO, FG_ALERT, + "Error: socket() failed in make_server_socket()" ); + return -1; + } + + // Give the socket a name. + name.sin_family = AF_INET; + name.sin_addr.s_addr = INADDR_ANY; + 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, + "Error: bind() failed in make_server_socket()" ); + return -1; + } + + // Find the assigned port number + length = sizeof(struct sockaddr_in); + if ( getsockname(sock, (struct sockaddr *) &name, &length) ) { + FG_LOG( FG_IO, FG_ALERT, + "Error: getsockname() failed in make_server_socket()" ); + return -1; + } + port = ntohs(name.sin_port); + + return sock; +} + + +int SGSocket::make_client_socket () { + struct sockaddr_in name; + struct hostent *hp; + + FG_LOG( FG_IO, FG_INFO, "Make client socket()" ); + + // Create the socket. + sock = socket (PF_INET, SOCK_STREAM, 0); + if (sock < 0) { + FG_LOG( FG_IO, FG_ALERT, + "Error: socket() failed in make_client_socket()" ); + return -1; + } + + // specify address family + name.sin_family = AF_INET; + + // get the hosts official name/info + hp = gethostbyname( hostname.c_str() ); + + // Connect this socket to the host and the port specified on the + // command line +#if defined( __CYGWIN__ ) || defined( __CYGWIN32__ ) + bcopy(hp->h_addr, (char *)(&(name.sin_addr.s_addr)), hp->h_length); +#else + bcopy(hp->h_addr, &(name.sin_addr.s_addr), hp->h_length); +#endif + name.sin_port = htons(port); + + if ( connect(sock, (struct sockaddr *) &name, + sizeof(struct sockaddr_in)) < 0 ) + { +#ifdef _MSC_VER + _close(sock); +#else + std::close(sock); +#endif + FG_LOG( FG_IO, FG_ALERT, + "Error: connect() failed in make_client_socket()" ); + return -1; + } + + return sock; +} + + +// If specified as a server (out direction for now) open the master +// listening socket. If specified as a client, open a connection to a +// server. + +bool SGSocket::open( SGProtocolDir dir ) { + if ( port_str == "" || port_str == "any" ) { + port = 0; + } else { + port = atoi( port_str.c_str() ); + } + + client_connections.clear(); + + if ( dir == SG_IO_OUT ) { + // 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(); + FG_LOG( FG_IO, FG_INFO, "socket is connected to port = " << port ); + + // Specify the maximum length of the connection queue + listen(sock, SG_MAX_SOCKET_QUEUE); + + } else if ( dir == SG_IO_IN ) { + // this means client for now + + sock = make_client_socket(); + } else { + FG_LOG( FG_IO, FG_ALERT, + "Error: bidirection mode not available yet for sockets." ); + return false; + } + + if ( sock < 0 ) { + FG_LOG( FG_IO, FG_ALERT, "Error opening socket: " << hostname + << ":" << port ); + return false; + } + + return true; +} + + +// read data from socket (client) +// read a block of data of specified size +int SGSocket::read( char *buf, int length ) { + int result = 0; + + // check for potential input + fd_set ready; + FD_ZERO(&ready); + FD_SET(sock, &ready); + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 0; + + // test for any input read on sock (returning immediately, even if + // nothing) + select(32, &ready, 0, 0, &tv); + + if ( FD_ISSET(sock, &ready) ) { +#ifdef _MSC_VER + result = _read( sock, buf, length ); +#else + result = std::read( sock, buf, length ); +#endif + if ( result != length ) { + FG_LOG( FG_IO, FG_INFO, + "Warning: read() not enough bytes." ); + } + } + + return result; +} + + +// read a line of data, length is max size of input buffer +int SGSocket::readline( char *buf, int length ) { + int result = 0; + + // check for potential input + fd_set ready; + FD_ZERO(&ready); + FD_SET(sock, &ready); + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 0; + + // test for any input read on sock (returning immediately, even if + // nothing) + select(32, &ready, 0, 0, &tv); + + if ( FD_ISSET(sock, &ready) ) { + // read a chunk, keep in the save buffer until we have the + // requested amount read + + char *buf_ptr = save_buf + save_len; +#ifdef _MSC_VER + result = _read( sock, buf_ptr, SG_IO_MAX_MSG_SIZE - save_len ); +#else + result = std::read( sock, buf_ptr, SG_IO_MAX_MSG_SIZE - save_len ); +#endif + save_len += result; + // cout << "current read = " << buf_ptr << endl; + // cout << "current save_buf = " << save_buf << endl; + // cout << "save_len = " << save_len << endl; + } + + // 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 (server) +int SGSocket::write( char *buf, int length ) { + + // check for any new client connection requests + fd_set ready; + FD_ZERO(&ready); + FD_SET(sock, &ready); + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 0; + + // test for any input on sock (returning immediately, even if + // nothing) + select(32, &ready, 0, 0, &tv); + + // any new connections? + if ( FD_ISSET(sock, &ready) ) { + int msgsock = accept(sock, 0, 0); + if ( msgsock < 0 ) { + FG_LOG( FG_IO, FG_ALERT, + "Error: accept() failed in write()" ); + return 0; + } else { + client_connections.push_back( msgsock ); + } + } + + bool error_condition = false; + FG_LOG( FG_IO, FG_INFO, "Client connections = " << + client_connections.size() ); + for ( int i = 0; i < (int)client_connections.size(); ++i ) { + int msgsock = client_connections[i]; + + // read and junk any possible incoming messages. + // char junk[ SG_IO_MAX_MSG_SIZE ]; + // std::read( msgsock, junk, SG_IO_MAX_MSG_SIZE ); + + // write the interesting data to the socket +#ifdef _MSC_VER + if ( _write(msgsock, buf, length) < 0 ) { +#else + if ( std::write(msgsock, buf, length) < 0 ) { +#endif + FG_LOG( FG_IO, FG_ALERT, "Error writing to socket: " << port ); + error_condition = true; + } else { +#ifdef _POSIX_SYNCHRONIZED_IO + // fdatasync(msgsock); +#else + // fsync(msgsock); +#endif + } + } + + if ( error_condition ) { + return 0; + } + + return length; +} + + +// write null terminated string to socket (server) +int SGSocket::writestring( char *str ) { + int length = strlen( str ); + return write( str, length ); +} + + +// close the port +bool SGSocket::close() { + for ( int i = 0; i < (int)client_connections.size(); ++i ) { + int msgsock = client_connections[i]; +#ifdef _MSC_VER + _close( msgsock ); +#else + std::close( msgsock ); +#endif + } + +#ifdef _MSC_VER + _close( sock ); +#else + std::close( sock ); +#endif + return true; +} diff --git a/simgear/io/sg_socket.hxx b/simgear/io/sg_socket.hxx new file mode 100644 index 00000000..199b6dba --- /dev/null +++ b/simgear/io/sg_socket.hxx @@ -0,0 +1,97 @@ +// sg_socket.hxx -- 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$ + + +#ifndef _SG_SOCKET_HXX +#define _SG_SOCKET_HXX + + +#ifndef __cplusplus +# error This library requires C++ +#endif + +#include + +#include + +#include + +#include "iochannel.hxx" + +FG_USING_STD(string); + + +#define SG_MAX_SOCKET_QUEUE 32 + + +class SGSocket : public SGIOChannel { + + string hostname; + string port_str; + + char save_buf[ 2 * SG_IO_MAX_MSG_SIZE ]; + int save_len; + + int sock; + short unsigned int port; + + // make a server (master listening) socket + int make_server_socket(); + + // make a client socket + int make_client_socket(); + + int_list client_connections; + +public: + + SGSocket(); + ~SGSocket(); + + // open the file based on specified direction + bool open( SGProtocolDir dir ); + + // 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( char *buf, int length ); + + // write null terminated string to a socket + int writestring( char *str ); + + // close file + bool close(); + + inline string get_hostname() const { return hostname; } + inline void set_hostname( const string& hn ) { hostname = hn; } + inline string get_port_str() const { return port_str; } + inline void set_port_str( const string& p ) { port_str = p; } +}; + + +#endif // _SG_SOCKET_HXX + + -- 2.39.5