/*  -*- mode: c++; c-basic-offset: 4; -*-
 *
 *  MICO --- a free CORBA implementation
 *  Copyright (C) 1997-98 Kay Roemer & Arno Puder
 *
 *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *  Send comments and/or bug reports to:
 *                 mico@informatik.uni-frankfurt.de
 */

#ifndef __mico_iop_h__
#define __mico_iop_h__

#ifndef HAVE_THREADS
#  define USE_IOP_CACHE
#endif

class GIOPCodec;

class GIOPInContext {
    CORBA::DataDecoder *_dc;
    CORBA::Buffer *_buf;
    CORBA::Boolean _delete_buf;
#ifdef HAVE_THREADS
    CORBA::Boolean _delete_dc;
#endif
public:
    GIOPInContext (GIOPCodec *, CORBA::Buffer *,
		   CORBA::CodesetConv *csc = 0,
		   CORBA::CodesetConv *wcsc = 0);
    ~GIOPInContext ();
    void converters (CORBA::CodesetConv *csc, CORBA::CodesetConv *wcsc);
    CORBA::DataDecoder *dc()
    { return _dc; }

    void buffer (CORBA::Buffer *);
    CORBA::DataDecoder *_retn();
};

class GIOPOutContext {
    CORBA::DataEncoder *_ec;
    CORBA::Buffer *_buf;
    CORBA::Boolean _delete_buf;
#ifdef HAVE_THREADS
    CORBA::Boolean _delete_ec;
#endif
public:
    GIOPOutContext (GIOPCodec *, CORBA::CodesetConv *csc = 0,
		    CORBA::CodesetConv *wcsc = 0);
    GIOPOutContext (CORBA::DataEncoder *);
    ~GIOPOutContext ();
    void converters (CORBA::CodesetConv *csc, CORBA::CodesetConv *wcsc);
    CORBA::DataEncoder *ec()
    { return _ec; }

    void reset ();

    CORBA::Buffer *_retn();
};

#define GIOP_BYTEORDER_BIT 1
#define GIOP_FRAGMENT_BIT 2

class GIOPCodec;
typedef GIOPCodec *GIOPCodec_ptr;
typedef ObjVar<GIOPCodec> GIOPCodec_var;

class GIOPCodec : public CORBA::ServerlessObject {
    CORBA::DataDecoder *_dc_proto;
    CORBA::DataEncoder *_ec_proto;
    CORBA::ULong _headerlen;
    CORBA::ULong _size_offset;
    CORBA::UShort _giop_ver;

    CORBA::ULong put_header (GIOPOutContext &out, CORBA::GIOP::MsgType);
    void put_size (GIOPOutContext &out, CORBA::ULong key);
    void put_contextlist (GIOPOutContext &out,
			  const CORBA::IOP::ServiceContextList &ctx,
			  CORBA::Boolean codesets = FALSE);
    void put_target (GIOPOutContext &out, CORBA::Object_ptr obj);
    CORBA::Boolean put_args (GIOPOutContext &out, CORBA::ORBRequest *,
			     CORBA::Boolean inp);

    CORBA::Boolean get_contextlist (GIOPInContext &in,
				    CORBA::IOP::ServiceContextList &ctx,
				    CORBA::Boolean codesets = FALSE);
    CORBA::Boolean get_target (GIOPInContext &in, CORBA::Object_ptr obj);
public:
    GIOPCodec (CORBA::DataDecoder *dc, CORBA::DataEncoder *ec);
    ~GIOPCodec ();

    CORBA::DataDecoder *dc_proto()
    { return _dc_proto; }

    CORBA::DataEncoder *ec_proto()
    { return _ec_proto; }

    CORBA::UShort version () const
    { return _giop_ver; }

    CORBA::ULong header_length ()
    { return _headerlen; }

    CORBA::Boolean put_invoke_request (GIOPOutContext &out,
				       CORBA::ULong req_id,
				       CORBA::Octet response_flags,
				       CORBA::Object_ptr obj,
				       CORBA::ORBRequest *req,
				       CORBA::Principal_ptr pr);

