1
0
Fork 0

Added first stab at a socket class.

Fixed readline() bug in fg_serial.cxx and fg_socket.cxx.
Fixed process() bug in nmea.cxx and garmin.cxx.
This commit is contained in:
curt 1999-11-20 15:41:48 +00:00
parent ed98ee8a31
commit 57163baca0
5 changed files with 428 additions and 19 deletions

View file

@ -116,7 +116,7 @@ int FGSerial::readline( char *buf, int length ) {
// shift save buffer
for ( i = result; i < save_len; ++i ) {
save_buf[ i - result ] = save_buf[result];
save_buf[ i - result ] = save_buf[i];
}
save_len -= result;

304
src/Network/fg_socket.cxx Normal file
View file

@ -0,0 +1,304 @@
// fg_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 <Include/compiler.h>
#include <sys/time.h> // select()
#include <sys/types.h> // socket(), bind(), select(), accept()
#include <sys/socket.h> // socket(), bind(), listen(), accept()
#include <netinet/in.h> // struct sockaddr_in
#include <netdb.h> // gethostbyname()
#include <unistd.h> // select()
#include STL_STRING
#include <Debug/logstream.hxx>
#include "fg_socket.hxx"
FG_USING_STD(string);
FGSocket::FGSocket() :
save_len(0)
{
}
FGSocket::~FGSocket() {
}
int FGSocket::make_server_socket () {
struct sockaddr_in name;
socklen_t length;
// 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 FGSocket::make_client_socket () {
struct sockaddr_in name;
struct hostent *hp;
// 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
bcopy(hp->h_addr, &(name.sin_addr.s_addr), hp->h_length);
name.sin_port = htons(port);
if ( connect(sock, (struct sockaddr *) &name,
sizeof(struct sockaddr_in)) < 0 )
{
std::close(sock);
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 FGSocket::open( FGProtocol::fgProtocolDir dir ) {
if ( port_str == "" || port_str == "any" ) {
port = 0;
} else {
port = atoi( port_str.c_str() );
}
client_connections.clear();
if ( dir == FGProtocol::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();
cout << "socket is connected to port = " << port << endl;
// Specify the maximum length of the connection queue
listen(sock, FG_MAX_SOCKET_QUEUE);
} else if ( dir == FGProtocol::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 FGSocket::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) ) {
result = std::read( sock, buf, length );
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 FGSocket::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;
result = std::read( sock, buf_ptr, FG_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';
cout << "fg_serial 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 FGSocket::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;
for ( int i = 0; i < (int)client_connections.size(); ++i ) {
int msgsock = client_connections[i];
if ( std::write(msgsock, buf, length) < 0 ) {
FG_LOG( FG_IO, FG_ALERT, "Error writing to socket: " << port );
error_condition = true;
}
}
if ( error_condition ) {
return 0;
}
return length;
}
// close the port
bool FGSocket::close() {
for ( int i = 0; i < (int)client_connections.size(); ++i ) {
int msgsock = client_connections[i];
std::close( msgsock );
}
std::close( sock );
return true;
}

95
src/Network/fg_socket.hxx Normal file
View file

@ -0,0 +1,95 @@
// fg_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 _FG_SOCKET_HXX
#define _FG_SOCKET_HXX
#ifndef __cplusplus
# error This library requires C++
#endif
#include <Include/compiler.h>
#include <string>
#include <Include/fg_types.hxx>
#include "iochannel.hxx"
#include "protocol.hxx"
FG_USING_STD(string);
#define FG_MAX_SOCKET_QUEUE 32
class FGSocket : public FGIOChannel {
string hostname;
string port_str;
char save_buf[ 2 * FG_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:
FGSocket();
~FGSocket();
// open the file based on specified direction
bool open( FGProtocol::fgProtocolDir dir );
// read data from file
int read( char *buf, int length );
// read data from file
int readline( char *buf, int length );
// write data to a file
int write( char *buf, int length );
// 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 // _FG_SOCKET_HXX

View file

@ -154,11 +154,11 @@ bool FGGarmin::gen_message() {
// parse Garmin message
bool FGGarmin::parse_message() {
FG_LOG( FG_IO, FG_DEBUG, "parse garmin message" );
FG_LOG( FG_IO, FG_INFO, "parse garmin message" );
string msg = buf;
msg = msg.substr( 0, length );
FG_LOG( FG_IO, FG_DEBUG, "entire message = " << msg );
FG_LOG( FG_IO, FG_INFO, "entire message = " << msg );
string::size_type begin_line, end_line, begin, end;
begin_line = begin = 0;
@ -168,12 +168,12 @@ bool FGGarmin::parse_message() {
while ( end_line != string::npos ) {
string line = msg.substr(begin_line, end_line - begin_line);
begin_line = end_line + 1;
FG_LOG( FG_IO, FG_DEBUG, " input line = " << line );
FG_LOG( FG_IO, FG_INFO, " input line = " << line );
// leading character
string start = msg.substr(begin, 1);
++begin;
FG_LOG( FG_IO, FG_DEBUG, " start = " << start );
FG_LOG( FG_IO, FG_INFO, " start = " << start );
// sentence
end = msg.find(",", begin);
@ -183,7 +183,7 @@ bool FGGarmin::parse_message() {
string sentence = msg.substr(begin, end - begin);
begin = end + 1;
FG_LOG( FG_IO, FG_DEBUG, " sentence = " << sentence );
FG_LOG( FG_IO, FG_INFO, " sentence = " << sentence );
double lon_deg, lon_min, lat_deg, lat_min;
double lon, lat, speed, heading, altitude;
@ -197,7 +197,7 @@ bool FGGarmin::parse_message() {
string utc = msg.substr(begin, end - begin);
begin = end + 1;
FG_LOG( FG_IO, FG_DEBUG, " utc = " << utc );
FG_LOG( FG_IO, FG_INFO, " utc = " << utc );
// junk
end = msg.find(",", begin);
@ -207,7 +207,7 @@ bool FGGarmin::parse_message() {
string junk = msg.substr(begin, end - begin);
begin = end + 1;
FG_LOG( FG_IO, FG_DEBUG, " junk = " << junk );
FG_LOG( FG_IO, FG_INFO, " junk = " << junk );
// lat val
end = msg.find(",", begin);
@ -236,7 +236,7 @@ bool FGGarmin::parse_message() {
}
cur_fdm_state->set_Latitude( lat * DEG_TO_RAD );
FG_LOG( FG_IO, FG_DEBUG, " lat = " << lat );
FG_LOG( FG_IO, FG_INFO, " lat = " << lat );
// lon val
end = msg.find(",", begin);
@ -265,7 +265,7 @@ bool FGGarmin::parse_message() {
}
cur_fdm_state->set_Longitude( lon * DEG_TO_RAD );
FG_LOG( FG_IO, FG_DEBUG, " lon = " << lon );
FG_LOG( FG_IO, FG_INFO, " lon = " << lon );
double sl_radius, lat_geoc;
fgGeodToGeoc( cur_fdm_state->get_Latitude(),
@ -286,7 +286,7 @@ bool FGGarmin::parse_message() {
speed = atof( speed_str.c_str() );
cur_fdm_state->set_V_equiv_kts( speed );
cur_fdm_state->set_V_ground_speed( speed );
FG_LOG( FG_IO, FG_DEBUG, " speed = " << speed );
FG_LOG( FG_IO, FG_INFO, " speed = " << speed );
// heading
end = msg.find(",", begin);
@ -300,7 +300,7 @@ bool FGGarmin::parse_message() {
cur_fdm_state->set_Euler_Angles( cur_fdm_state->get_Phi(),
cur_fdm_state->get_Theta(),
heading * DEG_TO_RAD );
FG_LOG( FG_IO, FG_DEBUG, " heading = " << heading );
FG_LOG( FG_IO, FG_INFO, " heading = " << heading );
} else if ( sentence == "PGRMZ" ) {
// altitude
end = msg.find(",", begin);
@ -327,7 +327,7 @@ bool FGGarmin::parse_message() {
cur_fdm_state->set_Altitude( altitude );
FG_LOG( FG_IO, FG_DEBUG, " altitude = " << altitude );
FG_LOG( FG_IO, FG_INFO, " altitude = " << altitude );
}
@ -373,14 +373,24 @@ bool FGGarmin::process() {
return false;
}
} else if ( get_direction() == in ) {
if ( io->readline( buf, FG_MAX_MSG_SIZE ) ) {
parse_message();
if ( length = io->readline( buf, FG_MAX_MSG_SIZE ) ) {
FG_LOG( FG_IO, FG_ALERT, "Success reading data." );
if ( parse_message() ) {
FG_LOG( FG_IO, FG_ALERT, "Success parsing data." );
} else {
FG_LOG( FG_IO, FG_ALERT, "Error parsing data." );
}
} else {
FG_LOG( FG_IO, FG_ALERT, "Error reading data." );
return false;
}
if ( io->readline( buf, FG_MAX_MSG_SIZE ) ) {
parse_message();
if ( length = io->readline( buf, FG_MAX_MSG_SIZE ) ) {
FG_LOG( FG_IO, FG_ALERT, "Success reading data." );
if ( parse_message() ) {
FG_LOG( FG_IO, FG_ALERT, "Success parsing data." );
} else {
FG_LOG( FG_IO, FG_ALERT, "Error parsing data." );
}
} else {
FG_LOG( FG_IO, FG_ALERT, "Error reading data." );
return false;

View file

@ -476,13 +476,13 @@ bool FGNMEA::process() {
return false;
}
} else if ( get_direction() == in ) {
if ( io->readline( buf, FG_MAX_MSG_SIZE ) ) {
if ( length = io->readline( buf, FG_MAX_MSG_SIZE ) ) {
parse_message();
} else {
FG_LOG( FG_IO, FG_ALERT, "Error reading data." );
return false;
}
if ( io->readline( buf, FG_MAX_MSG_SIZE ) ) {
if ( length = io->readline( buf, FG_MAX_MSG_SIZE ) ) {
parse_message();
} else {
FG_LOG( FG_IO, FG_ALERT, "Error reading data." );