tinywebd

changeset 0:9c9e24956d99

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Tue, 14 Apr 2015 02:13:29 +0300
parents
children f425a9805d17
files .hgignore Makefile src/main.c
diffstat 3 files changed, 186 insertions(+), 0 deletions(-) [+]
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/.hgignore	Tue Apr 14 02:13:29 2015 +0300
     1.3 @@ -0,0 +1,4 @@
     1.4 +\.o$
     1.5 +\.d$
     1.6 +\.swp$
     1.7 +^tinywebd$
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/Makefile	Tue Apr 14 02:13:29 2015 +0300
     2.3 @@ -0,0 +1,18 @@
     2.4 +src = $(wildcard src/*.c)
     2.5 +obj = $(src:.c=.o)
     2.6 +dep = $(obj:.o=.d)
     2.7 +bin = tinywebd
     2.8 +
     2.9 +CFLAGS = -pedantic -Wall -g
    2.10 +
    2.11 +$(bin): $(obj)
    2.12 +	$(CC) -o $@ $(obj) $(LDFLAGS)
    2.13 +
    2.14 +-include $(dep)
    2.15 +
    2.16 +%.d: %.c
    2.17 +	@$(CPP) $(CFLAGS) $< -MM -MT $(@:.d=.o) >$@
    2.18 +
    2.19 +.PHONY: clean
    2.20 +clean:
    2.21 +	rm -f $(obj) $(bin)
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/src/main.c	Tue Apr 14 02:13:29 2015 +0300
     3.3 @@ -0,0 +1,164 @@
     3.4 +#include <stdio.h>
     3.5 +#include <stdlib.h>
     3.6 +#include <string.h>
     3.7 +#include <errno.h>
     3.8 +#include <unistd.h>
     3.9 +#include <fcntl.h>
    3.10 +#include <sys/select.h>
    3.11 +#include <sys/types.h>
    3.12 +#include <sys/socket.h>
    3.13 +#include <arpa/inet.h>
    3.14 +
    3.15 +struct client {
    3.16 +	int s;
    3.17 +	char *rcvbuf;
    3.18 +	int bufsz;
    3.19 +	struct client *next;
    3.20 +};
    3.21 +
    3.22 +int start_server(void);
    3.23 +int accept_conn(int lis);
    3.24 +int handle_client(struct client *c);
    3.25 +
    3.26 +static int lis;
    3.27 +static int port = 8080;
    3.28 +static struct client *clist;
    3.29 +
    3.30 +int main(int argc, char **argv)
    3.31 +{
    3.32 +	if((lis = start_server()) == -1) {
    3.33 +		return 1;
    3.34 +	}
    3.35 +
    3.36 +	for(;;) {
    3.37 +		struct client *c, dummy;
    3.38 +		int maxfd = lis;
    3.39 +		fd_set rdset;
    3.40 +
    3.41 +		FD_ZERO(&rdset);
    3.42 +		FD_SET(lis, &rdset);
    3.43 +
    3.44 +		c = clist;
    3.45 +		while(c) {
    3.46 +			if(c->s > maxfd) {
    3.47 +				maxfd = c->s;
    3.48 +			}
    3.49 +			FD_SET(c->s, &rdset);
    3.50 +			c = c->next;
    3.51 +		}
    3.52 +
    3.53 +		while(select(maxfd + 1, &rdset, 0, 0, 0) == -1 && errno == EINTR);
    3.54 +
    3.55 +		c = clist;
    3.56 +		while(c) {
    3.57 +			if(FD_ISSET(c->s, &rdset)) {
    3.58 +				handle_client(c);
    3.59 +			}
    3.60 +			c = c->next;
    3.61 +		}
    3.62 +
    3.63 +		if(FD_ISSET(lis, &rdset)) {
    3.64 +			accept_conn(lis);
    3.65 +		}
    3.66 +
    3.67 +		dummy.next = clist;
    3.68 +		c = &dummy;
    3.69 +
    3.70 +		while(c->next) {
    3.71 +			struct client *n = c->next;
    3.72 +
    3.73 +			if(n->s == -1) {
    3.74 +				/* marked for removal */
    3.75 +				c->next = n->next;
    3.76 +				free(n);
    3.77 +			} else {
    3.78 +				c = c->next;
    3.79 +			}
    3.80 +		}
    3.81 +	}
    3.82 +}
    3.83 +
    3.84 +int start_server(void)
    3.85 +{
    3.86 +	int s;
    3.87 +	struct sockaddr_in sa;
    3.88 +
    3.89 +	if((s = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
    3.90 +		perror("failed to create listening socket");
    3.91 +		return -1;
    3.92 +	}
    3.93 +	fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK);
    3.94 +
    3.95 +	memset(&sa, 0, sizeof sa);
    3.96 +	sa.sin_family = AF_INET;
    3.97 +	sa.sin_addr.s_addr = INADDR_ANY;
    3.98 +	sa.sin_port = htons(port);
    3.99 +
   3.100 +	if(bind(s, (struct sockaddr*)&sa, sizeof sa) == -1) {
   3.101 +		fprintf(stderr, "failed to bind socket to port %d: %s\n", port, strerror(errno));
   3.102 +		return -1;
   3.103 +	}
   3.104 +	listen(s, 16);
   3.105 +
   3.106 +	return s;
   3.107 +}
   3.108 +
   3.109 +int accept_conn(int lis)
   3.110 +{
   3.111 +	int s;
   3.112 +	struct client *c;
   3.113 +	struct sockaddr_in addr;
   3.114 +	socklen_t addr_sz = sizeof addr;
   3.115 +
   3.116 +	if((s = accept(lis, (struct sockaddr*)&addr, &addr_sz)) == -1) {
   3.117 +		perror("failed to accept incoming connection");
   3.118 +		return -1;
   3.119 +	}
   3.120 +	fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK);
   3.121 +
   3.122 +	if(!(c = malloc(sizeof *c))) {
   3.123 +		perror("failed to allocate memory while accepting connection");
   3.124 +		return -1;
   3.125 +	}
   3.126 +	c->s = s;
   3.127 +	c->rcvbuf = 0;
   3.128 +	c->bufsz = 0;
   3.129 +	c->next = clist;
   3.130 +	clist = c;
   3.131 +	return 0;
   3.132 +}
   3.133 +
   3.134 +int handle_client(struct client *c)
   3.135 +{
   3.136 +	static char buf[2048];
   3.137 +	int rdsz;
   3.138 +
   3.139 +	while((rdsz = recv(c->s, buf, sizeof buf, 0)) > 0) {
   3.140 +		if(c->rcvbuf) {
   3.141 +			int newsz = c->bufsz + rdsz;
   3.142 +			char *newbuf = realloc(buf, newsz);
   3.143 +			if(!newbuf) {
   3.144 +				fprintf(stderr, "failed to allocate %d byte buffer\n", newsz);
   3.145 +				/* TODO http error */
   3.146 +				goto drop;
   3.147 +			}
   3.148 +
   3.149 +			memcpy(newbuf + c->bufsz, buf, rdsz);
   3.150 +
   3.151 +			c->rcvbuf = newbuf;
   3.152 +			c->bufsz = newsz;
   3.153 +		}
   3.154 +	}
   3.155 +
   3.156 +	/* TODO: parse header, drop on invalid, determine if the request
   3.157 +	 * is complete and process
   3.158 +	 */
   3.159 +
   3.160 +	if(rdsz == -1 && errno != EAGAIN) {
   3.161 +drop:
   3.162 +		close(c->s);
   3.163 +		c->s = -1;
   3.164 +		free(c->rcvbuf);
   3.165 +	}
   3.166 +	return 0;
   3.167 +}