tinywebd
diff src/main.c @ 0:9c9e24956d99
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Tue, 14 Apr 2015 02:13:29 +0300 |
parents | |
children | f425a9805d17 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/main.c Tue Apr 14 02:13:29 2015 +0300 1.3 @@ -0,0 +1,164 @@ 1.4 +#include <stdio.h> 1.5 +#include <stdlib.h> 1.6 +#include <string.h> 1.7 +#include <errno.h> 1.8 +#include <unistd.h> 1.9 +#include <fcntl.h> 1.10 +#include <sys/select.h> 1.11 +#include <sys/types.h> 1.12 +#include <sys/socket.h> 1.13 +#include <arpa/inet.h> 1.14 + 1.15 +struct client { 1.16 + int s; 1.17 + char *rcvbuf; 1.18 + int bufsz; 1.19 + struct client *next; 1.20 +}; 1.21 + 1.22 +int start_server(void); 1.23 +int accept_conn(int lis); 1.24 +int handle_client(struct client *c); 1.25 + 1.26 +static int lis; 1.27 +static int port = 8080; 1.28 +static struct client *clist; 1.29 + 1.30 +int main(int argc, char **argv) 1.31 +{ 1.32 + if((lis = start_server()) == -1) { 1.33 + return 1; 1.34 + } 1.35 + 1.36 + for(;;) { 1.37 + struct client *c, dummy; 1.38 + int maxfd = lis; 1.39 + fd_set rdset; 1.40 + 1.41 + FD_ZERO(&rdset); 1.42 + FD_SET(lis, &rdset); 1.43 + 1.44 + c = clist; 1.45 + while(c) { 1.46 + if(c->s > maxfd) { 1.47 + maxfd = c->s; 1.48 + } 1.49 + FD_SET(c->s, &rdset); 1.50 + c = c->next; 1.51 + } 1.52 + 1.53 + while(select(maxfd + 1, &rdset, 0, 0, 0) == -1 && errno == EINTR); 1.54 + 1.55 + c = clist; 1.56 + while(c) { 1.57 + if(FD_ISSET(c->s, &rdset)) { 1.58 + handle_client(c); 1.59 + } 1.60 + c = c->next; 1.61 + } 1.62 + 1.63 + if(FD_ISSET(lis, &rdset)) { 1.64 + accept_conn(lis); 1.65 + } 1.66 + 1.67 + dummy.next = clist; 1.68 + c = &dummy; 1.69 + 1.70 + while(c->next) { 1.71 + struct client *n = c->next; 1.72 + 1.73 + if(n->s == -1) { 1.74 + /* marked for removal */ 1.75 + c->next = n->next; 1.76 + free(n); 1.77 + } else { 1.78 + c = c->next; 1.79 + } 1.80 + } 1.81 + } 1.82 +} 1.83 + 1.84 +int start_server(void) 1.85 +{ 1.86 + int s; 1.87 + struct sockaddr_in sa; 1.88 + 1.89 + if((s = socket(PF_INET, SOCK_STREAM, 0)) == -1) { 1.90 + perror("failed to create listening socket"); 1.91 + return -1; 1.92 + } 1.93 + fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK); 1.94 + 1.95 + memset(&sa, 0, sizeof sa); 1.96 + sa.sin_family = AF_INET; 1.97 + sa.sin_addr.s_addr = INADDR_ANY; 1.98 + sa.sin_port = htons(port); 1.99 + 1.100 + if(bind(s, (struct sockaddr*)&sa, sizeof sa) == -1) { 1.101 + fprintf(stderr, "failed to bind socket to port %d: %s\n", port, strerror(errno)); 1.102 + return -1; 1.103 + } 1.104 + listen(s, 16); 1.105 + 1.106 + return s; 1.107 +} 1.108 + 1.109 +int accept_conn(int lis) 1.110 +{ 1.111 + int s; 1.112 + struct client *c; 1.113 + struct sockaddr_in addr; 1.114 + socklen_t addr_sz = sizeof addr; 1.115 + 1.116 + if((s = accept(lis, (struct sockaddr*)&addr, &addr_sz)) == -1) { 1.117 + perror("failed to accept incoming connection"); 1.118 + return -1; 1.119 + } 1.120 + fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK); 1.121 + 1.122 + if(!(c = malloc(sizeof *c))) { 1.123 + perror("failed to allocate memory while accepting connection"); 1.124 + return -1; 1.125 + } 1.126 + c->s = s; 1.127 + c->rcvbuf = 0; 1.128 + c->bufsz = 0; 1.129 + c->next = clist; 1.130 + clist = c; 1.131 + return 0; 1.132 +} 1.133 + 1.134 +int handle_client(struct client *c) 1.135 +{ 1.136 + static char buf[2048]; 1.137 + int rdsz; 1.138 + 1.139 + while((rdsz = recv(c->s, buf, sizeof buf, 0)) > 0) { 1.140 + if(c->rcvbuf) { 1.141 + int newsz = c->bufsz + rdsz; 1.142 + char *newbuf = realloc(buf, newsz); 1.143 + if(!newbuf) { 1.144 + fprintf(stderr, "failed to allocate %d byte buffer\n", newsz); 1.145 + /* TODO http error */ 1.146 + goto drop; 1.147 + } 1.148 + 1.149 + memcpy(newbuf + c->bufsz, buf, rdsz); 1.150 + 1.151 + c->rcvbuf = newbuf; 1.152 + c->bufsz = newsz; 1.153 + } 1.154 + } 1.155 + 1.156 + /* TODO: parse header, drop on invalid, determine if the request 1.157 + * is complete and process 1.158 + */ 1.159 + 1.160 + if(rdsz == -1 && errno != EAGAIN) { 1.161 +drop: 1.162 + close(c->s); 1.163 + c->s = -1; 1.164 + free(c->rcvbuf); 1.165 + } 1.166 + return 0; 1.167 +}