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 +}