    CORBA:: Boolean put_invoke_reply (GIOPOutContext &out,
				      CORBA::ULong req_id,
				      CORBA::GIOP::ReplyStatusType,
				      CORBA::Object_ptr obj,
				      CORBA::ORBRequest *req);

    CORBA::Boolean put_invoke_reply_offset (GIOPOutContext &out,
					    CORBA::ORBRequest *req);

    CORBA::Boolean put_cancel_request (GIOPOutContext &out,
				       CORBA::ULong req_id);

    CORBA::Boolean put_locate_request (GIOPOutContext &out,
				       CORBA::ULong req_id,
				       CORBA::Object_ptr obj);

    CORBA::Boolean put_locate_reply (GIOPOutContext &out,
				     CORBA::ULong req_id,
				     CORBA::GIOP::LocateStatusType,
				     CORBA::Object_ptr obj);

    CORBA::Boolean put_bind_request (GIOPOutContext &out,
				     CORBA::ULong req_id,
				     const char *repoid,
				     const CORBA::ORB::ObjectTag &);

    CORBA::Boolean put_bind_reply (GIOPOutContext &out,
				   CORBA::ULong req_id,
				   CORBA::GIOP::LocateStatusType,
				   CORBA::Object_ptr obj);

    CORBA::Boolean put_close_msg (GIOPOutContext &out);

    CORBA::Boolean put_error_msg (GIOPOutContext &out);

    CORBA::Boolean get_header (GIOPInContext &in, CORBA::GIOP::MsgType &,
			       CORBA::ULong &sz, CORBA::Octet &flags);
    CORBA::Boolean check_header (GIOPInContext &in, CORBA::GIOP::MsgType &,
				 CORBA::ULong &sz, CORBA::Octet &flags);

    CORBA::Boolean get_invoke_request (GIOPInContext &in,
				       CORBA::ULong &req_id,
				       CORBA::Octet &response_flags,
				       CORBA::Object_ptr obj,
				       CORBA::ORBRequest * &req,
				       CORBA::Principal_ptr pr);


    CORBA::Boolean get_invoke_reply1 (GIOPInContext &in,
				      CORBA::ULong &req_id,
				      CORBA::GIOP::ReplyStatusType &,
				      CORBA::IOP::ServiceContextList &ctx);

    CORBA::Boolean get_invoke_reply2 (GIOPInContext &in,
				      CORBA::ULong req_id,
				      CORBA::GIOP::ReplyStatusType,
				      CORBA::Object_ptr &obj,
				      CORBA::ORBRequest *req,
				      CORBA::IOP::ServiceContextList &ctx);

    CORBA::Boolean get_cancel_request (GIOPInContext &in,
				       CORBA::ULong &req_id);

    CORBA::Boolean get_locate_request (GIOPInContext &in,
				       CORBA::ULong &req_id,
				       CORBA::Object_ptr obj);

    CORBA::Boolean get_locate_reply (GIOPInContext &in,
				     CORBA::ULong &req_id,
				     CORBA::GIOP::LocateStatusType &,
				     CORBA::Object_ptr &obj);

    CORBA::Boolean get_bind_request (GIOPInContext &in,
				     char *& repoid,
				     CORBA::ORB::ObjectTag &);

    CORBA::Boolean get_bind_reply (GIOPInContext &in,
				   CORBA::GIOP::LocateStatusType &,
				   CORBA::Object_ptr &obj);

    CORBA::Boolean get_close_msg (GIOPInContext &in);

    CORBA::Boolean get_error_msg (GIOPInContext &in);

    CORBA::Boolean get_fragment_header (GIOPInContext &in,
					CORBA::ULong &req_id,
					CORBA::Boolean &has_id);


    static GIOPCodec_ptr _duplicate (GIOPCodec_ptr o)
    {
	if (o)
	    o->_ref();
	return o;
    }
    static GIOPCodec_ptr _nil ()
    {
	return 0;
    }
};


class GIOPRequest : public CORBA::ORBRequest {
    string _opname;

    CORBA::DataDecoder *_idc;
    CORBA::ULong _istart;

    CORBA::DataEncoder *_oec;
    CORBA::DataDecoder *_odc;
    CORBA::ULong _ostart;
    CORBA::Buffer _obuf;

