RelativePath="..\..\simgear\io\sg_socket_udp.hxx"\r
>\r
</File>\r
+ <File RelativePath="..\..\simgear\io\sg_netChannel.hxx"></File>\r
+ <File RelativePath="..\..\simgear\io\sg_netChannel.cxx"></File>\r
+ <File RelativePath="..\..\simgear\io\sg_netChat.hxx"></File>\r
+ <File RelativePath="..\..\simgear\io\sg_netChat.cxx"></File>\r
+ <File RelativePath="..\..\simgear\io\sg_netBuffer.cxx"></File>\r
+ <File RelativePath="..\..\simgear\io\sg_netBuffer.hxx"></File>\r
</Filter>\r
<Filter\r
Name="Lib_sgmagvar"\r
sg_serial.hxx \
sg_socket.hxx \
sg_socket_udp.hxx \
- raw_socket.hxx
+ raw_socket.hxx \
+ sg_netBuffer.hxx \
+ sg_netChannel.hxx \
+ sg_netChat.hxx
libsgio_a_SOURCES = \
iochannel.cxx \
sg_serial.cxx \
sg_socket.cxx \
sg_socket_udp.cxx \
- raw_socket.cxx
+ raw_socket.cxx \
+ sg_netBuffer.cxx \
+ sg_netChannel.cxx \
+ sg_netChat.cxx
INCLUDES = -I$(top_srcdir)
--- /dev/null
+/*
+ Copied from PLIB into SimGear
+
+ PLIB - A Suite of Portable Game Libraries
+ Copyright (C) 1998,2002 Steve Baker
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ For further information visit http://plib.sourceforge.net
+
+ $Id: netBuffer.cxx 1568 2002-09-02 06:05:49Z sjbaker $
+*/
+
+#include "sg_netBuffer.hxx"
+
+#include <simgear/debug/logstream.hxx>
+
+namespace simgear {
+
+NetBuffer::NetBuffer( int _max_length )
+{
+ length = 0 ;
+ max_length = _max_length ;
+ data = new char [ max_length+1 ] ; //for null terminator
+}
+
+NetBuffer::~NetBuffer ()
+{
+ delete[] data ;
+}
+
+void NetBuffer::remove ()
+{
+ length = 0 ;
+}
+
+void NetBuffer::remove (int pos, int n)
+{
+ assert (pos>=0 && pos<length && (pos+n)<=length) ;
+ //if (pos>=0 && pos<length && (pos+n)<=length)
+ {
+ memmove(&data[pos],&data[pos+n],length-(pos+n)) ;
+ length -= n ;
+ }
+}
+
+bool NetBuffer::append (const char* s, int n)
+{
+ if ((length+n)<=max_length)
+ {
+ memcpy(&data[length],s,n) ;
+ length += n ;
+ return true ;
+ }
+ return false ;
+}
+
+bool NetBuffer::append (int n)
+{
+ if ((length+n)<=max_length)
+ {
+ length += n ;
+ return true ;
+ }
+ return false ;
+}
+
+NetBufferChannel::NetBufferChannel (int in_buffer_size, int out_buffer_size) :
+ in_buffer (in_buffer_size),
+ out_buffer (out_buffer_size),
+ should_close (0)
+{ /* empty */
+}
+
+void NetBufferChannel::handleClose ( void )
+{
+ in_buffer.remove () ;
+ out_buffer.remove () ;
+ should_close = 0 ;
+ NetChannel::handleClose () ;
+}
+
+
+bool NetBufferChannel::bufferSend (const char* msg, int msg_len)
+{
+ if ( out_buffer.append(msg,msg_len) )
+ return true ;
+
+ SG_LOG(SG_IO, SG_WARN, "NetBufferChannel: output buffer overflow!" ) ;
+ return false ;
+}
+
+void NetBufferChannel::handleBufferRead (NetBuffer& buffer)
+{
+ /* do something here */
+ buffer.remove();
+}
+
+void
+NetBufferChannel::handleRead (void)
+{
+ int max_read = in_buffer.getMaxLength() - in_buffer.getLength() ;
+ if (max_read)
+ {
+ char* data = in_buffer.getData() + in_buffer.getLength() ;
+ int num_read = recv (data, max_read) ;
+ if (num_read > 0)
+ {
+ in_buffer.append (num_read) ;
+ //ulSetError ( UL_DEBUG, "netBufferChannel: %d read", num_read ) ;
+ }
+ }
+ if (in_buffer.getLength())
+ {
+ handleBufferRead (in_buffer);
+ }
+}
+
+void
+NetBufferChannel::handleWrite (void)
+{
+ if (out_buffer.getLength())
+ {
+ if (isConnected())
+ {
+ int length = out_buffer.getLength() ;
+ if (length>512)
+ length=512;
+ int num_sent = NetChannel::send (
+ out_buffer.getData(), length);
+ if (num_sent > 0)
+ {
+ out_buffer.remove (0, num_sent);
+ //ulSetError ( UL_DEBUG, "netBufferChannel: %d sent", num_sent ) ;
+ }
+ }
+ }
+ else if (should_close)
+ {
+ close();
+ }
+}
+
+} // of namespace simgear
--- /dev/null
+/*
+ Copied from PLIB into SimGear
+
+ PLIB - A Suite of Portable Game Libraries
+ Copyright (C) 1998,2002 Steve Baker
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ For further information visit http://plib.sourceforge.net
+
+ $Id: netBuffer.h 1901 2004-03-21 18:19:11Z sjbaker $
+*/
+
+/****
+* NAME
+* netBuffer - network buffer class
+*
+* DESCRIPTION
+* Clients and servers built on top of netBufferChannel
+* automatically support pipelining.
+*
+* Pipelining refers to a protocol capability. Normally,
+* a conversation with a server has a back-and-forth
+* quality to it. The client sends a command, and
+* waits for the response. If a client needs to send
+* many commands over a high-latency connection,
+* waiting for each response can take a long time.
+*
+* For example, when sending a mail message to many recipients
+* with SMTP, the client will send a series of RCPT commands, one
+* for each recipient. For each of these commands, the server will
+* send back a reply indicating whether the mailbox specified is
+* valid. If you want to send a message to several hundred recipients,
+* this can be rather tedious if the round-trip time for each command
+* is long. You'd like to be able to send a bunch of RCPT commands
+* in one batch, and then count off the responses to them as they come.
+*
+* I have a favorite visual when explaining the advantages of
+* pipelining. Imagine each request to the server is a boxcar on a train.
+* The client is in Los Angeles, and the server is in New York.
+* Pipelining lets you hook all your cars in one long chain; send
+* them to New York, where they are filled and sent back to you.
+* Without pipelining you have to send one car at a time.
+*
+* Not all protocols allow pipelining. Not all servers support it;
+* Sendmail, for example, does not support pipelining because it tends
+* to fork unpredictably, leaving buffered data in a questionable state.
+* A recent extension to the SMTP protocol allows a server to specify
+* whether it supports pipelining. HTTP/1.1 explicitly requires that
+* a server support pipelining.
+*
+* NOTES
+* When a user passes in a buffer object, it belongs to
+* the user. When the library gives a buffer to the user,
+* the user should copy it.
+*
+* AUTHORS
+* Sam Rushing <rushing@nightmare.com> - original version for Medusa
+* Dave McClurg <dpm@efn.org> - modified for use in PLIB
+*
+* CREATION DATE
+* Dec-2000
+*
+****/
+
+#ifndef SG_NET_BUFFER_H
+#define SG_NET_BUFFER_H
+
+#include <simgear/io/sg_netChannel.hxx>
+
+namespace simgear
+{
+
+// ===========================================================================
+// NetBuffer
+// ===========================================================================
+
+class NetBuffer
+{
+protected:
+ int length ;
+ int max_length ;
+ char* data ;
+
+public:
+ NetBuffer( int _max_length );
+ ~NetBuffer ();
+ int getLength() const { return length ; }
+ int getMaxLength() const { return max_length ; }
+
+ /*
+ ** getData() returns a pointer to the data
+ ** Note: a zero (0) byte is appended for convenience
+ ** but the data may have internal zero (0) bytes already
+ */
+ char* getData() { data [length] = 0 ; return data ; }
+ const char* getData() const { ((char*)data) [length] = 0 ; return data ; }
+
+ void remove ();
+ void remove (int pos, int n);
+ bool append (const char* s, int n);
+ bool append (int n);
+};
+
+// ===========================================================================
+// NetBufferChannel
+// ===========================================================================
+
+class NetBufferChannel : public NetChannel
+{
+ NetBuffer in_buffer;
+ NetBuffer out_buffer;
+ int should_close ;
+
+ virtual bool readable (void)
+ {
+ return (NetChannel::readable() &&
+ (in_buffer.getLength() < in_buffer.getMaxLength()));
+ }
+
+ virtual void handleRead (void) ;
+
+ virtual bool writable (void)
+ {
+ return (out_buffer.getLength() || should_close);
+ }
+
+ virtual void handleWrite (void) ;
+
+public:
+
+ NetBufferChannel (int in_buffer_size = 4096, int out_buffer_size = 16384);
+ virtual void handleClose ( void );
+
+ void closeWhenDone (void) { should_close = 1 ; }
+
+ virtual bool bufferSend (const char* msg, int msg_len);
+ virtual void handleBufferRead (NetBuffer& buffer);
+};
+
+} // namespace simgear
+
+#endif // SG_NET_BUFFER_H
--- /dev/null
+/*
+ Copied from PLIB into SimGear
+
+ PLIB - A Suite of Portable Game Libraries
+ Copyright (C) 1998,2002 Steve Baker
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ For further information visit http://plib.sourceforge.net
+
+ $Id: netChannel.cxx 1906 2004-03-22 19:44:50Z sjbaker $
+*/
+
+// TODO:
+// have all socket-related functions assert that the socket has not
+// been closed. [a read event may close it, and a write event may try
+// to write or something...]
+// Maybe assert valid handle, too?
+
+#include "sg_netChannel.hxx"
+
+#include <memory>
+
+#include <simgear/debug/logstream.hxx>
+
+namespace simgear {
+
+static NetChannel* channels = 0 ;
+
+NetChannel::NetChannel ()
+{
+ closed = true ;
+ connected = false ;
+ accepting = false ;
+ write_blocked = false ;
+ should_delete = false ;
+
+ next_channel = channels ;
+ channels = this ;
+}
+
+NetChannel::~NetChannel ()
+{
+ close();
+
+ NetChannel* prev = NULL ;
+
+ for ( NetChannel* ch = channels; ch != NULL;
+ ch = ch -> next_channel )
+ {
+ if (ch == this)
+ {
+ ch = ch -> next_channel ;
+ if ( prev != NULL )
+ prev -> next_channel = ch ;
+ else
+ channels = ch ;
+ next_channel = 0 ;
+ break;
+ }
+ prev = ch ;
+ }
+}
+
+void
+NetChannel::setHandle (int handle, bool is_connected)
+{
+ close () ;
+ Socket::setHandle ( handle ) ;
+ connected = is_connected ;
+ //if ( connected ) this->handleConnect();
+ closed = false ;
+}
+
+bool
+NetChannel::open (void)
+{
+ close();
+ if (Socket::open(true)) {
+ closed = false ;
+ setBlocking ( false ) ;
+ return true ;
+ }
+ return false ;
+}
+
+int
+NetChannel::listen ( int backlog )
+{
+ accepting = true ;
+ return Socket::listen ( backlog ) ;
+}
+
+int
+NetChannel::connect ( const char* host, int port )
+{
+ int result = Socket::connect ( host, port ) ;
+ if (result == 0) {
+ connected = true ;
+ //this->handleConnect();
+ return 0;
+ } else if (isNonBlockingError ()) {
+ return 0;
+ } else {
+ // some other error condition
+ this->handleError (result);
+ close();
+ return -1;
+ }
+}
+
+int
+NetChannel::send (const void * buffer, int size, int flags)
+{
+ int result = Socket::send (buffer, size, flags);
+
+ if (result == (int)size) {
+ // everything was sent
+ write_blocked = false ;
+ return result;
+ } else if (result >= 0) {
+ // not all of it was sent, but no error
+ write_blocked = true ;
+ return result;
+ } else if (isNonBlockingError ()) {
+ write_blocked = true ;
+ return 0;
+ } else {
+ this->handleError (result);
+ close();
+ return -1;
+ }
+
+}
+
+int
+NetChannel::recv (void * buffer, int size, int flags)
+{
+ int result = Socket::recv (buffer, size, flags);
+
+ if (result > 0) {
+ return result;
+ } else if (result == 0) {
+ close();
+ return 0;
+ } else if (isNonBlockingError ()) {
+ return 0;
+ } else {
+ this->handleError (result);
+ close();
+ return -1;
+ }
+}
+
+void
+NetChannel::close (void)
+{
+ if ( !closed )
+ {
+ this->handleClose();
+
+ closed = true ;
+ connected = false ;
+ accepting = false ;
+ write_blocked = false ;
+ }
+
+ Socket::close () ;
+}
+
+void
+NetChannel::handleReadEvent (void)
+{
+ if (accepting) {
+ if (!connected) {
+ connected = true ;
+ //this->handleConnect();
+ }
+ this->handleAccept();
+ } else if (!connected) {
+ connected = true ;
+ //this->handleConnect();
+ this->handleRead();
+ } else {
+ this->handleRead();
+ }
+}
+
+void
+NetChannel::handleWriteEvent (void)
+{
+ if (!connected) {
+ connected = true ;
+ //this->handleConnect();
+ }
+ write_blocked = false ;
+ this->handleWrite();
+}
+
+bool
+NetChannel::poll (unsigned int timeout)
+{
+ if (!channels)
+ return false ;
+
+ enum { MAX_SOCKETS = 256 } ;
+ Socket* reads [ MAX_SOCKETS+1 ] ;
+ Socket* writes [ MAX_SOCKETS+1 ] ;
+ Socket* deletes [ MAX_SOCKETS+1 ] ;
+ int nreads = 0 ;
+ int nwrites = 0 ;
+ int ndeletes = 0 ;
+ int nopen = 0 ;
+ NetChannel* ch;
+ for ( ch = channels; ch != NULL; ch = ch -> next_channel )
+ {
+ if ( ch -> should_delete )
+ {
+ assert(ndeletes<MAX_SOCKETS);
+ deletes[ndeletes++] = ch ;
+ }
+ else if ( ! ch -> closed )
+ {
+ nopen++ ;
+ if (ch -> readable()) {
+ assert(nreads<MAX_SOCKETS);
+ reads[nreads++] = ch ;
+ }
+ if (ch -> writable()) {
+ assert(nwrites<MAX_SOCKETS);
+ writes[nwrites++] = ch ;
+ }
+ }
+ }
+ reads[nreads] = NULL ;
+ writes[nwrites] = NULL ;
+ deletes[ndeletes] = NULL ;
+
+ int i ;
+ for ( i=0; deletes[i]; i++ )
+ {
+ ch = (NetChannel*)deletes[i];
+ delete ch ;
+ }
+
+ if (!nopen)
+ return false ;
+ if (!nreads && !nwrites)
+ return true ; //hmmm- should we shutdown?
+
+ Socket::select (reads, writes, timeout) ;
+
+ for ( i=0; reads[i]; i++ )
+ {
+ ch = (NetChannel*)reads[i];
+ if ( ! ch -> closed )
+ ch -> handleReadEvent();
+ }
+
+ for ( i=0; writes[i]; i++ )
+ {
+ ch = (NetChannel*)writes[i];
+ if ( ! ch -> closed )
+ ch -> handleWriteEvent();
+ }
+
+ return true ;
+}
+
+void
+NetChannel::loop (unsigned int timeout)
+{
+ while ( poll (timeout) ) ;
+}
+
+
+void NetChannel::handleRead (void) {
+ SG_LOG(SG_IO, SG_WARN, "Network:" << getHandle() << ": unhandled read");
+}
+
+void NetChannel::handleWrite (void) {
+ SG_LOG(SG_IO, SG_WARN, "Network:" << getHandle() << ": unhandled write");
+}
+
+void NetChannel::handleAccept (void) {
+ SG_LOG(SG_IO, SG_WARN, "Network:" << getHandle() << ": unhandled accept");
+}
+
+void NetChannel::handleError (int error) {
+ SG_LOG(SG_IO, SG_WARN,"Network:" << getHandle() << ": errno: " << strerror(errno) <<"(" << errno << ")");
+}
+
+} // of namespace simgear
--- /dev/null
+/*
+ NetChannel - copied from PLIB
+
+ PLIB - A Suite of Portable Game Libraries
+ Copyright (C) 1998,2002 Steve Baker
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ For further information visit http://plib.sourceforge.net
+
+ $Id: netChannel.h 1899 2004-03-21 17:41:07Z sjbaker $
+*/
+
+/****
+* NAME
+* netChannel - network channel class
+*
+* DESCRIPTION
+* netChannel is adds event-handling to the low-level
+* netSocket class. Otherwise, it can be treated as
+* a normal non-blocking socket object.
+*
+* The direct interface between the netPoll() loop and
+* the channel object are the handleReadEvent and
+* handleWriteEvent methods. These are called
+* whenever a channel object 'fires' that event.
+*
+* The firing of these low-level events can tell us whether
+* certain higher-level events have taken place, depending on
+* the timing and state of the connection.
+*
+* AUTHORS
+* Sam Rushing <rushing@nightmare.com> - original version for Medusa
+* Dave McClurg <dpm@efn.org> - modified for use in PLIB
+*
+* CREATION DATE
+* Dec-2000
+*
+****/
+
+#ifndef SG_NET_CHANNEL_H
+#define SG_NET_CHANNEL_H
+
+#include <simgear/io/raw_socket.hxx>
+
+namespace simgear
+{
+
+class NetChannel : public Socket
+{
+ bool closed, connected, accepting, write_blocked, should_delete ;
+ NetChannel* next_channel ;
+
+ friend bool netPoll (unsigned int timeout);
+
+public:
+
+ NetChannel () ;
+ virtual ~NetChannel () ;
+
+ void setHandle (int s, bool is_connected = true);
+ bool isConnected () const { return connected; }
+ bool isClosed () const { return closed; }
+ void shouldDelete () { should_delete = true ; }
+
+ // --------------------------------------------------
+ // socket methods
+ // --------------------------------------------------
+
+ bool open ( void ) ;
+ void close ( void ) ;
+ int listen ( int backlog ) ;
+ int connect ( const char* host, int port ) ;
+ int send ( const void * buf, int size, int flags = 0 ) ;
+ int recv ( void * buf, int size, int flags = 0 ) ;
+
+ // poll() eligibility predicates
+ virtual bool readable (void) { return (connected || accepting); }
+ virtual bool writable (void) { return (!connected || write_blocked); }
+
+ // --------------------------------------------------
+ // event handlers
+ // --------------------------------------------------
+
+ void handleReadEvent (void);
+ void handleWriteEvent (void);
+
+// These are meant to be overridden.
+ virtual void handleClose (void) {
+ }
+
+ virtual void handleRead (void);
+ virtual void handleWrite (void);
+ virtual void handleAccept (void);
+ virtual void handleError (int error);
+
+ static bool poll (unsigned int timeout = 0 ) ;
+ static void loop (unsigned int timeout = 0 ) ;
+};
+
+} // of namespace simgear
+
+#endif // SG_NET_CHANNEL_H
--- /dev/null
+/*
+ Copied from PLIB into SimGear
+
+ PLIB - A Suite of Portable Game Libraries
+ Copyright (C) 1998,2002 Steve Baker
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ For further information visit http://plib.sourceforge.net
+
+ $Id: NetChat.cxx 2117 2007-09-13 23:21:09Z fayjf $
+*/
+
+#include <simgear/io/sg_netChat.hxx>
+
+#include <cstring> // for strdup
+
+namespace simgear {
+
+void
+NetChat::setTerminator (const char* t)
+{
+ if (terminator) delete[] terminator;
+ terminator = strdup(t);
+}
+
+const char*
+NetChat::getTerminator (void)
+{
+ return terminator;
+}
+
+// return the size of the largest prefix of needle at the end
+// of haystack
+
+#define MAX(a,b) (((a)>(b))?(a):(b))
+
+static int
+find_prefix_at_end (const NetBuffer& haystack, const char* needle)
+{
+ const char* hd = haystack.getData();
+ int hl = haystack.getLength();
+ int nl = strlen(needle);
+
+ for (int i = MAX (nl-hl, 0); i < nl; i++) {
+ //if (haystack.compare (needle, hl-(nl-i), nl-i) == 0) {
+ if (memcmp(needle, &hd[hl-(nl-i)], nl-i) == 0) {
+ return (nl-i);
+ }
+ }
+ return 0;
+}
+
+static int
+find_terminator (const NetBuffer& haystack, const char* needle)
+{
+ if (needle && *needle)
+ {
+ const char* data = haystack.getData();
+ const char* ptr = strstr(data,needle);
+ if (ptr != NULL)
+ return(ptr-data);
+ }
+ return -1;
+}
+
+bool NetChat::push (const char* s)
+{
+ return bufferSend ( s, strlen(s) ) ;
+}
+
+void
+NetChat::handleBufferRead (NetBuffer& in_buffer)
+{
+ // Continue to search for terminator in in_buffer,
+ // while calling collect_incoming_data. The while loop is
+ // necessary because we might read several data+terminator combos
+ // with a single recv().
+
+ while (in_buffer.getLength()) {
+
+ // special case where we're not using a terminator
+ if (terminator == 0 || *terminator == 0) {
+ collectIncomingData (in_buffer.getData(),in_buffer.getLength());
+ in_buffer.remove ();
+ return;
+ }
+
+ int terminator_len = strlen(terminator);
+
+ int index = find_terminator ( in_buffer, terminator ) ;
+
+ // 3 cases:
+ // 1) end of buffer matches terminator exactly:
+ // collect data, transition
+ // 2) end of buffer matches some prefix:
+ // collect data to the prefix
+ // 3) end of buffer does not match any prefix:
+ // collect data
+
+ if (index != -1) {
+ // we found the terminator
+ collectIncomingData ( in_buffer.getData(), index ) ;
+ in_buffer.remove (0, index + terminator_len);
+ foundTerminator();
+ } else {
+ // check for a prefix of the terminator
+ int num = find_prefix_at_end (in_buffer, terminator);
+ if (num) {
+ int bl = in_buffer.getLength();
+ // we found a prefix, collect up to the prefix
+ collectIncomingData ( in_buffer.getData(), bl - num ) ;
+ in_buffer.remove (0, bl - num);
+ break;
+ } else {
+ // no prefix, collect it all
+ collectIncomingData (in_buffer.getData(), in_buffer.getLength());
+ in_buffer.remove();
+ }
+ }
+ }
+}
+
+} // of namespace simgear
+
+
--- /dev/null
+/*
+ Copied from PLIB into SimGear
+
+ PLIB - A Suite of Portable Game Libraries
+ Copyright (C) 1998,2002 Steve Baker
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ For further information visit http://plib.sourceforge.net
+
+ $Id: netChat.h 1568 2002-09-02 06:05:49Z sjbaker $
+*/
+
+/****
+* NAME
+* netChat - network chat class
+*
+* DESCRIPTION
+* This class adds support for 'chat' style protocols -
+* where one side sends a 'command', and the other sends
+* a response (examples would be the common internet
+* protocols - smtp, nntp, ftp, etc..).
+*
+* The handle_buffer_read() method looks at the input
+* stream for the current 'terminator' (usually '\r\n'
+* for single-line responses, '\r\n.\r\n' for multi-line
+* output), calling found_terminator() on its receipt.
+*
+* EXAMPLE
+* Say you build an nntp client using this class.
+* At the start of the connection, you'll have
+* terminator set to '\r\n', in order to process
+* the single-line greeting. Just before issuing a
+* 'LIST' command you'll set it to '\r\n.\r\n'.
+* The output of the LIST command will be accumulated
+* (using your own 'collect_incoming_data' method)
+* up to the terminator, and then control will be
+* returned to you - by calling your found_terminator()
+*
+* AUTHORS
+* Sam Rushing <rushing@nightmare.com> - original version for Medusa
+* Dave McClurg <dpm@efn.org> - modified for use in PLIB
+*
+* CREATION DATE
+* Dec-2000
+*
+****/
+
+#ifndef SG_NET_CHAT_H
+#define SG_NET_CHAT_H
+
+#include <simgear/io/sg_netBuffer.hxx>
+
+namespace simgear
+{
+
+class NetChat : public NetBufferChannel
+{
+ char* terminator;
+
+ virtual void handleBufferRead (NetBuffer& buffer) ;
+
+public:
+
+ NetChat () : terminator (0) {}
+
+ void setTerminator (const char* t);
+ const char* getTerminator (void);
+
+ bool push (const char* s);
+
+ virtual void collectIncomingData (const char* s, int n) {}
+ virtual void foundTerminator (void) {}
+};
+
+} // of namespace simgear
+
+#endif // SG_NET_CHAT_H