]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/dope/server/l4/server.cc
Inital import
[l4.git] / l4 / pkg / dope / server / l4 / server.cc
1 /*
2  * \brief   DOpE server module
3  * \date    2002-11-13
4  * \author  Norman Feske <nf2@inf.tu-dresden.de>
5  *
6  * This module is the main communication interface
7  * between DOpE clients and DOpE.
8  */
9
10 /*
11  * Copyright (C) 2002-2004  Norman Feske  <nf2@os.inf.tu-dresden.de>
12  * Technische Universitaet Dresden, Operating Systems Research Group
13  *
14  * This file is part of the DOpE package, which is distributed under
15  * the  terms  of the  GNU General Public Licence 2.  Please see the
16  * COPYING file for details.
17  */
18
19 /*** GENERAL ***/
20 #include <cstdlib>
21 #include <cstdio>
22 #include <ctype.h>
23
24 /*** DOPE SPECIFIC ***/
25 #include "dopestd.h"
26 #include "thread.h"
27 #include "server.h"
28 #include "appman.h"
29 #include "script.h"
30 #include "scope.h"
31 #include "screen.h"
32 #include "messenger.h"
33 #include "userstate.h"
34 #include "scheduler.h"
35 #include <l4/dope/dopedef.h>
36
37 #include <l4/re/env>
38 #include <l4/re/namespace>
39 #include <l4/re/util/cap_alloc>
40 #include <l4/sys/factory>
41 #include <l4/sys/typeinfo_svr>
42 #include <l4/cxx/exceptions>
43
44 #include <l4/cxx/iostream>
45 #include <l4/cxx/l4iostream>
46 #include <l4/cxx/minmax>
47
48 #include <l4/re/protocols>
49 #include <l4/re/util/object_registry>
50 #include <l4/re/util/video/goos_svr>
51 #include <l4/re/util/event_svr>
52 #include <l4/re/util/event_buffer>
53 #include <l4/re/c/event.h>
54 #include <l4/re/video/goos>
55
56 #include <l4/sys/debugger.h>
57 #include <pthread-l4.h>
58
59 static struct userstate_services *userstate;
60 static struct thread_services    *thread;
61 static struct appman_services    *appman;
62 static struct script_services    *script;
63 static struct scope_services     *scope;
64 static struct screen_services    *screen;
65 static struct scheduler_services *scheduler;
66 static struct messenger_services *msg;
67
68 extern "C" int init_server(struct dope_services *d);
69
70
71 static int get_val(const char *configstr, const char *var, unsigned long *val)
72 {
73   char *a;
74   a = strstr(configstr, var);
75   if (!a)
76     return 0;
77   *val = strtoul(a + strlen(var), NULL, 0);
78   return 1;
79 }
80
81 static int get_string(const char *configstr, const char *var,
82                       char **val, unsigned long *vallen)
83 {
84   char *a;
85   a = strstr(configstr, var);
86   if (!a)
87     return 0;
88   a += strlen(var);
89   *val = a;
90   while (*a && !isspace(*a))
91     a++;
92   *vallen = a - *val;
93   return 1;
94 }
95
96 // ------------------------------------------------------------------------
97 static L4Re::Util::Object_registry *dope_registry;
98
99 // ------------------------------------------------------------------------
100
101 static L4::Cap<void> rcv_cap()
102 {
103   static L4::Cap<void> _rcv = L4Re::Util::cap_alloc.alloc<void>();
104   return _rcv;
105 }
106
107 class Dope_base : public L4Re::Util::Event_svr<Dope_base>,
108                   public L4::Server_object
109 {
110 protected:
111   s32 app_id;
112   L4Re::Util::Event_buffer evbuf;
113
114   int cmd(const char *c);
115   int cmd_ret(const char *c, char *result, unsigned long res_len);
116   int create_event();
117
118   bool register_appid(s32 ai, Dope_base *obj);
119
120 public:
121   void event_cb(l4re_event_t *e, unsigned nr_events);
122   static Dope_base *get_obj(s32 ai);
123   static L4::Cap<void> rcv_cap() { return ::rcv_cap(); }
124
125 private:
126   static void check_appid(s32 ai);
127   static Dope_base *appid_to_obj[MAX_APPS];
128 };
129
130 Dope_base *Dope_base::appid_to_obj[MAX_APPS];
131
132 void Dope_base::check_appid(s32 ai)
133 {
134   if (ai >= MAX_APPS)
135     {
136       printf("Oops: %d >= MAX_APPS\n", ai);
137       exit(1);
138     }
139 }
140
141 bool Dope_base::register_appid(s32 ai, Dope_base *obj)
142 {
143   check_appid(ai);
144   appid_to_obj[ai] = obj;
145   return true;
146 }
147
148 Dope_base *Dope_base::get_obj(s32 ai)
149 {
150   check_appid(ai);
151   return appid_to_obj[ai];
152 }
153
154 extern "C" void dope_event_inject(s32 appid, l4re_event_t *e,
155                                   unsigned nr_events)
156 {
157   Dope_base::get_obj(appid)->event_cb(e, nr_events);
158 }
159
160 int Dope_base::cmd(const char *c)
161 {
162   INFO(printf("Server(exec_cmd): cmd %s execution requested by app_id=%u\n", c, (u32)app_id);)
163   appman->lock(app_id);
164   int ret = script->exec_command(app_id, (char *)c, NULL, 0);
165   appman->unlock(app_id);
166   if (ret < 0)
167     printf("DOpE(exec_cmd): Error - command \"%s\" returned %d\n", c, ret);
168   return ret;
169 }
170
171 int Dope_base::cmd_ret(const char *c, char *result, unsigned long res_len)
172 {
173   INFO(printf("Server(exec_req): cmd %s execution requested by app_id=%u\n",
174               c, (u32)app_id);)
175   appman->lock(app_id);
176   result[0] = 0;
177   int ret = script->exec_command(app_id, (char *)c, result, res_len);
178   appman->unlock(app_id);
179   INFO(printf("Server(exec_req): send result msg: %s\n", result));
180
181   if (ret < 0) printf("DOpE(exec_req): Error - command \"%s\" returned %d\n", c, ret);
182   return ret;
183 }
184
185 int
186 Dope_base::create_event()
187 {
188   long r;
189
190   L4Re::Util::Auto_cap<L4Re::Dataspace>::Cap b
191     = L4Re::Util::cap_alloc.alloc<L4Re::Dataspace>();
192   if (!b.is_valid())
193     return -L4_ENOMEM;
194
195   if ((r = L4Re::Env::env()->mem_alloc()->alloc(L4_PAGESIZE, b.get())) < 0)
196     return r;
197
198   if ((r = evbuf.attach(b.get(), L4Re::Env::env()->rm())) < 0)
199     return r;
200
201   memset(evbuf.buf(), 0, b.get()->size());
202
203   _ds  = b.release();
204
205   return 0;
206 }
207
208 void Dope_base::event_cb(l4re_event_t *e, unsigned nr_events)
209 {
210 #if 0
211   printf("emmit event (client=%p): event (t=%d c=%d v=%d stream=%lx)\n",
212          this, e->type, e->code, e->value, e->stream_id);
213 #endif
214   for (unsigned i = 0; i < nr_events; ++i)
215     evbuf.put(*reinterpret_cast<L4Re::Event_buffer::Event const*>(&e[i]));
216   _irq.trigger();
217 }
218
219
220 // ------------------------------------------------------------------------
221
222 class Dope_app : public Dope_base
223 {
224 public:
225   explicit Dope_app(const char *configstr);
226   int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
227   int dispatch_dope_app(l4_umword_t, L4::Ipc_iostream &ios);
228
229   int client_cmd(L4::Ipc_iostream &ios);
230   int client_cmd_req(L4::Ipc_iostream &ios);
231   int client_vscreen_get_fb(L4::Ipc_iostream &ios);
232   int client_get_keystate(L4::Ipc_iostream &ios);
233 };
234
235 Dope_app::Dope_app(const char *configstr)
236 {
237   dope_registry->register_obj(this);
238
239   unsigned long val;
240   char *s;
241   char buf[80];
242   const char *appname = "App";
243
244   if (get_string(configstr, "name=", &s, &val))
245     {
246       strncpy(buf, s, val);
247       buf[val] = 0;
248       appname = buf;
249     }
250
251   if (int r = create_event())
252     throw (L4::Runtime_error(r));
253
254   app_id = appman->reg_app(appname);
255   register_appid(app_id, this);
256
257   SCOPE *rootscope = scope->create();
258   appman->set_rootscope(app_id, rootscope);
259   INFO(printf("Server(init_app): application init request. appname=%s\n", appname));
260 }
261
262 int Dope_app::client_cmd(L4::Ipc_iostream &ios)
263 {
264   unsigned long len;
265   char buf_in[256];
266
267   len = sizeof(buf_in);
268   ios >> L4::ipc_buf_cp_in(buf_in, len);
269   buf_in[len] = 0;
270
271   cmd(buf_in);
272   return -L4_EOK;
273 }
274
275 int Dope_app::client_cmd_req(L4::Ipc_iostream &ios)
276 {
277   unsigned long len;
278   char buf_in[256];
279   char buf_out[256];
280
281   len = sizeof(buf_in);
282   ios >> L4::ipc_buf_cp_in(buf_in, len);
283   buf_in[len] = 0;
284
285   cmd_ret(buf_in, buf_out, sizeof(buf_out));
286
287   len = strlen(buf_out);
288   if (len >= sizeof(buf_out))
289     {
290       len = sizeof(buf_out) - 1;
291       buf_out[sizeof(buf_out) - 1] = 0;
292     }
293
294   ios << L4::ipc_buf_cp_out(buf_out, len);
295
296   return -L4_EOK;
297 }
298
299 int Dope_app::client_vscreen_get_fb(L4::Ipc_iostream &ios)
300 {
301   unsigned long len;
302   char buf_in[30];
303   char buf[40];
304
305   len = sizeof(buf_in);
306   ios >> L4::ipc_buf_cp_in(buf_in, len);
307   buf_in[len] = 0;
308
309   snprintf(buf, sizeof(buf), "%s.map()", buf_in);
310   cmd_ret(buf, buf_in, sizeof(buf_in));
311   l4_cap_idx_t x = strtoul(&buf_in[3], NULL, 0);
312   L4::Cap<L4Re::Dataspace> ds = L4::Cap<L4Re::Dataspace>(x);
313   ios << ds;
314   return -L4_EOK;
315 }
316
317 int Dope_app::client_get_keystate(L4::Ipc_iostream &ios)
318 {
319   long x;
320   ios >> x; // get keycode
321   x = userstate->get_keystate(x);
322   ios << x; // send state
323   return -L4_EOK;
324 }
325
326 int Dope_app::dispatch_dope_app(l4_umword_t, L4::Ipc_iostream &ios)
327 {
328   L4::Opcode op;
329   ios >> op;
330
331   switch (op)
332     {
333     case Dope::Dope_app_::Cmd:
334       return client_cmd(ios);
335     case Dope::Dope_app_::Cmd_req:
336       return client_cmd_req(ios);
337     case Dope::Dope_app_::Vscreen_get_fb:
338       return client_vscreen_get_fb(ios);
339     case Dope::Dope_app_::Get_keystate:
340       return client_get_keystate(ios);
341     default:
342       return -L4_ENOSYS;
343     };
344 }
345
346 int Dope_app::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
347 {
348   l4_msgtag_t tag;
349   ios >> tag;
350
351   switch (tag.label())
352     {
353     case Dope::Protocol::App:
354       return dispatch_dope_app(obj, ios);
355     case L4Re::Protocol::Event:
356     case L4_PROTO_IRQ:
357       return L4Re::Util::Event_svr<Dope_base>::dispatch(obj, ios);
358     default:
359       return -L4_EBADPROTO;
360     };
361 }
362
363
364 // ------------------------------------------------------------------------
365
366 class Dope_fb : public L4Re::Util::Video::Goos_svr,
367                 public Dope_base
368 {
369 public:
370   explicit Dope_fb(const char *configstr);
371   int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
372
373   virtual int refresh(int x, int y, int w, int h);
374 };
375
376 Dope_fb::Dope_fb(const char *configstr)
377 {
378   unsigned long val;
379   unsigned xpos = 20, ypos = 20;
380
381   dope_registry->register_obj(this);
382
383   _screen_info.width     = 300;
384   _screen_info.height    = 200;
385
386
387   if (get_val(configstr, "w=", &val))
388     _screen_info.width  = val;
389   if (get_val(configstr, "h=", &val))
390     _screen_info.height = val;
391
392   if (get_val(configstr, "x=", &val))
393     xpos = val;
394   if (get_val(configstr, "y=", &val))
395     ypos = val;
396
397   L4Re::Video::Pixel_info pixinfo(16, 5, 11, 6, 5, 5, 0);
398   pixinfo.bytes_per_pixel(2);
399
400   _screen_info.flags        = L4Re::Video::Goos::F_pointer;
401   _screen_info.num_static_views   = 1;
402   _screen_info.num_static_buffers = 1;
403   _screen_info.pixel_info   = pixinfo;
404
405   init_infos();
406   _view_info.bytes_per_line = _screen_info.width * 2;
407   _view_info.buffer_offset  = 0;
408
409   const char *appname = "fb";
410   //const char *listener = "listener";
411   char *s;
412   char buf[80];
413
414   if (get_string(configstr, "name=", &s, &val))
415     {
416       strncpy(buf, s, val);
417       buf[val] = 0;
418       appname = buf;
419     }
420
421   app_id = appman->reg_app(appname);
422   register_appid(app_id, this);
423
424   SCOPE *rootscope = scope->create();
425   //THREAD *listener_thread = thread->alloc_thread();
426   appman->set_rootscope(app_id, rootscope);
427
428   INFO(printf("Server(init_fb): fb init request. appname=%s\n", appname));
429
430   //thread->ident2thread(listener, listener_thread);
431   //appman->reg_list_thread(app_id, listener_thread);
432   //appman->reg_listener(app_id, (void *)&listener_thread->tid);
433
434   //appman->reg_app_thread(app_id, (THREAD *)&client_thread);
435
436   if (int r = create_event())
437     throw (L4::Runtime_error(r));
438
439   cmd("x=new Window()");
440   cmd("y=new VScreen()");
441   snprintf(buf, sizeof(buf), "y.setmode(%ld,%ld,\"RGB16\")",
442                              _screen_info.width, _screen_info.height);
443   buf[sizeof(buf)-1] = 0;
444   cmd(buf);
445
446   snprintf(buf, sizeof(buf), "x.set(-x %d -y %d -content y -workw %ld -workh %ld)",
447                              xpos, ypos,
448                              _screen_info.width, _screen_info.height);
449   buf[sizeof(buf)-1] = 0;
450   cmd(buf);
451
452   snprintf(buf, sizeof(buf), "y.bind(\"press\",   1)");
453   buf[sizeof(buf)-1] = 0;
454   cmd(buf);
455
456   snprintf(buf, sizeof(buf), "y.bind(\"release\",  1)");
457   buf[sizeof(buf)-1] = 0;
458   cmd(buf);
459
460   snprintf(buf, sizeof(buf), "y.bind(\"motion\",   1)");
461   buf[sizeof(buf)-1] = 0;
462   cmd(buf);
463
464   cmd("x.open()");
465
466   cmd_ret("y.map()", buf, sizeof(buf));
467
468   printf("y.map() = %s\n", buf);
469
470   l4_cap_idx_t x = strtoul(&buf[3], NULL, 0);
471   _fb_ds = L4::Cap<L4Re::Dataspace>(x);
472
473 //  printf("fb_ds = %lx\n", _fb_ds.cap());
474 //  printf("evbuf2 = %p\n", evbuf.buf());
475 }
476
477 int Dope_fb::refresh(int x, int y, int w, int h)
478 {
479   char buf[70];
480   // Hmm: y is a VSCREEN, so we could use y->vscr->refresh(y, ...)
481   snprintf(buf, sizeof(buf), "y.refresh(-x %d -y %d -w %d -h %d)", x, y, w, h);
482   buf[sizeof(buf) - 1] = 0;
483   cmd(buf);
484   return L4_EOK;
485 }
486
487 int Dope_fb::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
488 {
489   l4_msgtag_t tag;
490   ios >> tag;
491
492   switch (tag.label())
493     {
494     case L4Re::Protocol::Goos:
495        return L4Re::Util::Video::Goos_svr::dispatch(obj, ios);
496     case L4Re::Protocol::Event:
497     case L4_PROTO_IRQ:
498        return L4Re::Util::Event_svr<Dope_base>::dispatch(obj, ios);
499     default:
500        return -L4_EBADPROTO;
501     }
502 }
503
504 // ------------------------------------------------------------------------
505
506 class Controller : public L4::Server_object
507 {
508 public:
509   int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
510 };
511
512 int
513 Controller::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
514 {
515   l4_msgtag_t tag;
516   ios >> tag;
517
518   switch (tag.label())
519     {
520     case L4::Meta::Protocol:
521       return L4::Util::handle_meta_request<L4::Factory>(ios);
522     case L4::Factory::Protocol:
523       break;
524     default:
525       return -L4_EBADPROTO;
526     }
527
528   L4::Factory::Proto op;
529   L4::Ipc::Varg arg;
530   ios >> op >> arg;
531   if (!arg.is_of<char const*>())
532     return -L4_EINVAL;
533
534   unsigned long size = 100;
535   char s[size];
536   strncpy(s, arg.value<char const*>(), cxx::min<int>(size, arg.length()));
537   s[size] = 0;
538
539   try
540     {
541       switch (op)
542         {
543         default:
544           printf("Invalid object type requested\n");
545           return -L4_ENODEV;
546
547         case L4Re::Video::Goos::Protocol:
548             {
549               Dope_fb *x = new Dope_fb(s);
550               ios << x->obj_cap();
551               return L4_EOK;
552             }
553         case 0: // dope iface
554             {
555               Dope_app *x = new Dope_app(s);
556               ios << x->obj_cap();
557               return L4_EOK;
558             }
559         }
560     }
561   catch (L4::Runtime_error const &e)
562     {
563       return e.err_no();
564     }
565 }
566
567 struct My_loop_hooks :
568   public L4::Ipc_svr::Ignore_errors,
569   public L4::Ipc_svr::Default_timeout,
570   public L4::Ipc_svr::Compound_reply
571 {
572   void setup_wait(L4::Ipc_istream &istr, L4::Ipc_svr::Reply_mode)
573   {
574     istr.reset();
575     istr << L4::Small_buf(rcv_cap().cap(), L4_RCV_ITEM_LOCAL_ID);
576     l4_utcb_br_u(istr.utcb())->bdr = 0;
577   }
578 };
579
580 /*** DOpE SERVER THREAD ***/
581 static void *server_thread(void *)
582 {
583   static Controller ctrl;
584
585   l4_debugger_set_object_name(pthread_getl4cap(pthread_self()), "dope-srv");
586
587   dope_registry = new L4Re::Util::Object_registry
588       (L4::Cap<L4::Thread>(pthread_getl4cap(pthread_self())),
589        L4Re::Env::env()->factory());
590
591   if (!dope_registry)
592     return NULL;
593
594   static L4::Server<My_loop_hooks> dope_server(l4_utcb());
595
596   if (!dope_registry->register_obj(&ctrl, "dope").is_valid())
597     {
598       printf("Service registration failed.\n");
599       return NULL;
600     }
601
602   INFO(printf("Server(server_thread): entering server loop\n"));
603   dope_server.loop(dope_registry);
604
605   return NULL;
606 }
607
608
609 /******************************************************
610  *** FUNCTIONS THAT ARE CALLED BY THE SERVER THREAD ***
611  ******************************************************/
612
613 long dope_manager_init_app_component(void *,
614     const char* ,//appname,
615     const char* ,//listener,
616     void *)
617 {
618   printf("%s %d\n", __func__, __LINE__); 
619 #if 0
620         s32 app_id = appman->reg_app((char *)appname);
621         SCOPE *rootscope = scope->create();
622         THREAD *listener_thread = thread->alloc_thread();
623         appman->set_rootscope(app_id, rootscope);
624
625         INFO(printf("Server(init_app): application init request. appname=%s, listener=%s (new app_id=%x)\n", appname, listener, (int)app_id));
626
627         thread->ident2thread(listener, listener_thread);
628         appman->reg_list_thread(app_id, listener_thread);
629         appman->reg_listener(app_id, (void *)&listener_thread->tid);
630         return app_id;
631 #endif
632         return 0;
633 }
634
635
636 void dope_manager_deinit_app_component(void *,
637                                        long ,//app_id,
638                                        void *)
639 {
640   printf("%s %d\n", __func__, __LINE__); 
641 #if 0
642         struct thread client_thread = { *_dice_corba_obj };
643
644         /* check if the app_id belongs to the client */
645         if (!thread->thread_equal(&client_thread, appman->get_listener(app_id))) {
646                 printf("Server(deinit_app): Error: permission denied\n");
647                 return;
648         }
649
650         INFO(printf("Server(deinit_app): application (id=%u) deinit requested\n", (u32)app_id);)
651         scheduler->release_app(app_id);
652         userstate->release_app(app_id);
653         screen->forget_children(app_id);
654         appman->unreg_app(app_id);
655 #endif
656 }
657
658
659 long dope_manager_exec_cmd_component(void *,
660                                      long ,//app_id,
661                                      const char* ,//cmd,
662                                      void *)
663 {
664 #if 0
665         struct thread client_thread = { *_dice_corba_obj };
666         int ret;
667
668         /* check if the app_id belongs to the client */
669         if (!thread->thread_equal(&client_thread, appman->get_listener(app_id))) {
670                 printf("Server(exec_cmd): Error: permission denied\n");
671                 return DOPE_ERR_PERM;
672         }
673
674         appman->reg_app_thread(app_id, (THREAD *)&client_thread);
675         INFO(printf("Server(exec_cmd): cmd %s execution requested by app_id=%u\n", cmd, (u32)app_id);)
676 //      printf("Server(exec_cmd): cmd %s execution requested by app_id=%u\n", cmd, (u32)app_id);
677         appman->lock(app_id);
678         ret = script->exec_command(app_id, (char *)cmd, NULL, 0);
679         appman->unlock(app_id);
680         if (ret < 0) printf("DOpE(exec_cmd): Error - command \"%s\" returned %d\n", cmd, ret);
681         return ret;
682 #endif
683         return 0;
684 }
685
686
687 long dope_manager_exec_req_component(void *,
688                                      long ,//app_id,
689                                      const char* ,//cmd,
690                                      char /*result*/[256],
691                                      int * , //res_len,
692                                      void *)
693 {
694 #if 0
695         struct thread client_thread = { *_dice_corba_obj };
696         int ret;
697
698         /* check if the app_id belongs to the client */
699         if (!thread->thread_equal(&client_thread, appman->get_listener(app_id))) {
700                 printf("Server(exec_req): Error: permission denied\n");
701                 return DOPE_ERR_PERM;
702         }
703
704         appman->reg_app_thread(app_id, (THREAD *)&client_thread);
705
706         INFO(printf("Server(exec_req): cmd %s execution requested by app_id=%u\n", cmd, (u32)app_id);)
707         appman->lock(app_id);
708         result[0] = 0;
709         ret = script->exec_command(app_id, (char *)cmd, &result[0], *res_len);
710         appman->unlock(app_id);
711         INFO(printf("Server(exec_req): send result msg: %s\n", result));
712
713         if (ret < 0) printf("DOpE(exec_req): Error - command \"%s\" returned %d\n", cmd, ret);
714         result[255] = 0;
715         return ret;
716 #endif
717         return 0;
718 }
719
720
721 long dope_manager_get_keystate_component(void *,
722                                          long keycode,
723                                          void *)
724 {
725         return userstate->get_keystate(keycode);
726 }
727
728
729 char dope_manager_get_ascii_component(void  *,
730                                       long keycode,
731                                       void *)
732 {
733         return userstate->get_ascii(keycode);
734 }
735
736
737 /*************************
738  *** SERVICE FUNCTIONS ***
739  *************************/
740
741 /*** START SERVING ***/
742 static void start(void)
743 {
744         INFO(printf("Server(start): creating server thread\n");)
745         thread->start_thread(NULL, &server_thread, NULL);
746 }
747
748
749 /****************************************
750  *** SERVICE STRUCTURE OF THIS MODULE ***
751  ****************************************/
752
753 static struct server_services services = {
754         start,
755 };
756
757
758 /**************************
759  *** MODULE ENTRY POINT ***
760  **************************/
761
762 extern "C" int init_server(struct dope_services *d)
763 {
764   thread    = (thread_services *)d->get_module("Thread 1.0");
765   appman    = (appman_services *)d->get_module("ApplicationManager 1.0");
766   script    = (script_services *)d->get_module("Script 1.0");
767   msg       = (messenger_services *)d->get_module("Messenger 1.0");
768   userstate = (userstate_services *)d->get_module("UserState 1.0");
769   scope     = (scope_services *)d->get_module("Scope 1.0");
770   screen    = (screen_services *)d->get_module("Screen 1.0");
771   scheduler = (scheduler_services *)d->get_module("Scheduler 1.0");
772
773   d->register_module("Server 1.0", &services);
774   return 1;
775 }