protocol_stream.cpp
上传用户:psq1974
上传日期:2007-01-06
资源大小:1195k
文件大小:8k
- /* Copyright (C) 1998, 1999 State University of New York at Stony Brook
- Author: Andrew V. Shuvalov ( andrew@ecsl.cs.sunysb.edu )
- Software license is located in file "COPYING"
- */
- #include "stdafx.h"
- #include "protocol_stream.h"
- #include "exceptions.h"
- #include "../../pusher/src/timeval.h"
- const char protocol_stream::prompt[] = ">>>";
- const char protocol_stream::command[] = "command";
- protocol_stream::protocol_stream( SOCKET _s, int gen_timeout )
- : sock( _s ), everything_read( false ), input_buffer_offset( 0 ),
- input_buffer_end( 0 ), genericTimeout( gen_timeout * 1000 )
- {
- }
- bool protocol_stream::test_for_input( int millisec )
- {
- fd_set set;
- FD_ZERO( &set );
- FD_SET( sock, &set );
- Timeval diff( 0, millisec * 1000 );
- int ret = select( FD_SETSIZE, &set, NULL, NULL, &diff.val() );
- if( ret == -1 )
- throw NetworkException( "select: %s", sys_errlist[ errno ] );
- if( !ret ) // timeval expires
- return false;
- return true;
- }
- bool protocol_stream::test_for_any_pending_input( int millisec )
- {
- # ifdef WIN32
- if( !buffer_is_empty() )
- return true;
- # else
- # endif
- if( test_for_input( millisec ))
- return true;
- return false;
- }
- bool protocol_stream::buffer_is_empty()
- {
- if( input_buffer_offset < input_buffer_end )
- return false;
- return true;
- }
- bool protocol_stream::eof()
- {
- return false;
- }
- int protocol_stream::peek()
- {
- if( !buffer_is_empty() )
- return (unsigned) input_buffer[ input_buffer_offset ];
- // buffer is empty - move marker to start
- input_buffer_offset = 0;
- input_buffer_end = 0;
- // buffer is empty - read a little
- // freeze for a while...
- if( !test_for_input( genericTimeout ) )
- return -1;
- // read
- int res = recv( sock, input_buffer, sizeof( input_buffer ), 0 );
- if( res > 0 )
- {
- input_buffer_end = res;
- // put zero at the end..
- input_buffer[ input_buffer_end ] = ' ';
- return (unsigned) input_buffer[ input_buffer_offset ];
- }
- // error
- return -1;
- }
- int protocol_stream::get( char &location )
- {
- int ch = peek();
- if( ch == -1 )
- {
- location = ' ';
- return -1;
- }
- // copy value to location
- location = input_buffer[ input_buffer_offset ];
- input_buffer_offset ++;
- return ch;
- }
- #ifdef WIN32 // for poor OS's
- char *protocol_stream::getline( char *buf, unsigned size )
- {
- // default:
- *buf = ' ';
- *( input_buffer + input_buffer_end ) = ' ';
- // de we have something in buffer?
- if( !buffer_is_empty() )
- {
- // find 'n'
- char *ptr = strchr( input_buffer + input_buffer_offset, 'n' );
- if( ptr )
- {
- // we have found end-of-line
- unsigned register size_to_copy = ptr - input_buffer
- - input_buffer_offset;
- if( size_to_copy > size )
- size_to_copy = size;
- memcpy( buf, input_buffer + input_buffer_offset, size_to_copy );
- // and zero at the end...
- buf[ size_to_copy ] = ' ';
- // we must skip the 'n' as well
- input_buffer_offset += size_to_copy + 1;
- return buf;
- }
- else
- {
- // no end-of-line, we may try to hold for a second and read from
- // the network
- // first check if buffer must be moved:
- if( input_buffer_offset >= sizeof( input_buffer ) / 2 )
- {
- memcpy( input_buffer, input_buffer + input_buffer_offset,
- input_buffer_end - input_buffer_offset );
- input_buffer_end = input_buffer_end - input_buffer_offset;
- input_buffer_offset = 0;
- }
- // this call is recursive, so it must have a dalay inside
- if( test_for_input( 100 ) )
- {
- // we have data
- int res = recv( sock, input_buffer + input_buffer_end,
- sizeof( input_buffer ) -
- (input_buffer_end - input_buffer_offset), 0 );
- if( res > 0 )
- {
- input_buffer_end += res;
- // put zero at the end..
- input_buffer[ input_buffer_end ] = ' ';
- // we have new data, try to recursively call itself
- return getline( buf, size );
- }
- if( res < 0 )
- {
- // error
- return NULL;
- }
- }
- // nothing.. maybe we reached prompt?
- char *ptr = strstr( input_buffer + input_buffer_offset, prompt );
- if( ptr )
- {
- // prompt reached
- unsigned register size_to_copy = ptr -
- (input_buffer + input_buffer_offset) + sizeof( prompt ) - 1;
- if( size_to_copy > size )
- size_to_copy = size;
- memcpy( buf, input_buffer + input_buffer_offset, size_to_copy );
-
- input_buffer_offset += size_to_copy;
- return buf;
- }
- } // if( ptr )
- } // if( !buffer_is_empty() )
- else
- {
- // buffer is empty - reset pointers
- input_buffer_offset = 0;
- input_buffer_end = 0;
- // buffer is empty - read a little
- // freeze for a while...
- if( !test_for_input( genericTimeout ) )
- return NULL;
- // read
- int res = recv( sock, input_buffer, sizeof( input_buffer ), 0 );
- if( res > 0 )
- {
- input_buffer_end = res;
- // put zero at the end..
- input_buffer[ input_buffer_end ] = ' ';
- // and call itself recursively
- return getline( buf, size );
- }
- if( res < 0 )
- throw NetworkException( "recv: %s", sys_errlist[ errno ] );
- }
- return buf;
- }
- #endif
- protocol_stream& protocol_stream::operator >>( std::string &s )
- {
- if( everything_read ) {
- s = "";
- return *this;
- }
- char buf[1024];
- if( before_mark )
- {
- // load until mark
- while( !eof() )
- {
- getline( buf, sizeof( buf ));
- if( !buf[0] )
- continue;
- if( buf[0] == '#' ) {
- messages.push_back( s );
- continue;
- }
- if( !strcmp( buf, "->" )) {
- before_mark = false;
- break;
- }
- }
- if( everything_read ) {
- s = "";
- return *this;
- }
- }
- while( !eof() )
- {
- getline( buf, sizeof( buf ));
- // check for special messages, which may indicate error
- if( !s.compare( "#!disconnect" ))
- throw ProtocolException( "disconnected" );
- if( buf[0] == '#' ) {
- messages.push_back( s );
- continue;
- }
- if( !strcmp( buf, "<-" )) {
- skip_to_prompt();
- everything_read = true;
- break;
- }
- s = buf;
- s.c_str(); // terminate
- // cout << s << endl;
- return *this;
- }
- s = "";
- s.c_str(); // terminate
- return *this;
- }
- protocol_stream& protocol_stream::operator >>( int &value )
- {
- std::string s;
- *this >> s;
- value = atoi( s.c_str() );
- return *this;
- }
- protocol_stream& protocol_stream::operator >>
- ( std::vector< std::string > &lines )
- {
- wait_input();
- while( true )
- {
- std::string s;
- *this >> s;
-
- if( everything_read )
- break;
- lines.push_back( s );
- }
- return *this;
- }
- protocol_stream& protocol_stream::operator <<( const std::string &s )
- {
- const char *str = s.c_str();
- send( sock, str, s.length(), 0 );
- // confirmation is mandatory
- wait_input();
- return *this;
- }
- void protocol_stream::skip_to_prompt()
- {
- char buf[ 1024 ];
- // nothing to do
- if( everything_read ) {
- return;
- }
- while( !eof() )
- {
- int ch = peek();
- if( ch == -1 )
- break;
- if( ch != '>' )
- {
- getline( buf, sizeof( buf ));
- if( !buf[0] )
- continue;
- if( ch == '#' ) {
- std::string s( buf );
- messages.push_back( s );
- }
- }
- else // input char by char
- {
- for( int i = 0; i < 3; i++ )
- get( buf[i] );
- buf[3] = ' ';
- std::string s( buf );
- if( !s.length() )
- continue;
- if( !s.compare( prompt ))
- {
- // and set the flag that we don't expect any input anymore..
- everything_read = true;
- break;
- }
- // ups! this is not our string... append the end of string
- getline( buf + 3, sizeof( buf ) - 3 );
- }
- }
- }
- void protocol_stream::skip_to_prompt( std::vector< std::string > &msgs )
- {
- skip_to_prompt();
- append_messages( msgs );
- }
-
- void protocol_stream::append_messages( std::vector< std::string > &msgs )
- {
- if( !messages.empty() )
- msgs.insert( msgs.end(), messages.begin(), messages.end() );
- messages.clear();
- }