1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
|
#pike __REAL_VERSION__
#include "remote.h"
import ".";
//! Remote RPC server.
int portno;
//! @decl Stdio.Port port
//!
//! Port for the @[Remote.Server].
object port;
//! @decl array(Connection) connections
//!
//! Open connections.
array connections = ({ });
//! @decl Minicontext sctx
//!
//! Server context.
object sctx;
int max_call_threads;
//! The server @[Context] class.
class Minicontext
{
mapping(string:mixed) id2val = ([ ]);
mapping(mixed:string) val2id = ([ ]);
string id_for(mixed thing)
{
return val2id[thing];
}
object object_for(string id, object con)
{
object o = id2val[id];
if(functionp(o) || programp(o))
o = o(con);
if(objectp(o) && functionp(o->close))
con->add_close_callback(o->close);
return o;
}
void add(string name, object|program what)
{
id2val[name] = what;
val2id[what] = name;
}
}
void got_connection(object f)
{
object c = f->accept();
c->set_blocking();
object con = Connection(0, max_call_threads);
object ctx = Context(gethostname()+"-"+portno);
if (!c)
error("Failed to accept connection: %s\n", strerror (f->errno()));
con->start_server(c, ctx);
ctx->set_server_context(sctx, con);
connections += ({ con });
}
//! @decl void create(string host, int port, void|int max_call_threads)
//! Create a @[Remote.Server].
//!
//! @param host
//! @param port
//! Hostname and port for the @[Remote.Server].
//!
//! @param max_call_threads
//! Maximum number of concurrent threads.
void create(string host, int p, void|int _max_call_threads)
{
portno = p;
max_call_threads = _max_call_threads;
port = Stdio.Port();
port->set_id(port);
if(host)
{
if(!port->bind(p, got_connection, host))
error("Failed to bind port: %s\n", strerror (port->errno()));
}
else if(!port->bind(p, got_connection))
error("Failed to bind port: %s\n", strerror (port->errno()));
DEBUGMSG("listening to " + host + ":" + p + "\n");
if(!portno)
sscanf(port->query_address(), "%*s %d", portno);
sctx = Minicontext();
}
//! Provide a named @[thing] to the @[Remote.Client](s).
//!
//! @param name
//! Name to provide @[thing] under.
//!
//! @param thing
//! Thing to provide.
void provide(string name, mixed thing)
{
DEBUGMSG("providing "+name+"\n");
sctx->add(name, thing);
}
//! Shut down the @[Remote.Server] for new connections.
void close()
{
DEBUGMSG("closing listening port\n");
destruct (port);
}
//! Shut down the @[Remote.Server] and terminate all current clients.
void close_all()
{
DEBUGMSG("closing listening port and all connections\n");
destruct (port);
foreach (connections, object conn) conn->close();
}
//! Check if the @[Remote.Server] is closed.
int closed()
{
return !!port;
}
void destroy()
{
DEBUGMSG("destruct" + (port ? " - closing listening port\n" : "\n"));
catch (destruct (port));
}
|