    GIOPCodec_ptr _codec;

    CORBA::Boolean _is_except;
public:
    GIOPRequest (const char *op, CORBA::DataDecoder *indata, GIOPCodec *);
    ~GIOPRequest ();
    
    const char *op_name();
    
    CORBA::Boolean get_in_args (CORBA::NVList_ptr iparams,
                                CORBA::Context_ptr &ctx);
    CORBA::Boolean get_in_args (StaticAnyList *iparams,
                                CORBA::Context_ptr &ctx);
    CORBA::Boolean get_in_args (CORBA::DataEncoder *);
    
    CORBA::Boolean get_out_args (CORBA::Any *res, CORBA::NVList_ptr oparams,
                                 CORBA::Exception *&ex);
    CORBA::Boolean get_out_args (CORBA::StaticAny *res, StaticAnyList *oparams,
                                 CORBA::Exception *&ex);
    CORBA::Boolean get_out_args (CORBA::DataEncoder *,
                                 CORBA::Boolean &is_except);
    
    CORBA::Boolean set_out_args (CORBA::Any *res, CORBA::NVList_ptr oparams);
    CORBA::Boolean set_out_args (CORBA::StaticAny *res,
                                 StaticAnyList *oparams);
    void set_out_args (CORBA::Exception *ex);
    CORBA::Boolean set_out_args (CORBA::DataDecoder *,
                                 CORBA::Boolean is_except);

    CORBA::Boolean copy_out_args (CORBA::ORBRequest *);
    CORBA::Boolean copy_in_args (CORBA::ORBRequest *);
    
    const char *type ();
    CORBA::ByteOrder input_byteorder ();
    CORBA::ByteOrder output_byteorder ();
    CORBA::Codeset::CodesetId csid ();
    CORBA::Codeset::CodesetId wcsid ();

    static GIOPRequest* _nil ()
    {
	return 0;
    }
    static GIOPRequest* _duplicate (GIOPRequest *o)
    {
	if (o)
	    o->_ref();
	return o;
    }
};


class GIOPSimpleProf : public CORBA::IORProfile {
public:
    CORBA::Octet *_objkey;
    CORBA::ULong _length;
public:
    GIOPSimpleProf ();
    GIOPSimpleProf (const GIOPSimpleProf &);
    ~GIOPSimpleProf ();
    GIOPSimpleProf &operator= (const GIOPSimpleProf &);

    void encode (CORBA::DataEncoder &) const;
    const CORBA::Address *addr () const;
    ProfileId id () const;
    ProfileId encode_id () const;
    void objectkey (CORBA::Octet *, CORBA::Long length);
    const CORBA::Octet *objectkey (CORBA::Long &length) const;
    CORBA::Boolean reachable ();
    void print (ostream &) const;
    
    CORBA::IORProfile *clone () const;
    CORBA::Long compare (const CORBA::IORProfile &) const;
    CORBA::Boolean operator== (const CORBA::IORProfile &) const;
    CORBA::Boolean operator< (const CORBA::IORProfile &) const;
};


#ifdef HAVE_THREADS
class GIOPConnReader;
class GIOPConnWriter;
#endif
struct GIOPConnCallback;

