| server.c - quark - quark web server | |
| git clone git://git.suckless.org/quark | |
| Log | |
| Files | |
| Refs | |
| LICENSE | |
| --- | |
| server.c (3823B) | |
| --- | |
| 1 /* See LICENSE file for copyright and license details. */ | |
| 2 #include <errno.h> | |
| 3 #include <pthread.h> | |
| 4 #include <stddef.h> | |
| 5 #include <stdlib.h> | |
| 6 #include <string.h> | |
| 7 | |
| 8 #include "connection.h" | |
| 9 #include "queue.h" | |
| 10 #include "server.h" | |
| 11 #include "util.h" | |
| 12 | |
| 13 struct worker_data { | |
| 14 int insock; | |
| 15 size_t nslots; | |
| 16 const struct server *srv; | |
| 17 }; | |
| 18 | |
| 19 static void * | |
| 20 server_worker(void *data) | |
| 21 { | |
| 22 queue_event *event = NULL; | |
| 23 struct connection *connection, *c, *newc; | |
| 24 struct worker_data *d = (struct worker_data *)data; | |
| 25 int qfd; | |
| 26 ssize_t nready; | |
| 27 size_t i; | |
| 28 | |
| 29 /* allocate connections */ | |
| 30 if (!(connection = calloc(d->nslots, sizeof(*connection)))) { | |
| 31 die("calloc:"); | |
| 32 } | |
| 33 | |
| 34 /* create event queue */ | |
| 35 if ((qfd = queue_create()) < 0) { | |
| 36 exit(1); | |
| 37 } | |
| 38 | |
| 39 /* add insock to the interest list (with data=NULL) */ | |
| 40 if (queue_add_fd(qfd, d->insock, QUEUE_EVENT_IN, 1, NULL) < 0) { | |
| 41 exit(1); | |
| 42 } | |
| 43 | |
| 44 /* allocate event array */ | |
| 45 if (!(event = reallocarray(event, d->nslots, sizeof(*event)))) { | |
| 46 die("reallocarray:"); | |
| 47 } | |
| 48 | |
| 49 for (;;) { | |
| 50 /* wait for new activity */ | |
| 51 if ((nready = queue_wait(qfd, event, d->nslots)) < 0) { | |
| 52 exit(1); | |
| 53 } | |
| 54 | |
| 55 /* handle events */ | |
| 56 for (i = 0; i < (size_t)nready; i++) { | |
| 57 c = queue_event_get_data(&event[i]); | |
| 58 | |
| 59 if (queue_event_is_error(&event[i])) { | |
| 60 if (c != NULL) { | |
| 61 queue_rem_fd(qfd, c->fd); | |
| 62 c->res.status = 0; | |
| 63 connection_log(c); | |
| 64 connection_reset(c); | |
| 65 } | |
| 66 | |
| 67 continue; | |
| 68 } | |
| 69 | |
| 70 if (c == NULL) { | |
| 71 /* add new connection to the interest li… | |
| 72 if (!(newc = connection_accept(d->insock, | |
| 73 connectio… | |
| 74 d->nslots… | |
| 75 /* | |
| 76 * the socket is either blocking | |
| 77 * or something failed. | |
| 78 * In both cases, we just carry … | |
| 79 */ | |
| 80 continue; | |
| 81 } | |
| 82 | |
| 83 /* | |
| 84 * add event to the interest list | |
| 85 * (we want IN, because we start | |
| 86 * with receiving the header) | |
| 87 */ | |
| 88 if (queue_add_fd(qfd, newc->fd, | |
| 89 QUEUE_EVENT_IN, | |
| 90 0, newc) < 0) { | |
| 91 /* not much we can do here */ | |
| 92 continue; | |
| 93 } | |
| 94 } else { | |
| 95 /* serve existing connection */ | |
| 96 connection_serve(c, d->srv); | |
| 97 | |
| 98 if (c->fd == 0) { | |
| 99 /* we are done */ | |
| 100 memset(c, 0, sizeof(struct conne… | |
| 101 continue; | |
| 102 } | |
| 103 | |
| 104 /* | |
| 105 * rearm the event based on the state | |
| 106 * we are "stuck" at | |
| 107 */ | |
| 108 switch(c->state) { | |
| 109 case C_RECV_HEADER: | |
| 110 if (queue_mod_fd(qfd, c->fd, | |
| 111 QUEUE_EVENT_IN, | |
| 112 c) < 0) { | |
| 113 connection_reset(c); | |
| 114 break; | |
| 115 } | |
| 116 break; | |
| 117 case C_SEND_HEADER: | |
| 118 case C_SEND_BODY: | |
| 119 if (queue_mod_fd(qfd, c->fd, | |
| 120 QUEUE_EVENT_OUT, | |
| 121 c) < 0) { | |
| 122 connection_reset(c); | |
| 123 break; | |
| 124 } | |
| 125 break; | |
| 126 default: | |
| 127 break; | |
| 128 } | |
| 129 } | |
| 130 } | |
| 131 } | |
| 132 | |
| 133 return NULL; | |
| 134 } | |
| 135 | |
| 136 void | |
| 137 server_init_thread_pool(int insock, size_t nthreads, size_t nslots, | |
| 138 const struct server *srv) | |
| 139 { | |
| 140 pthread_t *thread = NULL; | |
| 141 struct worker_data *d = NULL; | |
| 142 size_t i; | |
| 143 | |
| 144 /* allocate worker_data structs */ | |
| 145 if (!(d = reallocarray(d, nthreads, sizeof(*d)))) { | |
| 146 die("reallocarray:"); | |
| 147 } | |
| 148 for (i = 0; i < nthreads; i++) { | |
| 149 d[i].insock = insock; | |
| 150 d[i].nslots = nslots; | |
| 151 d[i].srv = srv; | |
| 152 } | |
| 153 | |
| 154 /* allocate and initialize thread pool */ | |
| 155 if (!(thread = reallocarray(thread, nthreads, sizeof(*thread))))… | |
| 156 die("reallocarray:"); | |
| 157 } | |
| 158 for (i = 0; i < nthreads; i++) { | |
| 159 if (pthread_create(&thread[i], NULL, server_worker, &d[i… | |
| 160 if (errno == EAGAIN) { | |
| 161 die("You need to run as root or have " | |
| 162 "CAP_SYS_RESOURCE set, or are trying… | |
| 163 "to create more threads than the " | |
| 164 "system can offer"); | |
| 165 } else { | |
| 166 die("pthread_create:"); | |
| 167 } | |
| 168 } | |
| 169 } | |
| 170 | |
| 171 /* wait for threads */ | |
| 172 for (i = 0; i < nthreads; i++) { | |
| 173 if ((errno = pthread_join(thread[i], NULL))) { | |
| 174 warn("pthread_join:"); | |
| 175 } | |
| 176 } | |
| 177 } |