John Floren avatar John Floren committed ee9773f

Added initial Linux support

Comments (0)

Files changed (9)

+all:
+	gcc -static -pthread -o tully hash.c pstring.c protocol.c linux.c
+
 // A Pascal-style string
 typedef struct pstring {
 	uint	length;
-	uchar	*data;
+	unsigned char	*data;
 } pstring;
 
 // An entry in the hash table
 	int		(*proc)(Client*);
 	int		nargs; // number of arguments (size of the pstring array)
 } Command;
+
+
+// Our hash table
+htable *ht;
+#ifdef PLAN9
 #include <u.h>
 #include <libc.h>
+#else
+#include "linux.h"
+#endif
+
 #include "dat.h"
 #include "pstring.h"
 #include "hash.h"
 
 /* Bernstein's hash */
 uint 
-hash(uchar *buf, int len)
+hash(unsigned char *buf, int len)
 {
 	unsigned int hash = 5381;
 
+#include "linux.h"
+#include "dat.h"
+#include "protocol.h"
+
+#define MAXCLIENTS 1024
+
+pthread_t threads[MAXCLIENTS];
+
+int sock;
+
+void*
+handler_wrapper(void *arg)
+{
+	int *fd;
+
+	fd = (int*)arg;
+	handler(*fd);
+}
+
+void*
+reaper(void *arg)
+{
+	int i;
+	void *ret;
+	for (;;) {
+		for (i = 0; i < MAXCLIENTS; i++) {
+			if (threads[i] != NULL) {
+				pthread_tryjoin_np(threads[i], &ret);
+			}
+		}
+	}
+}
+
+void
+main()
+{
+        int fd, i;
+        int on = 1;
+        struct sockaddr_in servaddr;
+
+	ht = inittable(1);
+
+	pthread_rwlock_init(&ht->l, NULL);
+
+        sock = socket(AF_INET, SOCK_STREAM, 0);
+        if (sock < 0) {
+                printf("something wicked happened\n");
+                exit(-1);
+        }
+        setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+
+        memset(&servaddr, 0, sizeof(servaddr));
+        servaddr.sin_family = AF_INET;
+        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
+        servaddr.sin_port = htons(6379);
+
+        bind(sock, (struct sockaddr *)&servaddr, sizeof(servaddr));
+
+        listen(sock, 100);
+
+	for (;;) {
+		fd = accept(sock, NULL, NULL);
+		if (fd < 0)
+			exits("listen failed");
+
+		for (i = 0; i < MAXCLIENTS; i++) {
+			if (threads[i] == NULL) { 
+				pthread_create(&threads[i], NULL, handler_wrapper, &fd);
+				break;
+			}
+		}
+	
+	}
+}
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <pthread.h>
+
+#define sprint sprintf
+#define print printf
+#define fprint dprintf
+#define OREAD O_RDONLY
+#define exits(S) pthread_exit((int)(S))
+#define RWLock pthread_rwlock_t
+
+#define nil NULL
+
+#define mallocz(a, b) malloc(a)
+
+#define rlock pthread_rwlock_rdlock
+#define runlock pthread_rwlock_unlock
+#define wlock pthread_rwlock_wrlock
+#define wunlock pthread_rwlock_unlock
 #include "hash.h"
 #include "pstring.h"
 
-htable *ht;
-
-void 
-errorreply(Client *c, char* s)
-{
-	if (s) {
-		fprint(c->fd, "-%s\r\n", s);
-	}
-}
-
-void
-statusreply(Client *c, char* s)
-{
-	if (s) {
-		fprint(c->fd, "+%s\r\n", s);
-	}
-}
-
-void
-bulkreply(Client *c, pstring *s)
-{
-	if (s) {
-		fprint(c->fd, "$%d\r\n", s->length);
-		write(c->fd, s->data, s->length);
-		fprint(c->fd, "\r\n");
-	}
-}
-
-void
-nilreply(Client *c)
-{
-	fprint(c->fd, "$-1\r\n");
-}
-
-int
-gethandler(Client *c)
-{
-	pstring *r;
-
-//	print("get: fd %d\n", fd);
-	r = get(ht, c->args[1]);
-	if (r == nil) {
-		nilreply(c);
-		return 0;
-	}
-	bulkreply(c, r);
-	freepstring(r);
-	return 0;
-}
-
-int
-sethandler(Client *c)
-{
-//	print("set: fd %d\n", fd);
-	set(ht, c->args[1], c->args[2]);
-	statusreply(c, "OK");
-	return 0;
-}
-
-int
-quithandler(Client *c)
-{
-	close(c->fd);
-	exits(0);
-	return 0; // this is stupid, but it keeps the compiler quiet
-}
-
-Command commands[] = {
-	{"get", gethandler, 1},
-	{"set", sethandler, 2},
-	{"quit", quithandler, 0},
-};
-
-/*
- Clean up the client, deallocating stuff if needed.
- If done is set, will close the fd and exit the current thread
-*/
-void
-cleanclient(Client *c, int done)
-{
-	int i;
-
-	if (c->args != nil)
-		for (i = 0; i < c->nargs; i++) {
-			freepstring(c->args[i]);
-//			if (c->args[i] != nil) {
-//				if (c->args[i]->data != nil)
-//					free(c->args[i]->data);
-//				free(c->args[i]);
-//			}
-		}
-	free(c->args); // according to malloc(2), this is safe even if args is nil
-	c->args = nil;
-	if (done) {
-		//print("quitting\n");
-		close(c->fd);
-		exits(0);
-	}
-}
-
-int 
-readnum(int sockd, void *vptr, int maxlen) 
-{
-	int n, rc;
-	char	c, *buffer;
-
-	buffer = vptr;
-
-	for ( n = 1; n < maxlen; n++ ) {
-		if ( (rc = readn(sockd, &c, 1)) == 1 ) {
-			*buffer++ = c;
-			if ( c == '\n' && *(buffer-2) == '\r') {
-				*(buffer-1) = 0;
-				break;
-			}
-		} else if ( rc <= 0 ) {
-			close(sockd);
-			exits(0);
-		}
-	}
-
-	*buffer = 0;
-
-	n = atoi(vptr);
-	return n;
-}
-
-// Read a string (possibly binary) off the line. It is of the form:
-// <len bytes>\r\n
-// Toss out the CRLF and create a p-string from the data.
-pstring*
-readpstring(int fd, int len)
-{
-	int n;
-	char c;
-	pstring *result;
-
-	result = mallocz(sizeof(pstring), 1);
-
-	result->length = len;
-	result->data = mallocz(sizeof(uchar)*len, 1);
-
-	n = readn(fd, result->data, len);
-
-	if (n != len) 
-		goto readerr;
-
-	n = readn(fd, &c, 1);
-	if (n != 1 || c != '\r')
-		goto readerr;
-
-	n = readn(fd, &c, 1);
-	if (n != 1 || c != '\n')
-		goto readerr;
-
-	return result;
-
-readerr:
-	free(result->data);
-	free(result);
-	if (n <= 0) {
-		close(fd);
-		exits(0);
-	}
-	return nil;
-}
-
-void
-handler(int fd)
-{
-	Client c;
-	int n, arglen, i;
-	pstring *tmp;
-	char buf[128];
-	int foundcommand = 0;
-	char *s;
-
-	//print("new client fd = %d\n", fd);
-
-	c.fd = fd;
-	//c.args = mallocz(sizeof(pstring*)*3, 1); // allocate 3 slots, this should actually be big enough for anything for now
-
-	for (;;) {
-		/* All commands start with '*' followed by the # of arguments */
-		n = readn(fd, buf, 1);
-		if (n != 1 || buf[0] != '*') {
-			if (n <= 0)
-				cleanclient(&c, 1);
-			errorreply(&c, "ERROR");
-			cleanclient(&c, 0);
-			continue;
-		}
-
-		c.nargs = readnum(fd, buf, 128);
-		if (c.nargs <= 0) {
-			errorreply(&c, "ERROR");
-			cleanclient(&c, 0);
-			continue;
-		}
-
-		c.args = mallocz(sizeof(pstring*)*c.nargs, 1);
-
-		// Read in the arguments
-		for (i = 0; i < c.nargs; i++) {
-			n = readn(fd, buf, 1);
-			if ((buf[0] != '$') || (n != 1)) {
-				if (n <= 0) { cleanclient(&c, 1); }
-				errorreply(&c, "ERROR");
-				cleanclient(&c, 0);
-				break;
-			}
-	
-			arglen = readnum(fd, buf, 128);
-			if (arglen <= 0) {
-				errorreply(&c, "ERROR");
-				cleanclient(&c, 0);
-				break;
-			}
-	
-			tmp = readpstring(fd, arglen);
-			if (tmp == nil) {
-				errorreply(&c, "ERROR");
-				cleanclient(&c, 0);
-				break;
-			}
-	
-			c.args[i] = tmp;
-		}
-
-		// Make sure we successfully finished the loop
-		// c.args will be nil if we had an error
-		if (!c.args)
-			continue;
-
-		// we do all the commands as lower case for simplicity
-		pstringtolower(c.args[0]);
-
-		for (i = 0; i < (sizeof(commands)/sizeof(commands[0])); i++) {
-			if (!memcmp(c.args[0]->data, commands[i].name, (c.args[0]->length < strlen(commands[i].name) ? c.args[0]->length : strlen(commands[i].name))) && c.nargs - 1 == commands[i].nargs) {
-				foundcommand = 1;
-				(commands[i].proc)(&c);
-				break;
-			}
-		}
-		if (!foundcommand) {
-			s = pstring2cstring(c.args[0]);
-			print("unknown command %s\n", s);
-			free(s);
-		}
-		cleanclient(&c, 0);
-	}
-	//close(fd);
-	//exits(0);
-}
-
 void
 main()
 {
+#ifdef PLAN9
+#include <u.h>
+#include <libc.h>
+#include <ctype.h>
+#else
+#include <stdio.h>
+//#include <string.h>
+//#include <stdlib.h>
+//#include <sys/types.h>
+//#include <sys/stat.h>
+//#include <fcntl.h>
+//#include <unistd.h>
+#include "linux.h"
+#endif
+
+#include "dat.h"
+#include "hash.h"
+#include "pstring.h"
+
+/* This comes directly from the Plan 9 libc source */
+long
+readn(int f, void *av, long n)
+{
+	char *a;
+	long m, t;
+
+	a = av;
+	t = 0;
+	while(t < n){
+		m = read(f, a+t, n-t);
+		if(m <= 0){
+			if(t == 0)
+				return m;
+			break;
+		}
+		t += m;
+	}
+	return t;
+}
+
+
+void 
+errorreply(Client *c, char* s)
+{
+	if (s) {
+		fprint(c->fd, "-%s\r\n", s);
+	}
+}
+
+void
+statusreply(Client *c, char* s)
+{
+	if (s) {
+		fprint(c->fd, "+%s\r\n", s);
+	}
+}
+
+void
+bulkreply(Client *c, pstring *s)
+{
+	if (s) {
+		fprint(c->fd, "$%d\r\n", s->length);
+		write(c->fd, s->data, s->length);
+		fprint(c->fd, "\r\n");
+	}
+}
+
+void
+nilreply(Client *c)
+{
+	fprint(c->fd, "$-1\r\n");
+}
+
+int
+gethandler(Client *c)
+{
+	pstring *r;
+
+//	print("get: fd %d\n", fd);
+	r = get(ht, c->args[1]);
+	if (r == nil) {
+		nilreply(c);
+		return 0;
+	}
+	bulkreply(c, r);
+	freepstring(r);
+	return 0;
+}
+
+int
+sethandler(Client *c)
+{
+//	print("set: fd %d\n", fd);
+	set(ht, c->args[1], c->args[2]);
+	statusreply(c, "OK");
+	return 0;
+}
+
+int
+quithandler(Client *c)
+{
+	close(c->fd);
+	exits(0);
+	return 0; // this is stupid, but it keeps the compiler quiet
+}
+
+Command commands[] = {
+	{"get", gethandler, 1},
+	{"set", sethandler, 2},
+	{"quit", quithandler, 0},
+};
+
+/*
+ Clean up the client, deallocating stuff if needed.
+ If done is set, will close the fd and exit the current thread
+*/
+void
+cleanclient(Client *c, int done)
+{
+	int i;
+
+	if (c->args != nil)
+		for (i = 0; i < c->nargs; i++) {
+			freepstring(c->args[i]);
+//			if (c->args[i] != nil) {
+//				if (c->args[i]->data != nil)
+//					free(c->args[i]->data);
+//				free(c->args[i]);
+//			}
+		}
+	free(c->args); // according to malloc(2), this is safe even if args is nil
+	c->args = nil;
+	if (done) {
+		//print("quitting\n");
+		close(c->fd);
+		exits(0);
+	}
+}
+
+int 
+readnum(int sockd, void *vptr, int maxlen) 
+{
+	int n, rc;
+	char	c, *buffer;
+
+	buffer = vptr;
+
+	for ( n = 1; n < maxlen; n++ ) {
+		if ( (rc = readn(sockd, &c, 1)) == 1 ) {
+			*buffer++ = c;
+			if ( c == '\n' && *(buffer-2) == '\r') {
+				*(buffer-1) = 0;
+				break;
+			}
+		} else if ( rc <= 0 ) {
+			close(sockd);
+			exits(0);
+		}
+	}
+
+	*buffer = 0;
+
+	n = atoi(vptr);
+	return n;
+}
+
+// Read a string (possibly binary) off the line. It is of the form:
+// <len bytes>\r\n
+// Toss out the CRLF and create a p-string from the data.
+pstring*
+readpstring(int fd, int len)
+{
+	int n;
+	char c;
+	pstring *result;
+
+	result = mallocz(sizeof(pstring), 1);
+
+	result->length = len;
+	result->data = mallocz(sizeof(unsigned char)*len, 1);
+
+	n = readn(fd, result->data, len);
+
+	if (n != len) 
+		goto readerr;
+
+	n = readn(fd, &c, 1);
+	if (n != 1 || c != '\r')
+		goto readerr;
+
+	n = readn(fd, &c, 1);
+	if (n != 1 || c != '\n')
+		goto readerr;
+
+	return result;
+
+readerr:
+	free(result->data);
+	free(result);
+	if (n <= 0) {
+		close(fd);
+		exits(0);
+	}
+	return nil;
+}
+
+void
+handler(int fd)
+{
+	Client c;
+	int n, arglen, i;
+	pstring *tmp;
+	char buf[128];
+	int foundcommand = 0;
+	char *s;
+
+	//print("new client fd = %d\n", fd);
+
+	c.fd = fd;
+	//c.args = mallocz(sizeof(pstring*)*3, 1); // allocate 3 slots, this should actually be big enough for anything for now
+
+	for (;;) {
+		/* All commands start with '*' followed by the # of arguments */
+		n = readn(fd, buf, 1);
+		if (n != 1 || buf[0] != '*') {
+			if (n <= 0)
+				cleanclient(&c, 1);
+			errorreply(&c, "ERROR");
+			cleanclient(&c, 0);
+			continue;
+		}
+
+		c.nargs = readnum(fd, buf, 128);
+		if (c.nargs <= 0) {
+			errorreply(&c, "ERROR");
+			cleanclient(&c, 0);
+			continue;
+		}
+
+		c.args = mallocz(sizeof(pstring*)*c.nargs, 1);
+
+		// Read in the arguments
+		for (i = 0; i < c.nargs; i++) {
+			n = readn(fd, buf, 1);
+			if ((buf[0] != '$') || (n != 1)) {
+				if (n <= 0) { cleanclient(&c, 1); }
+				errorreply(&c, "ERROR");
+				cleanclient(&c, 0);
+				break;
+			}
+	
+			arglen = readnum(fd, buf, 128);
+			if (arglen <= 0) {
+				errorreply(&c, "ERROR");
+				cleanclient(&c, 0);
+				break;
+			}
+	
+			tmp = readpstring(fd, arglen);
+			if (tmp == nil) {
+				errorreply(&c, "ERROR");
+				cleanclient(&c, 0);
+				break;
+			}
+	
+			c.args[i] = tmp;
+		}
+
+		// Make sure we successfully finished the loop
+		// c.args will be nil if we had an error
+		if (!c.args)
+			continue;
+
+		// we do all the commands as lower case for simplicity
+		pstringtolower(c.args[0]);
+
+		for (i = 0; i < (sizeof(commands)/sizeof(commands[0])); i++) {
+			if (!memcmp(c.args[0]->data, commands[i].name, (c.args[0]->length < strlen(commands[i].name) ? c.args[0]->length : strlen(commands[i].name))) && c.nargs - 1 == commands[i].nargs) {
+				foundcommand = 1;
+				(commands[i].proc)(&c);
+				break;
+			}
+		}
+		if (!foundcommand) {
+			s = pstring2cstring(c.args[0]);
+			print("unknown command %s\n", s);
+			free(s);
+		}
+		cleanclient(&c, 0);
+	}
+	//close(fd);
+	//exits(0);
+}
+void errorreply(Client *c, char* s);
+void statusreply(Client *c, char* s);
+void bulkreply(Client *c, pstring *s);
+void nilreply(Client *c);
+int gethandler(Client *c);
+int sethandler(Client *c);
+int quithandler(Client *c);
+void cleanclient(Client *c, int done);
+int readnum(int sockd, void *vptr, int maxlen);
+pstring* readpstring(int fd, int len);
+void handler(int fd);
+#ifdef PLAN9
 #include <u.h>
 #include <libc.h>
+#else
+#include "linux.h"
+#endif
+
 #include "dat.h"
 
 /* 
 	p = mallocz(sizeof(pstring), 1);
 
 	p->length = strlen(s);
-	p->data = (uchar*)strdup(s);
+	p->data = (unsigned char*)strdup(s);
 	return p;
 }
 
 pstringcmp(pstring *s1, pstring *s2)
 {
 	int i, len;
-	uchar c1, c2;
-	uchar *d1, *d2;
+	unsigned char c1, c2;
+	unsigned char *d1, *d2;
 
 	d1 = s1->data;
 	d2 = s2->data;
 	r = mallocz(sizeof(pstring), 1);
 
 	r->length = s->length;
-	r->data = mallocz(sizeof(uchar)*(r->length), 1);
+	r->data = mallocz(sizeof(unsigned char)*(r->length), 1);
 	memcpy(r->data, s->data, r->length);
 	return r;
 }
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.