class GIOPConn : public CORBA::TransportCallback,
		 public CORBA::DispatcherCallback,
                 public MICOMT::StateRefCnt {
    CORBA::Dispatcher *_disp;
    CORBA::Transport *_transp;
    list<CORBA::Buffer *> _outbufs;
    CORBA::Buffer *_inbufs;
    CORBA::Buffer *_inbuf, *_infrag;
    CORBA::ULong _inlen;
    CORBA::Octet _inflags;
    GIOPConnCallback *_cb;
    GIOPCodec_ptr _codec;
    CORBA::Long _refcnt;
    CORBA::Long _idle_tmout;
    CORBA::Boolean _have_tmout;
    CORBA::Boolean _have_wselect;
    GIOPInContext _inctx;

    void do_write ();

#ifdef HAVE_THREADS
    GIOPConnReader *_reader;
    GIOPConnWriter *_writer;

    CORBA::Boolean do_InputReady();
    void do_CloseConnection();

    void check_idle () {};
    void check_busy () {};
#else
    CORBA::Boolean do_InputReady() {
	return  do_InputReadyCallback( input() );
    };
    void do_CloseConnection() {
	_cb->callback (this, GIOPConnCallback::Closed);
    };
    void check_idle ();
    void check_busy ();
#endif // HAVE_THREADS

public:
    void do_read ( const CORBA::Boolean break_after_read = FALSE );
    void output_handler (CORBA::Buffer *);

    GIOPConn (CORBA::Dispatcher *, CORBA::Transport *, GIOPConnCallback *,
	      GIOPCodec *, CORBA::Long tmout = 0);
    void terminate();
    virtual ~GIOPConn ();

#ifdef HAVE_THREADS
    void start();
    void output (CORBA::Buffer *);

    CORBA::Boolean check_events () { return FALSE; };

    void ref () { _refcnt++; };
    CORBA::Boolean deref (CORBA::Boolean all = FALSE);
#else
    void start() {};
    void output (CORBA::Buffer *b) { output_handler( b); };

    CORBA::Boolean check_events ();

    void ref ();
    CORBA::Boolean deref (CORBA::Boolean all = FALSE);
#endif

    CORBA::Boolean do_InputReadyCallback(CORBA::Buffer *b);

    virtual void callback (CORBA::Transport *,
			   CORBA::TransportCallback::Event);
    virtual void callback (CORBA::Dispatcher *,
			   CORBA::DispatcherCallback::Event);

    CORBA::Buffer *input ();
    void flush ();

    CORBA::Transport *transport ()
    { return _transp; }

    GIOPCodec *codec ()
    { return _codec; }

    void cancel (CORBA::ULong reqid);
    void buffering (CORBA::Boolean dobuffering);
};

struct GIOPConnCallback {
    enum Event { InputReady, Closed, Idle };
    virtual CORBA::Boolean callback (GIOPConn *, Event) = 0;
    virtual CORBA::Boolean input_callback (GIOPConn *, CORBA::Buffer *) = 0;
    virtual ~GIOPConnCallback ();
#ifdef HAVE_THREADS
    void sendORBMsg (GIOPConn *, ORBMsg::Event);
    //#else
    //    void kill_conn (GIOPConn *conn, CORBA::Boolean redo = FALSE) { kill_conn_callback( conn, redo ); };
#endif
};

inline CORBA::Boolean
GIOPConn::do_InputReadyCallback(CORBA::Buffer *b) {
    return _cb->input_callback (this, b);
};

struct GIOPConnMsg {
    GIOPConnMsg(GIOPConn *_conn, CORBA::Buffer *_b, GIOPConnCallback::Event _ev):
	conn(_conn), b(_b), ev(_ev) {};

    GIOPConn                *conn;
    CORBA::Buffer           *b;
    GIOPConnCallback::Event ev;
};

#ifdef HAVE_THREADS

class GIOPConnWriter: public activeOperation {
protected:
    GIOPConn *conn;
public:
    GIOPConnWriter( GIOPConn *_conn );
    virtual ~GIOPConnWriter();
    
    void process( msg_type * msg );
    void send_msg( msg_type * msg);
    virtual Operation *copy() const { return NULL; };
};

class GIOPConnReader: public Operation {
protected:
    GIOPConn *conn;
public:
    GIOPConnReader( GIOPConn *_conn );
    void _run();
    virtual Operation *copy() const { return NULL; };
};

class InputHandler: public passiveOperation {
public:
    InputHandler();
    //    InputHandler( const MICO::InputHandler::InputHandler & );
    InputHandler( ThreadPool& _tp );

    void process( msg_type * msg );
    virtual Operation *copy() const;
};

class DummyDispatcher: public CORBA::Dispatcher {
public:
    virtual ~DummyDispatcher () {};

