/*********************************************************************\ * Copyright (c) 1991 by Wen-King Su (wen-king@vlsi.cs.caltech.edu) * * Copyright (c) 1993 by Phil Richards (pgr@prg.ox.ac.uk) * * Copyright (c) 2004 by Radim Kolar * * * * You may copy or modify this file in any manner you wish, provided * * that this notice is always included, and that you hold the author * * harmless for any loss or damage resulting from the installation or * * use of this software. * \*********************************************************************/ #include "client.h" #include "lock.h" #include #ifndef FSP_NOLOCKING static char key_string[sizeof(FSP_KEY_PREFIX)+32]; static char code_str[] = "0123456789:_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; #include static jmp_buf my_interrupt_env; static RETSIGTYPE (*old_intr_handler)(int); static RETSIGTYPE interrupted_lock(int sig) { /* this prints the interrupt message *AND* resets the interrupt handler */ (*old_intr_handler)(sig); if (client_intr_state > 1) longjmp(my_interrupt_env, 0); } static void make_key_string(u_long server_addr, u_int server_port) { u_long v1, v2; char *p; strcpy(key_string, FSP_KEY_PREFIX); for (p = 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 flock function call *************/ /********************************************************************/ #ifdef FSP_USE_FLOCK /* this will cause an unfortunate redefinition of F_OK etc, but... */ #include int key_persists = 1; static int lock_fd; static u_int okey; u_int client_get_key(void) { if (!setjmp(my_interrupt_env)) { old_intr_handler = signal(SIGINT, interrupted_lock); if (flock(lock_fd, LOCK_EX) < 0) { perror("flock"); exit(1); } (void)signal(SIGINT, old_intr_handler); if (read(lock_fd, &okey, sizeof(okey)) < 0) { perror("read"); exit(1); } if (lseek(lock_fd, 0L, 0) < 0) { perror("seek"); exit(1); } return(okey); } ffprintf(STDERR, "?couldn't get key from lock\n"); return -1; } void client_put_key(u_int key) { if (write(lock_fd, (char*)&key, sizeof(key)) < 0) { perror("write"); exit(1); } if (lseek(lock_fd, 0L, 0) < 0) { perror("seek"); exit(1); } if (flock(lock_fd, LOCK_UN) < 0) { perror("unflock"); exit(1); } } void client_init_key(u_long server_addr, u_int server_port, u_int key) { mode_t omask; okey = key; make_key_string(server_addr, server_port); omask = umask(0); lock_fd = open(key_string, O_RDWR | O_CREAT, 0666); (void)umask(omask); } void client_finish_key(void) { (void)close(lock_fd); } #endif /********************************************************************/ /******* For those systems that has lockf function call *************/ /********************************************************************/ #ifdef FSP_USE_LOCKF int key_persists = 1; static u_int lock_fd; static u_int okey; u_int client_get_key(void) { if (!setjmp(my_interrupt_env)) { old_intr_handler = signal(SIGINT, interrupted_lock); if (lockf(lock_fd, F_LOCK, sizeof(okey)) < 0) { perror("lockf"); exit(1); } (void)signal(SIGINT, old_intr_handler); if (read(lock_fd, &okey, sizeof(okey)) < 0) { perror("readlk"); exit(1); } if (lseek(lock_fd, 0L, 0) < 0) { perror("seek"); exit(1); } return(okey); } ffprintf(STDERR, "?couldn't get key from lock\n"); return -1; } void client_put_key(u_int key) { if (write(lock_fd, &key, sizeof(key)) < 0) { perror("write"); exit(1); } if (lseek(lock_fd, 0L, 0) < 0) { perror("seek"); exit(1); } if (lockf(lock_fd, F_ULOCK, sizeof(key)) < 0) { perror("unlockf"); exit(1); } } void client_init_key(u_long server_addr, u_int server_port, u_int key) { mode_t omask; okey = key; make_key_string(server_addr, server_port); omask = umask(0); lock_fd = open(key_string, O_RDWR | O_CREAT, 0666); (void)umask(omask); } void client_finish_key(void) { (void)close(lock_fd); } #endif /********************************************************************/ /******* For those systems that has SysV shared memory + lockf ******/ /********************************************************************/ #ifdef FSP_USE_SHAREMEM_AND_LOCKF #include #include #include int key_persists = 1; static u_int *share_key; static u_int lock_fd; static int lock_shm; u_int client_get_key(void) { if (!setjmp(my_interrupt_env)) { old_intr_handler = signal(SIGINT, interrupted_lock); if (lockf(lock_fd, F_LOCK, 2) < 0) { perror("lockf"); exit(1); } (void)signal(SIGINT, old_intr_handler); return(*share_key); } ffprintf(STDERR, "?couldn't get key from lock\n"); return -1; } void client_put_key(u_int key) { *share_key = key; if (lockf(lock_fd, F_ULOCK, 2) < 0) { perror("unlockf"); exit(1); } } void client_init_key(u_long server_addr, u_int server_port, u_int key) { mode_t omask; key_t lock_key; make_key_string(server_addr, server_port); omask = umask(0); lock_fd = open(key_string, O_RDWR | O_CREAT, 0666); umask(omask); if ((lock_key = ftok(key_string, 238)) < 0) { perror("ftok"); exit(1); } if ((lock_shm = shmget(lock_key, 2*sizeof(u_int), IPC_CREAT | 0666)) < 0) { perror("shmget"); exit(1); } if (!(share_key = (u_int *)shmat(lock_shm, 0, 0))) { perror("shmat"); exit(1); } } /* I haven't got a clue what I'm doing here -- this is all guesswork! */ void client_finish_key(void) { if (shmdt((char *)share_key) < 0) { perror("shmdt"); exit(1); } shmctl(lock_shm,IPC_RMID,NULL); (void)close(lock_fd); } #endif /********************************************************************/ /******* For those who do not want to use locking *******************/ /********************************************************************/ #ifdef FSP_NOLOCKING int key_persists = 0; static u_int okey; u_int client_get_key(void) { return (int)okey; } void client_put_key(u_int key) { okey = key; } void client_init_key(u_long server_addr, u_int server_port, u_int key) { okey = key; } void client_finish_key(void) { ; } #endif /********************************************************************/ /******* For those systems that has SysV shared memory + semop ******/ /********************************************************************/ #ifdef FSP_USE_SHAREMEM_AND_SEMOP #ifdef HAVE_UNISTD_H #include #endif #include #include #include #include #ifdef _SEM_SEMUN_UNDEFINED union semun { int val; struct semid_ds *buf; unsigned short int *array; struct seminfo *__buf; }; #endif int key_persists = 1; static u_int *share_key; static int lock_shm; static int lock_sem; u_int client_get_key (void) { struct sembuf sem; sem.sem_num = 0; sem.sem_op = -1; sem.sem_flg = SEM_UNDO; if (!setjmp(my_interrupt_env)) { old_intr_handler = signal(SIGINT, interrupted_lock); if(semop(lock_sem,&sem,1) == -1 ) { perror("semop"); exit(1); } (void)signal(SIGINT, old_intr_handler); return(*share_key); } ffprintf(STDERR, "?couldn't get key from lock\n"); return -1; } void client_put_key (u_int key) { struct sembuf sem; sem.sem_num = 0; sem.sem_op = 1; sem.sem_flg = SEM_UNDO; *share_key = key; if(semop(lock_sem,&sem,1) == -1) { perror("semop"); exit(1); } } void client_init_key (u_long server_addr, u_int server_port, u_int key) { mode_t omask; key_t lock_key; int fd; union semun sun; struct sembuf sem; make_key_string(server_addr,server_port); omask = umask(0); fd = open(key_string,O_RDWR|O_CREAT,0666); umask(omask); close(fd); if((lock_key = ftok(key_string,238)) == -1) { perror("ftok"); exit(1); } if((lock_shm = shmget(lock_key,2*sizeof(u_int),IPC_CREAT|0666)) == -1) { perror("shmget"); exit(1); } if(!(share_key = (unsigned int *) shmat(lock_shm,(char*)0,0))) { perror("shmat"); exit(1); } if((lock_sem = semget(lock_key,0,0)) == -1) { /* create a new semaphore and init it */ if((lock_sem = semget(lock_key,2,IPC_CREAT|0666)) == -1) { perror("semget"); } /* we need to init this semaphore */ sun.val=1; if(semctl(lock_sem,0,SETVAL,sun) == -1) { perror("semctl setval"); exit(1); } *share_key = key; } /* increase in use counter */ sem.sem_num = 1; sem.sem_op = 1; sem.sem_flg = SEM_UNDO; if(semop(lock_sem,&sem,1) == -1) { perror("semop"); exit(1); } } void client_finish_key(void) { int rc; struct sembuf sem; if (shmdt((char *)share_key) < 0) { perror("shmdt"); exit(1); } /* check if we are only one process holding lock */ rc = semctl(lock_sem,1,GETVAL); if (rc == -1) { perror("semctl"); exit(1); } if (rc == 1) { /* safe to destroy */ if ( (semctl(lock_sem,0,IPC_RMID) < 0) || (shmctl(lock_shm,IPC_RMID,NULL) < 0) || (unlink(key_string) < 0) ) rc++;/* 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_sem,&sem,1) == -1) { perror("semop"); } } } #endif /********************************************************************/ /********************************************************************/ /********************************************************************/