/* * Lock Server 1.0 * Copyright (C) 2003 Cole Tuininga, Andrew Cameron * Copyright (C) 2000-2002 Cole Tuininga * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef __MINGW32__ #define FD_SETSIZE 1024 #endif #include #include #include #include #include #include #ifdef __MINGW32__ #include "syslog.h" #else #include #endif #include #include #include #ifndef __MINGW32__ #include #endif #include #include #include #include #ifdef __MINGW32__ #include #include #include #define ioctl ioctlsocket WORD wVersionRequested; WSADATA wsaData; int err; #else #include #include #include #include #include #endif #ifndef SIGSYS #define SIGSYS SIGUNUSED #endif #ifdef __MINGW32__ #define SIGPIPE 3 #define SIGHUP 5 #define SIGTSTP 8 #define SIGSTOP 16 #define SIGUSR1 18 #define SIGUNUSED 99 #endif #ifndef __MINGW32__ #ifndef HOME #define HOME "/usr/local/lockserver" #endif #else #ifndef HOME #define HOME "/lockserver" #endif #endif #define LOCKFILE ".lf" #define REPORTFILE "ls.report" #define LOCKDUMP "lockdump" #define HOSTS "hosts" #define CONFIG "config" #define MAGIC "lserv" #define HASHSIZE 40 #define MAXHOSTS 256 #define MAXCONQUEUE 500 #define PORTNUM 8675 #define SELWAITS 0 #define SELWAITU 500000 /* Commands */ #define WHOOWNS 0x1 #define GIMME 0x2 #define CONTLOC 0x3 #define RENEW 0x4 #define RELSPEC 0x5 #define RELALL 0x6 #define SHOWCONT 0x7 #define STATS 0x8 typedef struct { unsigned long TTL; unsigned long TTW; time_t RequestTS; time_t LastUpdateTS; time_t ObtainTS; char *key; char *index; char *owner; unsigned short priority; } lock; typedef struct lq { lock *l; struct lq *next; } lockqueue; /* Function prototypes */ void read_hosts(FILE *); int read_old_locks(int); void write_current_locks(int); void noble_no_death(); void noble_death(); void noble_death_and_a_core(); void graceful_death(); void close_sockets(); void close_socket(int); void reload_configs(); int check_ip(char *); void do_cleanup(); void client_deal(int); int hashfunction(char *); lock *find_owner(char *, char *); lock *find_lock(char *, char *, char *); unsigned int kill_off(char *, char *, char *); unsigned int kill_all(char *); unsigned int add_contender(lock *); unsigned int get_contend_loc(lock *); char *format_time(int); void pd(char *); /* print debug */ #ifdef __MINGW32__ int write_socket(SOCKET s, const char *buf, int len); int read_socket(SOCKET s, char *buf, int len); #endif /* Globals */ lockqueue *owners[HASHSIZE]; lockqueue *contenders[HASHSIZE]; #ifndef __MINGW32__ int open_sockets[MAXCONQUEUE]; #else SOCKET open_sockets[MAXCONQUEUE]; #endif char *allow_hosts[MAXHOSTS]; int debug; time_t startTS; long requests[10]; long rejects=0; long okeedokee=0; long badboys=0; int graceclose=0; fd_set readfds, testfds; int main(int argc, char *argv[]) { int fd, i, j, result, cip, len, readytoclose, nread, nb; FILE *fh; DIR *dp; char *lockfile, *lockdump, *hostfile; char **addrs=0; struct timeval *selwait; #ifndef __MINGW32__ int server_sockfd, client_sockfd; size_t server_len, client_len; #else SOCKET server_sockfd, client_sockfd; size_t server_len, client_len; #endif struct sockaddr_in server_address; struct sockaddr_in client_address; struct sockaddr_in sin; struct hostent *host; debug = 0; if(argc > 1 && !strcmp(argv[1],"-d")) { debug = 1; } /* #ifdef __MINGW32__ debug =1; #endif */ /* If the "HOME" directory doesn't exist, we're creating it. So there. 8P~ */ pd("Checking \"HOME\" directory..."); dp=opendir(HOME); if(!dp) { #ifdef __MINGW32__ if(mkdir(HOME) == -1) { #else if(mkdir(HOME, 0700) == -1) { #endif /* Ok - maybe we're not creating it. 87( */ openlog("lockserver", LOG_PID, LOG_DAEMON); syslog(LOG_ERR, "Could not create HOME directory."); syslog(LOG_ERR, strerror(errno)); closelog(); exit(EXIT_FAILURE); } } else { closedir(dp); } pd("Okee dokee.\n"); /* Let's make sure we're alone out here... */ pd("Getting lock..."); lockfile = (char *) malloc(sizeof(char) * \ ( strlen(LOCKFILE) + strlen(HOME) + 2)); sprintf(lockfile,"%s/%s",HOME,LOCKFILE); fd = open(lockfile, (O_RDWR | O_CREAT | O_EXCL), \ (S_IRUSR | S_IWUSR)); if(fd == -1) { openlog("lockserver", LOG_PID, LOG_DAEMON); syslog(LOG_ERR,"Can't get lockfile."); syslog(LOG_ERR, strerror(errno)); closelog(); exit(EXIT_FAILURE); } close(fd); pd("Okee dokee.\n"); /* Make sure we have CLEAN hash - none of this imported stuff */ for(i = 0; i < HASHSIZE; i++) { owners[i] = (lockqueue *) 0; contenders[i] = (lockqueue *) 0; } for(i = 0; i < MAXCONQUEUE; i++) open_sockets[i] = -1; pd("Reading from old lock file "); /* Read from the old lock file */ lockdump = (char *) malloc (sizeof(char) * \ (strlen(HOME) + strlen(LOCKDUMP) + 2)); sprintf(lockdump, "%s/%s", HOME, LOCKDUMP); fd=open(lockdump, O_RDONLY); if(fd != -1) { read_old_locks(fd); close(fd); } pd(" done.\n"); pd("Read acceptable hosts "); /* Read list of acceptable hosts */ for(i = 0; i < MAXHOSTS; i++) allow_hosts[i]=(char *) 0; hostfile = (char *) malloc (sizeof(char) * \ (strlen(HOME) + strlen(HOSTS) + 2)); sprintf(hostfile, "%s/%s", HOME, HOSTS); fh = fopen(hostfile, "r"); if(!fh) { openlog("lockserver", LOG_PID, LOG_DAEMON); syslog(LOG_ERR, "Can't open allowed hosts file."); syslog(LOG_ERR, strerror(errno)); closelog(); unlink(lockfile); exit(EXIT_FAILURE); } else { read_hosts(fh); fclose(fh); } free(hostfile); pd(" read.\n"); time(&startTS); /* Daemonize ourselves... */ #ifndef __MINGW32__ if(!debug) { if(fork() == 0) { int fl; int num_fds = getdtablesize(); for(fl = 0; fl <= num_fds; ++fl) close(fl); setsid(); } else exit(EXIT_SUCCESS); chdir("/"); umask(0); } #endif /* Signal settings */ signal(SIGINT, noble_death); signal(SIGTSTP, noble_death); signal(SIGSTOP, noble_death); signal(SIGSEGV, noble_death_and_a_core); signal(SIGHUP, reload_configs); signal(SIGSYS, graceful_death); signal(SIGUSR1, noble_no_death); signal(SIGPIPE, SIG_IGN); /* Here's the meat folks - this is the stuff that "does it" */ #ifndef __MINGW32__ server_sockfd = socket(AF_INET, SOCK_STREAM, 0); #else wVersionRequested = MAKEWORD( 2, 2 ); err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) { /* Tell the user that we could not find a usable */ /* WinSock DLL. */ pd("Unable to find a Suitable Winsock DLL\n"); } /* Confirm that the WinSock DLL supports 2.2.*/ /* Note that if the DLL supports versions greater */ /* than 2.2 in addition to 2.2, it will still return */ /* 2.2 in wVersion since that is the version we */ /* requested. */ if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 ) { /* Tell the user that we could not find a usable */ /* WinSock DLL. */ WSACleanup( ); pd("Unable to find a Suitable Winsock DLL\n"); } /* The WinSock DLL is acceptable. Proceed. */ server_sockfd = socket(AF_INET, SOCK_STREAM, 0); #endif server_address.sin_family = AF_INET; server_address.sin_port = htons(PORTNUM); server_address.sin_addr.s_addr = htonl(INADDR_ANY); server_len = sizeof(server_address); result = bind(server_sockfd, (struct sockaddr *)&server_address, server_len); if(result == -1) { openlog("lockserver", LOG_PID, LOG_DAEMON); syslog(LOG_WARNING, "Binding problem."); syslog(LOG_WARNING, strerror(errno)); closelog(); } while(result == -1) { sleep(1); result = bind(server_sockfd, (struct sockaddr *)&server_address, server_len); if(result != -1) pd("Cool - we finally bound!\n"); } result = listen(server_sockfd, MAXCONQUEUE); open_sockets[0] = server_sockfd; selwait = (struct timeval *) malloc (sizeof(struct timeval)); FD_ZERO(&readfds); FD_SET(server_sockfd, &readfds); pd("Server socket is set up...\n"); while(1) { selwait->tv_sec = (time_t) SELWAITS; selwait->tv_usec = (long) SELWAITU; testfds = readfds; result = select(FD_SETSIZE, &testfds, (fd_set *) 0, (fd_set *) 0, selwait); if(result == 0) { /* Timed out */ do_cleanup(); } else if(result != -1) { /* Time to deal with a client */ do_cleanup(); for(fd = 0; fd < FD_SETSIZE; fd++) { if(FD_ISSET(fd, &testfds) && fd == server_sockfd) { /* Time for a new client */ client_len=sizeof(client_address); #ifndef __MINGW32__ client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_address, &client_len); #else client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_address,&client_len); if(client_sockfd == INVALID_SOCKET) { result = WSAGetLastError(); } #endif for(i = 0; i < MAXCONQUEUE && open_sockets[i] != -1 && open_sockets[i] != client_sockfd; i++); if(i >= MAXCONQUEUE) { /* We're full - go away! */ rejects ++; j = 2; #ifndef __MINGW32__ write(client_sockfd, &j, 1); #else write_socket(client_sockfd, &j, 1); #endif close_socket(client_sockfd); } else { len = sizeof sin; if(getpeername(client_sockfd, (struct sockaddr *) &sin, &len) < 0) { openlog("lockserver", LOG_PID, LOG_DAEMON); syslog(LOG_ERR, strerror(errno)); closelog(); noble_death(); } else { if((host = gethostbyaddr((char *) &sin.sin_addr, sizeof(sin.sin_addr), AF_INET)) == NULL) { openlog("lockserver", LOG_PID, LOG_DAEMON); syslog(LOG_ERR, strerror(errno)); closelog(); noble_death(); } else addrs = host->h_addr_list; } cip = 0; while(*addrs && !cip) { if(check_ip(inet_ntoa(*(struct in_addr *)*addrs))) cip = 1; addrs++; } if(!cip) { badboys++; j = 0; write(client_sockfd, &j, 1); pd("Host not allowed! Closing connection.\n"); close_socket(client_sockfd); } else { okeedokee++; j = 1; #ifndef __MINGW32__ nb = write(client_sockfd, &j, 1); #else nb = write_socket(client_sockfd, &j, 1); #endif if(nb == -1 && errno == EPIPE) { close_socket(client_sockfd); } else { open_sockets[i] = client_sockfd; pd("Host accepted.\n"); FD_SET(client_sockfd, &readfds); client_deal(client_sockfd); } } } } else if(FD_ISSET(fd, &testfds)) { ioctl(fd, FIONREAD, &nread); if(nread) { /* Client wants something */ client_deal(fd); } else { /* Client is gone... */ close_socket(fd); } } } } if(graceclose) { /* Check to see if we're ready to die */ readytoclose = 1; for(i = 0; i < HASHSIZE; i++) { if(owners[i] || contenders[i]) readytoclose = 0; } if(readytoclose) { pd("Ok - it's time to go...\n"); close_sockets(); lockfile = (char *) malloc(sizeof(char) * \ (strlen(LOCKFILE) + strlen(HOME) + 2)); sprintf(lockfile,"%s/%s",HOME,LOCKFILE); unlink(lockfile); free(lockfile); exit(EXIT_SUCCESS); } } } #ifndef __MINGW32__ close(server_sockfd); #else closesocket(server_sockfd); #endif unlink(lockfile); exit(EXIT_SUCCESS); } int read_old_locks(int fd) { lockqueue *search; lock *l; time_t dt, ut, diff; int i, j, oc, hashsize, hashent, numlocks, retval=0; int keylen, indlen, ownlen; char *c; c = (char *) malloc (sizeof(char) * (strlen(MAGIC) + 1)); read(fd, c, strlen(MAGIC)); c[strlen(MAGIC)] = '\0'; if(strcmp(c, MAGIC)) { openlog("lockserver", LOG_PID, LOG_DAEMON); syslog(LOG_WARNING, "Incorrect magic from saved locks. Old lock file unusable."); closelog(); return -1; } free(c); time(&ut); read(fd, &dt, sizeof(time_t)); diff = ut - dt; read(fd, &hashsize, sizeof(int)); if(hashsize != HASHSIZE) { openlog("lockserver", LOG_PID, LOG_DAEMON); syslog(LOG_WARNING, "Different hash size in saved locks. Old lock file unusable."); closelog(); return -1; } for(oc = 0; oc < 2; oc ++) { for(i = 0; i < hashsize; i++) { pd("."); read(fd, &hashent, sizeof(int)); read(fd, &numlocks, sizeof(int)); search = 0; for(j = 0; j < numlocks; j++) { retval ++; l = (lock *) malloc (sizeof(lock)); read(fd, &(l->TTL), sizeof(long)); read(fd, &(l->TTW), sizeof(long)); read(fd, &(l->RequestTS), sizeof(time_t)); read(fd, &(l->LastUpdateTS), sizeof(time_t)); l->LastUpdateTS += diff; read(fd, &(l->ObtainTS), sizeof(time_t)); read(fd, &keylen, sizeof(int)); l->key = (char *) malloc (sizeof(char) * (keylen + 1)); read(fd, l->key, keylen); l->key[keylen] = '\0'; read(fd, &indlen, sizeof(int)); l->index = (char *) malloc (sizeof(char) * (indlen + 1)); read(fd, l->index, indlen); l->index[indlen] = '\0'; read(fd, &ownlen, sizeof(int)); l->owner = (char *) malloc (sizeof(char) * (ownlen + 1)); read(fd, l->owner, ownlen); l->owner[ownlen] = '\0'; read(fd, &(l->priority), sizeof(short)); if(!search) { search = (lockqueue *) malloc (sizeof(lockqueue)); if(!oc) { owners[hashent] = search; } else { contenders[hashent] = search; } } else { search->next = (lockqueue *) malloc (sizeof(lockqueue)); search = search->next; } search->l = l; search->next = 0; } } } return retval; } void write_current_locks(int fd) { lockqueue *search; char *c; int i, numqueue, size; time_t dt; c = (char *) malloc (sizeof(char) * (strlen(MAGIC) + 1)); strncpy(c, MAGIC, (strlen(MAGIC) + 1)); write(fd, c, strlen(c)); free(c); time(&dt); write(fd, &dt, sizeof(time_t)); numqueue = HASHSIZE; write(fd, &numqueue, sizeof(int)); for(i = 0; i < HASHSIZE; i++) { pd("."); /* The index */ write(fd, &i, sizeof(int)); /* Num indexes */ search = owners[i]; numqueue = 0; while(search) { numqueue++; search = search->next; } write(fd, &numqueue, sizeof(int)); /* The entries */ search = owners[i]; while(search) { write(fd, &(search->l->TTL), sizeof(long)); write(fd, &(search->l->TTW), sizeof(long)); write(fd, &(search->l->RequestTS), sizeof(time_t)); write(fd, &(search->l->LastUpdateTS), sizeof(time_t)); write(fd, &(search->l->ObtainTS), sizeof(time_t)); size = strlen(search->l->key); write(fd, &size, sizeof(int)); write(fd, search->l->key, strlen(search->l->key)); size = strlen(search->l->index); write(fd, &size, sizeof(int)); write(fd, search->l->index, strlen(search->l->index)); size = strlen(search->l->owner); write(fd, &size, sizeof(int)); write(fd, search->l->owner, strlen(search->l->owner)); write(fd, &(search->l->priority), sizeof(short)); search = search->next; } } for(i = 0; i < HASHSIZE; i++) { pd("."); /* The index */ write(fd, &i, sizeof(int)); /* Num indexes */ search = contenders[i]; numqueue = 0; while(search) { numqueue++; search = search->next; } write(fd, &numqueue, sizeof(int)); /* The entries */ search = contenders[i]; while(search) { write(fd, &(search->l->TTL), sizeof(long)); write(fd, &(search->l->TTW), sizeof(long)); write(fd, &(search->l->RequestTS), sizeof(time_t)); write(fd, &(search->l->LastUpdateTS), sizeof(time_t)); write(fd, &(search->l->ObtainTS), sizeof(time_t)); size = strlen(search->l->key); write(fd, &size, sizeof(int)); write(fd, search->l->key, strlen(search->l->key)); size = strlen(search->l->index); write(fd, &size, sizeof(int)); write(fd, search->l->index, strlen(search->l->index)); size = strlen(search->l->owner); write(fd, &size, sizeof(int)); write(fd, search->l->owner, strlen(search->l->owner)); write(fd, &(search->l->priority), sizeof(short)); search = search->next; } } return; } void reload_configs() { FILE *fh; char *hostfile; int i; for(i = 0; i < MAXHOSTS; i++) { if(allow_hosts[i]) free(allow_hosts[i]); allow_hosts[i] = 0; } hostfile = (char *) malloc (sizeof(char) * \ (strlen(HOME) + strlen(HOSTS) + 2)); sprintf(hostfile, "%s/%s", HOME, HOSTS); fh = fopen(hostfile, "r"); read_hosts(fh); fclose(fh); free(hostfile); return; } void read_hosts(FILE *fh) { char buffer[17]; int i, j, firstempty = -1; /* Find the first empty entry */ for(i = 0; i < MAXHOSTS && allow_hosts[i]; i++); if(i < MAXHOSTS) firstempty=i; if(firstempty == -1) return; for(i = 0; i < MAXHOSTS && fgets(buffer, 17, fh); i++) { pd("."); buffer[strlen(buffer)-1]='\0'; for(j = 0; allow_hosts[j] && strcmp(buffer,allow_hosts[j]) \ && j < MAXHOSTS; j++); if(!allow_hosts[i] || j >= MAXHOSTS) { allow_hosts[(i + firstempty)] = (char *) malloc \ (sizeof(char) * (strlen(buffer) + 1)); strncpy(allow_hosts[(i + firstempty)], buffer, \ (sizeof(char) * (strlen(buffer) + 1))); } } if( i >= MAXHOSTS && fgets(buffer, 17, fh)) { openlog("lockserver", LOG_PID, LOG_DAEMON); syslog(LOG_WARNING, "Hosts table full."); closelog(); } return; } void close_socket(int fd) { int nread, i, garbage; ioctl(fd, FIONREAD, &nread); if(nread) for(i = 0; i < nread; i++) read(fd, &garbage, 1); for(i = 0; i < MAXCONQUEUE && open_sockets[i] != fd; i++); if(i < MAXCONQUEUE) { shutdown(fd, 0); #ifdef __MINGW32__ closesocket(fd); #else close(fd); #endif open_sockets[i] = -1; FD_CLR(fd, &readfds); } return; } void close_sockets() { int i; pd("Closing sockets ... "); for(i = 0; i < MAXCONQUEUE; i++) { if(open_sockets[i] != -1) { #ifndef __MINGW32__ close(open_sockets[i]); #else closesocket(open_sockets[i]); #endif open_sockets[i] = -1; } } pd("done.\n"); return; } void noble_no_death() { int fd; FILE *fh; char *ftime; char *lockstat = (char *) malloc (sizeof(char) * \ (strlen(HOME) + strlen(REPORTFILE) + 2)); char *lockdump = (char *) malloc (sizeof(char) * \ (strlen(HOME) + strlen(LOCKDUMP) + 2)); unsigned int i, j; unsigned long m; lockqueue *s; time_t t,dif; pd("Dumping stats..."); sprintf(lockstat, "%s/%s", HOME, REPORTFILE); fh = fopen(lockstat,"w"); if(fh) { time(&t); dif = t - startTS; fprintf(fh, "Uptime: "); ftime = format_time(dif); fprintf(fh, "%s\n", ftime); fprintf(fh, "\n"); fprintf(fh, "Lock requests: ............ %ld\n", requests[GIMME]); fprintf(fh, "Owner lookups: ............ %ld\n", requests[WHOOWNS]); fprintf(fh, "Location lookups: ......... %ld\n", requests[CONTLOC]); fprintf(fh, "Lock renewals: ............ %ld\n", requests[RENEW]); fprintf(fh, "Specific lock releases: ... %ld\n", requests[RELSPEC]); fprintf(fh, "General lock releases: .... %ld\n", requests[RELALL]); fprintf(fh, "Lock dump requests: ....... %ld\n", requests[SHOWCONT]); fprintf(fh, "Statistics requests: ...... %ld\n", requests[STATS]); fprintf(fh, "\n"); fprintf(fh, "Unknown commands: ......... %ld\n", requests[0]); fprintf(fh, "\n"); fprintf(fh, "Accepted connections: ..... %ld\n", okeedokee); fprintf(fh, "Rejected connections: ..... %ld\n", badboys); fprintf(fh, "Too full connections: ..... %ld\n", rejects); for(i = 1, j = 0; i < MAXCONQUEUE; i++) if(open_sockets[i] != -1) j++; fprintf(fh, "Current connections: ...... %d\n", j); fprintf(fh, "\n"); for(i = 0, m = 0; i < HASHSIZE; i++) { s = owners[i]; while(s) { m++; s = s->next; } } fprintf(fh, "Current lock owners: ...... %ld\n", m); for(i = 0, m = 0; i < HASHSIZE; i++) { s = contenders[i]; while(s) { m++; s = s->next; } } fprintf(fh, "Current lock contenders: .. %ld\n", m); free(ftime); fclose(fh); pd("dumped.\n"); } else pd("Unsuccessful dump.\n"); pd("Dumping locks to dumpfile "); sprintf(lockdump, "%s/%s", HOME, LOCKDUMP); fd = open(lockdump, (O_WRONLY | O_CREAT | O_TRUNC), \ (S_IRUSR | S_IWUSR)); if(fd != -1) { write_current_locks(fd); close(fd); } free(lockdump); pd(" done.\n"); requests[STATS] ++; return; } void graceful_death() { if(!graceclose) { pd("Ahhh ... a graceful closing.\n"); graceclose = 1; } else { pd("Changed our minds - not closing down.\n"); graceclose = 0; } return; } void noble_death() { int fd; char *lockfile; char *lockdump = (char *) malloc (sizeof(char) * \ (strlen(HOME) + strlen(LOCKDUMP) + 2)); pd("Preparing to die in a noble manner ...\n"); close_sockets(); pd("Dumping locks to dumpfile "); sprintf(lockdump,"%s/%s",HOME,LOCKDUMP); fd = open(lockdump, (O_WRONLY | O_CREAT | O_TRUNC), \ (S_IRUSR | S_IWUSR)); if(fd != -1) { write_current_locks(fd); close(fd); } free(lockdump); pd(" done.\n"); lockfile = (char *) malloc(sizeof(char) * \ ( strlen(LOCKFILE) + strlen(HOME) + 2)); sprintf(lockfile,"%s/%s",HOME,LOCKFILE); unlink(lockfile); free(lockfile); pd("Fa\n"); pd(" r\n"); pd(" e\n"); pd("\n"); pd(" t\n"); pd(" h\n"); pd(" e\n"); pd(" e\n"); pd("\n"); pd(" w\n"); pd(" e\n"); pd(" l\n"); pd(" l\n"); pd(" .\n"); pd(" .\n"); pd(" .\n"); exit(EXIT_SUCCESS); } void noble_death_and_a_core() { char *lockfile; pd("Alas ... for I am dying ... I have been slain by the fault of seg...\n"); openlog("lockserver", LOG_PID, LOG_DAEMON); syslog(LOG_ERR, "Seg fault has occurred. Shutting down.\n"); closelog(); close_sockets(); lockfile = (char *) malloc(sizeof(char) * \ ( strlen(LOCKFILE) + strlen(HOME) + 2)); sprintf(lockfile,"%s/%s",HOME,LOCKFILE); unlink(lockfile); free(lockfile); pd("Fa\n"); pd(" r\n"); pd(" e\n"); pd("\n"); pd(" t\n"); pd(" h\n"); pd(" e\n"); pd(" e\n"); pd("\n"); pd(" w\n"); pd(" e\n"); pd(" l\n"); pd(" l\n"); pd(" .\n"); pd(" .\n"); pd(" .\n"); abort(); } int check_ip(char *ip) { int i; for(i = 0; allow_hosts[i] && i < MAXHOSTS; i++) { if(!strcmp(ip, allow_hosts[i])) return(1); } return(0); } typedef struct il { char *index; struct il *next; } index_list; #define MAXSYMBOLS 65536 char *keys[MAXSYMBOLS], *ct; index_list *indexes[MAXSYMBOLS], *iter, *liter; /* This is the "reaper" so to speak. It goes through and cleans out that which needs cleaning. Usurps some, smacks others...*/ void do_cleanup() { lockqueue *search, *last = 0, *findend, *n; int i,j; time_t t; /* Clear the stuff */ for(i = 0; i < MAXSYMBOLS; i++) { keys[i] = (char *) 0; indexes[i] = (index_list *) 0; } time(&t); /* First we're going to clean house. If ya be timed out, you're getting swept out with the garbage. Now. */ for(i = 0; i < HASHSIZE; i++) { /* Owners... */ last = 0; search = owners[i]; while(search) { if((t - search->l->LastUpdateTS) > search->l->TTL) { /* heh heh ... let the reaping begin! */ pd("We're reaping an owner. BWAH HAH HAH HAH HAH HA HA!\n"); pd("\tKey: "); pd(search->l->key); pd("\n"); pd("\tIndex: "); pd(search->l->index); pd("\n"); pd("\tOwner: "); pd(search->l->owner); pd("\n"); if(!last) { owners[i] = search->next; free(search->l->key); free(search->l->index); free(search->l->owner); free(search->l); free(search); search = owners[i]; } else { last->next = search->next; free(search->l->key); free(search->l->index); free(search->l->owner); free(search->l); free(search); search = last->next; } } else { last = search; search = search->next; } } /* ... and contenders */ last = 0; search = contenders[i]; while(search) { if((t - search->l->LastUpdateTS) > search->l->TTW) { /* heh heh ... let the reaping begin! */ pd("We're reaping a contender. BWAH HAH HAH HAH HAH HA HA!\n"); pd("\tKey: "); pd(search->l->key); pd("\n"); pd("\tIndex: "); pd(search->l->index); pd("\n"); pd("\tOwner: "); pd(search->l->owner); pd("\n"); if(!last) { contenders[i] = search->next; free(search->l->key); free(search->l->index); free(search->l->owner); free(search->l); free(search); search = contenders[i]; } else { last->next = search->next; free(search->l->key); free(search->l->index); free(search->l->owner); free(search->l); free(search); search = last->next; } } else { last = search; search = search->next; } } } /* Ok - now for the fun. We have to decide who gets to become * lock owners. Here's the premise. We go through the owners * and find out what keys/indexes are already locked. From * there we start wading through the contenders, and moving * them if appropriate. * * My apologies if this logic is incomprehensible. 8) */ for(i = 0; i < HASHSIZE; i++) { search = owners[i]; while(search) { for(j = 0; keys[j] && strcmp(keys[j], search->l->key) && j < MAXSYMBOLS; j++); if(keys[j]) { iter = indexes[j]; liter = 0; while(iter && strcmp(iter->index, search->l->index)) { liter = iter; iter = iter->next; } if(!iter) { iter = (index_list *) malloc (sizeof(index_list)); iter->index = (char *) malloc (sizeof(char) * \ (strlen(search->l->index) + 1)); strncpy(iter->index, search->l->index, \ (strlen(search->l->index) + 1)); iter->next = (index_list *) 0; if(!liter) indexes[j] = iter; else liter->next = iter; } } else if (j == MAXSYMBOLS) { openlog("lockserver", LOG_PID, LOG_DAEMON); syslog(LOG_ERR, \ "Ran out of room for symbols during cleanup."); closelog(); noble_death(); } else { /* Ahh - new key for us */ keys[j] = (char *) malloc (sizeof(char) * \ (strlen(search->l->key) + 1)); strncpy(keys[j], search->l->key, (strlen(search->l->key) + 1)); iter = (index_list *) malloc (sizeof(index_list)); iter->index = (char *) malloc (sizeof(char) * \ (strlen(search->l->index) + 1)); strncpy(iter->index, search->l->index, \ (strlen(search->l->index) + 1)); iter->next = (index_list *) 0; indexes[j] = iter; } search = search->next; } } for(i = 0; i < HASHSIZE; i++) { search = contenders[i]; last = 0; while(search) { for(j = 0; keys[j] && strcmp(keys[j], search->l->key) && j < MAXSYMBOLS; j++) {}; if(keys[j]) { iter = indexes[j]; /* If we are looking for a broad based lock and there * are any indexes, we have to make sure nobody else * goes after the lock, so we fake it as locked. Then * we just move on with life. */ if(indexes[j] && !strcmp(search->l->key,"*")) { while(iter->next) iter = iter->next; iter->next = (index_list *) malloc (sizeof(index_list)); iter = iter->next; iter->index = (char *) malloc (sizeof(char) * 2); iter->next = 0; strcpy(iter->index,"*"); search = search->next; continue; } /* find if there's an index we care about */ iter = indexes[j]; while(iter && strcmp(iter->index, search->l->index) && strcmp(iter->index, "*")) { iter = iter->next; } if(!iter) { iter = indexes[j]; while(iter->next) iter = iter->next; iter->next = (index_list *) malloc (sizeof(index_list)); iter = iter->next; iter->next = 0; iter->index = (char *) malloc (sizeof(char) * \ (strlen(search->l->index) + 1)); strncpy(iter->index, search->l->index, \ (strlen(search->l->index) + 1)); if(last) last->next = search->next; else contenders[i] = search->next; findend = owners[i]; while(findend && findend->next) findend = findend->next; n = search; n->next = 0; time(&t); n->l->LastUpdateTS = t; n->l->ObtainTS = t; if(last) search = last->next; else search = contenders[i]; if(findend) findend->next = n; else owners[i] = n; } else /* else somebody already has the lock */ search = search->next; } else if (j == MAXSYMBOLS) { openlog("lockserver", LOG_PID, LOG_DAEMON); syslog(LOG_ERR, \ "Ran out of room for symbols during cleanup."); closelog(); noble_death(); } else { /* Mark it as locked */ keys[j] = (char *) malloc (sizeof(char) * \ (strlen(search->l->key) + 1)); strncpy(keys[j], search->l->key, (strlen(search->l->key) + 1)); iter = (index_list *) malloc (sizeof(index_list)); iter->index = (char *) malloc (sizeof(char) * \ (strlen(search->l->index) + 1)); strncpy(iter->index, search->l->index, \ (strlen(search->l->index) + 1)); iter->next = (index_list *) 0; indexes[j] = iter; /* And move them to lock */ if(last) last->next = search->next; else contenders[i] = search->next; findend = owners[i]; while(findend && findend->next) findend = findend->next; n = search; n->next = 0; time(&t); n->l->LastUpdateTS = t; if(last) search = last->next; else search = contenders[i]; if(findend) findend->next = n; else owners[i] = n; } } } for(i = 0; i < MAXSYMBOLS; i++) { ct = keys[i]; if(ct) free(ct); keys[i] = 0; iter = indexes[i]; while(iter) { liter = iter; iter = iter->next; free(liter->index); free(liter); } indexes[i] = 0; } } /* At this point the basic algorithm is to take the ASCII value of * each character in the key, sum 'em up and mod by HASHSIZE. * * Note: In any revisions of this function in the future, it * will be important that ANY unique key will generate a unique * index into the hash. The data structure for the lock storage * will depend on this. */ int hashfunction(char *key) { int i,s,retval=0; s=strlen(key); for(i = 0; i < s; i++) retval += key[i]; retval %= HASHSIZE; return retval; } void client_deal(int client_sockfd) { int command = 0x0; int keysize = 0x0; char *key; int indexsize = 0x0; char *index; int ownersize = 0x0; char *owner; int TTL = 0x0, TTW = 0x0; int priority = 0x0; int hashind; time_t ts; lock *l; lockqueue *s; char *ret; char rlen; int nb; int i, j; unsigned int contend_loc, mask, k, num_locks; unsigned long m; #ifndef __MINGW32__ nb = read(client_sockfd, &command, 1); #else nb = read_socket(client_sockfd, &command, 1); #endif if(!nb) { close_socket(client_sockfd); return; } switch(command) { case WHOOWNS: pd("Who owns the following?\n"); /* Get key */ #ifndef __MINGW32__ nb = read(client_sockfd, &keysize, 1); #else nb = read_socket(client_sockfd, &keysize, 1); #endif if(!nb) { close_socket(client_sockfd); return; } key = (char *) malloc (sizeof(char) * (keysize + 1)); #ifndef __MINGW32__ nb = read(client_sockfd, key, keysize); #else nb = read_socket(client_sockfd, key, keysize); #endif if(!nb) { close_socket(client_sockfd); return; } key[keysize] = '\0'; pd("\tKey: "); pd(key); pd("\n"); /* Get index*/ #ifndef __MINGW32__ nb = read(client_sockfd, &indexsize, 1); #else nb = read_socket(client_sockfd, &indexsize, 1); #endif if(!nb) { close_socket(client_sockfd); return; } index = (char *) malloc (sizeof(char) * (indexsize + 1)); #ifndef __MINGW32__ nb = read(client_sockfd, index, indexsize); #else nb = read_socket(client_sockfd, index, indexsize); #endif if(!nb) { close_socket(client_sockfd); return; } index[indexsize] = '\0'; pd("\tIndex: "); pd(index); pd("\n\n"); l = find_owner(key, index); if(l) { pd("Found an owner:\n"); ret = (char *) malloc (sizeof(char) * \ (strlen(l->owner) + 2)); sprintf(ret, "%c%s", strlen(l->owner), l->owner); rlen=strlen(ret); pd("\tOwner: "); pd(l->owner); pd("\n"); } else { pd("No owner found.\n"); ret = (char *) malloc (sizeof(char)); ret[0] = 0; rlen = 1; } #ifndef __MINGW32__ nb = write(client_sockfd, ret, rlen); #else nb = write_socket(client_sockfd, ret, rlen); #endif if(nb == -1 && errno == EPIPE) { close_socket(client_sockfd); return; } free(key); free(index); free(ret); pd("\n"); break; case GIMME: /* Request Lock */ pd("I want a lock! Now dammit!\n"); /* Get key */ #ifndef __MINGW32__ nb = read(client_sockfd, &keysize, 1); #else nb = read_socket(client_sockfd, &keysize, 1); #endif if(!nb) { close_socket(client_sockfd); return; } key = (char *) malloc (sizeof(char) * (keysize + 1)); #ifndef __MINGW32__ nb = read(client_sockfd, key, keysize); #else nb = read_socket(client_sockfd, key, keysize); #endif if(!nb) { close_socket(client_sockfd); return; } key[keysize] = '\0'; pd("\tKey: "); pd(key); pd("\n"); /* Get index */ #ifndef __MINGW32__ read(client_sockfd, &indexsize, 1); #else read_socket(client_sockfd, &indexsize, 1); #endif index = (char *) malloc (sizeof(char) * (indexsize + 1)); #ifndef __MINGW32__ nb = read(client_sockfd, index, indexsize); #else nb = read_socket(client_sockfd, index, indexsize); #endif if(!nb) { close_socket(client_sockfd); return; } index[indexsize] = '\0'; pd("\tIndex: "); pd(index); pd("\n"); /* Get owner */ #ifndef __MINGW32__ nb = read(client_sockfd, &ownersize, 1); #else nb = read_socket(client_sockfd, &ownersize, 1); #endif if(!nb) { close_socket(client_sockfd); return; } owner = (char *) malloc (sizeof(char) * (ownersize + 1)); #ifndef __MINGW32__ nb = read(client_sockfd, owner, ownersize); #else nb = read_socket(client_sockfd, owner, ownersize); #endif if(!nb) { close_socket(client_sockfd); return; } owner[ownersize] = '\0'; pd("\tOwner: "); pd(owner); pd("\n"); /* Get TTL */ #ifndef __MINGW32__ nb = read(client_sockfd, &TTL, 1); #else nb = read_socket(client_sockfd, &TTL, 1); #endif if(!nb) { close_socket(client_sockfd); return; } TTL = TTL << 8; #ifndef __MINGW32__ nb = read(client_sockfd, &TTL, 1); #else nb = read_socket(client_sockfd, &TTL, 1); #endif if(!nb) { close_socket(client_sockfd); return; } /* Get TTW */ #ifndef __MINGW32__ nb = read(client_sockfd, &TTW, 1); #else nb = read_socket(client_sockfd, &TTW, 1); #endif if(!nb) { close_socket(client_sockfd); return; } TTW = TTW << 8; #ifndef __MINGW32__ nb = read(client_sockfd, &TTW, 1); #else nb = read_socket(client_sockfd, &TTW, 1); #endif if(!nb) { close_socket(client_sockfd); return; } /* Get priority */ #ifndef __MINGW32__ nb = read(client_sockfd, &priority, 1); #else nb = read_socket(client_sockfd, &priority, 1); #endif if(!nb) { close_socket(client_sockfd); return; } l = find_lock(key, index, owner); contend_loc = 0x0; if(graceclose) { pd("Denying a lock because of graceful close\n"); contend_loc = 0x0; } else if(!l) { pd("Ok this is officially a new lock.\n"); l = (lock *) malloc (sizeof(lock)); l->TTL = TTL; l->TTW = TTW; l->priority = priority; l->key = (char *) malloc (sizeof(char) \ * (strlen(key) + 1)); strncpy(l->key, key, (strlen(key)+1)); l->index = (char *) malloc (sizeof(char) \ * (strlen(index) + 1)); strncpy(l->index, index, (strlen(index)+1)); l->owner = (char *) malloc (sizeof(char) \ * (strlen(owner) + 1)); strncpy(l->owner, owner, (strlen(owner)+1)); time(&ts); l->RequestTS = ts; l->LastUpdateTS = ts; contend_loc = add_contender(l); pd("Inserted.\n"); } else { pd("Uh, this lock already exists.\n"); time(&ts); l->LastUpdateTS = ts; contend_loc = get_contend_loc(l); } mask = 0xffff; if(contend_loc & ~mask) { openlog("lockserver", LOG_PID, LOG_DAEMON); syslog(LOG_WARNING, \ "Contender location is more than 2 bytes."); closelog(); } mask = 0xff00; j = ((contend_loc & mask) >> 8); #ifndef __MINGW32__ nb = write(client_sockfd, &j, 1); #else nb = write_socket(client_sockfd, &j, 1); #endif if(nb == -1 && errno == EPIPE) { close_socket(client_sockfd); return; } mask = 0xff; j = contend_loc & mask; #ifndef __MINGW32__ nb = write(client_sockfd, &j, 1); #else nb = write_socket(client_sockfd, &j, 1); #endif if(nb == -1 && errno == EPIPE) { close_socket(client_sockfd); return; } free(key); free(index); free(owner); pd("\n"); break; case CONTLOC: /* Where do I stand? */ pd("Contender location:\n"); /* Get key */ #ifndef __MINGW32__ nb = read(client_sockfd, &keysize, 1); #else nb = read_socket(client_sockfd, &keysize, 1); #endif if(!nb) { close_socket(client_sockfd); return; } key = (char *) malloc (sizeof(char) * (keysize + 1)); #ifndef __MINGW32__ nb = read(client_sockfd, key, keysize); #else nb = read_socket(client_sockfd, key, keysize); #endif if(!nb) { close_socket(client_sockfd); return; } key[keysize] = '\0'; pd("\tKey: "); pd(key); pd("\n"); /* Get index */ #ifndef __MINGW32__ nb = read(client_sockfd, &indexsize, 1); #else nb = read_socket(client_sockfd, &indexsize, 1); #endif if(!nb) { close_socket(client_sockfd); return; } index = (char *) malloc (sizeof(char) * (indexsize + 1)); #ifndef __MINGW32__ nb = read(client_sockfd, index, indexsize); #else nb = read_socket(client_sockfd, index, indexsize); #endif if(!nb) { close_socket(client_sockfd); return; } index[indexsize] = '\0'; pd("\tIndex: "); pd(index); pd("\n"); /* Get owner */ #ifndef __MINGW32__ nb = read(client_sockfd, &ownersize, 1); #else nb = read_socket(client_sockfd, &ownersize, 1); #endif if(!nb) { close_socket(client_sockfd); return; } owner = (char *) malloc (sizeof(char) * (ownersize + 1)); #ifndef __MINGW32__ nb = read(client_sockfd, owner, ownersize); #else nb = read_socket(client_sockfd, owner, ownersize); #endif if(!nb) { close_socket(client_sockfd); return; } owner[ownersize] = '\0'; pd("\tOwner: "); pd(owner); pd("\n"); l = find_lock(key, index, owner); if(l) pd("Found lock...\n"); else pd("Lock not found...\n"); contend_loc = 0x0; if(l) contend_loc = get_contend_loc(l); mask = 0xffff; if(contend_loc & ~mask) { openlog("lockserver", LOG_PID, LOG_DAEMON); syslog(LOG_WARNING, \ "Contender location is more than 2 bytes."); closelog(); } mask = 0xff00; j = ((contend_loc & mask) >> 8); #ifndef __MINGW32__ nb = write(client_sockfd, &j, 1); #else nb = write_socket(client_sockfd, &j, 1); #endif if(nb == -1 && errno == EPIPE) { close_socket(client_sockfd); return; } mask = 0xff; j = contend_loc & mask; #ifndef __MINGW32__ nb = write(client_sockfd, &j, 1); #else nb = write_socket(client_sockfd, &j, 1); #endif if(nb == -1 && errno == EPIPE) { close_socket(client_sockfd); return; } free(key); free(index); free(owner); pd("\n"); break; case RENEW: /* I still want it! */ pd("Let's renew a lock!\n"); /* Get key */ #ifndef __MINGW32__ nb = read(client_sockfd, &keysize, 1); #else nb = read_socket(client_sockfd, &keysize, 1); #endif if(!nb) { close_socket(client_sockfd); return; } key = (char *) malloc (sizeof(char) * (keysize + 1)); #ifndef __MINGW32__ nb = read(client_sockfd, key, keysize); #else nb = read_socket(client_sockfd, key, keysize); #endif if(!nb) { close_socket(client_sockfd); return; } key[keysize] = '\0'; pd("\tKey: "); pd(key); pd("\n"); /* Get index */ #ifndef __MINGW32__ nb = read(client_sockfd, &indexsize, 1); #else nb = read_socket(client_sockfd, &indexsize, 1); #endif if(!nb) { close_socket(client_sockfd); return; } index = (char *) malloc (sizeof(char) * (indexsize + 1)); #ifndef __MINGW32__ nb = read(client_sockfd, index, indexsize); #else nb = read_socket(client_sockfd, index, indexsize); #endif if(!nb) { close_socket(client_sockfd); return; } index[indexsize] = '\0'; pd("\tIndex: "); pd(index); pd("\n"); /* Get owner */ #ifndef __MINGW32__ nb = read(client_sockfd, &ownersize, 1); #else nb = read_socket(client_sockfd, &ownersize, 1); #endif if(!nb) { close_socket(client_sockfd); return; } owner = (char *) malloc (sizeof(char) * (ownersize + 1)); #ifndef __MINGW32__ nb = read(client_sockfd, owner, ownersize); #else nb = read_socket(client_sockfd, owner, ownersize); #endif if(!nb) { close_socket(client_sockfd); return; } owner[ownersize] = '\0'; pd("\tOwner: "); pd(owner); pd("\n"); l = find_lock(key, index, owner); if(l) { pd("Found lock...\n"); time(&ts); l->LastUpdateTS = ts; } else pd("Lock not found...\n"); if(l) j = 1; else j = 0; #ifndef __MINGW32__ nb = write(client_sockfd, &j, 1); #else nb = write_socket(client_sockfd, &j, 1); #endif if(nb == -1 && errno == EPIPE) { close_socket(client_sockfd); return; } free(key); free(index); free(owner); pd("\n"); break; case RELSPEC: /* Ok - I'm ready to let go ... a little */ pd("Hmm. We want to release a specific lock...\n"); /* Get key */ #ifndef __MINGW32__ nb = read(client_sockfd, &keysize, 1); #else nb = read_socket(client_sockfd, &keysize, 1); #endif if(!nb) { close_socket(client_sockfd); return; } key = (char *) malloc (sizeof(char) * (keysize + 1)); #ifndef __MINGW32__ nb = read(client_sockfd, key, keysize); #else nb = read_socket(client_sockfd, key, keysize); #endif if(!nb) { close_socket(client_sockfd); return; } key[keysize] = '\0'; pd("\tKey: "); pd(key); pd("\n"); /* Get index */ #ifndef __MINGW32__ nb = read(client_sockfd, &indexsize, 1); #else nb = read_socket(client_sockfd, &indexsize, 1); #endif if(!nb) { close_socket(client_sockfd); return; } index = (char *) malloc (sizeof(char) * (indexsize + 1)); #ifndef __MINGW32__ nb = read(client_sockfd, index, indexsize); #else nb = read_socket(client_sockfd, index, indexsize); #endif if(!nb) { close_socket(client_sockfd); return; } index[indexsize] = '\0'; pd("\tIndex: "); pd(index); pd("\n"); /* Get owner */ #ifndef __MINGW32__ nb = read(client_sockfd, &ownersize, 1); #else nb = read_socket(client_sockfd, &ownersize, 1); #endif if(!nb) { close_socket(client_sockfd); return; } owner = (char *) malloc (sizeof(char) * (ownersize + 1)); #ifndef __MINGW32__ nb = read(client_sockfd, owner, ownersize); #else nb = read_socket(client_sockfd, owner, ownersize); #endif if(!nb) { close_socket(client_sockfd); return; } owner[ownersize] = '\0'; pd("\tOwner: "); pd(owner); pd("\n"); num_locks = kill_off(key, index, owner); pd("Killing spree done.\n"); mask = 0xffff; if(num_locks & ~mask) { openlog("lockserver", LOG_PID, LOG_DAEMON); syslog(LOG_WARNING, \ "# of locks removed is more than 2 bytes."); closelog(); } mask = 0xff00; j = ((num_locks & mask) >> 8); #ifndef __MINGW32__ nb = write(client_sockfd, &j, 1); #else nb = write_socket(client_sockfd, &j, 1); #endif if(nb == -1 && errno == EPIPE) { close_socket(client_sockfd); return; } mask = 0xff; j = num_locks & mask; #ifndef __MINGW32__ nb = write(client_sockfd, &j, 1); #else nb = write_socket(client_sockfd, &j, 1); #endif if(nb == -1 && errno == EPIPE) { close_socket(client_sockfd); return; } free(key); free(index); free(owner); pd("\n"); break; case RELALL: /* Ok - everybody out of the pool... */ pd("Kill! Kill! Kill 'em all!\n"); /* Get owner */ #ifndef __MINGW32__ nb = read(client_sockfd, &ownersize, 1); #else nb = read_socket(client_sockfd, &ownersize, 1); #endif if(!nb) { close_socket(client_sockfd); return; } owner = (char *) malloc (sizeof(char) * (ownersize + 1)); #ifndef __MINGW32__ nb = read(client_sockfd, owner, ownersize); #else nb = read_socket(client_sockfd, owner, ownersize); #endif if(!nb) { close_socket(client_sockfd); return; } owner[ownersize] = '\0'; pd("\tOwner: "); pd(owner); pd("\n"); num_locks = kill_all(owner); pd("Bloodbath completed.\n"); mask = 0xffff; if(num_locks & ~mask) { openlog("lockserver", LOG_PID, LOG_DAEMON); syslog(LOG_WARNING, \ "# of locks removed is more than 2 bytes."); closelog(); } mask = 0xff00; j = ((num_locks & mask) >> 8); #ifndef __MINGW32__ nb = write(client_sockfd, &j, 1); #else nb = write_socket(client_sockfd, &j, 1); #endif if(nb == -1 && errno == EPIPE) { close_socket(client_sockfd); return; } mask = 0xff; j = num_locks & mask; #ifndef __MINGW32__ nb = write(client_sockfd, &j, 1); #else nb = write_socket(client_sockfd, &j, 1); #endif if(nb == -1 && errno == EPIPE) { close_socket(client_sockfd); return; } free(owner); pd("\n"); break; case SHOWCONT: /* Get key */ #ifndef __MINGW32__ nb = read(client_sockfd, &keysize, 1); #else nb = read_socket(client_sockfd, &keysize, 1); #endif if(!nb) { close_socket(client_sockfd); return; } key = (char *) malloc (sizeof(char) * (keysize + 1)); #ifndef __MINGW32__ nb = read(client_sockfd, key, keysize); #else nb = read_socket(client_sockfd, key, keysize); #endif if(!nb) { close_socket(client_sockfd); return; } key[keysize] = '\0'; /* Gotta find out how many first */ hashind = hashfunction(key); num_locks = 0; s = owners[hashind]; while(s) { if(!strcmp(s->l->key, key)) num_locks++; s = s->next; } s = contenders[hashind]; while(s) { if(!strcmp(s->l->key, key)) num_locks++; s = s->next; } mask = 0xff00; j = ((num_locks & mask) >> 8); #ifndef __MINGW32__ nb = write(client_sockfd, &j, 1); #else nb = write_socket(client_sockfd, &j, 1); #endif if(nb == -1 && errno == EPIPE) { close_socket(client_sockfd); return; } mask = 0xff; j = num_locks & mask; #ifndef __MINGW32__ nb = write(client_sockfd, &j, 1); #else nb = write_socket(client_sockfd, &j, 1); #endif if(nb == -1 && errno == EPIPE) { close_socket(client_sockfd); return; } /* Ok - time to send da stuff */ for(i=0; i<2; i++) { if(!i) s = owners[hashind]; else s = contenders[hashind]; while(s) { if(!strcmp(s->l->key, key)) { /* priority */ #ifndef __MINGW32__ nb = write(client_sockfd, &(s->l->priority), 1); #else nb = write_socket(client_sockfd, &(s->l->priority), 1); #endif if(nb == -1 && errno == EPIPE) { close_socket(client_sockfd); return; } /* TTL */ mask = 0xff00; j = ((s->l->TTL & mask) >> 8); #ifndef __MINGW32__ nb = write(client_sockfd, &j, 1); #else nb = write_socket(client_sockfd, &j, 1); #endif if(nb == -1 && errno == EPIPE) { close_socket(client_sockfd); return; } mask = 0xff; j = s->l->TTL & mask; #ifndef __MINGW32__ nb = write(client_sockfd, &j, 1); #else nb = write_socket(client_sockfd, &j, 1); #endif if(nb == -1 && errno == EPIPE) { close_socket(client_sockfd); return; } /* TTW */ mask = 0xff00; j = ((s->l->TTW & mask) >> 8); #ifndef __MINGW32__ nb = write(client_sockfd, &j, 1); #else nb = write_socket(client_sockfd, &j, 1); #endif if(nb == -1 && errno == EPIPE) { close_socket(client_sockfd); return; } mask = 0xff; j = s->l->TTW & mask; #ifndef __MINGW32__ nb = write(client_sockfd, &j, 1); #else nb = write_socket(client_sockfd, &j, 1); #endif if(nb == -1 && errno == EPIPE) { close_socket(client_sockfd); return; } /* Index */ j = strlen(s->l->index); #ifndef __MINGW32__ nb = write(client_sockfd, &j, 1); #else nb = write_socket(client_sockfd, &j, 1); #endif if(nb == -1 && errno == EPIPE) { close_socket(client_sockfd); return; } nb = write(client_sockfd, s->l->index, j); if(nb == -1 && errno == EPIPE) { close_socket(client_sockfd); return; } /* Owner */ j = strlen(s->l->owner); #ifndef __MINGW32__ nb = write(client_sockfd, &j, 1); #else nb = write_socket(client_sockfd, &j, 1); #endif if(nb == -1 && errno == EPIPE) { close_socket(client_sockfd); return; } #ifndef __MINGW32__ nb = write(client_sockfd, s->l->owner, j); #else nb = write_socket(client_sockfd, s->l->owner, j); #endif if(nb == -1 && errno == EPIPE) { close_socket(client_sockfd); return; } j = !i; #ifndef __MINGW32__ nb = write(client_sockfd, &j, 1); #else nb = write_socket(client_sockfd, &j, 1); #endif if(nb == -1 && errno == EPIPE) { close_socket(client_sockfd); return; } } s = s->next; } } free(key); break; case STATS: /* So, like, what's happenin' man? */ /* Send uptime (4 bytes) # of seconds */ time(&ts); ts = ts - startTS; for(i = (sizeof(time_t) - 1); i >= 0; i--) { j = ((ts >> (i * 8)) & 0xFF); #ifndef __MINGW32__ nb = write(client_sockfd, &j, 1); #else nb = write_socket(client_sockfd, &j, 1); #endif if(nb == -1 && errno == EPIPE) { close_socket(client_sockfd); return; } } /* Send stats, starting with 0x0 - going to 0x8 (4 bytes each) */ for(i = 0; i < 9; i++) { for(j = (sizeof(long) - 1); j >= 0; j--) { k = ((requests[i] >> (j * 8)) & 0xFF); #ifndef __MINGW32__ nb = write(client_sockfd, &k, 1); #else nb = write_socket(client_sockfd, &k, 1); #endif if(nb == -1 && errno == EPIPE) { close_socket(client_sockfd); return; } } } /* Connection stats */ /* Accepted */ for(i = sizeof(long) - 1; i >= 0; i--) { j = ((okeedokee >> (i * 8)) & 0xFF); #ifndef __MINGW32__ nb = write(client_sockfd, &j, 1); #else nb = write_socket(client_sockfd, &j, 1); #endif if(nb == -1 && errno == EPIPE) { close_socket(client_sockfd); return; } } /* Rejected */ for(i = sizeof(long) - 1; i >= 0; i--) { j = ((badboys >> (i * 8)) & 0xFF); #ifndef __MINGW32__ nb = write(client_sockfd, &j, 1); #else nb = write_socket(client_sockfd, &j, 1); #endif if(nb == -1 && errno == EPIPE) { close_socket(client_sockfd); return; } } /* Too busy denies */ for(i = sizeof(long) - 1; i >= 0; i--) { j = ((rejects >> (i * 8)) & 0xFF); #ifndef __MINGW32__ nb = write(client_sockfd, &j, 1); #else nb = write_socket(client_sockfd, &j, 1); #endif if(nb == -1 && errno == EPIPE) { close_socket(client_sockfd); return; } } /* Owners */ m = 0; for(i = 0; i < HASHSIZE; i++) { s = owners[i]; while(s) { m++; s = s->next; } } for(i = sizeof(long) - 1; i >= 0; i--) { j = ((m >> (i * 8)) & 0xFF); #ifndef __MINGW32__ nb = write(client_sockfd, &j, 1); #else nb = write_socket(client_sockfd, &j, 1); #endif if(nb == -1 && errno == EPIPE) { close_socket(client_sockfd); return; } } /* Contenders */ m = 0; for(i = 0; i < HASHSIZE; i++) { s = contenders[i]; while(s) { m++; s = s->next; } } for(i = sizeof(long) - 1; i >= 0; i--) { j = ((m >> (i * 8)) & 0xFF); #ifndef __MINGW32__ nb = write(client_sockfd, &j, 1); #else nb = write_socket(client_sockfd, &j, 1); #endif if(nb == -1 && errno == EPIPE) { close_socket(client_sockfd); return; } } /* Current connections */ k=0; for(i = 1; i < MAXCONQUEUE; i++) if(open_sockets[i] != -1) k++; j = (k >> 8) & 0xFF; #ifndef __MINGE32__ nb = write(client_sockfd, &j, 1); #else nb = write_socket(client_sockfd, &j, 1); #endif if(nb == -1 && errno == EPIPE) { close_socket(client_sockfd); return; } j = k & 0xFF; #ifndef __MINGW32__ nb = write(client_sockfd, &j, 1); #else nb = write_socket(client_sockfd, &j, 1); #endif if(nb == -1 && errno == EPIPE) { close_socket(client_sockfd); return; } break; default: command = 0; }; requests[command] ++; return; } lock *find_owner(char *key, char *index) { int hashind; lockqueue *search; hashind = hashfunction(key); search = owners[hashind]; while(search && ( strcmp(search->l->key, key) || (strcmp(search->l->index,index) && strcmp(search->l->index,"*")))) { search=search->next; } if(search) return (search->l); return (lock *) 0; } lock *find_lock(char *key, char *index, char *owner) { int hashind; lockqueue *search; hashind = hashfunction(key); /* Start looking in owner */ search = owners[hashind]; while(search && ( (strcmp(search->l->key, key) || strcmp(search->l->owner, owner) || (strcmp(search->l->index, index) && strcmp(search->l->index, "*"))))) { search = search->next; } if(search) return(search->l); /* Ok - not an owner. At least a contender? */ search = contenders[hashind]; while(search && ( strcmp(search->l->key, key) || strcmp(search->l->owner, owner) || (strcmp(search->l->index, index) && strcmp(search->l->index, "*")))) { search = search->next; } if(search) return(search->l); return (lock *) 0; } unsigned int add_contender(lock *l) { int hashind, retval=0; lockqueue *last, *search, *insertion; /* Let's get the data ready to be dropped in */ insertion = (lockqueue *) malloc (sizeof(lockqueue)); insertion->l = l; insertion->next = (lockqueue *) 0; hashind = hashfunction(l->key); last = 0; /* Let's try ownership first. Maybe they'll get lucky */ search = owners[hashind]; while(search && ( strcmp(search->l->key, l->key) || (strcmp(l->index, search->l->index) && strcmp(search->l->index, "*") && strcmp(l->index, "*")))) { last = search; search = search->next; } if(!search) { /* Sweet! We get it immediately */ if(!owners[hashind]) { /* We're the only folks in the queue */ owners[hashind] = insertion; } else /* Going in at the end */ last->next = insertion; return(1); } else retval = 2; /* Oh boy ... we get to wade through the contenders */ search = contenders[hashind]; last = (lockqueue *) 0; while(search && search->l->priority <= l->priority) { if(!strcmp(search->l->key, l->key) && (!strcmp(search->l->index, l->index) || !strcmp(search->l->index, "*") || !strcmp(l->index, "*"))) retval ++; last = search; search = search->next; } if(!contenders[hashind]) /* Ok - first in line */ contenders[hashind] = insertion; else if(!last) { contenders[hashind] = insertion; insertion->next = search; } else { /* We're in the queue ... somewhere */ insertion->next = search; last->next = insertion; } return retval; } unsigned int get_contend_loc(lock *l) { int hashind, retval=0; lockqueue *search; hashind = hashfunction(l->key); /* Ownership area */ search = owners[hashind]; while(search && (search->l != l)) { if(!strcmp(search->l->key, l->key) && (!strcmp(search->l->index, l->index) || (!strcmp(search->l->index, "*")))) retval++; search=search->next; } if(search) return(1); retval = 2; search = contenders[hashind]; /* (In a raspy voice): I coulda beena contenda... */ while(search && (search->l != l)) { if(!strcmp(search->l->key, l->key) && (!strcmp(search->l->index, l->index) || (!strcmp(search->l->index, "*") || !strcmp(l->index,"*")))) retval++; search=search->next; } if(!search) retval=0; return retval; } unsigned int kill_off(char *key, char *index, char *owner) { int retval = 0; int hashind; lockqueue *search, *last = 0; hashind = hashfunction(key); /* Check owner area first */ search = owners[hashind]; while(search) { if(!strcmp(search->l->key, key) && (!strlen(owner) || !strcmp(search->l->owner, owner)) && (!strcmp(search->l->index, index) || !strcmp(index,"*"))) { /* Ah hah! It needs deadifying */ if(!last) { owners[hashind] = search->next; free(search->l->key); free(search->l->index); free(search->l->owner); free(search->l); free(search); search = owners[hashind]; retval ++; } else { last->next = search->next; free(search->l->key); free(search->l->index); free(search->l->owner); free(search->l); free(search); search = last->next; retval ++; } } else { last = search; search = search->next; } } /* And now the contenders */ search = contenders[hashind]; last = 0; while(search) { if(!strcmp(search->l->key, key) && (!strlen(owner) || !strcmp(search->l->owner, owner)) && (!strcmp(search->l->index, index) || !strcmp(index, "*"))) { /* Ah hah! It needs deadifying */ if(!last) { contenders[hashind] = search->next; free(search->l->key); free(search->l->index); free(search->l->owner); free(search->l); free(search); search = contenders[hashind]; retval ++; } else { last->next = search->next; free(search->l->key); free(search->l->index); free(search->l->owner); free(search->l); free(search); search = last->next; retval ++; } } else { last = search; search = search->next; } } return retval; } unsigned int kill_all(char *owner) { int retval = 0, i; lockqueue *search, *last = 0; /* Clean out the owners... */ for(i = 0; i < HASHSIZE; i++) { search = owners[i]; last = 0; while(search) { if(!strlen(owner) || !strcmp(search->l->owner,owner)) { retval ++; /* Ok, now we take 'im out */ if(!last) { owners[i] = search->next; free(search->l->key); free(search->l->index); free(search->l->owner); free(search->l); free(search); search = owners[i]; } else { last->next = search->next; free(search->l->key); free(search->l->index); free(search->l->owner); free(search->l); free(search); search = last->next; } } else { last = search; search = search->next; } } } /* And then the contenders... */ for(i = 0; i < HASHSIZE; i++) { search = contenders[i]; last = 0; while(search) { if(!strlen(owner) || !strcmp(search->l->owner,owner)) { retval ++; /* Ok, now we take 'im out */ if(!last) { contenders[i] = search->next; free(search->l->key); free(search->l->index); free(search->l->owner); free(search->l); free(search); search = contenders[i]; } else { last->next = search->next; free(search->l->key); free(search->l->index); free(search->l->owner); free(search->l); free(search); search = last->next; } } else { last = search; search = search->next; } } } return retval; } void pd(char *message) { if(message && debug) fprintf(stderr,"%s",message); return; } char *format_time(int seconds) { int play, op=0; char *retval = 0; char *addon = 0; retval = (char *) malloc (sizeof(char)); retval[0] = 0; /* Days */ play = seconds / (60*60*24); if(play) { addon = (char *) malloc (sizeof(char) * 12); sprintf(addon, "%d day%s", play, (play > 1) ? "s" : ""); seconds %= (60*60*24); play = sizeof(char) * (strlen(retval) + strlen(addon) + 1); op = strlen(retval); if(op) play += 2; retval = realloc(retval,play); if(op) strcpy(&retval[strlen(retval)], ", "); strcpy(&retval[strlen(retval)], addon); free(addon); } /* Hours */ play = seconds / (60*60); if(play) { addon = (char *) malloc (sizeof(char) * 10); sprintf(addon, "%d hour%s", play, (play > 1) ? "s" : ""); seconds %= (60*60); play = sizeof(char) * (strlen(retval) + strlen(addon) + 1); op = strlen(retval); if(op) play += 2; retval = realloc(retval,play); if(op) strcpy(&retval[strlen(retval)], ", "); strcpy(&retval[strlen(retval)], addon); free(addon); } /* Minutes */ play = seconds / 60; if(play) { addon = (char *) malloc (sizeof(char) * 13); sprintf(addon, "%d minute%s", play, (play > 1) ? "s" : ""); seconds %= 60; play = sizeof(char) * (strlen(retval) + strlen(addon) + 1); op = strlen(retval); if(op) play += 2; retval = realloc(retval,play); if(op) strcpy(&retval[strlen(retval)], ", "); strcpy(&retval[strlen(retval)], addon); free(addon); } /* Seconds */ play = seconds; if(play) { addon = (char *) malloc (sizeof(char) * 13); sprintf(addon, "%d second%s", play, (play > 1) ? "s" : ""); play = sizeof(char) * (strlen(retval) + strlen(addon) + 1); op = strlen(retval); if(op) play += 2; retval = realloc(retval,play); if(op) strcpy(&retval[strlen(retval)], ", "); strcpy(&retval[strlen(retval)], addon); free(addon); } return retval; } #ifdef __MINGW32__ /* Example code to log to Event log. */ #define TBUF_LEN 2048 #define FMT_LEN 1024 void syslog(int pri, char *fmt, ...) { va_list ap; va_start(ap, fmt); vsyslog(pri, fmt, ap); va_end(ap); } void vsyslog(int pri, char *fmt, va_list ap){ char ch, *p, *t; int tbuf_left, fmt_left, prlen, saved_errno; char tbuf[TBUF_LEN], fmt_cpy[FMT_LEN]; p = tbuf; tbuf_left = TBUF_LEN; saved_errno = errno; /* * We wouldn't need this mess if printf handled %m, or if * strerror() had been invented before syslog(). */ for (t = fmt_cpy, fmt_left = FMT_LEN; (ch = *fmt); ++fmt) { if (ch == '%' && fmt[1] == 'm') { ++fmt; prlen = _snprintf(t, fmt_left, "%s", strerror(saved_errno)); if (prlen >= fmt_left) prlen = fmt_left - 1; t += prlen; fmt_left -= prlen; } else { if (fmt_left > 1) { *t++ = ch; fmt_left--; } } } *t = '\0'; _vsnprintf(p, tbuf_left, fmt_cpy, ap); /* Now, actually report it. */ /****************************/ puts(fmt_cpy); return; } void openlog(char *ident, int logstat, int logfac){ } void closelog() { } int write_socket(SOCKET s, const char *buf, int len) { int result; result = send(s,buf,len,0); if(result == SOCKET_ERROR) { errno = WSAGetLastError(); if(errno == WSAENOTCONN) { errno = EPIPE; return -1; } } return result; } int read_socket(SOCKET s, char *buf, int len) { int result; result = recv(s,buf,len,0); if(result == 0) { errno = EPIPE; return -1; } if(result == SOCKET_ERROR) { errno = WSAGetLastError(); if(errno == WSAENOTCONN) { errno = EPIPE; return -1; } } return result; } #endif