    void rd_event (CORBA::DispatcherCallback *, CORBA::Long fd) {};
    void wr_event (CORBA::DispatcherCallback *, CORBA::Long fd) {};
    void ex_event (CORBA::DispatcherCallback *, CORBA::Long fd) {};
    void tm_event (CORBA::DispatcherCallback *, CORBA::ULong tmout) {};
    void remove (CORBA::DispatcherCallback *, CORBA::Dispatcher::Event) {};
    void run (CORBA::Boolean infinite = TRUE) {};
    void move (CORBA::Dispatcher *) {};
    CORBA::Boolean idle () const { return TRUE; };
 
    virtual void block (CORBA::Boolean b) {};;
    virtual CORBA::Boolean isblocking () { return TRUE; };
};                                                                              

class GIOPConnMgr {
protected:
    DummyDispatcher dummyDisp;

public:
    CORBA::Dispatcher *Dispatcher() { return &dummyDisp; };
};

#else

class GIOPConnMgr {
public:
    CORBA::Dispatcher *Dispatcher() { return _orb->dispatcher(); };
};

#endif // HAVE_THREADS

class IIOPProxyInvokeRec {
public:
    typedef CORBA::ULong MsgId;
    typedef CORBA::Codeset::CodesetId CodesetId;
private:
    CORBA::ORBMsgId _id;
    MsgId _msgid;
    GIOPConn *_conn;
    CORBA::ORBRequest *_req;
    CodesetId _csid;
    CodesetId _wcsid;

    CORBA::Boolean _active;
public:
    IIOPProxyInvokeRec ()
    {}

    ~IIOPProxyInvokeRec ()
    {}

    void free ()
    {}

    void init (CORBA::ORBMsgId id, GIOPConn *conn, CORBA::ORBRequest *req = 0,
	       CodesetId cs = 0, CodesetId wcs = 0)
    {
	_id = id;
	_msgid = CORBA::ORB::get_msgid(id);
	_conn = conn;
	_req = req;
	_csid = cs;
	_wcsid = wcs;
	_active = TRUE;
    }

    CORBA::Boolean active() const
    { return _active; };

    void deactivate()
    { _active = FALSE; };

    GIOPConn *conn () const
    { return _conn; }

    CORBA::ORBRequest *request () const
    { return _req; }

    CodesetId csid () const
    { return _csid; }

    CodesetId wcsid () const
    { return _wcsid; }

    CORBA::ORBMsgId id () const
    { return _id; }

    MsgId msgid () const
    { return _msgid; }
};

class IIOPProxy : public CORBA::ObjectAdapter, public GIOPConnCallback, public GIOPConnMgr {
    typedef map<MsgId, IIOPProxyInvokeRec *, less<MsgId> > MapIdConn;

    struct addrcomp :
	binary_function<const CORBA::Address *, const CORBA::Address *, bool> {
	bool operator() (const CORBA::Address *a1,
			 const CORBA::Address *a2) const
	{ return a1->compare (*a2) < 0; }
    };
    typedef map<const CORBA::Address *, GIOPConn *, addrcomp> MapAddrConn;
    typedef vector<CORBA::IORProfile::ProfileId> ProfIdVec;

    ProfIdVec _valid_profiles;
    MICOMT::Locked<MapIdConn> _ids;
    MICOMT::Locked<MapAddrConn> _conns;
    CORBA::ORB_ptr _orb;

#ifdef USE_IOP_CACHE
    IIOPProxyInvokeRec *_cache_rec;
    CORBA::Boolean _cache_used;
#endif

    CORBA::Boolean get_codeset_ids (CORBA::Object_ptr,
				    CORBA::Codeset::CodesetId &csid,
				    CORBA::Codeset::CodesetId &wcsid);

    IIOPProxyInvokeRec *create_invoke ();
    IIOPProxyInvokeRec *pull_invoke (CORBA::ORBMsgId);
    void add_invoke (IIOPProxyInvokeRec *);
    void del_invoke (IIOPProxyInvokeRec *);
    void abort_invoke (CORBA::ORBMsgId);
    void redo_invoke  (CORBA::ORBMsgId);

    GIOPConn *make_conn (CORBA::Object_ptr);
    GIOPConn *make_conn (const CORBA::Address *, CORBA::Boolean create = TRUE);

