]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/dope/server/l4/server.cc
71514f1f1675b4ba1020cfcfb6d2be4d9ca8943f
[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, w, h;
380
381   dope_registry->register_obj(this);
382
383   _screen_info.width     = 300;
384   _screen_info.height    = 200;
385
386   if (sscanf(configstr, "%dx%d", &w, &h) == 2)
387     {
388       _screen_info.width = w;
389       _screen_info.height = h;
390     }
391
392   if (char *a = strstr(configstr, "pos="))
393     sscanf(a + 4, "%d,%d", &xpos, &ypos);
394
395   L4Re::Video::Pixel_info pixinfo(16, 5, 11, 6, 5, 5, 0);
396   pixinfo.bytes_per_pixel(2);
397
398   _screen_info.flags        = L4Re::Video::Goos::F_pointer;
399   _screen_info.num_static_views   = 1;
400   _screen_info.num_static_buffers = 1;
401   _screen_info.pixel_info   = pixinfo;
402
403   init_infos();
404   _view_info.bytes_per_line = _screen_info.width * 2;
405   _view_info.buffer_offset  = 0;
406
407   const char *appname = "fb";
408   //const char *listener = "listener";
409   char *s;
410   char buf[80];
411
412   if (get_string(configstr, "name=", &s, &val))
413     {
414       strncpy(buf, s, val);
415       buf[val] = 0;
416       appname = buf;
417     }
418
419   app_id = appman->reg_app(appname);
420   register_appid(app_id, this);
421
422   SCOPE *rootscope = scope->create();
423   //THREAD *listener_thread = thread->alloc_thread();
424   appman->set_rootscope(app_id, rootscope);
425
426   INFO(printf("Server(init_fb): fb init request. appname=%s\n", appname));
427
428   //thread->ident2thread(listener, listener_thread);
429   //appman->reg_list_thread(app_id, listener_thread);
430   //appman->reg_listener(app_id, (void *)&listener_thread->tid);
431
432   //appman->reg_app_thread(app_id, (THREAD *)&client_thread);
433
434   if (int r = create_event())
435     throw (L4::Runtime_error(r));
436
437   cmd("x=new Window()");
438   cmd("y=new VScreen()");
439   snprintf(buf, sizeof(buf), "y.setmode(%ld,%ld,\"RGB16\")",
440                              _screen_info.width, _screen_info.height);
441   buf[sizeof(buf)-1] = 0;
442   cmd(buf);
443
444   snprintf(buf, sizeof(buf), "x.set(-x %d -y %d -content y -workw %ld -workh %ld)",
445                              xpos, ypos,
446                              _screen_info.width, _screen_info.height);
447   buf[sizeof(buf)-1] = 0;
448   cmd(buf);
449
450   snprintf(buf, sizeof(buf), "y.bind(\"press\",   1)");
451   buf[sizeof(buf)-1] = 0;
452   cmd(buf);
453
454   snprintf(buf, sizeof(buf), "y.bind(\"release\",  1)");
455   buf[sizeof(buf)-1] = 0;
456   cmd(buf);
457
458   snprintf(buf, sizeof(buf), "y.bind(\"motion\",   1)");
459   buf[sizeof(buf)-1] = 0;
460   cmd(buf);
461
462   cmd("x.open()");
463
464   cmd_ret("y.map()", buf, sizeof(buf));
465
466   printf("y.map() = %s\n", buf);
467
468   l4_cap_idx_t x = strtoul(&buf[3], NULL, 0);
469   _fb_ds = L4::Cap<L4Re::Dataspace>(x);
470
471 //  printf("fb_ds = %lx\n", _fb_ds.cap());
472 //  printf("evbuf2 = %p\n", evbuf.buf());
473 }
474
475 int Dope_fb::refresh(int x, int y, int w, int h)
476 {
477   char buf[70];
478   // Hmm: y is a VSCREEN, so we could use y->vscr->refresh(y, ...)
479   snprintf(buf, sizeof(buf), "y.refresh(-x %d -y %d -w %d -h %d)", x, y, w, h);
480   buf[sizeof(buf) - 1] = 0;
481   cmd(buf);
482   return L4_EOK;
483 }
484
485 int Dope_fb::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
486 {
487   l4_msgtag_t tag;
488   ios >> tag;
489
490   switch (tag.label())
491     {
492     case L4Re::Protocol::Goos:
493        return L4Re::Util::Video::Goos_svr::dispatch(obj, ios);
494     case L4Re::Protocol::Event:
495     case L4_PROTO_IRQ:
496        return L4Re::Util::Event_svr<Dope_base>::dispatch(obj, ios);
497     default:
498        return -L4_EBADPROTO;
499     }
500 }
501
502 // ------------------------------------------------------------------------
503
504 class Controller : public L4::Server_object
505 {
506 public:
507   int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
508 };
509
510 int
511 Controller::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
512 {
513   l4_msgtag_t tag;
514   ios >> tag;
515
516   switch (tag.label())
517     {
518     case L4::Meta::Protocol:
519       return L4::Util::handle_meta_request<L4::Factory>(ios);
520     case L4::Factory::Protocol:
521       break;
522     default:
523       return -L4_EBADPROTO;
524     }
525
526   L4::Factory::Proto op;
527   L4::Ipc::Varg arg;
528   ios >> op >> arg;
529   if (!arg.is_of<char const*>())
530     return -L4_EINVAL;
531
532   unsigned long size = 100;
533   char s[size];
534   strncpy(s, arg.value<char const*>(), cxx::min<int>(size, arg.length()));
535   s[size] = 0;
536
537   try
538     {
539       switch (op)
540         {
541         default:
542           printf("Invalid object type requested\n");
543           return -L4_ENODEV;
544
545         case L4Re::Video::Goos::Protocol:
546             {
547               Dope_fb *x = new Dope_fb(s);
548               ios << x->obj_cap();
549               return L4_EOK;
550             }
551         case 0: // dope iface
552             {
553               Dope_app *x = new Dope_app(s);
554               ios << x->obj_cap();
555               return L4_EOK;
556             }
557         }
558     }
559   catch (L4::Runtime_error const &e)
560     {
561       return e.err_no();
562     }
563 }
564
565 struct My_loop_hooks :
566   public L4::Ipc_svr::Ignore_errors,
567   public L4::Ipc_svr::Default_timeout,
568   public L4::Ipc_svr::Compound_reply
569 {
570   void setup_wait(L4::Ipc_istream &istr, L4::Ipc_svr::Reply_mode)
571   {
572     istr.reset();
573     istr << L4::Small_buf(rcv_cap().cap(), L4_RCV_ITEM_LOCAL_ID);
574     l4_utcb_br_u(istr.utcb())->bdr = 0;
575   }
576 };
577
578 /*** DOpE SERVER THREAD ***/
579 static void *server_thread(void *)
580 {
581   static Controller ctrl;
582
583   l4_debugger_set_object_name(pthread_getl4cap(pthread_self()), "dope-srv");
584
585   dope_registry = new L4Re::Util::Object_registry
586       (L4::Cap<L4::Thread>(pthread_getl4cap(pthread_self())),
587        L4Re::Env::env()->factory());
588
589   if (!dope_registry)
590     return NULL;
591
592   static L4::Server<My_loop_hooks> dope_server(l4_utcb());
593
594   if (!dope_registry->register_obj(&ctrl, "dope").is_valid())
595     {
596       printf("Service registration failed.\n");
597       return NULL;
598     }
599
600   INFO(printf("Server(server_thread): entering server loop\n"));
601   dope_server.loop(dope_registry);
602
603   return NULL;
604 }
605
606
607 /******************************************************
608  *** FUNCTIONS THAT ARE CALLED BY THE SERVER THREAD ***
609  ******************************************************/
610
611 long dope_manager_init_app_component(void *,
612     const char* ,//appname,
613     const char* ,//listener,
614     void *)
615 {
616   printf("%s %d\n", __func__, __LINE__); 
617 #if 0
618         s32 app_id = appman->reg_app((char *)appname);
619         SCOPE *rootscope = scope->create();
620         THREAD *listener_thread = thread->alloc_thread();
621         appman->set_rootscope(app_id, rootscope);
622
623         INFO(printf("Server(init_app): application init request. appname=%s, listener=%s (new app_id=%x)\n", appname, listener, (int)app_id));
624
625         thread->ident2thread(listener, listener_thread);
626         appman->reg_list_thread(app_id, listener_thread);
627         appman->reg_listener(app_id, (void *)&listener_thread->tid);
628         return app_id;
629 #endif
630         return 0;
631 }
632
633
634 void dope_manager_deinit_app_component(void *,
635                                        long ,//app_id,
636                                        void *)
637 {
638   printf("%s %d\n", __func__, __LINE__); 
639 #if 0
640         struct thread client_thread = { *_dice_corba_obj };
641
642         /* check if the app_id belongs to the client */
643         if (!thread->thread_equal(&client_thread, appman->get_listener(app_id))) {
644                 printf("Server(deinit_app): Error: permission denied\n");
645                 return;
646         }
647
648         INFO(printf("Server(deinit_app): application (id=%u) deinit requested\n", (u32)app_id);)
649         scheduler->release_app(app_id);
650         userstate->release_app(app_id);
651         screen->forget_children(app_id);
652         appman->unreg_app(app_id);
653 #endif
654 }
655
656
657 long dope_manager_exec_cmd_component(void *,
658                                      long ,//app_id,
659                                      const char* ,//cmd,
660                                      void *)
661 {
662 #if 0
663         struct thread client_thread = { *_dice_corba_obj };
664         int ret;
665
666         /* check if the app_id belongs to the client */
667         if (!thread->thread_equal(&client_thread, appman->get_listener(app_id))) {
668                 printf("Server(exec_cmd): Error: permission denied\n");
669                 return DOPE_ERR_PERM;
670         }
671
672         appman->reg_app_thread(app_id, (THREAD *)&client_thread);
673         INFO(printf("Server(exec_cmd): cmd %s execution requested by app_id=%u\n", cmd, (u32)app_id);)
674 //      printf("Server(exec_cmd): cmd %s execution requested by app_id=%u\n", cmd, (u32)app_id);
675         appman->lock(app_id);
676         ret = script->exec_command(app_id, (char *)cmd, NULL, 0);
677         appman->unlock(app_id);
678         if (ret < 0) printf("DOpE(exec_cmd): Error - command \"%s\" returned %d\n", cmd, ret);
679         return ret;
680 #endif
681         return 0;
682 }
683
684
685 long dope_manager_exec_req_component(void *,
686                                      long ,//app_id,
687                                      const char* ,//cmd,
688                                      char /*result*/[256],
689                                      int * , //res_len,
690                                      void *)
691 {
692 #if 0
693         struct thread client_thread = { *_dice_corba_obj };
694         int ret;
695
696         /* check if the app_id belongs to the client */
697         if (!thread->thread_equal(&client_thread, appman->get_listener(app_id))) {
698                 printf("Server(exec_req): Error: permission denied\n");
699                 return DOPE_ERR_PERM;
700         }
701
702         appman->reg_app_thread(app_id, (THREAD *)&client_thread);
703
704         INFO(printf("Server(exec_req): cmd %s execution requested by app_id=%u\n", cmd, (u32)app_id);)
705         appman->lock(app_id);
706         result[0] = 0;
707         ret = script->exec_command(app_id, (char *)cmd, &result[0], *res_len);
708         appman->unlock(app_id);
709         INFO(printf("Server(exec_req): send result msg: %s\n", result));
710
711         if (ret < 0) printf("DOpE(exec_req): Error - command \"%s\" returned %d\n", cmd, ret);
712         result[255] = 0;
713         return ret;
714 #endif
715         return 0;
716 }
717
718
719 long dope_manager_get_keystate_component(void *,
720                                          long keycode,
721                                          void *)
722 {
723         return userstate->get_keystate(keycode);
724 }
725
726
727 char dope_manager_get_ascii_component(void  *,
728                                       long keycode,
729                                       void *)
730 {
731         return userstate->get_ascii(keycode);
732 }
733
734
735 /*************************
736  *** SERVICE FUNCTIONS ***
737  *************************/
738
739 /*** START SERVING ***/
740 static void start(void)
741 {
742         INFO(printf("Server(start): creating server thread\n");)
743         thread->start_thread(NULL, &server_thread, NULL);
744 }
745
746
747 /****************************************
748  *** SERVICE STRUCTURE OF THIS MODULE ***
749  ****************************************/
750
751 static struct server_services services = {
752         start,
753 };
754
755
756 /**************************
757  *** MODULE ENTRY POINT ***
758  **************************/
759
760 extern "C" int init_server(struct dope_services *d)
761 {
762   thread    = (thread_services *)d->get_module("Thread 1.0");
763   appman    = (appman_services *)d->get_module("ApplicationManager 1.0");
764   script    = (script_services *)d->get_module("Script 1.0");
765   msg       = (messenger_services *)d->get_module("Messenger 1.0");
766   userstate = (userstate_services *)d->get_module("UserState 1.0");
767   scope     = (scope_services *)d->get_module("Scope 1.0");
768   screen    = (screen_services *)d->get_module("Screen 1.0");
769   scheduler = (scheduler_services *)d->get_module("Scheduler 1.0");
770
771   d->register_module("Server 1.0", &services);
772   return 1;
773 }