client_base._pike
Go to the documentation of this file.
1 /* Copyright (C) 2000-2004 Thomas Bopp, Thorsten Hampel, Ludger Merkens
2  *
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.
7  *
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.
12  *
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
16  *
17  * $Id: client_base.pike,v 1.1 2008/03/31 13:39:57 exodusd Exp $
18  */
19 inherit "kernel/socket";
20 inherit "net/coal/binary";
21 #include <coal.h>
22 #include <macros.h>
23 #include <client.h>
24 class client_base : public socket,binary{
25 public:
26 
27 
28 
29 
30 
31 private mapping mObjects; // objects
32 private string sLastPacket; // last package while communicating
33 private int iOID; // the object id of the current object
34 private int iTID; // the current transaction id
35 private int iWaitTID;
36  mapping mVariables; // session variables
37  array aEvents;
38  int __connected;
39  int __downloadBytes;
40  int __last_response;
41  function downloadStore;
42 
43 private mixed miResult;
44 private int miCommand;
45 
46 int flag=1;
47  Thread.Mutex cmd_mutex = Thread.Mutex();
48  Thread.Mutex newmut = Thread.Mutex();
49  Thread.Condition cmd_cond = Thread.Condition();
50  Thread.Queue resultQueue = Thread.Queue();
51  Thread.MutexKey newmutkey;
52  Thread.Condition th = Thread.Condition();
53  object cmd_lock;
54 
55 string connected_server;
56 int connected_port;
57 
58 class SteamObj
59 {
60 public:
61  private int oID;
62  private string identifier = 0;
63  private int cl = 0;
64  private int(0..1) nowait;
65  private mapping(string:function) functions=([]);
66 
67  int get_object_id() {
68  return oID;
69  }
70 
71  object get_environment() {
72  return send_command(COAL_COMMAND, ({ "get_environment" }));
73  }
74 
75  int get_object_class() {
76  if ( cl == 0 ) {
77  int wid = iWaitTID;
78  int id = set_object(oID);
79  mixed res = send_command(COAL_COMMAND, ({ "get_object_class" }));
80  if ( intp(res) )
81  cl = res;
82  set_object(id);
83  iWaitTID = wid;
84  }
85  return cl;
86  }
87  int status() {
88  return 1; //PSTAT_SAVE_OK
89  }
90 
91  string get_identifier() {
92  if ( !stringp(identifier) ) {
93  int wid = iWaitTID;
94  int id = set_object(oID);
95  identifier = send_command(COAL_COMMAND, ({ "get_identifier" }));
96  set_object(id);
97  iWaitTID = wid;
98  }
99  return identifier;
100  }
101 
102  void create(int id) {
103  oID = id;
104  }
105 
106  int no_wait(void|int(0..1) _nowait)
107  {
108  if(!zero_type(_nowait) && nowait == !_nowait)
109  {
110  nowait=!!_nowait;
111  return !nowait;
112  }
113  else
114  return nowait;
115  }
116 
117  string function_name(function fun)
118  {
119  return search(functions, fun);
120  }
121 
122  array _indices()
123  {
124  mixed result = catch {
125  if(this_object()->__indices)
126  return this_object()->__indices();
127  };
128  if(result!=0)
129  return ::_indices();
130  }
131 
132  string _sprintf()
133  {
134  mixed describe="";
135  catch{ describe=`->("describe")(); };
136  string format = "";
137  if ( stringp(connected_server) ) format += "%s:";
138  else format += "%O:";
139  if ( intp(connected_port) ) format += "%d/";
140  else format += "%O/";
141  if ( stringp(describe) ) format += "%s";
142  else format += "%O";
143  return sprintf( format, connected_server, connected_port, describe );
144  }
145 
146  function `->(string fun)
147  {
148  if(::`->(fun))
149  return ::`->(fun);
150  else
151  {
152  if ( fun == "exec_code" )
153  return 0;
154  else if ( fun == "serialize_coal" )
155  return 0;
156  if(!functions->fun)
157  functions[fun]=lambda(mixed|void ... args)
158  {
159  return send_cmd(oID, fun, args, nowait);
160  };
161  return functions[fun];
162  }
163  }
164  function find_function(string fun) {
165  if(!functions->fun)
166  functions[fun]=lambda(mixed|void ... args)
167  {
168  return send_cmd(oID, fun, args, nowait);
169  };
170  return functions[fun];
171  }
172 };
173 
174 
175 /**
176  *
177  *
178  * @param
179  * @return
180  * @see
181  */
182 int set_object(int|object id)
183 {
184  int oldID = iOID;
185 
186  if ( objectp(id) )
187  iOID = id->get_object_id();
188  else
189  iOID = id;
190  return oldID;
191 }
192 
193 /**
194  *
195  *
196  * @param
197  * @return
198  * @see
199  */
200 protected:
201  object find_obj(int id)
202 {
203  if ( !mObjects[id] ) {
204  mObjects[id] = SteamObj(id);
205  //werror("Created:"+master()->describe_object(mObjects[id])+"\n");
206  }
207  return mObjects[id];
208 }
209 
210 public:
211 
212 object find_object(int id) { return find_obj(id); }
213 
214 
215 /**
216  *
217  *
218  * @param
219  * @return
220  * @see
221  */
222 int connect_server(string server, int port)
223 {
224  iTID = 1;
225  iOID = 0;
226 
227  sLastPacket = "";
228  __downloadBytes = 0;
229  mVariables = ([ ]);
230  mObjects = ([ ]);
231  aEvents = ({ });
232 
233  open_socket();
234  set_blocking();
235  if ( connect(server, port) ) {
236  MESSAGE("Connected to " + server + ":"+port +"\n");
237  connected_server=server;
238  connected_port=port;
239  __last_response = time(); // timestamp of last response
240  __connected = 1;
241  set_buffer(65536, "r");
242  set_buffer(65536, "w");
243  set_blocking();
244  thread_create(read_thread);
245  return 1;
246  }
247  return 0;
248 }
249 
250 void create()
251 {
252 }
253 
254 protected:
255  int write(string str)
256 {
257  __last_response = time();
258  return ::write(str);
259 }
260 
261 public:
262 
263 
264 /**
265  *
266  *
267  * @param
268  * @return
269  * @see
270  */
271 void read_callback(object id, string data)
272 {
273  __last_response = time();
274 
275  if ( functionp(downloadStore) ) {
276  mixed err = catch {
277  downloadStore(data);
278  };
279  __downloadBytes -= strlen(data);
280  if ( __downloadBytes <= 0 ) {
281  downloadStore(0);
282  downloadStore = 0; // download finished
283  }
284  return;
285  }
286  sLastPacket += data;
287  if ( __downloadBytes > 0 ) {
288  if ( __downloadBytes <= strlen(sLastPacket) )
289  resultQueue->write(sLastPacket);
290  return;
291  }
292 
293  mixed res = receive_binary(sLastPacket);
294  if ( arrayp(res) ) {
295  int tid = res[0][0];
296  int cmd = res[0][1];
297 
298  sLastPacket = res[2];
299  if ( tid == iWaitTID ) {
300  miResult = res[1];
301  miCommand = res[0][1];
302  resultQueue->write(miResult);
303  }
304  }
305 }
306 
307 string download(int bytes, void|function store)
308 {
309  // actually the last command should have been the upload response,
310  // so there shouldnt be anything on the line except events
311  // which should have been already processed
312  // everything else should be download data
313  string data;
314  __downloadBytes = bytes;
315 
316  if ( functionp(store) ) {
317  data = copy_value(sLastPacket[..bytes]);
318  __downloadBytes -= strlen(data);
319  if ( strlen(data) > 0 )
320  store(data);
321  if ( __downloadBytes <= 0 ) {
322  store(0);
323  return "";
324  }
325  downloadStore = store;
326  return "";
327  }
328  downloadStore = 0;
329 
330  if ( strlen(sLastPacket) >= bytes ) {
331  data = copy_value(sLastPacket[..bytes]);
332  if ( bytes > strlen(sLastPacket) )
333  sLastPacket = sLastPacket[bytes+1..];
334  else
335  sLastPacket = "";
336  __downloadBytes = 0;
337  return data;
338  }
339 
340  miResult = resultQueue->read();
341  data = copy_value(sLastPacket[..bytes]);
342  if ( strlen(sLastPacket) > bytes )
343  sLastPacket = sLastPacket[bytes+1..];
344  else
345  sLastPacket = "";
346  __downloadBytes = 0;
347  return data;
348 }
349 
350 /**
351  *
352  *
353  * @param
354  * @return
355  * @see
356  */
357 void handle_error(mixed err)
358 {
359  throw(err);
360 }
361 
362 /**
363  *
364  *
365  * @param
366  * @return
367  * @see
368  */
369 mixed send_command(int cmd, array args, int|void no_wait)
370 {
371 // newmutkey = newmut->lock(1);
372  if ( !no_wait ) iWaitTID = iTID;
373  aEvents = ({ });
374 
375  string msg = coal_compose(iTID++, cmd, iOID, 0, args);
376  string nmsg = copy_value(msg);
377 
378  send_message(nmsg);
379  if ( no_wait ) return 0;
380 
381  mixed result=0;
382  Thread.Thread(check_thread);
383  result = resultQueue->read();
384  th->signal();
385 // newmutkey = 0;
386  if ( miCommand == COAL_ERROR ) {
387  handle_error(result);
388  }
389  return result;
390 }
391 
392 void check_thread()
393 {
394  int start_time = time();
395  th->wait(cmd_mutex->lock(), 10);
396  if((time()-start_time) >=10){
397  resultQueue->write("sTeam connection lost.");
398  flag=0;
399  }
400  else
401  flag=1;
402 }
403 /**
404  *
405  *
406  * @param
407  * @return
408  * @see
409  */
410 mixed send_cmd(object|int obj, string func, mixed|void args, void|int no_wait)
411 {
412  int oid = set_object(obj);
413  if ( zero_type(args) )
414  args = ({ });
415  else if ( !arrayp(args) )
416  args = ({ args });
417 
418  mixed res = send_command(COAL_COMMAND, ({ func, args }), no_wait);
419  set_object(oid);
420  return res;
421 }
422 
423 /**
424  *
425  *
426  * @param
427  * @return
428  * @see
429  */
430 mixed
431 login(string name, string pw, int features, string|void cname, int|void novars)
432 {
433  if ( !stringp(cname) )
434  cname = "steam-pike";
435 
436  mixed loginData;
437  if ( features != 0 )
438  loginData =send_command(COAL_LOGIN, ({ name, pw, cname, features, __id }));
439  else
440  loginData =
441  send_command(COAL_LOGIN,({ name, pw, cname,CLIENT_FEATURES_ALL, __id}));
442 
443  if ( arrayp(loginData) && sizeof(loginData) >= 9 ) {
444  mVariables["user"] = iOID;
445  foreach ( indices(loginData[8]), string key ) {
446  mVariables[key] = loginData[8][key];
447  }
448  mVariables["rootroom"] = loginData[6];
449  sLastPacket = "";
450  if ( novars != 1 ) {
451  foreach ( values(loginData[9]), object cl ) {
452  set_object(cl->get_object_id());
453  mVariables[send_cmd(cl,"get_identifier")] = cl;
454  }
455  }
456  return name;
457  }
458  return 0;
459 }
460 
461 mixed logout()
462 {
463  werror("logout()!!!\n\n");
464  __connected = 0;
465  write(coal_compose(0, COAL_LOGOUT, 0, 0, 0));
466 }
467 
468 
469 void was_closed()
470 {
471  resultQueue->write("");
472  ::was_closed();
473 }
474 
475 
476 void write_error2file(mixed|string err, int recursive) {
477 
478  Stdio.File error_file;
479  string path;
480  array directory;
481  int file_counter =0;
482  int found=0;
483  path = getcwd();
484  directory = get_dir(path);
485  while (found==0){
486  int tmp_found=1;
487  tmp_found=Stdio.exist(path+"/install_error."+file_counter);
488  if (tmp_found==1){
489  file_counter = file_counter + 1;
490  }
491  else{
492  found = 1;
493  }
494  }
495 
496  if (recursive==1)
497  file_counter = file_counter -1;
498  error_file=Stdio.File (path+"/install_error."+file_counter ,"cwa");
499  if (stringp (err)){
500  error_file->write(err);
501  }
502  if(arrayp(err)){
503  foreach(err, mixed error){
504  if ( stringp(error) || intp(error) )
505  error_file->write((string)error);
506  else if ( objectp(error) )
507  error_file->write("<object...>\n");
508  else if ( arrayp(error) ){
509  write_error2file(error,1);
510  }
511  }
512  }
513  if (recursive!=0)
514  error_file->close();
515 }
516 
517 
518 
519 
520 
521 };