1 /* Copyright (C) 2000-2004 Thomas Bopp, Thorsten Hampel, Ludger Merkens
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 * $Id: client_base.pike,v 1.2 2009/08/07 15:22:37 nicke Exp $
20 inherit "/net/coal/binary";
23 #include <exception.h>
26 class client_base : public binary,serialize{
33 #define CLIENT_FEATURES ((1<<31)-1)
35 private string sLastPacket; // last package while communicating
36 private int iOID; // the object id of the current object
37 private int iTID; // the current transaction id
39 mapping mVariables; // session variables
41 private mapping mVariableReq; // requests for setting variables
42 private mapping mVariableReqInv; // inverse requests
43 private mapping mObjects; // objects
44 private mixed miResult;
45 private string sLoginName;
51 string decryptBuffer = "";
53 #define ERR_CONTINUE 0
57 // mutex stuff for threads
58 private Thread.Mutex command_mutex = Thread.Mutex();
59 private object read_lock, write_lock;
60 private Thread.Condition read_cond = Thread.Condition();
61 private Thread.Condition write_cond = Thread.Condition();
63 int set_object(object|int id);
64 mixed send_command(int cmd, array args, int|void do_wait);
71 private string identifier = 0;
77 int get_object_class() {
80 int id = set_object(oID);
81 mixed res = send_command(COAL_COMMAND, ({ "get_object_class" }));
89 string get_identifier() {
90 if ( !stringp(identifier) ) {
92 int id = set_object(oID);
93 identifier = send_command(COAL_COMMAND, ({ "get_identifier" }));
113 object find_obj(int id)
115 if ( !mObjects[id] ) {
116 mObjects[id] = SteamObj(id);
131 string translate_exception(int exc)
138 if ( exc & E_MEMORY )
139 ex += "memory fault,";
142 if ( exc & E_ACCESS )
143 ex += "access failure,";
144 if ( exc & E_PASSWORD )
145 ex += "wrong password,";
146 if ( exc & E_NOTEXIST )
147 ex += "non existing,";
148 if ( exc & E_FUNCTION )
150 if ( exc & E_FORMAT )
151 ex += "invalid format,";
152 if ( exc & E_OBJECT )
159 ex += "command will cause endless loop,";
161 ex += "object locked,";
192 get_variable(int|string key)
194 return mVariables[key];
206 set_variable(int|string key, mixed val)
208 mVariables[key] = val;
220 int connect_server(string server, int port)
225 mVariableReq = ([ ]);
226 mVariableReqInv = ([ ]);
230 sLoginName = "not logged in";
234 if ( connect(server, port) ) {
235 LOG("Connected to " + server + ":"+port +"\n");
237 set_buffer(65536, "r");
238 set_buffer(65536, "w");
240 thread_create(read_thread);
253 int receive_message(int id, string str)
255 int slen, tid, cmd, lid, len, n;
263 for ( n = 0; n < slen-10; n++ )
264 if ( str[n] == COMMAND_BEGIN_MASK )
270 len = (int)((str[1]<<24)+(str[2]<<16)+(str[3]<<8) + str[4]);
275 tid = (int)((str[5] << 24) + (str[6]<<16) + (str[7]<<8) + str[8]);
277 lid = (int)((str[10] << 24) + (str[11]<<16) + (str[12]<<8) + str[13]);
280 args = receive_args(18);
289 if ( cmd == COAL_ERROR ) {
291 int errRes = handle_error(miResult);
303 else if ( cmd == COAL_EVENT ) {
304 miResult += ({ lid });
305 handle_event(miResult);
308 //LOG(sprintf("%d:%O\n", tid,miResult));
311 if ( mVariableReq[tid] != 0 ) {
312 LOG("Setting variable "+ mVariableReq[tid] + "\n");
313 mVariables[mVariableReq[tid]] = args[0]; // ?
314 mVariableReq[tid] = 0;
316 if ( mVariableReqInv[tid] != 0 ) {
317 LOG("Setting variable "+ args[0] + ":"+
318 sprintf("%O", mVariableReqInv[tid])+"\n");
319 mVariables[args[0]] = mVariableReqInv[tid];
320 mVariableReqInv[tid] = 0;
323 sLastPacket = str[len..];
336 int handle_error(mixed err)
348 int handle_event(mixed event)
350 aEvents += ({ event });
366 read_lock = command_mutex->lock();
367 read_cond->wait(read_lock);
372 while ( rcv != iWaitTID && __connected ) {
373 resp = ::read(8192,1);
374 if ( !stringp(resp) ) {
379 if ( objectp(decryptRSA) ) {
380 resp = decryptBuffer + resp;
383 int l = strlen(resp);
384 string decryptBlock = "";
385 while ( i+64 <= l ) {
386 decryptBlock += decryptRSA->decrypt(resp[i..i+63]);
390 decryptBuffer = resp[(l-(l%64))..];
395 while ( rcv >= 0 && err == 0 && rcv != iWaitTID ) {
396 rcv = receive_message(0, sLastPacket);
399 write_cond->signal();
400 read_cond->wait(read_lock);
411 mixed send_command(int cmd, array args, int|void no_wait)
413 if ( !no_wait ) iWaitTID = iTID;
416 string msg = coal_compose(iTID++, cmd, iOID, 0, args);
417 string nmsg = copy_value(msg);
419 if ( objectp(encryptRSA) ) {
425 nmsg += encryptRSA->encrypt(msg[i..]);
427 nmsg += encryptRSA->encrypt(msg[i..i+31]);
435 write_cond->wait(write_lock);
437 throw(({"sTeam Server error:\n"+
438 translate_exception(miResult[0])+"\n"+
439 serialize(miResult)+"\n", backtrace() }));
453 mixed send_cmd(object|int obj, string func, mixed|void args, void|int no_wait)
455 int oid = set_object(obj);
456 if ( zero_type(args) )
458 else if ( !arrayp(args) )
461 mixed res = send_command(COAL_COMMAND, ({ func, args }), no_wait);
473 mixed login(string name, string pw, int features, string|void cname)
475 if ( objectp(write_lock) )
476 destruct(write_lock);
477 write_lock = command_mutex->lock();
479 if ( !stringp(cname) )
480 cname = "steam-pike";
484 loginData = send_command(COAL_LOGIN,({name, pw, cname, features }));
486 loginData = send_command(COAL_LOGIN,({name, pw, cname,CLIENT_FEATURES}));
487 if ( arrayp(loginData) && sizeof(loginData) >= 9 ) {
488 mVariables["user"] = iOID;
489 sLoginName = loginData[0];
490 foreach ( indices(loginData[8]), string key ) {
491 mVariables[key] = loginData[8][key];
493 mVariables["rootroom"] = loginData[6];
495 foreach ( values(loginData[9]), object cl ) {
496 set_object(cl->get_object_id());
497 mVariables[send_command(COAL_COMMAND, ({"get_identifier",({ })}))]
505 mixed server_hello(string cert)
507 return send_command(COAL_SERVERHELLO, ({ cert }));
513 if ( objectp(write_lock) )
514 destruct(write_lock);
515 write_lock = command_mutex->lock();
517 write(coal_compose(iTID++, COAL_LOGOUT,0, 0, ({ })));
528 int set_object(int|object id)
532 iOID = id->get_object_id();
576 void create(object|void id)