#include "global.h" #include "aitsess.h" #pragma GCC visibility push(hidden) int sessErrno; char sessError[MAX_STR + 1]; #pragma GCC visibility pop // ----------------------------------------------------------- // Error maintenance functions ... // sess_GetErrno() Get error code of last operation inline int sess_GetErrno() { return sessErrno; } // sess_GetError() Get error text of last operation inline const char *sess_GetError() { return sessError; } // sessDbg() Debug/Logging operations static inline int sessDbg(FILE *f, char *fmt, ...) { int ret = 0; va_list lst; va_start(lst, fmt); ret = vfprintf(f, fmt, lst); va_end(lst); return ret; } // ----------------------------------------------------------- /* * initSession() Initializing session structure, if session file not exists creating with specified tech * @cnID = Technology using in session. SHARED_IPC IPC tech; SHARED_MAP BSD MemoryMap tech * @csFName = Session filename for build key and identified * @Sess = Session item * return: 0 OK new key created, -1 error: no memory or file not created, 1 OK key finded */ inline int initSession(const int cnID, const char *csFName, tagSess ** __restrict Sess) { int h, ret = 0; char szStr[MAX_STR + 1]; if (!*Sess) { *Sess = malloc(sizeof(tagSess)); if (!*Sess) { LOGERR; return -1; } } memset(*Sess, 0, sizeof(tagSess)); // If key file exist, session already connected if (!access(csFName, F_OK)) ret = 1; // Build new key & new session h = open(csFName, O_WRONLY | O_CREAT, 0640); if (h == -1) { LOGERR; free(*Sess); return -1; } bzero(szStr, MAX_STR + 1); switch (cnID) { case SHARED_IPC: strcpy(szStr, "IPC@"); break; case SHARED_MAP: strcpy(szStr, "MAP@"); break; default: errno = EPROTONOSUPPORT; LOGERR; close(h); unlink(csFName); free(*Sess); return -1; } strcat(szStr, "AN_Session ver"); strcat(szStr, "\n"); write(h, szStr, strlen(szStr)); close(h); (*Sess)->type = cnID; return ret; } /* * freeSession() Free allocated memory for session item and delete session file if present name * @csFName = Session filename for delete, if NULL nothing delete * @Sess = Session item */ inline void freeSession(const char *csFName, tagSess ** __restrict Sess) { (*Sess)->type ^= (*Sess)->type; if (csFName) unlink(csFName); if (*Sess) free(*Sess); *Sess = NULL; } /* * map_createSession() MMAP Created session and allocated resources * @csFName = Session name for identified * @cnSeed = Seed for securing key * @cnSize = Allocated shared memory size in bytes * @Sess = Session item * return: 0 Ok successful, -1 error: not allocated resources */ int map_createSession(const char *csFName, const int cnSeed, const u_int cnSize, tagSess ** __restrict Sess) { int ret = 0; char szSName[2][FILENAME_MAX + 1]; void *mem; ret = initSession(SHARED_MAP, csFName, Sess); if (ret == -1 || !*Sess) return -1; // genkey (*Sess)->key = ftok(csFName, cnSeed); if ((*Sess)->key == -1) { LOGERR; freeSession(csFName, Sess); return -1; } // build semaphore & shared memory name memset(szSName, 0, (FILENAME_MAX + 1) * 2); snprintf(szSName[0], MAX_SEMNAME + 1, "/%X.ANS", (u_int) (*Sess)->key); snprintf(szSName[1], FILENAME_MAX + 1, "%s-%x.ANM", csFName, (u_int) (*Sess)->key); mem = malloc(cnSize); if (!mem) { LOGERR; freeSession(csFName, Sess); return -1; } else memset(mem, 0, cnSize); // create semaphore & add 1 (*Sess)->id.sid = sem_open(szSName[0], O_CREAT, 0644); if ((*Sess)->id.sid == SEM_FAILED) { LOGERR; map_destroySession(csFName, Sess); free(mem); return -1; } else sem_post((*Sess)->id.sid); // create file for shared memory storage (*Sess)->mem.fd = open(szSName[1], O_RDWR | O_CREAT, 0644); if ((*Sess)->mem.fd == -1) { LOGERR; map_destroySession(csFName, Sess); free(mem); return -1; } // if is new shared memory session, fill file with zeros if (!ret) { if (write((*Sess)->mem.fd, mem, cnSize) != cnSize) { LOGERR; map_destroySession(csFName, Sess); free(mem); return -1; } if (lseek((*Sess)->mem.fd, 0, SEEK_SET)) { LOGERR; map_destroySession(csFName, Sess); free(mem); return -1; } } (*Sess)->eom = cnSize; free(mem); return ret; } /* * map_destroySession() MMAP free shared resources * @csFName = Session name for delete * @Sess = Session item */ void map_destroySession(const char *csFName, tagSess ** __restrict Sess) { int flg = 1; char szSName[2][FILENAME_MAX + 1]; if (!*Sess) return; bzero(szSName, (FILENAME_MAX + 1) * 2); snprintf(szSName[0], MAX_SEMNAME + 1, "/%X.ANS", (u_int) (*Sess)->key); snprintf(szSName[1], FILENAME_MAX + 1, "%s-%x.ANM", csFName, (u_int) (*Sess)->key); if ((*Sess)->id.sid != SEM_FAILED) { if (sem_close((*Sess)->id.sid) == -1) flg = 0; if (sem_unlink(szSName[0]) == -1) /*flg = 0*/; } if ((*Sess)->mem.fd != -1) { if (close((*Sess)->mem.fd) == -1) flg = 0; if (unlink(szSName[1]) == -1) /*flg = 0*/; } (*Sess)->eom ^= (*Sess)->eom; freeSession(flg ? csFName : NULL, Sess); } /* * ipc_createSession() IPC Created session and allocated resources * @csFName = Session name for identified * @cnSeed = Seed for securing key * @cnSize = Allocated shared memory size in bytes * @Sess = Session item * return: 0 Ok successful, -1 error: not allocated resources */ int ipc_createSession(const char *csFName, const int cnSeed, const u_int cnSize, tagSess ** __restrict Sess) { int ret = 0; union semun sems; ret = initSession(SHARED_IPC, csFName, Sess); if (ret == -1 || !*Sess) return -1; // genkey (*Sess)->key = ftok(csFName, cnSeed); if ((*Sess)->key == -1) { LOGERR; freeSession(csFName, Sess); return -1; } // create semaphore (*Sess)->id.semid = semget((*Sess)->key, 1, 0644 | IPC_CREAT); if ((*Sess)->id.semid == -1) { LOGERR; ipc_destroySession(csFName, Sess); return -1; } // if is new shared memory session, init sempahore with 1 if (!ret) { sems.val = 1; if (semctl((*Sess)->id.semid, 0, SETVAL, sems) == -1) { LOGERR; ipc_destroySession(csFName, Sess); return -1; } } // create shared memory object (*Sess)->mem.shmid = shmget((*Sess)->key, cnSize, 0644 | IPC_CREAT); if ((*Sess)->mem.shmid == -1) { LOGERR; ipc_destroySession(csFName, Sess); return -1; } (*Sess)->eom = cnSize; return ret; } /* * ipc_destroySession() IPC free shared resources * @csFName = Session name for delete * @Sess = Session item */ void ipc_destroySession(const char *csFName, tagSess ** __restrict Sess) { int flg = 1; union semun sems; struct shmid_ds ds; if (!*Sess) return; if ((*Sess)->id.semid != -1) if (semctl((*Sess)->id.semid, 0, IPC_RMID, &sems) == -1) flg = 0; if ((*Sess)->mem.shmid != -1) if (shmctl((*Sess)->mem.shmid, IPC_RMID, &ds) == -1) flg = 0; (*Sess)->eom ^= (*Sess)->eom; freeSession(flg ? csFName : NULL, Sess); } /* * map_attachSession() MMAP Attach to shared memory & return begin address * @s = Session item * @procMem = Custom start address (optionl) *default must be 0* * return: NULL failed attach, !=NULL begin address of memory */ inline void *map_attachSession(tagSess * __restrict s, void *procMem) { struct stat sb; if (!s) return NULL; // Learn size of shared memory block sync(); if (fstat(s->mem.fd, &sb) == -1) { LOGERR; return NULL; } else s->eom = sb.st_size; // attach to memory s->addr = mmap(procMem, s->eom, PROT_READ | PROT_WRITE, MAP_SHARED, s->mem.fd, 0); if (s->addr == MAP_FAILED) { LOGERR; s->addr = NULL; } return s->addr; } /* * map_detachSession() MMAP Detach from shared memory * @s = Session item */ inline void map_detachSession(tagSess * __restrict s) { if (!s) return; msync(s->addr, 0, MS_SYNC | MS_INVALIDATE); if (s->addr && s->eom) { munmap(s->addr, s->eom); s->addr = NULL; } } /* * ipc_attachSession() IPC Attach to shared memory & return begin address * @s = Session item * @procMem = Custom start address (optionl) *default must be 0* * return: NULL failed attach, !=NULL begin address of memory */ inline void *ipc_attachSession(tagSess * __restrict s, void *procMem) { if (!s) return NULL; s->addr = shmat(s->mem.shmid, procMem, 0); if (s->addr == (void*) -1) { LOGERR; s->addr = NULL; } return s->addr; } /* * ipc_detachSession() IPC Detach from shared memory * @s = Session item */ inline void ipc_detachSession(tagSess * __restrict s) { if (!s) return; if (s->addr) { shmdt(s->addr); s->addr = NULL; } } /* * map_notSemaphore() MMAP negative block if semaphore isn`t signaled * @s = Session item */ inline void map_notSemaphore(tagSess * __restrict s) { int i = -1; if (!s) return; sem_getvalue(s->id.sid, &i); for (;i > 0; i--) sem_wait(s->id.sid); } /* * map_isSemaphored() MMAP Check semaphore * @s = Session item * return: -1 error: can`t return semaphore, 0 = false, 1 = true */ inline int map_isSemaphored(tagSess * __restrict s) { int val = -1; if (!s) return -1; sem_getvalue(s->id.sid, &val); return val ? 0 : 1; } /* * map_addSemaphore() MMAP unblock semaphore, increment semaphore * @s = Session item * return: 0 Ok, -1 error: can`t increment */ inline int map_addSemaphore(tagSess * __restrict s) { if (!s) return -1; return sem_post(s->id.sid); } /* * map_decSemaphore() MMAP block semaphore, decrement semaphore * @s = Session item * return: 0 Ok, -1 error: can`t decrement */ inline int map_decSemaphore(tagSess * __restrict s) { if (!s) return -1; return sem_wait(s->id.sid); } /* * ipc_notSemaphore() IPC negative block if semaphore isn`t signaled * @s = Session item */ inline void ipc_notSemaphore(tagSess * __restrict s) { struct sembuf sb = { 0, 0, 0 }; if (s) semop(s->id.semid, &sb, 1); } /* * ipc_isSemaphored() IPC Check semaphore * @s = Session item * return: -1 error: can`t return semaphore, 0 = false, 1 = true */ inline int ipc_isSemaphored(tagSess * __restrict s) { struct sembuf sb = { 0, 0, IPC_NOWAIT }; if (!s) return -1; return semop(s->id.semid, &sb, 1) + 1; } /* * ipc_addSemaphore() IPC unblock semaphore, increment semaphore * @s = Session item * return: 0 Ok, -1 error: can`t increment */ inline int ipc_addSemaphore(tagSess * __restrict s) { struct sembuf sb = { 0, 1, 0 }; if (!s) return -1; return semop(s->id.semid, &sb, 1); } /* * ipc_decSemaphore() IPC block semaphore, decrement semaphore * @s = Session item * return: 0 Ok, -1 error: can`t decrement */ inline int ipc_decSemaphore(tagSess * __restrict s) { struct sembuf sb = { 0, -1, 0 }; if (!s) return -1; return semop(s->id.semid, &sb, 1); }