0022904: Clean up sccsid variables
[occt.git] / src / OSD / OSD_Cmailbox.c
1 #if !defined( WNT ) && !defined(__hpux)
2
3 #ifdef HAVE_CONFIG_H
4 # include <config.h>
5 #endif
6
7 #include <stdio.h>
8 #include <errno.h>
9
10 #ifdef HAVE_SIGNAL_H
11 # include <signal.h>
12 #endif
13
14 #ifdef HAVE_STRING_H
15 # include <string.h>
16 #endif
17
18 #ifdef HAVE_SYS_TYPES_H
19 # include <sys/types.h>
20 #endif
21
22 #ifdef HAVE_UNISTD_H
23 # include <unistd.h>
24 #endif
25
26 /* #ifdef ANSI */
27 int create_sharedmemory (int **,char *,int);
28 int open_sharedmemory   (int **,char *,int);
29 int remove_sharedmemory (int * ,char *    );
30 /* #endif */
31
32 /* This is a multi-server & multi-client asynchronous mailbox management */
33
34
35 /* The UNIX mail box is based on shared memory 
36 /
37 /
38 / The messages are send via shared memory .
39 / AST like functions (VMS) are simulated with a signal handler using SIGUSR1.
40 /
41 / To manage multiple mail boxes , an internal use shared memory is used
42 / to communicate index among table of mail box informations .
43 /
44 /
45 / Primitives to manage mail boxes :
46 /  osd_crmbox     Create a mail box
47 /  osd_opmbox     Open a mail box
48 /  osd_clmbox     Close a mail box
49 /  osd_wrmbox     Write into a mail box
50 /
51 /  user function needed to receive messages :
52 /   user_function (int *box_id, char *box_name, char *message_address, int message_length)
53 /
54 /
55 /
56 / In following explanations, "special shared memory" designates an internal 
57 / data area implemented with shared memory used to send index of mail box 
58 / informations table for the signal handler.
59 /
60 / Algorithms :
61 /
62 /  To create a mail box      - Find a free entry in mail box infos table
63 /                            - If first mail box, create special shared memory
64 /                            - Create a shared memory for messages
65 /                            - Put PID of creator into shared memory
66 /                            - Install signal handler for SIGUSR1
67 /
68 /
69 /  To open a mailbox         - Find a free entry in mail box infos table
70 /                            - Attach shared memory to process
71 /                            - Get PID of creator from shared memory
72 /
73 /
74 /
75 /  To close a mail box       - Remove shared memory
76 /                            - Free entry in mail box infos table
77 /                            - If last mail box, remove special shared memory
78 /
79 /
80 /  To write in a mail box    - Write message into shared memory using 
81 /                              following protocol :
82 /                                 Length Message
83 /
84 /                            - Send signal SIGUSR1 to server process
85 /
86 /
87 /  To receive message        - Get mail box identification from special shared
88 /                              memory.
89 /                            - Get message with protocol
90 /                            - Get all informations for user function
91 /                            - Call user function
92 /                            - Arm again the signal handler
93 */
94
95
96
97 #define MAX_BOX    256          /* Maximum number of mail boxes */
98
99 /* Protocol to communicate PID of server to clients */
100
101 #define BEGIN_PROTOCOL 0xAABB
102 #define END_PROTOCOL   0xCCDD
103
104 #define SIZEOFNAME     64      /* length of mailbox name */
105
106
107 /* Mail boxes informations table */
108
109 static struct {
110
111   int channel;                  /* Id of shared memory (IPC)   */
112   int  size;                    /* Size of data area           */
113   int (* user_func) ();         /* User function               */
114   char name[SIZEOFNAME];        /* Name of mail box   VMS only */
115   int *address;                /* Address of data area        */
116
117 } id_table[MAX_BOX +1];         /* Allows up to MAX_BOX mail boxes */
118 /*  char *address;   */             /* Address of data area        */
119
120 static int first_mail_box = 1;  /* Flag to initialize mail boxes */
121 static int pid;                 /* Pid of server or client       */
122 static int nb_mail = 0;
123 static int max_mail = MAX_BOX;
124
125 /* For special shared memory only */
126
127 /*static char *shared_infos;*/      /* Address of shared memory     */
128 static int *shared_infos;      /* Address of shared memory     */
129 static int   shared_shmid;      /* Id (IPC) of shared memory    */
130
131
132
133
134 static struct {
135   int code1;      /* Beginning of protocol */
136   int pid;        /* PID of server         */
137   int code2;      /* End of protocol       */
138  } protocol;
139
140
141
142
143
144
145
146
147
148
149 /*====== Private : ======================================================
150
151   find an entry in the mail_box identification table
152
153   -----------------------------------------------------------------------*/
154
155 static int
156 alloc_entry()
157 {
158  int i;
159
160  /* If first use, initialize id_table */
161
162  if (first_mail_box) {
163   memset(id_table,0,sizeof(id_table));
164   first_mail_box = 0;
165
166   /* Allocate special shared memory named "XptY"  why not ?! */
167
168   if (! create_sharedmemory(&shared_infos, "XptY", sizeof( id_table ) ))
169      max_mail = 1;
170   else {
171      shared_shmid = open_sharedmemory (&shared_infos, "XptY", sizeof (id_table) );
172      if (shared_shmid == 0) max_mail = 1;
173     }
174  }
175
176
177  i = 1;
178  while ( id_table[i].address != NULL && i < MAX_BOX)
179   i++;
180
181  if (i == MAX_BOX-1) return -1;   /* Too many mail boxes opened */
182    else return (i);
183 }
184
185
186
187
188 /*========= Private : ===================================================
189
190  Remove special shared memory (internal use) when no more mail boxes
191
192  -----------------------------------------------------------------------*/
193
194 static void
195 keep_clean()
196 {
197  remove_sharedmemory (&shared_shmid,"Xpty");
198  first_mail_box = 1;
199 }
200
201
202
203
204
205 /*========= Private : ===================================================
206
207  Set specific error for Mail boxes
208  This allow more detailed error decoding
209
210  -----------------------------------------------------------------------*/
211
212 static void
213 set_err(int number)
214 {
215  errno = number + 256;   /* Set specific error for Mail boxes */
216 }
217
218
219
220
221 /*====== Private : ======================================================
222
223   Put PID of handler process into shared memory
224   using a special protocol  AABB pid CCDD
225
226 ----------------------------------------------------------------------*/
227
228
229 void
230 put_pid(int boxid)
231 {
232  protocol.code1 = BEGIN_PROTOCOL;
233  protocol.pid   = getpid();
234  protocol.code2 = END_PROTOCOL;
235  memcpy (id_table[boxid].address, &protocol, sizeof(protocol));
236 }
237
238 int
239 get_pid(int boxid)
240 {
241  memcpy(&protocol, id_table[boxid].address, sizeof(protocol));
242  if (protocol.code1 != BEGIN_PROTOCOL) return(-1);
243  if (protocol.pid   <= 2) return(-2);
244  if (protocol.code2 != END_PROTOCOL) return(-3);
245
246  pid = protocol.pid;
247
248  return(0);
249 }
250
251
252
253
254 /*====== Private : ======================================================
255
256   Mail box handler
257
258  This simulate a VMS AST function :
259    Asynchronous function
260
261 ----------------------------------------------------------------------*/
262
263 void
264 handler(int sig)
265 {         
266  int boxid;
267  int length;
268 /* char * address;*/
269  int * address;
270  char boxname [65];
271
272  memcpy (boxname, shared_infos, SIZEOFNAME); /* Get name of mailbox */
273
274  for (boxid=1; boxid <= MAX_BOX; boxid++)
275      if (strcmp(boxname,id_table[boxid].name) == 0) break;
276
277  if (boxid > MAX_BOX) return ; /* ****** What could we do ? ***** */
278  
279  address = id_table[boxid].address;
280
281  address += sizeof(protocol);            /* Pass the protocol     JPT */
282
283  memcpy(&length, address, sizeof(int));  /* Restore length of message */
284
285  address += sizeof(int);                 /* Adjust pointer to the message */
286
287  /* Call user function */
288
289  /* Don't forget to give again PID 
290     of handler process in case of multi-clients */
291
292
293 /* call user-function */
294  
295 (*id_table[boxid].user_func) (&boxid,
296                                 id_table[boxid].name,
297                                 address,
298                                 length
299                                );
300
301  /* Re-arm handler */
302
303   signal (SIGUSR1, handler); 
304
305
306 /* don't forget to give again PID of handler process in case of multi-clients
307  */ 
308  put_pid(boxid); 
309
310 }
311
312
313
314 /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
315 /
316 /                          P U B L I C       functions
317 /
318 /@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
319
320
321
322 /*====================== Create a mail box =========================
323
324   Returns 0 if failed
325           mail box identification if succeeded
326
327   ================================================================*/
328
329 int
330 create_mailbox(char *box_name, int box_size,
331                int (* async_func) (int *box_id, char *box_name,
332                char *message_address, int message_length) )
333 {
334 /* int status;*/
335  int index;
336  int shmid;
337  
338
339  /* Test function security */
340
341  if (async_func == NULL) {
342   set_err (EFAULT);
343   return (0);  /* Verifies function exists */
344  }
345
346  if (box_size == 0){
347   set_err (EINVAL);
348   return (0);
349  }
350
351  if (box_name == NULL) {
352   set_err (EFAULT);
353   return (0);
354  }
355
356  index = alloc_entry();               /* Find an entry for id_table */
357  if (index == -1) {
358   set_err(EMFILE);
359   keep_clean();
360   return(0);
361  }
362
363  if (max_mail == 1 && index > 0) {  /* If only one mail box authorized */
364   set_err (EMFILE);
365   return(0);
366  }
367
368  /* Create shared memory for the process */
369
370  shmid = create_sharedmemory ( &id_table[index].address, box_name, box_size);
371  if (shmid == 0) return (0);
372
373
374  put_pid (index);    /* Put pid of server into shared memory  */
375
376  id_table[index].channel = shmid;              /* Keep id of shared memory */
377  id_table[index].size = box_size;              /* Keep size of mail box */
378  strncpy(id_table[index].name,box_name,SIZEOFNAME);    /* Keep name of mail box */
379  id_table[index].user_func = async_func;       /* Keep user function */
380
381
382  /* Install asynchronous function : AST function */
383
384   signal (SIGUSR1,  handler); 
385
386  nb_mail++;          
387  return (index);
388 }
389
390
391
392 /*====================== Open a mail box =======================
393
394   Returns 0 if failed
395           mail box identification if succeeded
396
397   ================================================================*/
398
399 int
400 open_mailbox(char * box_name, int box_size)
401 {
402  int status;
403  int index;    /* Index for mail box informations access */
404
405  /* Test function security */
406
407  if (box_size == 0){
408   set_err (EINVAL);
409   return (0);
410  }
411
412  if (box_name == NULL) {
413   set_err (EFAULT);
414   return (0);
415  }
416
417  index = alloc_entry();               /* Find an entry for id_table */
418  if (index == -1) {
419   set_err(EMFILE);
420   if (nb_mail == 0) keep_clean();
421   return(0);
422  }
423
424  id_table[index].size = box_size;              /* Keep size of mail box */
425  strncpy(id_table[index].name,box_name,SIZEOFNAME);    /* Keep name of mail box */
426
427  /* Attach shared memory to the process */
428
429  status = open_sharedmemory ( (int **)&id_table[index].address, box_name,
430                        box_size);
431
432  if (status !=0)
433
434  if (get_pid (index) < 0){  /* Get pid from shared memory  */
435    set_err(ESRCH);
436    return (0);
437  }
438  
439
440  id_table[index].channel = status;
441
442  if (status != 0) {
443   return (index);    
444  } 
445  else {               /* Error */
446   id_table[index].address = NULL;    /* ensure pointer is empty */
447   keep_clean();
448   return(0);
449  }
450 }
451
452
453
454
455
456 /*====================== Close a mail box =======================*/
457
458 int
459 remove_mailbox(int *boxid, char *box_name)
460 {
461  if (boxid == 0){
462   set_err(EINVAL);
463   return (0);
464  }
465
466  if (box_name == NULL) {
467   set_err(EFAULT);
468   return (0);
469  }
470
471
472 /*  (*boxid)--; JPT */
473
474  nb_mail--;
475
476  /* If last mail box removed, remove special shared memory */
477
478  if (nb_mail == 0) keep_clean(); 
479
480  remove_sharedmemory (&id_table[*boxid].channel, box_name );  /* Close shared memory */
481  id_table[*boxid].address = NULL;
482
483  return (1);
484 }
485
486
487
488 /*====================== Write into a mail box =======================*/
489
490 int
491 write_mailbox(int *boxid, char *box_name, char *message, int length)
492 {
493  int status;
494 /* char * address;*/         /* Used for protocol  :  length   message */
495  int * address;         /* Used for protocol  :  length   message */
496  int  interm_length;     /* Used to copy length into shared memory */
497
498  if (*boxid == 0){
499   set_err(EBADF);
500   return (0);
501  }
502
503  if (message == NULL) {
504   set_err(EFAULT);
505   return (0);
506  }
507
508  /* (*boxid)--; JPT */
509
510  address = id_table[*boxid].address;
511
512  address += sizeof(protocol); /* After the protocol JPT */
513
514  interm_length = length; /* Use an intermediate variable for memcpy transfert */
515
516  memcpy(address, &interm_length, sizeof(int));  /* Put length of message */
517  address += sizeof(int);                        /* Adjust address for message */
518
519  memcpy(address, message, length+1); /* Put message */
520
521  memcpy(shared_infos, id_table[*boxid].name, SIZEOFNAME ); /* Give index in table infos */
522
523  status = kill (pid, SIGUSR1);   /* Send signal to server */
524  
525   if (status == 0) return (1);
526   else {
527    set_err(errno);
528    return (0);
529   }
530 }
531 #endif