UNIXworkcode

1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 * 4 * Copyright 2013 Olaf Wintermann. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <errno.h> 32 33 #include "../public/nsapi.h" 34 35 #include "sessionhandler.h" 36 #include "httprequest.h" 37 #include "httpparser.h" 38 #include "log.h" 39 #include "error.h" 40 #include "httplistener.h" 41 42 typedef struct _event_http_io { 43 HTTPRequest *request; 44 HttpParser *parser; 45 int error; 46 } EventHttpIO; 47 48 49 int connection_read(Connection *conn, void *buf, int len) { 50 return (int)read(conn->fd, buf, len); 51 } 52 53 int connection_write(Connection *conn, const void *buf, int len) { 54 return (int)write(conn->fd, buf, len); 55 } 56 57 void connection_close(Connection *conn) { 58 while(close(conn->fd)) { 59 if(errno != EINTR) { 60 log_ereport(LOG_VERBOSE, "connection close failed: %s", strerror(errno)); 61 break; 62 } 63 log_ereport(LOG_VERBOSE, "connection close: EINTR"); 64 } 65 } 66 67 int connection_ssl_read(Connection *conn, void *buf, int len) { 68 int ret = SSL_read(conn->ssl, buf, len); 69 if(ret <= 0) { 70 conn->ssl_error = SSL_get_error(conn->ssl, ret); 71 } 72 return ret; 73 } 74 75 int connection_ssl_write(Connection *conn, const void *buf, int len) { 76 int ret = SSL_write(conn->ssl, buf, len); 77 if(ret <= 0) { 78 conn->ssl_error = SSL_get_error(conn->ssl, ret); 79 } 80 return ret; 81 } 82 83 void connection_ssl_close(Connection *conn) { 84 if(!conn->ssl_error) { 85 int ret = SSL_shutdown(conn->ssl); 86 if(ret != 1) { 87 conn->ssl_error = SSL_get_error(conn->ssl, ret); 88 log_ereport(LOG_VERBOSE, "SSL_shutdown failed: %d", conn->ssl_error); 89 } 90 } 91 while(close(conn->fd)) { 92 if(errno != EINTR) { 93 log_ereport(LOG_VERBOSE, "connection close failed: %s", strerror(errno)); 94 break; 95 } 96 log_ereport(LOG_VERBOSE, "connection close: EINTR"); 97 } 98 } 99 100 void connection_destroy(Connection *conn) { 101 conn->close(conn); 102 if(conn->ssl) { 103 SSL_free(conn->ssl); 104 } 105 free(conn); 106 } 107 108 IOStream* create_connection_iostream( 109 SessionHandler *sh, 110 Connection *conn, 111 pool_handle_t *pool, 112 WSBool *ssl) 113 { 114 IOStream *io = NULL; 115 if(conn->ssl) { 116 io = sslstream_new(pool, conn->ssl); 117 *ssl = 1; 118 } else { 119 io = sysstream_new(pool, conn->fd); 120 *ssl = 0; 121 } 122 return io; 123 } 124 125 126 SessionHandler* create_basic_session_handler() { 127 BasicSessionHandler *handler = malloc(sizeof(BasicSessionHandler)); 128 handler->threadpool = threadpool_new(4, 8); 129 handler->sh.enqueue_connection = basic_enq_conn; 130 handler->sh.keep_alive = basic_keep_alive; 131 handler->sh.create_iostream = create_connection_iostream; 132 133 return (SessionHandler*)handler; 134 } 135 136 void basic_enq_conn(SessionHandler *handler, Connection *conn) { 137 BasicSessionHandler *sh = (BasicSessionHandler*)handler; 138 conn->session_handler = handler; 139 threadpool_run(sh->threadpool, basic_run_session, conn); 140 } 141 142 void* basic_run_session(void *data) { 143 Connection *conn = (Connection*)data; 144 145 HTTPRequest request; 146 http_request_init(&request); 147 request.connection = conn; 148 149 // read request 150 netbuf *buf = malloc(sizeof(netbuf)); 151 buf->rdtimeout = 120; 152 buf->pos = 0; 153 buf->cursize = 0; 154 buf->maxsize = 2048; 155 buf->sd = &conn->fd; 156 buf->inbuf = malloc(2048); 157 buf->errmsg = NULL; 158 159 request.netbuf = buf; 160 161 HttpParser *parser = http_parser_new(&request); 162 int state; 163 int r; 164 r = conn->read(conn, buf->inbuf + buf->pos, buf->maxsize - buf->pos); 165 if(r <= 0) { 166 // TODO: error handling 167 fprintf(stderr, "%s\n", "Error: Cannot read from socket"); 168 return NULL; 169 } 170 buf->cursize += r; 171 while((state = http_parser_process(parser)) != 0) { 172 if(state == 2) { 173 // TODO: error handling 174 fprintf(stderr, "%s\n", "Error: Cannot parse http request"); 175 return NULL; 176 } 177 r = conn->read(conn, buf->inbuf + buf->pos, buf->maxsize - buf->pos); 178 if(r == -1) { 179 // TODO: error handling 180 fprintf(stderr, "%s\n", "Error: Cannot read from socket"); 181 return NULL; 182 } 183 buf->cursize += r; 184 } 185 if(!http_parser_validate(parser)) { 186 log_ereport(LOG_FAILURE, "http_parser_validate failed"); 187 // TODO: send error 400 bad request 188 return NULL; 189 } 190 191 // process request 192 r = handle_request(&request, NULL, NULL); // TODO: use correct thread pool 193 194 // TODO: free, see evt_request_finish 195 196 return NULL; 197 } 198 199 void basic_keep_alive(SessionHandler *handler, Connection *conn) { 200 connection_destroy(conn); 201 } 202 203 204 /* ----- event session handler ----- */ 205 206 SessionHandler* create_event_session_handler() { 207 EventSessionHandler *handler = malloc(sizeof(EventSessionHandler)); 208 handler->eventhandler = get_default_event_handler(); 209 handler->sh.enqueue_connection = evt_enq_conn; 210 handler->sh.keep_alive = evt_keep_alive; 211 handler->sh.create_iostream = create_connection_iostream; 212 return (SessionHandler*)handler; 213 } 214 215 void evt_enq_conn(SessionHandler *handler, Connection *conn) { 216 HTTPRequest *request = malloc(sizeof(HTTPRequest)); 217 http_request_init(request); 218 request->connection = conn; 219 conn->session_handler = handler; 220 221 // set socket non blocking 222 int flags; 223 if ((flags = fcntl(conn->fd, F_GETFL, 0)) == -1) { 224 flags = 0; 225 } 226 if (fcntl(conn->fd, F_SETFL, flags | O_NONBLOCK) != 0) { 227 perror("Error: start_event_session: fcntl"); 228 // TODO: error 229 } 230 231 // TODO: remove code redundancy (basic_run_session) 232 233 // read request 234 netbuf *buf = malloc(sizeof(netbuf)); 235 buf->rdtimeout = 120; 236 buf->pos = 0; 237 buf->cursize = 0; 238 buf->maxsize = 2048; 239 buf->sd = &conn->fd; 240 buf->inbuf = malloc(2048); 241 buf->errmsg = NULL; 242 243 request->netbuf = buf; 244 245 HttpParser *parser = http_parser_new(request); 246 247 EventHttpIO *io = malloc(sizeof(EventHttpIO)); 248 if(io == NULL) { 249 // TODO: error handling 250 } 251 io->request = request; 252 io->parser = parser; 253 io->error = 0; 254 255 /* 256 * to start the request handling, we begin with a poll on the socket, 257 * 258 * evt_enq_conn() --> event handler --> handle_request() 259 */ 260 261 Event *event = malloc(sizeof(Event)); 262 ZERO(event, sizeof(Event)); 263 event->fn = conn->ssl && !conn->ssl_accepted ? evt_request_ssl_accept : evt_request_input; 264 event->finish = evt_request_finish; 265 event->cookie = io; 266 267 EventHandler *ev = ev_instance(((EventSessionHandler*)handler)->eventhandler); 268 269 if(ev_pollin(ev, conn->fd, event) != 0) { 270 // TODO: ev_pollin should log, intercept some errors here 271 log_ereport(LOG_FAILURE, "Cannot enqueue connection"); 272 connection_destroy(conn); 273 // TODO: free stuff 274 } 275 } 276 277 int evt_request_ssl_accept(EventHandler *handler, Event *event) { 278 EventHttpIO *io = event->cookie; 279 Connection *conn = io->request->connection; 280 281 int ret = SSL_accept(conn->ssl); 282 if(ret <= 0) { 283 int error = SSL_get_error(conn->ssl, ret); 284 char *errstr; 285 switch(error) { 286 default: errstr = "unknown"; break; 287 case SSL_ERROR_WANT_READ: { 288 event->events = EVENT_POLLIN; 289 return 1; 290 } 291 case SSL_ERROR_WANT_WRITE: { 292 event->events = EVENT_POLLOUT; 293 return 1; 294 } 295 case SSL_ERROR_ZERO_RETURN: errstr = "SSL_ERROR_ZERO_RETURN"; break; 296 case SSL_ERROR_WANT_CONNECT: errstr = "SSL_ERROR_WANT_CONNECT"; break; 297 case SSL_ERROR_WANT_ACCEPT: errstr = "SSL_ERROR_WANT_ACCEPT"; break; 298 case SSL_ERROR_WANT_X509_LOOKUP: errstr = "SSL_ERROR_WANT_X509_LOOKUP"; break; 299 case SSL_ERROR_SYSCALL: errstr = "SSL_ERROR_SYSCALL"; break; 300 case SSL_ERROR_SSL: errstr = "SSL_ERROR_SSL"; break; 301 } 302 log_ereport(LOG_VERBOSE, "SSL accept error[%d]: %s", error, errstr); 303 event->finish = evt_request_error; 304 io->error = 1; 305 return 0; 306 } 307 conn->ssl_accepted = WS_TRUE; 308 309 // SSL_accept successful, start request input now 310 event->fn = evt_request_input; 311 return evt_request_input(handler, event); 312 } 313 314 int evt_request_input(EventHandler *handler, Event *event) { 315 EventHttpIO *io = event->cookie; 316 HttpParser *parser = io->parser; 317 HTTPRequest *request = io->request; 318 Connection *conn = io->request->connection; 319 netbuf *buf = request->netbuf; 320 321 int state; 322 int r; 323 r = conn->read( 324 conn, 325 buf->inbuf + buf->pos, 326 buf->maxsize - buf->pos); 327 if(r <= 0) { 328 if(conn->ssl) { 329 // SSL specific error handling 330 switch(conn->ssl_error) { 331 case SSL_ERROR_WANT_READ: { 332 event->events = EVENT_POLLIN; 333 return 1; 334 } 335 case SSL_ERROR_WANT_WRITE: { 336 event->events = EVENT_POLLOUT; 337 return 1; 338 } 339 } 340 } 341 342 event->finish = evt_request_error; 343 io->error = 1; 344 return 0; 345 } 346 //fwrite(buf->inbuf + buf->pos, 1, r, stdout); 347 //printf("\n"); 348 349 buf->cursize += r; 350 state = http_parser_process(parser); 351 if(state == 2) { 352 // parse error 353 fatal_error(request, 400); 354 event->finish = evt_request_error; 355 io->error = 2; 356 return 0; 357 } else if(state == 1) { 358 /* 359 * we need more data -> return 1 to tell the event handler to 360 * continue polling 361 */ 362 event->events = EVENT_POLLIN; 363 return 1; 364 } 365 366 // we are done with reading 367 368 // set socket blocking 369 int flags; 370 if (-1 == (flags = fcntl(request->connection->fd, F_GETFL, 0))) { 371 flags = 0; 372 } 373 if (fcntl(request->connection->fd, F_SETFL, flags & ~O_NONBLOCK) != 0) { 374 // just close the connection if fcntl fails 375 event->finish = evt_request_error; 376 io->error = 3; 377 return 0; 378 } 379 380 if(!http_parser_validate(parser)) { 381 log_ereport(LOG_FAILURE, "http_parser_validate failed"); 382 // TODO: send error 400 bad request 383 event->finish = evt_request_error; 384 return 0; 385 } 386 387 /* 388 * process request 389 * 390 * We return 0 to finish request input. The event handler than stops 391 * polling and executes event->finish (evt_request_input_finish) 392 */ 393 return 0; 394 } 395 396 int evt_request_finish(EventHandler *h, Event *event) { 397 EventHttpIO *io = event->cookie; 398 HttpParser *parser = io->parser; 399 HTTPRequest *request = io->request; 400 401 int r = handle_request(request, NULL, h); 402 if(r != 0) { 403 // TODO: error message 404 connection_destroy(request->connection); 405 } 406 407 /* 408 * handle_request can return before the request is finished, but it copies 409 * all important data. We can free request, parser and event 410 * 411 * don't free request->netbuf and request->connection 412 */ 413 http_request_cleanup(request); 414 http_parser_free(parser); 415 416 free(io); 417 free(event); 418 419 return 0; 420 } 421 422 int evt_request_error(EventHandler *h, Event *event) { 423 EventHttpIO *io = event->cookie; 424 HttpParser *parser = io->parser; 425 HTTPRequest *request = io->request; 426 427 if(event->error) { 428 log_ereport(LOG_VERBOSE, "sessionhandler http io error: %d fd: %d", io->error, request->connection->fd); 429 } 430 431 free(request->netbuf->inbuf); 432 free(request->netbuf); 433 434 cfg_unref(request->connection->listener->cfg); 435 connection_destroy(request->connection); 436 437 http_request_cleanup(request); 438 http_parser_free(parser); 439 440 free(io); 441 free(event); 442 443 return 0; 444 } 445 446 void evt_keep_alive(SessionHandler *handler, Connection *conn) { 447 // TODO: set timeout 448 449 /* TODO: 450 * Don't just re-enqueue the connection 451 * create a evt_req_init function which does most of the evt_enq_conn stuff 452 * but don't poll. 453 * evt_keep_alive should poll and if an event occurs: 454 * evt_req_init 455 * evt_request_input 456 * evt_enq_conn should do: 457 * evt_req_init 458 * ev_pollin 459 */ 460 evt_enq_conn(handler, conn); 461 } 462