📄 client.cc
字号:
// $Header: /cvsroot/sourcenav/src/snavigator/demo/c++_demo/glish/Client.cc,v 1.1.1.1 2002/04/18 23:35:24 mdejong Exp $#include "system.h"#include <stdlib.h>#include <osfcn.h>#include <fcntl.h>#include <ctype.h>#include <string.h>#include <errno.h>#include <signal.h>#ifdef HAVE_SYS_SELECT_H#include <sys/select.h>#endifextern "C" {#include <netinet/in.h>#ifndef HAVE_STRDUPchar* strdup( const char* );#endif}#include "Sds/sdsgen.h"#include "Glish/Client.h"#include "BuiltIn.h"#include "Reporter.h"#include "Socket.h"#include "glish_event.h"#include "system.h"typedef RETSIGTYPE (*SigHandler)(int);static Client* current_client;static const char* prog_name = "glish-interpreter";static int did_init = 0;inline streq( const char* s1, const char* s2 ) { return ! strcmp( s1, s2 ); }void Client_signal_handler() { current_client->HandlePing(); }GlishEvent::GlishEvent( const char* arg_name, const Value* arg_value ) { name = arg_name; value = (Value*) arg_value; flags = 0; delete_name = delete_value = 0; }GlishEvent::GlishEvent( const char* arg_name, Value* arg_value ) { name = arg_name; value = arg_value; flags = 0; delete_name = 0; delete_value = 1; }GlishEvent::GlishEvent( char* arg_name, Value* arg_value ) { name = arg_name; value = arg_value; flags = 0; delete_name = delete_value = 1; }GlishEvent::~GlishEvent() { if ( delete_name ) delete (char*) name; if ( delete_value ) Unref( (Value*) value ); }int GlishEvent::IsRequest() const { return flags & GLISH_REQUEST_EVENT; }int GlishEvent::IsReply() const { return flags & GLISH_REPLY_EVENT; }void GlishEvent::SetIsRequest() { flags |= GLISH_REQUEST_EVENT; }void GlishEvent::SetIsReply() { flags |= GLISH_REPLY_EVENT; }class EventLink {public: EventLink( char* task_id, char* new_name, int initial_activity ) { id = task_id; name = new_name; fd = -1; active = initial_activity; path = 0; } ~EventLink() { delete id; delete name; delete path; } const char* ID() const { return id; } int FD() const { return fd; } int Active() const { return active; } const char* Name() const { return name; } const char* Path() const { return path; } void SetActive( int activity ) { active = activity; } void SetFD( int new_fd ) { fd = new_fd; } void SetPath( const char* p ) { path = strdup( p ); }private: char* id; char* name; int fd; int active; char* path; // if nil, indicates this is a non-local socket };Client::Client( int& argc, char** argv ) { char** orig_argv = argv; prog_name = argv[0]; --argc, ++argv; // remove program name from argument list ClientInit(); int suspend = 0; no_glish = 0; interpreter_tag = "*no-interpreter*"; if ( argc < 2 || ! streq( argv[0], "-id" ) ) { // We weren't invoked by the Glish interpreter. Set things up // so that we receive "events" from stdin and send them // to stdout. have_interpreter_connection = 0; client_name = prog_name; if ( argc == 0 || (argc >= 1 && !streq( argv[0], "-glish" )) ) { no_glish = 1; } if ( argc >= 1 && streq( argv[0], "-noglish" ) ) { no_glish = 1; --argc, ++argv; } else { read_fd = fileno( stdin ); write_fd = fileno( stdout ); if ( argc >= 1 && streq( argv[0], "-glish" ) ) // Eat up -glish argument. --argc, ++argv; } } else { have_interpreter_connection = 1; client_name = argv[1]; argc -= 2, argv += 2; if ( argc < 2 || (! streq( argv[0], "-host" ) && ! streq( argv[0], "-pipes" )) ) fatal->Report( "invalid Client argument list - missing connection arguments" ); if ( streq( argv[0], "-host" ) ) { // Socket connection. char* host = argv[1]; argc -= 2, argv += 2; if ( argc < 2 || ! streq( argv[0], "-port" ) ) fatal->Report( "invalid Client argument list - missing port number" ); int port = atoi( argv[1] ); argc -= 2, argv += 2; int socket = get_tcp_socket(); if ( ! remote_connection( socket, host, port ) ) fatal->Report( "could not establish Client connection to interpreter" ); read_fd = write_fd = socket; } else { // Pipe connection. ++argv, --argc; // skip -pipes argument if ( argc < 2 ) fatal->Report( "invalid Client argument list - missing pipe fds" ); read_fd = atoi( argv[0] ); write_fd = atoi( argv[1] ); argc -= 2, argv += 2; } if ( argc > 1 && streq( argv[0], "-interpreter" ) ) { interpreter_tag = argv[1]; argc -= 2, argv += 2; } if ( argc > 0 && streq( argv[0], "-suspend" ) ) { suspend = 1; --argc, ++argv; } } if ( suspend ) { int pid = int( getpid() ); fprintf( stderr, "%s @ %s, pid %d: suspending ...\n", prog_name, local_host, pid ); while ( suspend ) sleep( 1 ); // allow debugger to attach } if ( have_interpreter_connection ) SendEstablishedEvent(); CreateSignalHandler(); for ( int i = 1; i <= argc; ++i ) orig_argv[i] = *(argv++); orig_argv[i] = 0; argv = orig_argv; // Put argv[0] back into the argument count - it was removed // near the top of this routine. ++argc; }Client::Client( int client_read_fd, int client_write_fd, const char* name ) { client_name = prog_name = name; ClientInit(); no_glish = 0; have_interpreter_connection = 1; read_fd = client_read_fd; write_fd = client_write_fd; SendEstablishedEvent(); CreateSignalHandler(); }Client::~Client() { (void) install_signal_handler( SIGIO, former_handler ); if ( have_interpreter_connection ) PostEvent( "done", client_name ); if ( ! no_glish ) { close( read_fd ); close( write_fd ); } }GlishEvent* Client::NextEvent() { if ( no_glish ) return 0; if ( input_links.length() == 0 ) // Only one input channel, okay to block reading it. return GetEvent( read_fd ); fd_set input_fds; FD_ZERO( &input_fds ); AddInputMask( &input_fds ); while ( select( FD_SETSIZE, &input_fds, 0, 0, 0 ) < 0 ) { if ( errno != EINTR ) { fprintf( stderr, "%s: ", prog_name ); perror( "error during select()" ); return 0; } } return NextEvent( &input_fds ); }GlishEvent* Client::NextEvent( fd_set* mask ) { if ( no_glish ) return 0; if ( FD_ISSET( read_fd, mask ) ) return GetEvent( read_fd ); loop_over_list( input_links, i ) { int fd = input_links[i]; if ( FD_ISSET( fd, mask ) ) return GetEvent( fd ); } PostEvent( "error", "bad call to Client::NextEvent" ); return 0; }void Client::Unrecognized() { if ( ! last_event ) return; if ( last_event->name[0] == '*' ) // Internal event - ignore. return; PostEvent( "unrecognized", last_event->name ); }void Client::Error( const char* msg ) { if ( last_event ) PostEvent( "error", "bad \"%s\" event: %s", last_event->name, msg ); else PostEvent( "error", msg ); }void Client::Error( const char* fmt, const char* arg ) { char buf[8192]; sprintf( buf, fmt, arg ); Error( buf ); }void Client::PostEvent( const char* event_name, const Value* event_value ) { GlishEvent e( event_name, event_value ); SendEvent( &e ); }void Client::PostEvent( const GlishEvent* event ) { SendEvent( event ); }void Client::PostEvent( const char* event_name, const char* event_value ) { Value val( event_value ); PostEvent( event_name, &val ); }void Client::PostEvent( const char* event_name, const char* event_fmt, const char* event_arg ) { char buf[8192]; sprintf( buf, event_fmt, event_arg ); PostEvent( event_name, buf ); }void Client::PostEvent( const char* event_name, const char* event_fmt, const char* arg1, const char* arg2 ) { char buf[8192]; sprintf( buf, event_fmt, arg1, arg2 ); PostEvent( event_name, buf ); }void Client::Reply( const Value* event_value ) { if ( ! ReplyPending() ) error->Report( prog_name, " issued Reply without having received a corresponding request" ); else { GlishEvent e( (const char*) pending_reply, event_value ); e.SetIsReply(); PostEvent( &e ); delete pending_reply; pending_reply = 0; } }void Client::PostOpaqueSDS_Event( const char* event_name, int sds ) { GlishEvent e( event_name, (const Value*) 0 ); SendEvent( &e, sds ); }int Client::AddInputMask( fd_set* mask ) { if ( no_glish ) return 0; int num_added = 0; if ( ! FD_ISSET( read_fd, mask ) ) { FD_SET( read_fd, mask ); ++num_added; } // Now add in any fd's due to event links. loop_over_list( input_links, i ) if ( ! FD_ISSET( input_links[i], mask ) ) { FD_SET( input_links[i], mask ); ++num_added; } return num_added; }int Client::HasClientInput( fd_set* mask ) { if ( no_glish ) return 0; if ( FD_ISSET( read_fd, mask ) ) return 1; loop_over_list( input_links, i ) { if ( FD_ISSET( input_links[i], mask ) ) return 1; } return 0; }void Client::ClientInit() { if ( ! did_init ) { sds_init(); init_reporters(); init_values(); did_init = 1; } last_event = 0; pending_reply = 0; local_host = local_host_name(); }void Client::CreateSignalHandler() { current_client = this; former_handler = install_signal_handler( SIGIO, Client_signal_handler ); }void Client::SendEstablishedEvent() { Value* r = create_record(); r->SetField( "name", client_name ); r->SetField( "protocol", GLISH_CLIENT_PROTO_VERSION ); PostEvent( "established", r ); Unref( r ); }GlishEvent* Client::GetEvent( int fd ) { Unref( last_event ); if ( have_interpreter_connection ) { last_event = recv_event( fd ); if ( ! last_event && fd != read_fd ) { // A link has gone away; but don't return a nil // event, that'll cause us to go away too. Instead, // remove this fd from the list of input links and // cobble together a dummy event. input_links.remove( fd ); FD_Change( fd, 0 ); last_event = new GlishEvent( (const char*) "*dummy*", error_value() ); } if ( last_event ) { Value* v = last_event->value; if ( v->FieldVal( "*reply*", pending_reply ) ) { // Request/reply event; unwrap the request. Value* request = v->Field( "*request*" ); if ( ! request ) fatal->Report( "bad request/reply event" ); Ref( request ); Unref( v ); last_event->value = request; } } } else { char buf[512]; if ( ! fgets( buf, sizeof( buf ), stdin ) ) return 0; // Nuke final newline, if present. char* delim = strchr( buf, '\n' );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -