view lib/fsplib/lock.c @ 952:a490d94a5b8e

2008-03-28 Brian Masney <masneyb@gftp.org> * lib/Makefile.am lib/misc.c lib/socket-connect.c lib/socket-connect-getaddrinfo.c lib/socket-connect-gethostbyname.c lib/sockutils.c lib/gftp.h - cleaned up more of the socket functions and split them up into their own files. Cleanups and bug fixes to the DNS lookup code.
author masneyb
date Fri, 28 Mar 2008 11:44:36 +0000
parents db4b34e3f83f
children 26fb4e66736c
line wrap: on
line source

#include <string.h>
#include <stdio.h>
#include "lock.h"

#if defined(__NetBSD__) || defined(sun) || defined(hpux)
#define	_SEM_SEMUN_UNDEFINED	/**/
#endif

/* ************ Locking functions ***************** */
#ifndef FSP_NOLOCKING

static char code_str[] =
    "0123456789:_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

static void make_key_string(	FSP_LOCK *lock,
                                unsigned long server_addr,
			   	unsigned long server_port)
{
  unsigned long v1, v2;
  char *p;

  strcpy(lock->key_string,FSP_KEY_PREFIX);
  for(p = lock->key_string; *p; p++);
  v1 = server_addr;
  v2 = server_port;

  *p++ = code_str[v1 & 0x3f]; v1 >>= 6;
  *p++ = code_str[v1 & 0x3f]; v1 >>= 6;
  *p++ = code_str[v1 & 0x3f]; v1 >>= 6;
  v1 = v1 | (v2 << (32-3*6));
  *p++ = code_str[v1 & 0x3f]; v1 >>= 6;
  *p++ = code_str[v1 & 0x3f]; v1 >>= 6;
  *p++ = code_str[v1 & 0x3f]; v1 >>= 6;
  *p++ = code_str[v1 & 0x3f]; v1 >>= 6;
  *p++ = code_str[v1 & 0x3f]; v1 >>= 6;
  *p   = 0;
}
#endif

/********************************************************************/
/******* For those systems that has SysV shared memory + semop ******/
/********************************************************************/
#ifdef FSP_USE_SHAREMEM_AND_SEMOP

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>

#ifdef _SEM_SEMUN_UNDEFINED
union semun
{
  int val;
  struct semid_ds *buf;
  unsigned short int *array;
  struct seminfo *__buf;
};
#endif

unsigned short client_get_key (FSP_LOCK *lock)
{
  struct sembuf sem;
  sem.sem_num = 0;
  sem.sem_op = -1;
  sem.sem_flg = SEM_UNDO;
  
  if(semop(lock->lock_sem,&sem,1) == -1 )
  {
      perror("semop lock");
  }
  return(*lock->share_key);
}

void client_set_key (FSP_LOCK *lock,unsigned short key)
{
  struct sembuf sem;

  sem.sem_num = 0;
  sem.sem_op  = 1;
  sem.sem_flg = SEM_UNDO;

  *lock->share_key = key;
  if(semop(lock->lock_sem,&sem,1) == -1) {
    perror("semop unlock");
  }
}

int client_init_key (FSP_LOCK *lock,
                            unsigned long server_addr,
			    unsigned short server_port)
{
  mode_t omask;
  key_t lock_key;
  int fd;
  union semun su;
  struct sembuf sem;

  make_key_string(lock,server_addr,server_port);

  omask = umask(0);
  fd = open(lock->key_string,O_RDWR|O_CREAT,0666);
  umask(omask);
  close(fd);

  if((lock_key = ftok(lock->key_string,238)) == -1) {
    perror("ftok");
    return -1;
  }

  if((lock->lock_shm = shmget(lock_key,2*sizeof(unsigned int),IPC_CREAT|0666)) == -1) {
    perror("shmget");
    return -1;
  }

  if(!(lock->share_key = (unsigned int *) shmat(lock->lock_shm,NULL,0))) {
    perror("shmat");
    return -1;
  }

  if((lock->lock_sem = semget(lock_key,0,0)) == -1) {
      /* create a new semaphore and init it */
      if((lock->lock_sem = semget(lock_key,2,IPC_CREAT|0666)) == -1) {
	  perror("semget");
	  return -1;
      }
      /* we need to init this semaphore */
      su.val=1;
      if(semctl(lock->lock_sem,0,SETVAL,su) == -1)
      {
	  perror("semctl setval");
	  return -1;
      }
  }

  /* increase in use counter */
  sem.sem_num = 1;
  sem.sem_op = 1;
  sem.sem_flg = SEM_UNDO;

  if(semop(lock->lock_sem,&sem,1) == -1) {
      perror("semop incuse");
  }

  return 0;
}

