/*************************************************************************
* (C) 2008 AITNET ltd - Sofia/Bulgaria - <misho@aitbg.com>
* by Michael Pounov <misho@openbsd-bg.org>
*
* $Author: misho $
* $Id: aitsess.c,v 1.2 2011/04/30 21:35:21 misho Exp $
*
*************************************************************************/
#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, MEM_MODE);
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, MEM_MODE);
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, MEM_MODE);
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, MEM_MODE | 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, MEM_MODE | 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;
}
}
/*
* isAttached() Check for mapped/(attached) shared memory
* @s = Session item
* return: -1 null session item, 0 not attached, 1 attached memory
*/
inline int isAttached(tagSess * __restrict s)
{
if (!s)
return -1;
return (s->addr ? 1 : 0);
}
/*
* 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);
}
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>