tinycobol/lockserver/lockserver.c

2862 lines
63 KiB
C

/*
* 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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#ifdef __MINGW32__
#include "syslog.h"
#else
#include <syslog.h>
#endif
#include <signal.h>
#include <time.h>
#include <dirent.h>
#ifndef __MINGW32__
#include <netdb.h>
#endif
#include <sys/time.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/types.h>
#ifdef __MINGW32__
#include <winsock2.h>
#include <wininet.h>
#include <windows.h>
#define ioctl ioctlsocket
WORD wVersionRequested;
WSADATA wsaData;
int err;
#else
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/resource.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#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