a580e12000-09-27Fredrik Hübinette (Hubbe) #pike __REAL_VERSION__
a20af62000-09-26Fredrik Hübinette (Hubbe) 
19643a1999-06-13Mirar (Pontus Hagland) import .Helper; /* debug */ // function f=lambda() // { // call_out(f,0.5);
3524712015-05-26Martin Nilsson // if (!con)
19643a1999-06-13Mirar (Pontus Hagland) // return; // if (con->query_read_callback()!=recv) // werror("no read callback\n"); // werror("asyncs: %4d queue: %4d out: %4d\n", // sizeof(indices(async)), // sizeof(sendqueue), // out_req); // }; // mixed g=f(); //---------------- raw protocol -------------------------- /* connection object */ object con;
8970062003-03-12Marcus Agehall /* receive buffer */
19643a1999-06-13Mirar (Pontus Hagland) string buf=""; /* outstanding calls */
4b7f6b2014-08-15Martin Nilsson // private
19643a1999-06-13Mirar (Pontus Hagland) mapping(int:function(string:void)) async=([]); int ref=1; /* asynchronous messages callback list */
87bc7d1999-07-19Mirar (Pontus Hagland) mapping(int:array(function(string:void))) async_callbacks=([]);
19643a1999-06-13Mirar (Pontus Hagland)  /* max number of outstanding requests */ int max_out_req=4; /* queue of send-objects */ array(object) sendqueue=({}); /* outstanding requests */ int out_req; /*--- send/recv ------------------------ */
9eaf1d2008-06-28Martin Nilsson protected inline int conwrite(string what)
19643a1999-06-13Mirar (Pontus Hagland) { #ifdef LYSKOM_DEBUG werror("-> %O\n",what); #endif
7cdea42014-12-04Per Cederqvist  if (!con) return 0;
ead9722003-01-20Martin Nilsson  int i=con->write(what)==sizeof(what);
19643a1999-06-13Mirar (Pontus Hagland)  if (!i) { werror("write failed!!!\n"); _exit(1); } return i; } class Send { int ref; string request; function(string:void) callback;
3524712015-05-26Martin Nilsson 
19643a1999-06-13Mirar (Pontus Hagland)  void create(int rf,string r,function(string:void) c) { ref=rf; request=r; callback=c; }
ec1a0f2014-08-16Martin Nilsson  protected int cast(string type) { if( type=="int" ) return ref; return UNDEFINED; }
19643a1999-06-13Mirar (Pontus Hagland)  void write() { out_req++; async[ref]=callback;
dbb0a11999-10-18Johan Schön  conwrite(ref+" "+request+"\r\n"); #ifdef LYSKOM_DEBUG
1b41082002-01-16Martin Nilsson // werror("LYSKOM inserting callback %O for call %d\n",callback,ref);
dbb0a11999-10-18Johan Schön // werror("async: %O\n",async); #endif
19643a1999-06-13Mirar (Pontus Hagland)  } }
e9451b1999-11-02Johan Schön 
19643a1999-06-13Mirar (Pontus Hagland) int send(string request, function(string:void) callback) { int r=++ref; sendqueue+=({Send(r,request,callback)}); flush_queue(); return r; }
e9451b1999-11-02Johan Schön  /* FIXME: The code below isn't really threadsafe, but depends on context switching to be done when there's I/O... */
19643a1999-06-13Mirar (Pontus Hagland) void flush_queue() {
e9451b1999-11-02Johan Schön  while (sizeof(sendqueue) && out_req<max_out_req) { mixed tmp=sendqueue[0]; sendqueue=sendqueue[1..]; tmp->write(); }
19643a1999-06-13Mirar (Pontus Hagland) }
fed6fb1999-09-28Johan Schön #if !constant(thread_create) || LYSKOM_UNTHREADED
19643a1999-06-13Mirar (Pontus Hagland) mixed send_sync(string request) { return sync_do(++ref,request); } mixed sync_do(int ref,string|void request) { mixed err; string s; array res; con->set_blocking(); if (request) { if (!conwrite(ref+" "+request+"\r\n")) { connection_lost(); return lyskom_error(CONNECTION_CLOSED); } out_req++; } else { array(int) o=(array(int))sendqueue; int j=search(o,ref);
3524712015-05-26Martin Nilsson  if (j==-1)
19643a1999-06-13Mirar (Pontus Hagland)  { if (!async[ref]) error("request ref %d not in queue, but no callback\n",ref);
dbb0a11999-10-18Johan Schön #ifdef LYSKOM_DEBUG
1b41082002-01-16Martin Nilsson // werror("LYSKOM removing callback %O for call %d (handling ref %d in sync mode)\n",
dbb0a11999-10-18Johan Schön // async[ref],ref); #endif
19643a1999-06-13Mirar (Pontus Hagland)  m_delete(async,ref); } else { sendqueue[j]->write(); sendqueue=sendqueue[..j-1]+sendqueue[j+1..]; } } for (;;) { s=con->read(0x7fffffff,1);
3524712015-05-26Martin Nilsson  if (s=="")
19643a1999-06-13Mirar (Pontus Hagland)  { con->set_nonblocking(recv,0,0); connection_lost(); return lyskom_error(CONNECTION_CLOSED); } err=catch { res=recv(0,s,ref); }; if (err) { con->set_nonblocking(recv,0,0); throw(err); } if (res) break; } con->set_nonblocking(recv,0,0); return res; }
c8c4f61999-06-14Mirar (Pontus Hagland) #endif
19643a1999-06-13Mirar (Pontus Hagland)  void|array|object recv(mixed x,string what,void|int syn) { #ifdef LYSKOM_DEBUG werror("<- %O\n",what); #endif // werror("<- (%d bytes) (%d asyncs left)\n",sizeof(what), // sizeof(indices(async))); array|object ires=0; buf+=what; // wait for newline before we do anything at all
7b69642003-08-07Martin Nilsson  while (has_value(buf,"\n"))
19643a1999-06-13Mirar (Pontus Hagland)  { mixed res; int len; // ok, try to figure out what we got switch (buf[0]) { case ':': [res,len]=try_parse(buf[1..]); if (res) { buf=buf[len+1..];
fed6fb1999-09-28Johan Schön #if ! constant(thread_create) || LYSKOM_UNTHREADED
19643a1999-06-13Mirar (Pontus Hagland)  if (ref) call_out(got_async_message,0,res); else
c8c4f61999-06-14Mirar (Pontus Hagland) #endif
19643a1999-06-13Mirar (Pontus Hagland)  got_async_message(res); break; } return; case '=': [res,len]=try_parse(buf[1..]); if (res) { buf=buf[len+1..]; if (syn && (int)res[0] == syn) { ires=res[1..]; // this is what we wait for out_req--; break; }
fed6fb1999-09-28Johan Schön #if ! constant(thread_create) || LYSKOM_UNTHREADED
19643a1999-06-13Mirar (Pontus Hagland)  if (ref) call_out(got_reply,0,(int)res[0],res[1..]); else
c8c4f61999-06-14Mirar (Pontus Hagland) #endif
19643a1999-06-13Mirar (Pontus Hagland)  got_reply((int)res[0],res[1..]); out_req--; flush_queue(); break; } return; case '%': sscanf(buf,"%s\n%s",res,buf); int ref,no,status; if (sscanf(res,"%%%d %d %d",ref,no,status)==3) { if (ref==syn) { ires=lyskom_error(no,status); out_req--; break; }
fed6fb1999-09-28Johan Schön #if ! constant(thread_create) || LYSKOM_UNTHREADED
19643a1999-06-13Mirar (Pontus Hagland)  if (ref) call_out(got_reply,0,ref,lyskom_error(no,status)); else
c8c4f61999-06-14Mirar (Pontus Hagland) #endif
19643a1999-06-13Mirar (Pontus Hagland)  got_reply(ref,lyskom_error(no,status)); out_req--; flush_queue(); } else {
8970062003-03-12Marcus Agehall  werror("LysKOM.Raw: generic error received: %O\n",res);
19643a1999-06-13Mirar (Pontus Hagland)  } break; default: werror("LysKOM.Raw: protocol error: %O\n",buf); connection_lost(); return; } } return ires; }
c8c4f61999-06-14Mirar (Pontus Hagland) void read_thread() { string s; while ((s=con->read(8192,1))) { if (s=="") { connection_lost(); return; } recv(0,s); }
7cdea42014-12-04Per Cederqvist  connection_lost();
c8c4f61999-06-14Mirar (Pontus Hagland) }
fed6fb1999-09-28Johan Schön #if constant(thread_create) && !LYSKOM_UNTHREADED
c8c4f61999-06-14Mirar (Pontus Hagland) Thread.Fifo call_fifo=Thread.Fifo(); void call_thread() { array a; while ( (a=call_fifo->read()) ) a[0](a[1]); } #endif
19643a1999-06-13Mirar (Pontus Hagland) void connection_lost() { werror("CONNECTION LOST\n"); catch { con->close(); }; con=0; // send error to all outstanding requests foreach (values(async),function f)
fed6fb1999-09-28Johan Schön #if constant(thread_create) && !LYSKOM_UNTHREADED
c8c4f61999-06-14Mirar (Pontus Hagland)  if (f) call_fifo->write( ({f,lyskom_error(CONNECTION_CLOSED)}) ); call_fifo->write(0); #else
19643a1999-06-13Mirar (Pontus Hagland)  if (f) f(lyskom_error(CONNECTION_CLOSED));
c8c4f61999-06-14Mirar (Pontus Hagland) #endif
19643a1999-06-13Mirar (Pontus Hagland) }
c8c4f61999-06-14Mirar (Pontus Hagland) 
19643a1999-06-13Mirar (Pontus Hagland) void create(string server,void|int port,void|string whoami) { if (!port) port=4894; con=Stdio.File();
81ca3b2002-01-17Martin Nilsson  if (!con->connect(server,port))
19643a1999-06-13Mirar (Pontus Hagland)  {
81ca3b2002-01-17Martin Nilsson  object err=LysKOMError(-1,strerror(con->errno())-"\n", "Failed to connect to server " +server+".\n"); throw(err); return;
19643a1999-06-13Mirar (Pontus Hagland)  } conwrite("A"+H(whoami|| #if constant(getpwuid) && constant(getuid) (getpwuid(getuid())||({"*unknown*"}))[0]+ #else "*unknown*" #endif "%" #if constant(uname) +uname()->nodename #else "*unknown*" #endif )); string reply=con->read(7); #ifdef LYSKOM_DEBUG werror("<- %O\n",reply); #endif if (reply!="LysKOM\n") { con->close(); con=0; return; }
fed6fb1999-09-28Johan Schön #if constant(thread_create) && !LYSKOM_UNTHREADED
c8c4f61999-06-14Mirar (Pontus Hagland)  thread_create(read_thread); thread_create(call_thread);
bbdb9d2000-03-08Johan Schön #ifdef LYSKOM_DEBUG
e9451b1999-11-02Johan Schön  werror("LysKOM running threaded\n");
3524712015-05-26Martin Nilsson #endif
c8c4f61999-06-14Mirar (Pontus Hagland) #else
19643a1999-06-13Mirar (Pontus Hagland)  con->set_nonblocking(recv,0,0);
bbdb9d2000-03-08Johan Schön #ifdef LYSKOM_DEBUG
e9451b1999-11-02Johan Schön  werror("LysKOM running unthreaded\n");
3524712015-05-26Martin Nilsson #endif
c8c4f61999-06-14Mirar (Pontus Hagland) #endif
19643a1999-06-13Mirar (Pontus Hagland)  return; } array(array(mixed)|int) try_parse(string what) { array res=({}); int len=0;
3524712015-05-26Martin Nilsson 
19643a1999-06-13Mirar (Pontus Hagland)  array stack=({});
ead9722003-01-20Martin Nilsson  while (sizeof(what)>1)
19643a1999-06-13Mirar (Pontus Hagland)  { string a,b; switch(what[0]) { case '0'..'9': // int, bitfield or hollerith if (sscanf(what,"%[0-9]%s",a,b)<2 ||
3524712015-05-26Martin Nilsson  b=="")
19643a1999-06-13Mirar (Pontus Hagland)  return ({0,0}); // incomplete if (b[0]=='H') // hollerith {
ead9722003-01-20Martin Nilsson  if (sizeof(b)<=(int)a)
19643a1999-06-13Mirar (Pontus Hagland)  return ({0,0}); // incomplete res+=({b[1..(int)a]});
ead9722003-01-20Martin Nilsson  len+=sizeof(a)+sizeof(res[-1])+2;
19643a1999-06-13Mirar (Pontus Hagland)  b=b[(int)a+1..]; } else // bitfield or int { res+=({a});
ead9722003-01-20Martin Nilsson  len+=sizeof(a)+1;
19643a1999-06-13Mirar (Pontus Hagland)  } if (b=="") return ({0,0}); // incomplete switch (b[0]) { case ' ': // cont break; case '\n': // done // werror("ret: len=%d %O\n",len,res); return ({res,len}); default: werror("reached unknown: %O\n",b); exit(-1); } what=b[1..]; break; case '{': // array start; if (what[..1]=="{ ") { stack=({res})+stack; res=({}); len+=2; what=what[2..]; break; } if (what[..1]!="{") { werror("reached unknown: %O\n",what); exit(-1); } return ({0,0}); case '*': // empty array res+=({({})}); len+=2; switch (what[1]) { case ' ': // cont break; case '\n': // done return ({res,len}); default: werror("reached unknown: %O\n",b); exit(-1); } what=what[2..]; break; case '}': // array end; if (stack==({})) {
19fe732007-06-02Henrik Grubbström (Grubba)  werror("protocol error: stack underflow: %O\n",what);
19643a1999-06-13Mirar (Pontus Hagland)  connection_lost(); return ({0,0}); } res=stack[0]+({res}); stack=stack[1..];
3524712015-05-26Martin Nilsson 
19643a1999-06-13Mirar (Pontus Hagland)  len+=2; switch (what[1]) { case ' ': // cont break; case '\n': // done return ({res,len}); default: werror("reached unknown: %O\n",b); exit(-1); } what=what[2..]; break; default: werror("reached unknown: %O\n",what); exit(-1); } }
3524712015-05-26Martin Nilsson 
19643a1999-06-13Mirar (Pontus Hagland)  return ({0,0}); // incomplete } void got_reply(int ref,object|array what) {
dbb0a11999-10-18Johan Schön // werror("got_reply(): async: %O\n",async);
65340d2014-08-15Martin Nilsson  function call = m_delete(async,ref);
dbb0a11999-10-18Johan Schön #ifdef LYSKOM_DEBUG
1b41082002-01-16Martin Nilsson // werror("LYSKOM removing callback %O for call %d\n",call,ref);
dbb0a11999-10-18Johan Schön #endif
65340d2014-08-15Martin Nilsson 
19643a1999-06-13Mirar (Pontus Hagland)  if (!call) {
dbb0a11999-10-18Johan Schön  werror("LysKOM.Raw: lost callback for call %d %s\n",ref,
65340d2014-08-15Martin Nilsson  undefinedp(call)?"(lost from mapping??!)":"(zero value in mapping)");
19643a1999-06-13Mirar (Pontus Hagland)  werror(master()->describe_backtrace(backtrace())); return; }
fed6fb1999-09-28Johan Schön #if constant(thread_create) && !LYSKOM_UNTHREADED
c8c4f61999-06-14Mirar (Pontus Hagland)  call_fifo->write( ({call,what}) ); #else
19643a1999-06-13Mirar (Pontus Hagland)  call_out(call,0,what);
c8c4f61999-06-14Mirar (Pontus Hagland) #endif
19643a1999-06-13Mirar (Pontus Hagland) } void delete_async(int ref) { m_delete(async,ref); }
87bc7d1999-07-19Mirar (Pontus Hagland)  void add_async_callback(string which, function what, int dont_update) { int no=.ASync.name2no[which];
3524712015-05-26Martin Nilsson 
65340d2014-08-15Martin Nilsson  if (!no && !has_index(.ASync.name2no, which))
87bc7d1999-07-19Mirar (Pontus Hagland)  throw(LysKOMError( -1,"LysKOM: unsupported async", sprintf("There is no supported async call named %O", which) )); if (!async_callbacks[no]) async_callbacks[no]=({what}); else async_callbacks[no]+=({what}); } void remove_async_callback(string which, function what, void|int dont_update) { int no=.ASync.name2no[which];
3524712015-05-26Martin Nilsson 
65340d2014-08-15Martin Nilsson  if (!no && !has_index(.ASync.name2no, which))
87bc7d1999-07-19Mirar (Pontus Hagland)  throw(LysKOMError( -1,"LysKOM: unsupported async", sprintf("There is no supported async call named %O", which) )); async_callbacks[no]-=({what}); } array active_asyncs() { foreach (indices(async_callbacks),int z) if (async_callbacks[z]==({})) m_delete(async_callbacks,z); return indices(async_callbacks); } void got_async_message(array what) {
e9451b1999-11-02Johan Schön #ifdef LYSKOM_DEBUG
5819612001-10-09Johan Sundström  werror("got_async_message: :%s %s %O\n", what[0], mkmapping( values(.ASync.name2no), indices(.ASync.name2no))[(int)what[1]], @what[2..]); //werror("got_async_message: %O\n", what); #endif
4eda311999-10-17Johan Schön  catch {
87bc7d1999-07-19Mirar (Pontus Hagland)  if (async_callbacks[(int)what[1]]) async_callbacks[(int)what[1]](@.ASync["decode_"+what[1]](what[2..]));
4eda311999-10-17Johan Schön  };
87bc7d1999-07-19Mirar (Pontus Hagland) }