File:  [ELWIX - Embedded LightWeight unIX -] / libaitsess / src / aitsess.c
Revision 1.2: download - view: text, annotated - select for diffs - revision graph
Sat Apr 30 21:35:21 2011 UTC (13 years, 1 month ago) by misho
Branches: MAIN
CVS tags: sess2_1, SESS2_0, HEAD
VER 2.0

/*************************************************************************
* (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>