    void conn_error (GIOPConn *, CORBA::Boolean send_error = TRUE);
#ifdef HAVE_THREADS
    void deref_conn (GIOPConn *conn, CORBA::Boolean all = FALSE );
#else
    void deref_conn (GIOPConn *conn, CORBA::Boolean all = FALSE ) { conn->deref( all ) };
#endif

    CORBA::Boolean handle_input (GIOPConn *, CORBA::Buffer *);
    void exec_invoke_reply (GIOPInContext &, CORBA::ORBMsgId,
			    CORBA::GIOP::ReplyStatusType,
			    CORBA::Object_ptr, CORBA::ORBRequest *,
			    GIOPConn *conn);
    CORBA::Boolean handle_invoke_reply (GIOPConn *conn, GIOPInContext &);
    CORBA::Boolean handle_locate_reply (GIOPConn *conn, GIOPInContext &);
public:
    IIOPProxy (CORBA::ORB_ptr);
    ~IIOPProxy ();

    const char *get_oaid () const;
    CORBA::Boolean has_object (CORBA::Object_ptr);
    CORBA::Boolean is_local () const;
    
    CORBA::Boolean invoke (CORBA::ORBMsgId, CORBA::Object_ptr,
    			   CORBA::ORBRequest *,
    			   CORBA::Principal_ptr,
    			   CORBA::Boolean repsonse_exp);
    CORBA::Boolean bind (CORBA::ORBMsgId, const char *repoid,
    			 const CORBA::ORB::ObjectTag &,
    			 CORBA::Address *addr);
    CORBA::Boolean locate (CORBA::ORBMsgId, CORBA::Object_ptr);
    CORBA::Object_ptr skeleton (CORBA::Object_ptr);
    void cancel (CORBA::ORBMsgId);
    void shutdown (CORBA::Boolean wait_for_completion);
    
    void answer_invoke (CORBA::ORBMsgId, CORBA::Object_ptr,
    			CORBA::ORBRequest *,
    			CORBA::InvokeStatus);
    
    CORBA::Boolean callback (GIOPConn *, GIOPConnCallback::Event);
    CORBA::Boolean input_callback (GIOPConn *, CORBA::Buffer *);

    void kill_conn (GIOPConn *, CORBA::Boolean redo = FALSE);

};


class IIOPServerInvokeRec {
public:
    typedef CORBA::ULong MsgId;
private:
    CORBA::ORBRequest *_req;
    CORBA::Object_ptr _obj;
    CORBA::Principal_ptr _pr;
    CORBA::ORBMsgId _orbid;
    MsgId _orbmsgid;
    MsgId _reqid;
    GIOPConn *_conn;
    CORBA::Boolean _active;
public:
    IIOPServerInvokeRec ();
    ~IIOPServerInvokeRec ();
    void free ();

    void init_invoke (GIOPConn *conn, MsgId reqid, CORBA::ORBMsgId orbid,
		      CORBA::ORBRequest *req, CORBA::Object_ptr obj,
		      CORBA::Principal_ptr pr);
    void init_locate (GIOPConn *conn, MsgId reqid, CORBA::ORBMsgId orbid,
		      CORBA::Object_ptr obj);

    CORBA::Boolean active() const
    { return _active; };

    void deactivate()
    { _active = FALSE; };

    CORBA::ORBRequest *req()
    { return _req; }

    CORBA::ORBMsgId orbid()
    { return _orbid; }

    MsgId orbmsgid()
    { return _orbmsgid; }

    void orbid (CORBA::ORBMsgId id)
    { _orbid = id; }

    MsgId reqid()
    { return _reqid; }

    GIOPConn *conn()
    { return _conn; }
};