void client_destroy_key(FSP_LOCK *lock)
{
    int rc;
    struct sembuf sem;
    
    if (shmdt(lock->share_key) < 0)
    {
	perror("shmdt");
	return;
    }
    /* check if we are only one process holding lock */
    rc = semctl(lock->lock_sem,1,GETVAL);
    if (rc == 1)
    {
	/* safe to destroy */
	if (
	     (semctl(lock->lock_sem,0,IPC_RMID) < 0) ||
	     (shmctl(lock->lock_shm,IPC_RMID,NULL) < 0) ||
	     (unlink(lock->key_string) < 0) )
	    rc=0;/* ignore cleanup errors */
    }
    else 
	if(rc > 1)
	{
	      /* we need to decrease sem. */
	      sem.sem_num = 1;
	      sem.sem_op = -1;
	      sem.sem_flg = SEM_UNDO;

	      if(semop(lock->lock_sem,&sem,1) == -1) {
		  perror("semop decuse");
	      }
	}
}
#endif


/********************************************************************/
/******* For those who do not want to use locking *******************/
/********************************************************************/
#ifdef FSP_NOLOCKING

unsigned short client_get_key (FSP_LOCK *lock)
{
    return lock->share_key;
}

void client_set_key (FSP_LOCK *lock,unsigned short key)
{
    lock->share_key=key;
}

int client_init_key (FSP_LOCK *lock,
                            unsigned long server_addr,
			    unsigned short server_port)
{
    return 0;
}

void client_destroy_key(FSP_LOCK *lock)
{
    return;
}
#endif

/********************************************************************/
/******* For those systems that has lockf function call *************/
/********************************************************************/
#ifdef FSP_USE_LOCKF

#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

unsigned short client_get_key (FSP_LOCK *lock)
{
     unsigned int okey;

     if (lockf(lock->lock_fd, F_LOCK, sizeof(okey)) < 0)
     {
	    perror("lockf");
     }

     if (read(lock->lock_fd, &okey, sizeof(okey)) < 0)
     {
	    perror("readlk");
     }

     if (lseek(lock->lock_fd, 0L, 0) < 0)
     {
            perror("seek");
     }

    return(okey);
}

void client_set_key (FSP_LOCK *lock,unsigned short nkey)
{
    unsigned int key;

    key=nkey;

    if (write(lock->lock_fd, &key, sizeof(key)) < 0)
    {
	perror("write");
    }
    if (lseek(lock->lock_fd, 0L, 0) < 0)
    {
	perror("seek");
    }
    if (lockf(lock->lock_fd, F_ULOCK, sizeof(key)) < 0)
    {
	perror("unlockf");
    }
}

int client_init_key (FSP_LOCK *lock,
                            unsigned long server_addr,
			    unsigned short server_port)
{
    mode_t omask;

    make_key_string(lock,server_addr, server_port);

    omask = umask(0);
    lock->lock_fd = open(lock->key_string, O_RDWR | O_CREAT, 0666);
    (void)umask(omask);

    if(lock->lock_fd < 0)
	return -1;
    else
	return 0;	
}

void
client_destroy_key(FSP_LOCK *lock)
{
    (void)close(lock->lock_fd);
}
#endif