]> git.mxchange.org Git - simgear.git/commitdiff
Migrate relevant PLIB netXXX classes into SimGear.
authorJames Turner <zakalawe@mac.com>
Sat, 23 Oct 2010 19:07:35 +0000 (20:07 +0100)
committerJames Turner <zakalawe@mac.com>
Sun, 24 Oct 2010 00:12:42 +0000 (01:12 +0100)
projects/VC90/SimGear.vcproj
simgear/io/Makefile.am
simgear/io/sg_netBuffer.cxx [new file with mode: 0644]
simgear/io/sg_netBuffer.hxx [new file with mode: 0644]
simgear/io/sg_netChannel.cxx [new file with mode: 0644]
simgear/io/sg_netChannel.hxx [new file with mode: 0644]
simgear/io/sg_netChat.cxx [new file with mode: 0644]
simgear/io/sg_netChat.hxx [new file with mode: 0644]

index d0f32f1c45569039bf47cb01a3d8dd408ce0ebe7..cdfeb22265fbb2dea1c9c3e7e21446c906240b06 100644 (file)
                                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
index ee2294c4fa68231d68d14f3574aa61dc9fa6a34f..566af470612c61a2004c4ac5df1093c06ea0c024 100644 (file)
@@ -10,7 +10,10 @@ include_HEADERS = \
        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 \
@@ -20,7 +23,10 @@ libsgio_a_SOURCES = \
        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)
 
diff --git a/simgear/io/sg_netBuffer.cxx b/simgear/io/sg_netBuffer.cxx
new file mode 100644 (file)
index 0000000..126b4e2
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+    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
diff --git a/simgear/io/sg_netBuffer.hxx b/simgear/io/sg_netBuffer.hxx
new file mode 100644 (file)
index 0000000..bd18068
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+    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
diff --git a/simgear/io/sg_netChannel.cxx b/simgear/io/sg_netChannel.cxx
new file mode 100644 (file)
index 0000000..e02f073
--- /dev/null
@@ -0,0 +1,305 @@
+/*
+  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
diff --git a/simgear/io/sg_netChannel.hxx b/simgear/io/sg_netChannel.hxx
new file mode 100644 (file)
index 0000000..30af512
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+    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
diff --git a/simgear/io/sg_netChat.cxx b/simgear/io/sg_netChat.cxx
new file mode 100644 (file)
index 0000000..fcced48
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+    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
+
+
diff --git a/simgear/io/sg_netChat.hxx b/simgear/io/sg_netChat.hxx
new file mode 100644 (file)
index 0000000..e9ab2e0
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+    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