1: /*************************************************************************
2: * (C) 2008 AITNET ltd - Sofia/Bulgaria - <misho@aitbg.com>
3: * by Michael Pounov <misho@openbsd-bg.org>
4: *
5: * $Author: misho $
6: * $Id: aitsess.c,v 1.6 2012/07/22 22:13:48 misho Exp $
7: *
8: **************************************************************************
9: The ELWIX and AITNET software is distributed under the following
10: terms:
11:
12: All of the documentation and software included in the ELWIX and AITNET
13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
14:
15: Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
16: by Michael Pounov <misho@elwix.org>. All rights reserved.
17:
18: Redistribution and use in source and binary forms, with or without
19: modification, are permitted provided that the following conditions
20: are met:
21: 1. Redistributions of source code must retain the above copyright
22: notice, this list of conditions and the following disclaimer.
23: 2. Redistributions in binary form must reproduce the above copyright
24: notice, this list of conditions and the following disclaimer in the
25: documentation and/or other materials provided with the distribution.
26: 3. All advertising materials mentioning features or use of this software
27: must display the following acknowledgement:
28: This product includes software developed by Michael Pounov <misho@elwix.org>
29: ELWIX - Embedded LightWeight unIX and its contributors.
30: 4. Neither the name of AITNET nor the names of its contributors
31: may be used to endorse or promote products derived from this software
32: without specific prior written permission.
33:
34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37: ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44: SUCH DAMAGE.
45: */
46: #include "global.h"
47: #include "aitsess.h"
48:
49:
50: #pragma GCC visibility push(hidden)
51:
52: int sess_Errno;
53: char sess_Error[STRSIZ];
54:
55: #pragma GCC visibility pop
56:
57: // -----------------------------------------------------------
58:
59: // Error maintenance functions ...
60:
61: // sess_GetErrno() Get error code of last operation
62: inline int
63: sess_GetErrno()
64: {
65: return sess_Errno;
66: }
67: // sess_GetError() Get error text of last operation
68: inline const char *
69: sess_GetError()
70: {
71: return sess_Error;
72: }
73: // sess_SetErr() Set error to variables for internal use!!!
74: inline void
75: sess_SetErr(int eno, char *estr, ...)
76: {
77: va_list lst;
78:
79: sess_Errno = eno;
80: memset(sess_Error, 0, sizeof sess_Error);
81: va_start(lst, estr);
82: vsnprintf(sess_Error, sizeof sess_Error, estr, lst);
83: va_end(lst);
84: }
85:
86: // -----------------------------------------------------------
87:
88: /*
89: * sess_initSession() Initializing session structure, if session file not exists creating with specified tech
90: *
91: * @id = Technology using in session. SHARED_IPC IPC tech orSHARED_MAP BSD MemoryMap tech
92: * @csFName = Session filename for build key and identified
93: * @Sess = Session item, if =NULL allocate memory for session after use must be free!
94: * return: 0 OK new key created, -1 error: no memory or file not created, 1 OK key finded
95: */
96: int
97: sess_initSession(int id, const char *csFName, ait_sess_t ** __restrict Sess)
98: {
99: int h, ret = 0;
100: char szStr[STRSIZ];
101:
102: if (!csFName) {
103: sess_SetErr(EINVAL, "Filename is NULL");
104: return -1;
105: }
106: if (id < SHARED_UNKNOWN || id > SHARED_MAP) {
107: sess_SetErr(EPROTONOSUPPORT, "Session type not supported");
108: return -1;
109: }
110:
111: if (!*Sess) {
112: *Sess = io_malloc(sizeof(ait_sess_t));
113: if (!*Sess) {
114: LOGERR;
115: return -1;
116: }
117: }
118: memset(*Sess, 0, sizeof(ait_sess_t));
119: strlcpy((*Sess)->name, csFName, sizeof (*Sess)->name);
120:
121: h = open((*Sess)->name, O_WRONLY | O_CREAT | O_EXCL, MEM_MODE);
122: if (h == -1) {
123: if (errno != EEXIST) {
124: LOGERR;
125: io_free(*Sess);
126: return -1;
127: }
128: /* If key file exist, session already connected */
129: h = open((*Sess)->name, O_RDONLY);
130: if (h == -1) {
131: LOGERR;
132: io_free(*Sess);
133: return -1;
134: }
135: ret = read(h, szStr, sizeof szStr);
136: if (ret == -1) {
137: LOGERR;
138: close(h);
139: io_free(*Sess);
140: return -1;
141: }
142: if (!strncmp(szStr, "IPC@", 4) && id == SHARED_IPC) {
143: ret = 1;
144:
145: (*Sess)->sess.create = (int (*)(int, long, void*, ...)) ipc_createSession;
146: (*Sess)->sess.destroy = (void (*)(void*)) ipc_destroySession;
147: (*Sess)->sess.attach = (void* (*)(void*, void*)) ipc_attachSession;
148: (*Sess)->sess.detach = (void (*)(void*)) ipc_detachSession;
149: (*Sess)->sess.notSem = (void (*)(void*)) ipc_notSemaphore;
150: (*Sess)->sess.isSemOK = (int (*)(void*)) ipc_isSemaphoreOK;
151: (*Sess)->sess.incSem = (int (*)(void*)) ipc_incSemaphore;
152: (*Sess)->sess.decSem = (int (*)(void*)) ipc_decSemaphore;
153: } else if (!strncmp(szStr, "MAP@", 4) && id == SHARED_MAP) {
154: ret = 1;
155:
156: (*Sess)->sess.create = (int (*)(int, long, void*, ...)) map_createSession;
157: (*Sess)->sess.destroy = (void (*)(void*)) map_destroySession;
158: (*Sess)->sess.attach = (void* (*)(void*, void*)) map_attachSession;
159: (*Sess)->sess.detach = (void (*)(void*)) map_detachSession;
160: (*Sess)->sess.notSem = (void (*)(void*)) map_notSemaphore;
161: (*Sess)->sess.isSemOK = (int (*)(void*)) map_isSemaphoreOK;
162: (*Sess)->sess.incSem = (int (*)(void*)) map_incSemaphore;
163: (*Sess)->sess.decSem = (int (*)(void*)) map_decSemaphore;
164: } else {
165: sess_SetErr(EPROTONOSUPPORT,
166: "Session type not supported or wrong session type");
167: close(h);
168: io_free(*Sess);
169: return -1;
170: }
171: /* key found */
172: } else {
173: /* Build new key & new session */
174: if (id == SHARED_IPC) {
175: strlcpy(szStr, "IPC@", sizeof szStr);
176:
177: (*Sess)->sess.create = (int (*)(int, long, void*, ...)) ipc_createSession;
178: (*Sess)->sess.destroy = (void (*)(void*)) ipc_destroySession;
179: (*Sess)->sess.attach = (void* (*)(void*, void*)) ipc_attachSession;
180: (*Sess)->sess.detach = (void (*)(void*)) ipc_detachSession;
181: (*Sess)->sess.notSem = (void (*)(void*)) ipc_notSemaphore;
182: (*Sess)->sess.isSemOK = (int (*)(void*)) ipc_isSemaphoreOK;
183: (*Sess)->sess.incSem = (int (*)(void*)) ipc_incSemaphore;
184: (*Sess)->sess.decSem = (int (*)(void*)) ipc_decSemaphore;
185: } else if (id == SHARED_MAP) {
186: strlcpy(szStr, "MAP@", sizeof szStr);
187:
188: (*Sess)->sess.create = (int (*)(int, long, void*, ...)) map_createSession;
189: (*Sess)->sess.destroy = (void (*)(void*)) map_destroySession;
190: (*Sess)->sess.attach = (void* (*)(void*, void*)) map_attachSession;
191: (*Sess)->sess.detach = (void (*)(void*)) map_detachSession;
192: (*Sess)->sess.notSem = (void (*)(void*)) map_notSemaphore;
193: (*Sess)->sess.isSemOK = (int (*)(void*)) map_isSemaphoreOK;
194: (*Sess)->sess.incSem = (int (*)(void*)) map_incSemaphore;
195: (*Sess)->sess.decSem = (int (*)(void*)) map_decSemaphore;
196: } else {
197: sess_SetErr(EINVAL, "Session type must be specified");
198: close(h);
199: unlink(csFName);
200: io_free(*Sess);
201: return -1;
202: }
203: strlcat(szStr, "ELWIX_Session ("PACKAGE_STRING")\n", sizeof szStr);
204: write(h, szStr, strlen(szStr));
205:
206: ret = 0;
207: /* new key created */
208: }
209: close(h);
210:
211: (*Sess)->type = id;
212: (*Sess)->zcpy = (char) ret;
213: return ret;
214: }
215:
216: /*
217: * sess_freeSession() Free allocated memory for session item and delete session file if present name
218: *
219: * @Sess = Session item
220: * return: none
221: */
222: void
223: sess_freeSession(ait_sess_t ** __restrict Sess)
224: {
225: if (!Sess || !(*Sess))
226: return;
227:
228: if ((*Sess)->addr)
229: DETACH_MEMORY(*Sess);
230:
231: /*
232: memset(&(*Sess)->sess, 0, sizeof (*Sess)->sess);
233:
234: (*Sess)->type = SHARED_UNKNOWN;
235: */
236:
237: io_free(*Sess);
238: *Sess = NULL;
239: }
240:
241:
242: /*
243: * map_createSession() MMAP Created session and allocated resources
244: *
245: * @nSeed = Seed for securing key, if =-1 must add ready for use key
246: * @nSize = Allocated shared memory size in bytes
247: * @Sess = Session item
248: * @... = If nSeed == -1 add ready for use key value
249: * return: 0 Ok successful, -1 error: not allocated resources
250: */
251: int
252: map_createSession(int nSeed, long nSize, ait_sess_t * __restrict Sess, ...)
253: {
254: char szSName[2][FILENAME_MAX];
255: va_list lst;
256:
257: if (!Sess || !*Sess->name)
258: return -1;
259:
260: if (nSeed != -1) {
261: /* genkey */
262: Sess->key = ftok(Sess->name, nSeed);
263: if (Sess->key == -1) {
264: LOGERR;
265: return -1;
266: }
267: } else {
268: /* get key from va_args */
269: va_start(lst, Sess);
270: Sess->key = va_arg(lst, key_t);
271: va_end(lst);
272: }
273:
274: /* build semaphore & shared memory name */
275: memset(szSName, 0, sizeof szSName);
276: snprintf(szSName[0], MAX_SEMNAME, "/%X.ANS", (u_int) Sess->key);
277: #ifdef HAVE_SHM_OPEN
278: snprintf(szSName[1], FILENAME_MAX, "/%s-%x.ANM", Sess->name, (u_int) Sess->key);
279: #else
280: snprintf(szSName[1], FILENAME_MAX, "%s-%x.ANM", Sess->name, (u_int) Sess->key);
281: #endif
282:
283: /* create semaphore & add 1 */
284: Sess->id.sid = sem_open(szSName[0], O_CREAT, MEM_MODE);
285: if (Sess->id.sid == SEM_FAILED) {
286: LOGERR;
287: map_destroySession(Sess);
288: return -1;
289: }
290: /* if is new shared memory session, init sempahore with 1 */
291: if (!Sess->zcpy)
292: sem_post(Sess->id.sid);
293:
294: /* create file for shared memory storage */
295: #ifdef HAVE_SHM_OPEN
296: Sess->mem.fd = shm_open(szSName[1], O_RDWR | O_CREAT, MEM_MODE);
297: #else
298: Sess->mem.fd = open(szSName[1], O_RDWR | O_CREAT, MEM_MODE);
299: #endif
300: if (Sess->mem.fd == -1) {
301: LOGERR;
302: map_destroySession(Sess);
303: return -1;
304: }
305: if (!Sess->zcpy) {
306: #ifdef HAVE_SHM_OPEN
307: if (ftruncate(Sess->mem.fd, nSize) == -1) {
308: LOGERR;
309: map_destroySession(Sess);
310: return -1;
311: }
312: #else
313: /* if is new shared memory session, fill file with zeros */
314: if (lseek(Sess->mem.fd, nSize - 1, SEEK_SET) == -1) {
315: LOGERR;
316: map_destroySession(Sess);
317: return -1;
318: } else
319: write(Sess->mem.fd, "", 1);
320: lseek(Sess->mem.fd, 0, SEEK_SET);
321: #endif
322: }
323: Sess->eom = nSize;
324:
325: return (int) Sess->zcpy;
326: }
327:
328: /*
329: * map_destroySession() MMAP free shared resources
330: *
331: * @Sess = Session item
332: * return: none
333: */
334: void
335: map_destroySession(ait_sess_t * __restrict Sess)
336: {
337: char szSName[2][FILENAME_MAX];
338:
339: if (!Sess || sess_isAttached(Sess) || !*Sess->name)
340: return;
341:
342: memset(szSName, 0, sizeof szSName);
343: snprintf(szSName[0], MAX_SEMNAME, "/%X.ANS", (u_int) Sess->key);
344: #ifdef HAVE_SHM_UNLINK
345: snprintf(szSName[1], FILENAME_MAX, "/%s-%x.ANM", Sess->name, (u_int) Sess->key);
346: #else
347: snprintf(szSName[1], FILENAME_MAX, "%s-%x.ANM", Sess->name, (u_int) Sess->key);
348: #endif
349:
350: if (Sess->id.sid != SEM_FAILED) {
351: sem_close(Sess->id.sid);
352: sem_unlink(szSName[0]);
353: }
354: if (Sess->mem.fd > 2) {
355: close(Sess->mem.fd);
356: #ifdef HAVE_SHM_UNLINK
357: shm_unlink(szSName[1]);
358: #else
359: unlink(szSName[1]);
360: #endif
361: }
362: unlink(Sess->name);
363: memset(Sess->name, 0, sizeof Sess->name);
364: Sess->eom ^= Sess->eom;
365: Sess->key ^= Sess->key;
366: }
367:
368: /*
369: * ipc_createSession() IPC Created session and allocated resources
370: *
371: * @nSeed = Seed for securing key, if =-1 must add ready for use key
372: * @nSize = Allocated shared memory size in bytes
373: * @Sess = Session item
374: * @... = If nSeed == -1 add ready for use key value
375: * return: 0 Ok successful, -1 error: not allocated resources
376: */
377: int
378: ipc_createSession(int nSeed, long nSize, ait_sess_t * __restrict Sess, ...)
379: {
380: union semun sems;
381: va_list lst;
382:
383: if (!Sess || !*Sess->name)
384: return -1;
385:
386: if (nSeed != -1) {
387: /* genkey */
388: Sess->key = ftok(Sess->name, nSeed);
389: if (Sess->key == -1) {
390: LOGERR;
391: return -1;
392: }
393: } else {
394: /* get key from va_args */
395: va_start(lst, Sess);
396: Sess->key = va_arg(lst, key_t);
397: va_end(lst);
398: }
399:
400: /* create semaphore */
401: Sess->id.semid = semget(Sess->key, 1, MEM_MODE | IPC_CREAT);
402: if (Sess->id.semid == -1) {
403: LOGERR;
404: ipc_destroySession(Sess);
405: return -1;
406: }
407: /* if is new shared memory session, init sempahore with 1 */
408: if (!Sess->zcpy) {
409: sems.val = 1;
410: if (semctl(Sess->id.semid, 0, SETVAL, sems) == -1) {
411: LOGERR;
412: ipc_destroySession(Sess);
413: return -1;
414: }
415: }
416:
417: /* create shared memory object */
418: Sess->mem.shmid = shmget(Sess->key, nSize, MEM_MODE | IPC_CREAT);
419: if (Sess->mem.shmid == -1) {
420: LOGERR;
421: ipc_destroySession(Sess);
422: return -1;
423: } else
424: Sess->eom = nSize;
425:
426: return (int) Sess->zcpy;
427: }
428:
429: /*
430: * ipc_destroySession() IPC free shared resources
431: *
432: * @Sess = Session item
433: * return: none
434: */
435: void
436: ipc_destroySession(ait_sess_t * __restrict Sess)
437: {
438: union semun sems;
439: struct shmid_ds ds;
440:
441: if (!Sess || sess_isAttached(Sess))
442: return;
443:
444: if (Sess->id.semid != -1)
445: semctl(Sess->id.semid, 0, IPC_RMID, &sems);
446: if (Sess->mem.shmid != -1)
447: shmctl(Sess->mem.shmid, IPC_RMID, &ds);
448: unlink(Sess->name);
449: memset(Sess->name, 0, sizeof Sess->name);
450: Sess->eom ^= Sess->eom;
451: Sess->key ^= Sess->key;
452: }
453:
454:
455: /*
456: * map_attachSession() MMAP Attach to shared memory & return begin address
457: *
458: * @s = Session item
459: * @procMem = Custom start address (optionl) *default must be 0*
460: * return: NULL failed attach, !=NULL begin address of memory
461: */
462: void *
463: map_attachSession(ait_sess_t * __restrict s, void *procMem)
464: {
465: if (!s)
466: return NULL;
467:
468: sync();
469:
470: /* attach to memory */
471: s->addr = mmap(procMem, s->eom, PROT_READ | PROT_WRITE, MAP_SHARED, s->mem.fd, 0);
472: if (s->addr == MAP_FAILED) {
473: LOGERR;
474: s->addr = NULL;
475: }
476:
477: return s->addr;
478: }
479:
480: /*
481: * map_detachSession() MMAP Detach from shared memory
482: *
483: * @s = Session item
484: * return: none
485: */
486: void
487: map_detachSession(ait_sess_t * __restrict s)
488: {
489: if (!s)
490: return;
491:
492: msync(s->addr, 0, MS_SYNC | MS_INVALIDATE);
493:
494: if (s->addr && s->eom) {
495: munmap(s->addr, s->eom);
496: s->addr = NULL;
497: }
498: }
499:
500: /*
501: * ipc_attachSession() IPC Attach to shared memory & return begin address
502: *
503: * @s = Session item
504: * @procMem = Custom start address (optionl) *default must be 0*
505: * return: NULL failed attach, !=NULL begin address of memory
506: */
507: void *
508: ipc_attachSession(ait_sess_t * __restrict s, void *procMem)
509: {
510: if (!s)
511: return NULL;
512:
513: s->addr = shmat(s->mem.shmid, procMem, 0);
514: if (s->addr == (void*) -1) {
515: LOGERR;
516: s->addr = NULL;
517: }
518:
519: return s->addr;
520: }
521:
522: /*
523: * ipc_detachSession() IPC Detach from shared memory
524: *
525: * @s = Session item
526: * return: none
527: */
528: void
529: ipc_detachSession(ait_sess_t * __restrict s)
530: {
531: if (!s)
532: return;
533:
534: if (s->addr) {
535: shmdt(s->addr);
536: s->addr = NULL;
537: }
538: }
539:
540: /*
541: * sess_isAttached() Check for attached shared memory
542: *
543: * @s = Session item
544: * return: -1 null session item, 0 not attached, 1 attached memory
545: */
546: inline int
547: sess_isAttached(ait_sess_t * __restrict s)
548: {
549: if (!s)
550: return -1;
551:
552: return (s->addr ? 1 : 0);
553: }
554:
555:
556: /*
557: * map_notSemaphore() MMAP negative block if semaphore isn`t signaled
558: *
559: * @s = Session item
560: * return: none
561: */
562: void
563: map_notSemaphore(ait_sess_t * __restrict s)
564: {
565: int i = -1;
566:
567: if (!s)
568: return;
569:
570: sem_getvalue(s->id.sid, &i);
571: while (i > 0) {
572: sem_wait(s->id.sid);
573: i--;
574: }
575: }
576:
577: /*
578: * map_isSemaphoreOK() MMAP Check semaphore
579: *
580: * @s = Session item
581: * return: -1 error: can`t return semaphore, 0 = false, 1 = true
582: */
583: int
584: map_isSemaphoreOK(ait_sess_t * __restrict s)
585: {
586: int val = -1;
587:
588: if (!s)
589: return -1;
590:
591: sem_getvalue(s->id.sid, &val);
592: return (val ? 0 : 1);
593: }
594:
595: /*
596: * map_incSemaphore() MMAP unblock semaphore, increment semaphore
597: *
598: * @s = Session item
599: * return: 0 Ok, -1 error: can`t increment
600: */
601: int
602: map_incSemaphore(ait_sess_t * __restrict s)
603: {
604: if (!s)
605: return -1;
606:
607: return sem_post(s->id.sid);
608: }
609:
610: /*
611: * map_decSemaphore() MMAP block semaphore, decrement semaphore
612: *
613: * @s = Session item
614: * return: 0 Ok, -1 error: can`t decrement
615: */
616: int
617: map_decSemaphore(ait_sess_t * __restrict s)
618: {
619: if (!s)
620: return -1;
621:
622: return sem_wait(s->id.sid);
623: }
624:
625: /*
626: * ipc_notSemaphore() IPC negative block if semaphore isn`t signaled
627: *
628: * @s = Session item
629: * return: none
630: */
631: void
632: ipc_notSemaphore(ait_sess_t * __restrict s)
633: {
634: struct sembuf sb = { 0, 0, 0 };
635:
636: if (s)
637: semop(s->id.semid, &sb, 1);
638: }
639:
640: /*
641: * ipc_isSemaphoreOK() IPC Check semaphore
642: *
643: * @s = Session item
644: * return: -1 error: can`t return semaphore, 0 = false, 1 = true
645: */
646: int
647: ipc_isSemaphoreOK(ait_sess_t * __restrict s)
648: {
649: struct sembuf sb = { 0, 0, IPC_NOWAIT };
650:
651: if (!s)
652: return -1;
653:
654: return semop(s->id.semid, &sb, 1) + 1;
655: }
656:
657: /*
658: * ipc_incSemaphore() IPC unblock semaphore, increment semaphore
659: *
660: * @s = Session item
661: * return: 0 Ok, -1 error: can`t increment
662: */
663: int
664: ipc_incSemaphore(ait_sess_t * __restrict s)
665: {
666: struct sembuf sb = { 0, 1, 0 };
667:
668: if (!s)
669: return -1;
670:
671: return semop(s->id.semid, &sb, 1);
672: }
673:
674: /*
675: * ipc_decSemaphore() IPC block semaphore, decrement semaphore
676: *
677: * @s = Session item
678: * return: 0 Ok, -1 error: can`t decrement
679: */
680: int
681: ipc_decSemaphore(ait_sess_t * __restrict s)
682: {
683: struct sembuf sb = { 0, -1, 0 };
684:
685: if (!s)
686: return -1;
687:
688: return semop(s->id.semid, &sb, 1);
689: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>