tinywebd

annotate 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
rev   line source
nuclear@0 1 #include <stdio.h>
nuclear@0 2 #include <stdlib.h>
nuclear@0 3 #include <string.h>
nuclear@0 4 #include <errno.h>
nuclear@0 5 #include <unistd.h>
nuclear@0 6 #include <fcntl.h>
nuclear@0 7 #include <sys/select.h>
nuclear@0 8 #include <sys/types.h>
nuclear@0 9 #include <sys/socket.h>
nuclear@0 10 #include <arpa/inet.h>
nuclear@0 11
nuclear@0 12 struct client {
nuclear@0 13 int s;
nuclear@0 14 char *rcvbuf;
nuclear@0 15 int bufsz;
nuclear@0 16 struct client *next;
nuclear@0 17 };
nuclear@0 18
nuclear@0 19 int start_server(void);
nuclear@0 20 int accept_conn(int lis);
nuclear@0 21 int handle_client(struct client *c);
nuclear@0 22
nuclear@0 23 static int lis;
nuclear@0 24 static int port = 8080;
nuclear@0 25 static struct client *clist;
nuclear@0 26
nuclear@0 27 int main(int argc, char **argv)
nuclear@0 28 {
nuclear@0 29 if((lis = start_server()) == -1) {
nuclear@0 30 return 1;
nuclear@0 31 }
nuclear@0 32
nuclear@0 33 for(;;) {
nuclear@0 34 struct client *c, dummy;
nuclear@0 35 int maxfd = lis;
nuclear@0 36 fd_set rdset;
nuclear@0 37
nuclear@0 38 FD_ZERO(&rdset);
nuclear@0 39 FD_SET(lis, &rdset);
nuclear@0 40
nuclear@0 41 c = clist;
nuclear@0 42 while(c) {
nuclear@0 43 if(c->s > maxfd) {
nuclear@0 44 maxfd = c->s;
nuclear@0 45 }
nuclear@0 46 FD_SET(c->s, &rdset);
nuclear@0 47 c = c->next;
nuclear@0 48 }
nuclear@0 49
nuclear@0 50 while(select(maxfd + 1, &rdset, 0, 0, 0) == -1 && errno == EINTR);
nuclear@0 51
nuclear@0 52 c = clist;
nuclear@0 53 while(c) {
nuclear@0 54 if(FD_ISSET(c->s, &rdset)) {
nuclear@0 55 handle_client(c);
nuclear@0 56 }
nuclear@0 57 c = c->next;
nuclear@0 58 }
nuclear@0 59
nuclear@0 60 if(FD_ISSET(lis, &rdset)) {
nuclear@0 61 accept_conn(lis);
nuclear@0 62 }
nuclear@0 63
nuclear@0 64 dummy.next = clist;
nuclear@0 65 c = &dummy;
nuclear@0 66
nuclear@0 67 while(c->next) {
nuclear@0 68 struct client *n = c->next;
nuclear@0 69
nuclear@0 70 if(n->s == -1) {
nuclear@0 71 /* marked for removal */
nuclear@0 72 c->next = n->next;
nuclear@0 73 free(n);
nuclear@0 74 } else {
nuclear@0 75 c = c->next;
nuclear@0 76 }
nuclear@0 77 }
nuclear@0 78 }
nuclear@0 79 }
nuclear@0 80
nuclear@0 81 int start_server(void)
nuclear@0 82 {
nuclear@0 83 int s;
nuclear@0 84 struct sockaddr_in sa;
nuclear@0 85
nuclear@0 86 if((s = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
nuclear@0 87 perror("failed to create listening socket");
nuclear@0 88 return -1;
nuclear@0 89 }
nuclear@0 90 fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK);
nuclear@0 91
nuclear@0 92 memset(&sa, 0, sizeof sa);
nuclear@0 93 sa.sin_family = AF_INET;
nuclear@0 94 sa.sin_addr.s_addr = INADDR_ANY;
nuclear@0 95 sa.sin_port = htons(port);
nuclear@0 96
nuclear@0 97 if(bind(s, (struct sockaddr*)&sa, sizeof sa) == -1) {
nuclear@0 98 fprintf(stderr, "failed to bind socket to port %d: %s\n", port, strerror(errno));
nuclear@0 99 return -1;
nuclear@0 100 }
nuclear@0 101 listen(s, 16);
nuclear@0 102
nuclear@0 103 return s;
nuclear@0 104 }
nuclear@0 105
nuclear@0 106 int accept_conn(int lis)
nuclear@0 107 {
nuclear@0 108 int s;
nuclear@0 109 struct client *c;
nuclear@0 110 struct sockaddr_in addr;
nuclear@0 111 socklen_t addr_sz = sizeof addr;
nuclear@0 112
nuclear@0 113 if((s = accept(lis, (struct sockaddr*)&addr, &addr_sz)) == -1) {
nuclear@0 114 perror("failed to accept incoming connection");
nuclear@0 115 return -1;
nuclear@0 116 }
nuclear@0 117 fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK);
nuclear@0 118
nuclear@0 119 if(!(c = malloc(sizeof *c))) {
nuclear@0 120 perror("failed to allocate memory while accepting connection");
nuclear@0 121 return -1;
nuclear@0 122 }
nuclear@0 123 c->s = s;
nuclear@0 124 c->rcvbuf = 0;
nuclear@0 125 c->bufsz = 0;
nuclear@0 126 c->next = clist;
nuclear@0 127 clist = c;
nuclear@0 128 return 0;
nuclear@0 129 }
nuclear@0 130
nuclear@0 131 int handle_client(struct client *c)
nuclear@0 132 {
nuclear@0 133 static char buf[2048];
nuclear@0 134 int rdsz;
nuclear@0 135
nuclear@0 136 while((rdsz = recv(c->s, buf, sizeof buf, 0)) > 0) {
nuclear@0 137 if(c->rcvbuf) {
nuclear@0 138 int newsz = c->bufsz + rdsz;
nuclear@0 139 char *newbuf = realloc(buf, newsz);
nuclear@0 140 if(!newbuf) {
nuclear@0 141 fprintf(stderr, "failed to allocate %d byte buffer\n", newsz);
nuclear@0 142 /* TODO http error */
nuclear@0 143 goto drop;
nuclear@0 144 }
nuclear@0 145
nuclear@0 146 memcpy(newbuf + c->bufsz, buf, rdsz);
nuclear@0 147
nuclear@0 148 c->rcvbuf = newbuf;
nuclear@0 149 c->bufsz = newsz;
nuclear@0 150 }
nuclear@0 151 }
nuclear@0 152
nuclear@0 153 /* TODO: parse header, drop on invalid, determine if the request
nuclear@0 154 * is complete and process
nuclear@0 155 */
nuclear@0 156
nuclear@0 157 if(rdsz == -1 && errno != EAGAIN) {
nuclear@0 158 drop:
nuclear@0 159 close(c->s);
nuclear@0 160 c->s = -1;
nuclear@0 161 free(c->rcvbuf);
nuclear@0 162 }
nuclear@0 163 return 0;
nuclear@0 164 }