Pol  Revision:cb584c9
osmod.cpp
Go to the documentation of this file.
1 
6 #include "osmod.h"
7 
8 #include "../../bscript/berror.h"
9 #include "../../bscript/bobject.h"
10 #include "../../bscript/bstruct.h"
11 #include "../../bscript/impstr.h"
12 #include "../../clib/logfacility.h"
13 #include "../../clib/rawtypes.h"
14 #include "../../clib/refptr.h"
15 #include "../../clib/sckutil.h"
16 #include "../../clib/threadhelp.h"
17 #include "../../clib/weakptr.h"
18 #include "../../plib/systemstate.h"
19 #include "../exscrobj.h"
20 #include "../globals/script_internals.h"
21 #include "../globals/state.h"
22 #include "../item/item.h"
23 #include "../mobile/attribute.h"
24 #include "../mobile/charactr.h"
25 #include "../mobile/npc.h"
26 #include "../network/auxclient.h"
27 #include "../network/packethelper.h"
28 #include "../network/packets.h"
29 #include "../pktdef.h"
30 #include "../polcfg.h"
31 #include "../poldbg.h"
32 #include "../polsem.h"
33 #include "../profile.h"
34 #include "../schedule.h"
35 #include "../scrdef.h"
36 #include "../scrsched.h"
37 #include "../scrstore.h"
38 #include "../skills.h"
39 #include "../ufunc.h"
40 #include "../uoexec.h"
41 #include "npcmod.h"
42 #include "uomod.h"
43 
44 
45 #pragma comment( lib, "crypt32.lib" )
46 #include <ctime>
47 #include <curl/curl.h>
48 #include <memory>
49 #include <string.h>
50 #include <string>
51 #include <unordered_map>
52 
53 namespace Pol
54 {
55 namespace Bscript
56 {
57 using namespace Module;
58 template <>
61  {"create_debug_context", &OSExecutorModule::create_debug_context},
62  {"getprocess", &OSExecutorModule::getprocess},
63  {"get_process", &OSExecutorModule::getprocess},
64  {"getpid", &OSExecutorModule::getpid},
65  {"sleep", &OSExecutorModule::sleep},
66  {"sleepms", &OSExecutorModule::sleepms},
67  {"wait_for_event", &OSExecutorModule::wait_for_event},
68  {"events_waiting", &OSExecutorModule::events_waiting},
69  {"start_script", &OSExecutorModule::start_script},
70  {"start_skill_script", &OSExecutorModule::start_skill_script},
71  {"set_critical", &OSExecutorModule::set_critical},
72  {"is_critical", &OSExecutorModule::is_critical},
73  {"run_script_to_completion", &OSExecutorModule::run_script_to_completion},
74  {"run_script", &OSExecutorModule::run_script},
75  {"set_debug", &OSExecutorModule::mf_set_debug},
76  {"syslog", &OSExecutorModule::mf_Log},
77  {"system_rpm", &OSExecutorModule::mf_system_rpm},
78  {"set_priority", &OSExecutorModule::mf_set_priority},
79  {"unload_scripts", &OSExecutorModule::mf_unload_scripts},
80  {"set_script_option", &OSExecutorModule::mf_set_script_option},
81  {"clear_event_queue", &OSExecutorModule::mf_clear_event_queue},
82  {"set_event_queue_size", &OSExecutorModule::mf_set_event_queue_size},
83  {"OpenURL", &OSExecutorModule::mf_OpenURL},
84  {"OpenConnection", &OSExecutorModule::mf_OpenConnection},
85  {"Debugger", &OSExecutorModule::mf_debugger},
86  {"PerformanceMeasure", &OSExecutorModule::mf_performance_diff},
87  {"HTTPRequest", &OSExecutorModule::mf_HTTPRequest}};
88 } // namespace Bscript
89 namespace Module
90 {
91 using namespace Bscript;
92 
93 unsigned int getnewpid( Core::UOExecutor* uoexec )
94 {
95  return Core::scriptScheduler.get_new_pid( uoexec );
96 }
97 void freepid( unsigned int pid )
98 {
100 }
101 
103  : TmplExecutorModule<OSExecutorModule>( "OS", exec ),
104  critical( false ),
105  priority( 1 ),
106  warn_on_runaway( true ),
107  blocked_( false ),
108  sleep_until_clock_( 0 ),
109  in_hold_list_( NO_LIST ),
110  hold_itr_(),
111  pid_( getnewpid( static_cast<Core::UOExecutor*>( &exec ) ) ),
112  wait_type( WAIT_UNKNOWN ),
113  max_eventqueue_size( MAX_EVENTQUEUE_SIZE ),
114  events_()
115 {
116 }
117 
119 {
120  freepid( pid_ );
121  pid_ = 0;
122  while ( !events_.empty() )
123  {
124  Bscript::BObject ob( events_.front() );
125  events_.pop();
126  }
127 }
128 
129 unsigned int OSExecutorModule::pid() const
130 {
131  return pid_;
132 }
133 
135 {
137 }
138 
140 {
141  Core::UOExecutor* uoexec;
142  if ( find_uoexec( pid_, &uoexec ) )
143  {
144  uoexec->attach_debugger();
145  return new BLong( 1 );
146  }
147  else
148  return new BError( "Could not find UOExecutor for current process." );
149 }
150 
152 {
153  unsigned int pid;
154  if ( !getParam( 0, pid ) )
155  {
156  pid = pid_;
157  }
158  Core::UOExecutor* uoexec;
159  if ( find_uoexec( pid, &uoexec ) )
160  return new Core::ScriptExObjImp( uoexec );
161  else
162  return new BError( "Process not found" );
163 }
164 
166 {
167  return new BLong( pid_ );
168 }
169 /* Ok, this is going to be fun. In the case where we block,
170 the caller is going to take our return value and push
171 it on the value stack.
172 
173 What we'll do is push the value that should be returned
174 if a timeout occurs. THis way, for timeouts, all we have
175 to do is move the script back into the run queue.
176 
177 When we actually complete something, we'll have to
178 pop the value off the stack, and replace it with
179 the real result.
180 
181 Whew!
182 */
184 {
185  int nsecs;
186 
187  nsecs = (int)exec.paramAsLong( 0 );
188 
189  SleepFor( nsecs );
190 
191  return new BLong( 0 );
192 }
193 
195 {
196  int msecs;
197 
198  msecs = (int)exec.paramAsLong( 0 );
199 
200  SleepForMs( msecs );
201 
202  return new BLong( 0 );
203 }
204 
206 {
207  if ( !events_.empty() )
208  {
209  BObjectImp* imp = events_.front();
210  events_.pop();
211  return imp;
212  }
213  else
214  {
215  int nsecs = (int)exec.paramAsLong( 0 );
216 
217  if ( nsecs )
218  {
220  blocked_ = true;
222  }
223  return new BLong( 0 );
224  }
225 }
226 
228 {
229  return new BLong( static_cast<int>( events_.size() ) );
230 }
231 
233 {
234  const String* scriptname_str;
235  if ( exec.getStringParam( 0, scriptname_str ) )
236  {
237  BObjectImp* imp = exec.getParamImp( 1 );
238 
239  // FIXME needs to inherit available modules?
240  Core::ScriptDef sd;
241  if ( !sd.config_nodie( scriptname_str->value(), exec.prog()->pkg, "scripts/" ) )
242  {
243  return new BError( "Error in script name" );
244  }
245  if ( !sd.exists() )
246  {
247  return new BError( "Script " + sd.name() + " does not exist." );
248  }
249  UOExecutorModule* new_uoemod = Core::start_script( sd, imp->copy() );
250  if ( new_uoemod == nullptr )
251  {
252  return new BError( "Unable to start script" );
253  }
254  UOExecutorModule* this_uoemod = static_cast<UOExecutorModule*>( exec.findModule( "uo" ) );
255  if ( new_uoemod != nullptr && this_uoemod != nullptr )
256  {
257  new_uoemod->controller_ = this_uoemod->controller_;
258  }
259  Core::UOExecutor* uoexec = static_cast<Core::UOExecutor*>( &new_uoemod->exec );
260  return new Core::ScriptExObjImp( uoexec );
261  }
262  else
263  {
264  return new BError( "Invalid parameter type" );
265  }
266 }
267 
268 
270 {
271  Mobile::Character* chr;
272  const Mobile::Attribute* attr;
273 
274  if ( getCharacterParam( 0, chr ) && Core::getAttributeParam( exec, 1, attr ) )
275  {
276  if ( !attr->disable_core_checks && !Core::CanUseSkill( chr->client ) )
277  return new BLong( 0 );
278  else
279  {
280  const String* script_name;
281  Core::ScriptDef script;
282 
283  if ( exec.getStringParam( 2, script_name ) )
284  {
285  if ( !script.config_nodie( script_name->value(), exec.prog()->pkg, "scripts/skills/" ) )
286  {
287  return new BError( "Error in script name" );
288  }
289  if ( !script.exists() )
290  {
291  return new BError( "Script " + script.name() + " does not exist." );
292  }
293  }
294  else
295  {
296  if ( !attr->script_.empty() )
297  script = attr->script_;
298  else
299  return new BError( "No script defined for attribute " + attr->name + "." );
300  }
301 
303  script, true,
304  /* complain if not found */ Plib::systemstate.config.cache_interactive_scripts );
305 
306  if ( prog.get() != nullptr )
307  {
308  BObjectImp* imp = exec.getParamImp( 3 );
309  if ( imp )
310  {
311  if ( chr->start_script( prog.get(), true, imp->copy() ) )
312  {
313  if ( chr->hidden() && attr->unhides )
314  chr->unhide();
315  if ( attr->delay_seconds )
316  chr->disable_skills_until( Core::poltime() + attr->delay_seconds );
317  }
318  }
319  else
320  {
321  if ( chr->start_script( prog.get(), true ) )
322  {
323  if ( chr->hidden() && attr->unhides )
324  chr->unhide();
325  if ( attr->delay_seconds )
326  chr->disable_skills_until( Core::poltime() + attr->delay_seconds );
327  }
328  }
329  }
330  else
331  {
332  std::string msg = "Unable to start skill script:";
333  msg += script.c_str();
334  Core::send_sysmessage( chr->client, msg.c_str() );
335 
336  return new BLong( 0 );
337  }
338  return new BLong( 1 );
339  }
340  }
341  else
342  {
343  return new BError( "Invalid parameter type" );
344  }
345 }
346 
348 {
349  int crit;
350  if ( exec.getParam( 0, crit ) )
351  {
352  critical = ( crit != 0 );
353  return new BLong( 1 );
354  }
355  else
356  {
357  return new BError( "Invalid parameter type" );
358  }
359 }
360 
362 {
363  if ( critical )
364  return new BLong( 1 );
365  else
366  return new BLong( 0 );
367 }
368 
370 {
371  const char* scriptname = exec.paramAsString( 0 );
372  if ( scriptname == nullptr )
373  return new BLong( 0 );
374 
375  // FIXME needs to inherit available modules?
376  Core::ScriptDef script;
377 
378  if ( !script.config_nodie( scriptname, exec.prog()->pkg, "scripts/" ) )
379  return new BError( "Script descriptor error" );
380 
381  if ( !script.exists() )
382  return new BError( "Script does not exist" );
383 
384  return Core::run_script_to_completion( script, getParamImp( 1 ) );
385 }
386 
388 {
389  UOExecutorModule* this_uoemod = static_cast<UOExecutorModule*>( exec.findModule( "uo" ) );
390  Core::UOExecutor* this_uoexec = static_cast<Core::UOExecutor*>( &this_uoemod->exec );
391 
392  if ( this_uoexec->pChild == nullptr )
393  {
394  const String* scriptname_str;
395  if ( exec.getStringParam( 0, scriptname_str ) )
396  {
397  BObjectImp* imp = exec.getParamImp( 1 );
398 
399  // FIXME needs to inherit available modules?
400  Core::ScriptDef sd;
401  if ( !sd.config_nodie( scriptname_str->value(), exec.prog()->pkg, "scripts/" ) )
402  {
403  return new BError( "Error in script name" );
404  }
405  if ( !sd.exists() )
406  {
407  return new BError( "Script " + sd.name() + " does not exist." );
408  }
409  UOExecutorModule* new_uoemod = Core::start_script( sd, imp->copy() );
410  if ( new_uoemod == nullptr )
411  {
412  return new BError( "Unable to run script" );
413  }
414  if ( new_uoemod )
415  {
416  new_uoemod->controller_ = this_uoemod->controller_;
417  }
418  Core::UOExecutor* new_uoexec = static_cast<Core::UOExecutor*>( &new_uoemod->exec );
419  // OSExecutorModule* osemod = uoexec->os_module;
420  new_uoexec->pParent = this_uoexec;
421  this_uoexec->pChild = new_uoexec;
422 
423  // we want to forcefully do this instruction over again:
424  this_uoexec->PC--; // run_script(
425  this_uoexec->ValueStack.push_back(
426  BObjectRef( new BObject( UninitObject::create() ) ) ); // script_name,
427  // No need to push on "param" since the new BLong(0) below will take care of it.// param )
428 
429  // Put me on hold until my child is done.
430  suspend();
431 
432  return new BLong( 0 );
433  }
434  else
435  {
436  return new BError( "Invalid parameter type" );
437  }
438  }
439 
440  // else I am running a child script, and its ended
441  BObjectImp* ret;
442 
443  if ( this_uoexec->pChild->ValueStack.empty() )
444  ret = new BLong( 1 );
445  else
446  ret = this_uoexec->pChild->ValueStack.back().get()->impptr()->copy();
447 
448  this_uoexec->pChild->pParent = nullptr;
449  this_uoexec->pChild = nullptr;
450 
451  return ret;
452 }
453 
455 {
456  int dbg;
457  if ( getParam( 0, dbg ) )
458  {
459  if ( dbg )
461  return new BLong( 1 );
462  }
463  else
464  {
465  return new BError( "Invalid parameter type" );
466  }
467 }
468 
470 {
471  BObjectImp* imp = exec.getParamImp( 0 );
472  if ( imp->isa( BObjectImp::OTString ) )
473  {
474  String* str = static_cast<String*>( imp );
475  POLLOG << "[" << exec.scriptname() << "]: " << str->data() << "\n";
476  INFO_PRINT << "syslog [" << exec.scriptname() << "]: " << str->data() << "\n";
477  return new BLong( 1 );
478  }
479  else
480  {
481  std::string strval = imp->getStringRep();
482  POLLOG << "[" << exec.scriptname() << "]: " << strval << "\n";
483  INFO_PRINT << "syslog [" << exec.scriptname() << "]: " << strval << "\n";
484  return new BLong( 1 );
485  }
486 }
487 
489 {
490  return new BLong( static_cast<int>( Core::stateManager.profilevars.last_rpm ) );
491 }
492 
494 {
495  int newpri;
496  if ( getParam( 0, newpri, 1, 255 ) )
497  {
498  int oldpri = priority;
499  priority = static_cast<unsigned char>( newpri );
500  return new BLong( oldpri );
501  }
502  else
503  {
504  return new BError( "Invalid parameter type" );
505  }
506 }
507 
508 
510 {
511  const String* str;
512  if ( getStringParam( 0, str ) )
513  {
514  int n;
515  if ( str->length() == 0 )
517  else
518  n = Core::unload_script( str->data() );
519  return new BLong( n );
520  }
521  else
522  {
523  return new BError( "Invalid parameter type" );
524  }
525 }
526 
528 {
529  while ( !events_.empty() )
530  {
531  BObject ob( events_.front() );
532  events_.pop();
533  }
534  return new BLong( 1 );
535 }
536 
538 {
539  unsigned short param;
540  if ( getParam( 0, param ) )
541  {
542  unsigned short oldsize = max_eventqueue_size;
543  max_eventqueue_size = param;
544  return new BLong( oldsize );
545  }
546  else
547  return new BError( "Invalid parameter type" );
548 }
549 
551 {
552  Mobile::Character* chr;
553  const String* str;
554  if ( getCharacterParam( 0, chr ) && ( ( str = getStringParam( 1 ) ) != nullptr ) )
555  {
556  if ( chr->has_active_client() )
557  {
559  unsigned urllen;
560  const char* url = str->data();
561 
562  urllen = static_cast<unsigned int>( strlen( url ) );
563  if ( urllen > URL_MAX_LEN )
564  urllen = URL_MAX_LEN;
565 
566  msg->WriteFlipped<u16>( urllen + 4u );
567  msg->Write( url, static_cast<u16>( urllen + 1 ) );
568  msg.Send( chr->client );
569  return new BLong( 1 );
570  }
571  else
572  {
573  return new BError( "No client attached" );
574  }
575  }
576  else
577  {
578  return new BError( "Invalid parameter type" );
579  }
580 }
581 
582 
584 {
585  UOExecutorModule* this_uoemod = static_cast<UOExecutorModule*>( exec.findModule( "uo" ) );
586  Core::UOExecutor* this_uoexec = static_cast<Core::UOExecutor*>( &this_uoemod->exec );
587 
588  if ( this_uoexec->pChild == nullptr )
589  {
590  const String* host;
591  const String* scriptname_str;
592  BObjectImp* scriptparam;
593  unsigned short port;
594  int assume_string_int;
595  if ( getStringParam( 0, host ) && getParam( 1, port ) && getStringParam( 2, scriptname_str ) &&
596  getParamImp( 3, scriptparam ) && getParam( 4, assume_string_int ) )
597  {
598  // FIXME needs to inherit available modules?
599  Core::ScriptDef sd;
600  if ( !sd.config_nodie( scriptname_str->value(), exec.prog()->pkg, "scripts/" ) )
601  {
602  return new BError( "Error in script name" );
603  }
604  if ( !sd.exists() )
605  {
606  return new BError( "Script " + sd.name() + " does not exist." );
607  }
608  if ( !this_uoexec->suspend() )
609  {
610  DEBUGLOG << "Script Error in '" << this_uoexec->scriptname() << "' PC=" << this_uoexec->PC
611  << ": \n"
612  << "\tThe execution of this script can't be blocked!\n";
613  return new Bscript::BError( "Script can't be blocked" );
614  }
615 
617  std::string hostname( host->value() );
618  bool assume_string = assume_string_int != 0;
620  [uoexec_w, sd, hostname, port, scriptparam, assume_string]() {
621  Clib::Socket s;
622  bool success_open = s.open( hostname.c_str(), port );
623  {
624  Core::PolLock lck;
625  if ( !uoexec_w.exists() )
626  {
627  DEBUGLOG << "OpenConnection Script has been destroyed\n";
628  s.close();
629  return;
630  }
631  if ( !success_open )
632  {
633  uoexec_w.get_weakptr()->ValueStack.back().set(
634  new BObject( new BError( "Error connecting to client" ) ) );
635  }
636  else
637  {
638  uoexec_w.get_weakptr()->ValueStack.back().set( new BObject( new BLong( 1 ) ) );
639  }
640  uoexec_w.get_weakptr()->os_module->revive();
641  }
642  std::unique_ptr<Network::AuxClientThread> client(
643  new Network::AuxClientThread( sd, s, scriptparam->copy(), assume_string ) );
644  client->run();
645  } );
646 
647  return new BLong( 0 );
648  }
649  else
650  {
651  return new BError( "Invalid parameter type" );
652  }
653  }
654 
655  return new BError( "Invalid parameter type" );
656 }
657 
658 size_t curlWriteCallback( void* contents, size_t size, size_t nmemb, void* userp )
659 {
660  ( static_cast<std::string*>( userp ) )->append( static_cast<char*>( contents ), size * nmemb );
661  return size * nmemb;
662 }
663 
665 {
666  UOExecutorModule* this_uoemod = static_cast<UOExecutorModule*>( exec.findModule( "uo" ) );
667  Core::UOExecutor* this_uoexec = static_cast<Core::UOExecutor*>( &this_uoemod->exec );
668 
669  if ( this_uoexec->pChild == nullptr )
670  {
671  const String *url, *method;
672  BObjectImp* options;
673  if ( getStringParam( 0, url ) && getStringParam( 1, method ) && getParamImp( 2, options ) )
674  {
675  if ( !this_uoexec->suspend() )
676  {
677  DEBUGLOG << "Script Error in '" << this_uoexec->scriptname() << "' PC=" << this_uoexec->PC
678  << ": \n"
679  << "\tThe execution of this script can't be blocked!\n";
680  return new Bscript::BError( "Script can't be blocked" );
681  }
682 
684 
685  std::shared_ptr<CURL> curl_sp( curl_easy_init(), curl_easy_cleanup );
686  CURL* curl = curl_sp.get();
687  if ( curl )
688  {
689  curl_easy_setopt( curl, CURLOPT_URL, url->data() );
690  curl_easy_setopt( curl, CURLOPT_CUSTOMREQUEST, method->data() );
691  curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, curlWriteCallback );
692 
693  struct curl_slist* chunk = nullptr;
694  if ( options->isa( Bscript::BObjectImp::OTStruct ) )
695  {
696  Bscript::BStruct* opts = static_cast<Bscript::BStruct*>( options );
697  const BObjectImp* data = opts->FindMember( "data" );
698  if ( data != nullptr )
699  {
700  curl_easy_setopt( curl, CURLOPT_COPYPOSTFIELDS, data->getStringRep().c_str() );
701  }
702 
703  const BObjectImp* headers_ = opts->FindMember( "headers" );
704 
705  if ( headers_ != nullptr && headers_->isa( BObjectImp::OTStruct ) )
706  {
707  const BStruct* headers = static_cast<const BStruct*>( headers_ );
708 
709  for ( const auto& content : headers->contents() )
710  {
711  BObjectImp* ref = content.second->impptr();
712  std::string header = content.first + ": " + ref->getStringRep();
713  chunk = curl_slist_append( chunk, header.c_str() );
714  }
715  curl_easy_setopt( curl, CURLOPT_HTTPHEADER, chunk );
716  }
717  }
718 
719  Core::networkManager.auxthreadpool->push( [uoexec_w, curl_sp, chunk]() {
720  CURL* curl = curl_sp.get();
721  CURLcode res;
722  std::string readBuffer;
723  curl_easy_setopt( curl, CURLOPT_WRITEDATA, &readBuffer );
724 
725  /* Perform the request, res will get the return code */
726  res = curl_easy_perform( curl );
727  if ( chunk != nullptr )
728  curl_slist_free_all( chunk );
729  {
730  Core::PolLock lck;
731 
732  if ( !uoexec_w.exists() )
733  {
734  DEBUGLOG << "OpenConnection Script has been destroyed\n";
735  return;
736  }
737  /* Check for errors */
738  if ( res != CURLE_OK )
739  uoexec_w.get_weakptr()->ValueStack.back().set(
740  new BObject( new BError( curl_easy_strerror( res ) ) ) );
741  else
742  uoexec_w.get_weakptr()->ValueStack.back().set(
743  new BObject( new String( readBuffer ) ) );
744 
745  uoexec_w.get_weakptr()->os_module->revive();
746  }
747 
748  /* always cleanup */
749  // curl_easy_cleanup() is performed when the shared pointer deallocates
750  } );
751  }
752  else
753  {
754  return new BError( "curl_easy_init() failed" );
755  }
756  }
757  else
758  {
759  return new BError( "Invalid parameter type" );
760  }
761  }
762 
763  return new BError( "Invalid parameter type" );
764 }
765 
766 // signal_event() takes ownership of the pointer which is passed to it.
767 // Objects must not be touched or deleted after being sent here!
768 // TODO: Find a better way to enforce this in the codebase.
770 {
771  INC_PROFILEVAR( events );
772 
773  if ( blocked_ && ( wait_type == WAIT_EVENT ) ) // already being waited for
774  {
775  /* Now, the tricky part. The value to return on an error or
776  completion condition has already been pushed onto the value
777  stack - so, we need to replace it with the real result.
778  */
779  exec.ValueStack.back().set( new BObject( imp ) );
780  /* This executor will get moved to the run queue at the
781  next step_scripts(), where blocked is checked looking
782  for timed out or completed operations. */
783 
784  revive();
785  }
786  else // not being waited for, so queue for later.
787  {
788  if ( events_.size() < max_eventqueue_size )
789  {
790  events_.push( imp );
791  }
792  else
793  {
794  if ( Plib::systemstate.config.discard_old_events )
795  {
796  BObject ob( events_.front() );
797  events_.pop();
798  events_.push( imp );
799  }
800  else
801  {
802  BObject ob( imp );
803  if ( Plib::systemstate.config.loglevel >= 11 )
804  {
805  INFO_PRINT << "Event queue for " << exec.scriptname() << " is full, discarding event.\n";
806  ExecutorModule* em = exec.findModule( "npc" );
807  if ( em )
808  {
809  NPCExecutorModule* npcemod = static_cast<NPCExecutorModule*>( em );
810  INFO_PRINT << "NPC Serial: " << fmt::hexu( npcemod->npc.serial ) << " ("
811  << npcemod->npc.x << " " << npcemod->npc.y << " " << npcemod->npc.z << ")\n";
812  }
813 
814  INFO_PRINT << "Event: " << ob->getStringRep() << "\n";
815  }
816  return false; // Event-queue is full
817  }
818  }
819  }
820 
821  return true; // Event was successfully sent (perhaps by discarding old events)
822 }
823 
824 void OSExecutorModule::SleepFor( int nsecs )
825 {
826  if ( nsecs )
827  {
828  blocked_ = true;
831  }
832 }
833 
835 {
836  if ( msecs )
837  {
838  blocked_ = true;
841  }
842 }
843 
845 {
846  blocked_ = true;
848  sleep_until_clock_ = 0; // wait forever
849 }
850 
852 {
853  blocked_ = false;
854  if ( in_hold_list_ == TIMEOUT_LIST )
855  {
857  Core::scriptScheduler.revive_timeout( static_cast<Core::UOExecutor*>( &exec ), hold_itr_ );
858  }
859  else if ( in_hold_list_ == NOTIMEOUT_LIST )
860  {
862  Core::scriptScheduler.revive_notimeout( static_cast<Core::UOExecutor*>( &exec ) );
863  }
864  else if ( in_hold_list_ == DEBUGGER_LIST )
865  {
866  // stays right where it is.
867  }
868 }
870 {
871  return ( in_hold_list_ == DEBUGGER_LIST );
872 }
874 {
876  Core::scriptScheduler.revive_debugged( static_cast<Core::UOExecutor*>( &exec ) );
877 }
878 
880 const int SCRIPTOPT_DEBUG = 2;
881 const int SCRIPTOPT_NO_RUNAWAY = 3;
884 
886 {
887  int optnum;
888  int optval;
889  if ( getParam( 0, optnum ) && getParam( 1, optval ) )
890  {
891  int oldval;
892  switch ( optnum )
893  {
894  case SCRIPTOPT_NO_INTERRUPT:
895  oldval = critical ? 1 : 0;
896  critical = optval ? true : false;
897  break;
898  case SCRIPTOPT_DEBUG:
899  oldval = exec.getDebugLevel();
900  if ( optval )
902  else
904  break;
905  case SCRIPTOPT_NO_RUNAWAY:
906  oldval = warn_on_runaway ? 1 : 0;
907  warn_on_runaway = !optval;
908  break;
909  case SCRIPTOPT_CAN_ACCESS_OFFLINE_MOBILES:
910  {
911  Core::UOExecutor& uoexec = static_cast<Core::UOExecutor&>( exec );
912  oldval = uoexec.can_access_offline_mobiles ? 1 : 0;
913  uoexec.can_access_offline_mobiles = optval ? true : false;
914  }
915  break;
916  case SCRIPTOPT_AUXSVC_ASSUME_STRING:
917  {
918  Core::UOExecutor& uoexec = static_cast<Core::UOExecutor&>( exec );
919  oldval = uoexec.auxsvc_assume_string ? 1 : 0;
920  uoexec.auxsvc_assume_string = optval ? true : false;
921  }
922  break;
923  default:
924  return new BError( "Unknown Script Option" );
925  }
926  return new BLong( oldval );
927  }
928  else
929  {
930  return new BError( "Invalid parameter type" );
931  }
932 }
933 
935 {
936  return ( clear_event_queue() );
937 }
938 
939 namespace
940 {
941 struct ScriptDiffData
942 {
943  std::string name;
946  ScriptDiffData( Core::UOExecutor* ex )
947  : name( ex->scriptname() ), instructions( ex->instr_cycles ), pid( ex->os_module->pid() )
948  {
949  }
950  ScriptDiffData( Core::UOExecutor* ex, u64 instr ) : ScriptDiffData( ex )
951  {
952  instructions -= instr;
953  auto uoemod = static_cast<Module::UOExecutorModule*>( ex->findModule( "uo" ) );
954  if ( uoemod->attached_chr_ != nullptr )
955  name += " (" + uoemod->attached_chr_->name() + ")";
956  else if ( uoemod->attached_npc_ != nullptr )
957  name += " (" + static_cast<Mobile::NPC*>( uoemod->attached_npc_ )->templatename() + ")";
958  else if ( uoemod->attached_item_ )
959  name += " (" + uoemod->attached_item_->name() + ")";
960  }
961 
962  bool operator>( const ScriptDiffData& other ) const { return instructions > other.instructions; }
963 };
964 struct PerfData
965 {
966  std::unordered_map<u64, ScriptDiffData> data;
968  size_t max_scripts;
969  PerfData( weak_ptr<Core::UOExecutor> weak_ex, size_t max_count )
970  : data(), uoexec_w( weak_ex ), max_scripts( max_count )
971  {
972  }
973  static void collect_perf( PerfData* data_ptr )
974  {
975  std::unique_ptr<PerfData> data( data_ptr );
976  std::vector<ScriptDiffData> res;
977  if ( !data->uoexec_w.exists() )
978  {
979  DEBUGLOG << "PerformanceMeasure Script has been destroyed\n";
980  return;
981  }
982  double sum_instr( 0 );
983  const auto& runlist = Core::scriptScheduler.getRunlist();
984  const auto& ranlist = Core::scriptScheduler.getRanlist();
985  const auto& holdlist = Core::scriptScheduler.getHoldlist();
986  const auto& notimeoutholdlist = Core::scriptScheduler.getNoTimeoutHoldlist();
987  auto collect = [&]( Core::UOExecutor* scr ) {
988  auto itr = data->data.find( scr->os_module->pid() );
989  if ( itr == data->data.end() )
990  return;
991  res.emplace_back( scr, itr->second.instructions );
992  sum_instr += res.back().instructions;
993  };
994  for ( const auto& scr : runlist )
995  collect( scr );
996  for ( const auto& scr : ranlist )
997  collect( scr );
998  for ( const auto& scr : holdlist )
999  collect( scr.second );
1000  for ( const auto& scr : notimeoutholdlist )
1001  collect( scr );
1002  std::sort( res.begin(), res.end(), std::greater<ScriptDiffData>() );
1003 
1004  std::unique_ptr<ObjArray> arr( new ObjArray );
1005  for ( size_t i = 0; i < res.size() && i < data->max_scripts; ++i )
1006  {
1007  std::unique_ptr<BStruct> elem( new BStruct );
1008  elem->addMember( "name", new String( res[i].name ) );
1009  elem->addMember( "instructions", new Double( static_cast<double>( res[i].instructions ) ) );
1010  elem->addMember( "pid", new BLong( static_cast<int>( res[i].pid ) ) );
1011  elem->addMember( "percent", new Double( res[i].instructions / sum_instr * 100.0 ) );
1012  arr->addElement( elem.release() );
1013  }
1014  std::unique_ptr<BStruct> result( new BStruct );
1015  result->addMember( "scripts", arr.release() );
1016  result->addMember( "total_number_observed", new BLong( static_cast<int>( res.size() ) ) );
1017  result->addMember( "total_instructions", new Double( sum_instr ) );
1018  data->uoexec_w.get_weakptr()->ValueStack.back().set( new BObject( result.release() ) );
1019 
1020  data->uoexec_w.get_weakptr()->os_module->revive();
1021  }
1022 };
1023 
1024 } // namespace
1025 
1027 {
1028  int second_delta, max_scripts;
1029  if ( !getParam( 0, second_delta ) || !getParam( 1, max_scripts ) )
1030  return new BError( "Invalid parameter type" );
1031 
1032  auto this_uoemod = static_cast<UOExecutorModule*>( exec.findModule( "uo" ) );
1033  auto this_uoexec = static_cast<Core::UOExecutor*>( &this_uoemod->exec );
1034 
1035  if ( !this_uoexec->suspend() )
1036  {
1037  DEBUGLOG << "Script Error in '" << this_uoexec->scriptname() << "' PC=" << this_uoexec->PC
1038  << ": \n"
1039  << "\tThe execution of this script can't be blocked!\n";
1040  return new Bscript::BError( "Script can't be blocked" );
1041  }
1042 
1043  const auto& runlist = Core::scriptScheduler.getRunlist();
1044  const auto& ranlist = Core::scriptScheduler.getRanlist();
1045  const auto& holdlist = Core::scriptScheduler.getHoldlist();
1046  const auto& notimeoutholdlist = Core::scriptScheduler.getNoTimeoutHoldlist();
1047 
1048  std::unique_ptr<PerfData> perf( new PerfData( this_uoexec->weakptr, max_scripts ) );
1049  for ( const auto& scr : runlist )
1050  perf->data.insert( std::make_pair( scr->os_module->pid(), ScriptDiffData( scr ) ) );
1051  for ( const auto& scr : ranlist )
1052  perf->data.insert( std::make_pair( scr->os_module->pid(), ScriptDiffData( scr ) ) );
1053  for ( const auto& scr : holdlist )
1054  perf->data.insert(
1055  std::make_pair( scr.second->os_module->pid(), ScriptDiffData( scr.second ) ) );
1056  for ( const auto& scr : notimeoutholdlist )
1057  perf->data.insert( std::make_pair( scr->os_module->pid(), ScriptDiffData( scr ) ) );
1058 
1059  new Core::OneShotTaskInst<PerfData*>( nullptr,
1060  Core::polclock() + second_delta * Core::POLCLOCKS_PER_SEC,
1061  PerfData::collect_perf, perf.release() );
1062 
1063  return new BLong( 0 ); // dummy
1064 }
1065 }
1066 }
bool empty() const
Definition: scrdef.h:41
size_t curlWriteCallback(void *contents, size_t size, size_t nmemb, void *userp)
Definition: osmod.cpp:658
bool operator>(T *ptr, const ref_ptr< T > &rptr)
Definition: refptr.h:335
bool can_access_offline_mobiles
Definition: uoexec.h:60
unsigned short max_eventqueue_size
Definition: osmod.h:136
unsigned delay_seconds
Definition: attribute.h:50
bool auxsvc_assume_string
Definition: uoexec.h:61
const ExecList & getRanlist()
virtual std::string getStringRep() const =0
const EScriptProgram * prog() const
Definition: executor.h:423
ref_ptr< Bscript::EScriptProgram > find_script2(const ScriptDef &script, bool complain_if_not_found, bool cache_script)
Definition: scrstore.cpp:83
Bscript::BObjectImp * mf_debugger()
Definition: osmod.cpp:139
const std::string & value() const
Definition: impstr.h:67
bool in_debugger_holdlist() const
Definition: osmod.cpp:869
void setDebugLevel(DEBUG_LEVEL level)
Definition: executor.h:369
void SleepFor(int secs)
Definition: osmod.cpp:824
ValueStackCont ValueStack
Definition: executor.h:120
bool config_nodie(const std::string &name, const Plib::Package *pkg, const char *mainpfx)
Definition: scrdef.cpp:84
const int SCRIPTOPT_AUXSVC_ASSUME_STRING
Definition: osmod.cpp:883
int unload_all_scripts()
Definition: scrstore.cpp:148
SystemState systemstate
Definition: systemstate.cpp:12
bool isa(BObjectType type) const
Definition: bobject.h:353
Bscript::BObjectImp * mf_unload_scripts()
Definition: osmod.cpp:509
Network::Client * client
Definition: charactr.h:871
polclock_t polclock()
Definition: polclock.cpp:72
Bscript::BObjectImp * is_critical()
Definition: osmod.cpp:361
bool find_uoexec(unsigned int pid, UOExecutor **pp_uoexec)
Definition: scrsched.cpp:60
Bscript::BObjectImp * mf_set_script_option()
Definition: osmod.cpp:885
const HoldList & getHoldlist()
T * get() const
Definition: refptr.h:176
u64 instructions
Definition: osmod.cpp:944
bool getParam(unsigned param, int &value)
Definition: execmodl.cpp:62
bool signal_event(Bscript::BObjectImp *eventimp)
Definition: osmod.cpp:769
bool has_active_client() const
Definition: charactr.cpp:448
Bscript::BObjectImp * mf_Log()
Definition: osmod.cpp:469
const Contents & contents() const
Definition: bstruct.cpp:466
virtual BObjectImp * copy() const =0
T * get_weakptr() const
Definition: weakptr.h:110
u64 pid
Definition: osmod.cpp:945
BObjectImp * getParamImp(unsigned param)
Definition: execmodl.cpp:22
unsigned int pid() const
Definition: osmod.cpp:129
Core::CharacterRef controller_
Definition: uomod.h:314
bool open(const char *ipaddr, unsigned short port)
Definition: wnsckt.cpp:125
const ExecList & getRunlist()
Bscript::BObjectImp * mf_clear_event_queue()
Definition: osmod.cpp:934
int paramAsLong(unsigned param)
Definition: executor.cpp:240
Bscript::BObjectImp * set_critical()
Definition: osmod.cpp:347
Bscript::BObjectImp * mf_system_rpm()
Definition: osmod.cpp:488
const char * paramAsString(unsigned param)
Definition: executor.cpp:209
const int SCRIPTOPT_DEBUG
Definition: osmod.cpp:880
OSExecutorModule(Bscript::Executor &exec)
Definition: osmod.cpp:102
enum Pol::Module::OSExecutorModule::@9 in_hold_list_
int unload_script(const std::string &name_in)
Definition: scrstore.cpp:113
Bscript::BObjectImp * events_waiting()
Definition: osmod.cpp:227
bool getAttributeParam(Executor &exec, unsigned param, const Mobile::Attribute *&attr)
Definition: uoexhelp.cpp:610
const std::string & name() const
Definition: scrdef.h:45
unsigned short u16
Definition: rawtypes.h:26
const int SCRIPTOPT_NO_INTERRUPT
Definition: osmod.cpp:879
unsigned long long u64
Definition: rawtypes.h:38
bool exists() const
Definition: scrdef.cpp:126
#define URL_MAX_LEN
Definition: pktdef.h:73
std::unique_ptr< threadhelp::DynTaskThreadPool > auxthreadpool
Definition: network.h:99
#define DEBUGLOG
Definition: logfacility.h:237
void revive_timeout(UOExecutor *exec, TimeoutHandle hold_itr)
Definition: refptr.h:65
bool getCharacterParam(unsigned param, Mobile::Character *&chrptr)
Definition: osmod.h:153
Core::TimeoutHandle hold_itr_
Definition: osmod.h:121
NetworkManager networkManager
Definition: network.cpp:28
ExecutorModule * findModule(const std::string &name)
Definition: executor.cpp:3038
Bscript::BObjectImp * mf_set_event_queue_size()
Definition: osmod.cpp:537
Bscript::BObjectImp * getpid()
Definition: osmod.cpp:165
void Send(Client *client, int len=-1) const
Definition: packethelper.h:69
void revive_notimeout(UOExecutor *exec)
Bscript::BObjectImp * start_script()
Definition: osmod.cpp:232
bool exists() const
Definition: weakptr.h:115
unsigned int getnewpid(Core::UOExecutor *uoexec)
Definition: osmod.cpp:93
std::queue< Bscript::BObjectImp * > events_
Definition: osmod.h:137
UOExecutor * pChild
Definition: uoexec.h:64
static UninitObject * create()
Definition: bobject.h:482
Bscript::BObjectImp * sleepms()
Definition: osmod.cpp:194
const int SCRIPTOPT_CAN_ACCESS_OFFLINE_MOBILES
Definition: osmod.cpp:882
#define POLLOG
Definition: logfacility.h:219
weak_ptr< Core::UOExecutor > uoexec_w
Definition: osmod.cpp:967
Core::polclock_t sleep_until_clock_
Definition: osmod.h:112
const std::string & scriptname() const
Definition: execmodl.cpp:107
const int SCRIPTOPT_NO_RUNAWAY
Definition: osmod.cpp:881
weak_ptr_owner< UOExecutor > weakptr
Definition: uoexec.h:62
time_t poltime()
Definition: polclock.cpp:102
const String * getStringParam(unsigned param)
Definition: execmodl.cpp:36
std::unordered_map< u64, ScriptDiffData > data
Definition: osmod.cpp:966
Bscript::BObjectImp * run_script_to_completion()
Definition: osmod.cpp:369
UOExecutor * pParent
Definition: uoexec.h:64
unsigned char priority
Definition: osmod.h:63
StateManager stateManager
Definition: state.cpp:8
BObjectImp * create_debug_context()
Definition: poldbg.cpp:267
ScriptScheduler scriptScheduler
Bscript::BObjectImp * mf_OpenConnection()
Definition: osmod.cpp:583
bool CanUseSkill(Network::Client *client)
Definition: useskill.cpp:87
unsigned int get_new_pid(UOExecutor *exec)
Bscript::BObjectImp * mf_HTTPRequest()
Definition: osmod.cpp:664
Plib::Package const * pkg
Definition: eprog.h:123
const std::string & scriptname() const
Definition: executor.h:413
const char * c_str() const
Definition: scrdef.h:42
Bscript::BObjectImp * getprocess()
Definition: osmod.cpp:151
Bscript::BObjectImp * create_debug_context()
Definition: osmod.cpp:134
const String * getStringParam(unsigned param)
Definition: executor.cpp:347
void revive_debugged(UOExecutor *exec)
Bscript::BObjectImp * mf_performance_diff()
Definition: osmod.cpp:1026
std::string name
Definition: osmod.cpp:943
bool run_script_to_completion(const char *filename, Bscript::BObjectImp *parameter)
Definition: scrsched.cpp:333
Bscript::BObjectImp * mf_OpenURL()
Definition: osmod.cpp:550
bool start_script(Bscript::EScriptProgram *prog, bool start_attached, Bscript::BObjectImp *param2=nullptr, Bscript::BObjectImp *param3=nullptr, Bscript::BObjectImp *param4=nullptr)
Definition: chrituse.cpp:30
size_t max_scripts
Definition: osmod.cpp:968
const NoTimeoutHoldList & getNoTimeoutHoldlist()
Bscript::BObjectImp * sleep()
Definition: osmod.cpp:183
enum Pol::Module::OSExecutorModule::WAIT_TYPE wait_type
Bscript::BObjectImp * wait_for_event()
Definition: osmod.cpp:205
Core::ScriptDef script_
Definition: attribute.h:57
#define INFO_PRINT
Definition: logfacility.h:223
void start_script(const char *filename, Bscript::BObjectImp *param0, Bscript::BObjectImp *param1)
Definition: scrsched.cpp:150
const char * data() const
Definition: impstr.h:66
Bscript::BObjectImp * run_script()
Definition: osmod.cpp:387
Bscript::BObjectImp * clear_event_queue()
Definition: osmod.cpp:527
Definition: berror.cpp:12
const polclock_t POLCLOCKS_PER_SEC
Definition: polclock.h:29
const BObjectImp * FindMember(const char *name)
Definition: bstruct.cpp:216
Bscript::BObjectImp * start_skill_script()
Definition: osmod.cpp:269
void freepid(unsigned int pid)
Definition: osmod.cpp:97
size_t length() const
Definition: impstr.h:68
void send_sysmessage(Network::Client *client, const char *text, unsigned short font, unsigned short color)
Definition: ufunc.cpp:1147
void free_pid(unsigned int pid)
std::string name
Definition: attribute.h:40
bool hidden() const
Definition: charactr.h:941
BObjectImp * getParamImp(unsigned param)
Definition: executor.cpp:266
void SleepForMs(int msecs)
Definition: osmod.cpp:834
bool getParam(unsigned param, int &value)
Definition: executor.cpp:363
Bscript::BObjectImp * mf_set_priority()
Definition: osmod.cpp:493
Bscript::BObjectImp * mf_set_debug()
Definition: osmod.cpp:454
#define INC_PROFILEVAR(counter)
Definition: profile.h:85