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