class IIOPServer : public CORBA::ObjectAdapter,
		   public CORBA::ORBCallback, public GIOPConnCallback, public GIOPConnMgr,
		   public CORBA::TransportServerCallback {
    typedef CORBA::ULong MsgId;
    typedef map<MsgId, IIOPServerInvokeRec *, less<MsgId> > MapIdConn;
    typedef list<GIOPConn *> ListConn;
    typedef FastArray<CORBA::TransportServer> VecTranspServ;

    VecTranspServ _tservers;
    MICOMT::Locked<ListConn> _conns;

    MapIdConn _orbids;
    MICOMT::Mutex _orbids_mutex;

    CORBA::ORB_ptr _orb;

#ifdef USE_IOP_CACHE
    IIOPServerInvokeRec *_cache_rec;
    CORBA::Boolean _cache_used;
#endif

    IIOPServerInvokeRec *create_invoke();
    IIOPServerInvokeRec *pull_invoke_reqid (MsgId, GIOPConn *conn);
    IIOPServerInvokeRec *pull_invoke_orbid (CORBA::ORBMsgId);
    void add_invoke (IIOPServerInvokeRec *);
    void del_invoke_reqid (MsgId, GIOPConn *conn);
    void del_invoke_orbid (IIOPServerInvokeRec *);
    void abort_invoke_orbid (IIOPServerInvokeRec *);

    void conn_error (GIOPConn *, CORBA::Boolean send_error = TRUE);
    void conn_closed (GIOPConn *);
#ifdef HAVE_THREADS
    void deref_conn (GIOPConn *conn, CORBA::Boolean all = FALSE );
#else
    void deref_conn (GIOPConn *conn, CORBA::Boolean all = FALSE ) { conn->deref( all ) };
#endif

    CORBA::Boolean handle_input (GIOPConn *, CORBA::Buffer *);
    CORBA::ORBMsgId exec_invoke_request (GIOPInContext &, CORBA::Object_ptr,
			       CORBA::ORBRequest *,
			       CORBA::Principal_ptr, CORBA::Boolean resp_exp,
			       GIOPConn *conn,
			       CORBA::ORBMsgId msgid);
    CORBA::Boolean handle_invoke_request (GIOPConn *conn, GIOPInContext &);
    CORBA::Boolean handle_locate_request (GIOPConn *conn, GIOPInContext &);
    CORBA::Boolean handle_cancel_request (GIOPConn *conn, GIOPInContext &);

    void handle_invoke_reply (CORBA::ORBMsgId);
    void handle_locate_reply (CORBA::ORBMsgId);
    void handle_bind_reply   (CORBA::ORBMsgId);
public:
    IIOPServer (CORBA::ORB_ptr);
    ~IIOPServer ();

    CORBA::Boolean listen (CORBA::Address *, CORBA::Address *);
    CORBA::Boolean listen ();

    // ObjectAdapter methods
    const char *get_oaid () const;
    CORBA::Boolean has_object (CORBA::Object_ptr);
    CORBA::Boolean is_local () const;
    
    CORBA::Boolean invoke (CORBA::ORBMsgId, CORBA::Object_ptr,
    			   CORBA::ORBRequest *,
    			   CORBA::Principal_ptr,
    			   CORBA::Boolean repsonse_exp);
    CORBA::Boolean bind (CORBA::ORBMsgId, const char *repoid,
    			 const CORBA::ORB::ObjectTag &,
    			 CORBA::Address *addr);
    CORBA::Boolean locate (CORBA::ORBMsgId, CORBA::Object_ptr);
    CORBA::Object_ptr skeleton (CORBA::Object_ptr);
    void cancel (CORBA::ORBMsgId);
    void shutdown (CORBA::Boolean wait_for_completion);
    
    void answer_invoke (CORBA::ORBMsgId, CORBA::Object_ptr,
    			CORBA::ORBRequest *,
    			CORBA::InvokeStatus);

    // ORBCallback interface
    CORBA::Boolean waitfor (CORBA::ORB_ptr, CORBA::ORBMsgId,  CORBA::ORBCallback::Event, CORBA::Long);
    void notify (CORBA::ORB_ptr, CORBA::ORBMsgId, CORBA::ORBCallback::Event);

    CORBA::Boolean callback (GIOPConn *, GIOPConnCallback::Event);
    CORBA::Boolean input_callback (GIOPConn *, CORBA::Buffer *);
    void callback (CORBA::TransportServer *,
		   CORBA::TransportServerCallback::Event);

    void kill_conn (GIOPConn *, CORBA::Boolean redo = FALSE);
};

#endif // __mico_iop_h__
