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 "../public/nsapi.h" 30 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <fcntl.h> 34 #include <sys/shm.h> 35 #include <sys/types.h> 36 #include <sys/ipc.h> 37 #include <sys/socket.h> 38 #include <sys/file.h> 39 #include <netinet/in.h> 40 #include <netdb.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <fcntl.h> 44 #include <unistd.h> 45 #include <strings.h> 46 #include <stdbool.h> 47 #include <pthread.h> 48 49 #include <ucx/map.h> 50 51 #include "../util/atomic.h" 52 #include "httplistener.h" 53 #include "netsite.h" 54 55 #include "session.h" 56 #include "configmanager.h" 57 #include "log.h" 58 59 UcxMap *listener_map = NULL; 60 61 int start_all_listener() { 62 ServerConfiguration *conf = cfgmgr_get_server_config(); 63 UcxList *ls = conf->listeners; 64 while(ls) { 65 HttpListener *listener = ls->data; 66 http_listener_start(listener); 67 ls = ls->next; 68 } 69 70 return 0; 71 } 72 73 HttpListener* http_listener_create(ListenerConfig *conf) { 74 if(listener_map == NULL) { 75 listener_map = ucx_map_new(16); 76 } 77 78 HttpListener *fl = ucx_map_sstr_get(listener_map, conf->name); 79 if(fl == NULL) { 80 return http_listener_new(conf); 81 } 82 83 HttpListener* newls = calloc(1, sizeof(HttpListener)); 84 if(newls == NULL) { 85 // TODO: error 86 } 87 88 newls->name = conf->name; 89 newls->cfg = conf->cfg; 90 newls->nacceptors = conf->nacceptors; 91 newls->default_vs.vs_name = conf->vs.ptr; 92 newls->port = fl->port; 93 newls->server_socket = fl->server_socket; 94 newls->running = 1; 95 newls->threadpool = NULL; 96 newls->ref = 2; // 1 reference is fl->next 97 98 newls->session_handler = fl->session_handler; // TODO 99 100 // the listener threadpool might be changed 101 if(conf->threadpool.ptr != NULL) { 102 newls->threadpool = get_threadpool(conf->threadpool); 103 } 104 if(newls->threadpool == NULL) { 105 newls->threadpool = get_default_threadpool(); 106 } 107 108 // create acceptor threads 109 newls->acceptors = calloc(newls->nacceptors, sizeof(void*)); 110 for (int i=0;i<newls->nacceptors;i++) { 111 newls->acceptors[i] = acceptor_new(newls); 112 } 113 114 // fl hold one reference of newls 115 fl->next = newls; 116 117 118 ucx_map_sstr_put(listener_map, newls->name, newls); 119 120 for (int i=0;i<newls->nacceptors;i++) { 121 acceptor_start(newls->acceptors[i]); 122 } 123 124 // check if a restart is required to apply all changes 125 126 if(newls->port != conf->port) { 127 // TODO: log 128 } 129 130 return newls; 131 } 132 133 HttpListener* http_listener_new(ListenerConfig *conf) { 134 // TODO: remove 135 if(listener_map == NULL) { 136 listener_map = ucx_map_new(16); 137 } 138 139 HttpListener *fl = ucx_map_sstr_get(listener_map, conf->name); 140 if(fl != NULL) { 141 return fl; 142 } 143 // end remove 144 145 HttpListener *listener = malloc(sizeof(HttpListener)); 146 listener->running = 0; 147 listener->cfg = conf->cfg; 148 listener->name = conf->name; 149 listener->default_vs.vs_name = conf->vs.ptr; 150 listener->threadpool = NULL; 151 if(conf->threadpool.ptr != NULL) { 152 listener->threadpool = get_threadpool(conf->threadpool); 153 } 154 if(listener->threadpool == NULL) { 155 listener->threadpool = get_default_threadpool(); 156 } 157 if(conf->blockingio) { 158 listener->session_handler = create_basic_session_handler(); 159 } else { 160 listener->session_handler = create_event_session_handler(); 161 } 162 listener->nacceptors = conf->nacceptors; 163 listener->port = conf->port; 164 listener->ref = 1; 165 listener->next = NULL; 166 listener->ssl = NULL; 167 168 int error = 0; 169 170 if(conf->ssl) { 171 listener->ssl = malloc(sizeof(HttpSSL)); 172 173 SSL_CTX *ctx = SSL_CTX_new(SSLv23_server_method()); 174 SSL_CTX_set_options( 175 ctx, 176 SSL_OP_SINGLE_DH_USE | SSL_OP_NO_SSLv3); 177 if(conf->disable_proto.ptr) { 178 ssize_t n = 0; 179 sstr_t *plist = sstrsplit(conf->disable_proto, S(","), &n); 180 if(plist) { 181 for(int i=0;i<n;i++) { 182 sstr_t proto = plist[i]; 183 log_ereport( 184 LOG_VERBOSE, 185 "Listener %s: Disable protocol %s", 186 listener->name.ptr, 187 proto.ptr); 188 if(!sstrcasecmp(sstrtrim(proto), S("SSLv2"))) { 189 SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2); 190 } else if(!sstrcasecmp(sstrtrim(proto), S("SSLv3"))) { 191 SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3); 192 } else if(!sstrcasecmp(sstrtrim(proto), S("TLSv1"))) { 193 SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1); 194 } else if(!sstrcasecmp(sstrtrim(proto), S("TLSv1.1"))) { 195 #ifdef SSL_OP_NO_TLSv1_1 196 SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1_1); 197 #else 198 log_ereport( 199 LOG_WARN, 200 "Listener: %s: TLSv1.1 already not supported", 201 listener->name.ptr); 202 #endif 203 } else if(sstrcasecmp(sstrtrim(proto), S("TLSv1.2"))) { 204 #ifdef SSL_OP_NO_TLSv1_2 205 SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1_2); 206 #else 207 log_ereport( 208 LOG_WARN, 209 "Listener: %s: TLSv1.2 already not supported", 210 listener->name.ptr); 211 #endif 212 } else if(sstrcasecmp(sstrtrim(proto), S("TLSv1.3"))) { 213 #ifdef SSL_OP_NO_TLSv1_3 214 SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1_3); 215 #else 216 log_ereport( 217 LOG_WARN, 218 "Listener: %s: TLSv1.3 already not supported", 219 listener->name.ptr); 220 #endif 221 } else { 222 error = 1; 223 log_ereport( 224 LOG_MISCONFIG, 225 "Listener: %s: Unknown protocol %s", 226 listener->name.ptr, 227 proto.ptr); 228 } 229 free(proto.ptr); 230 } 231 free(plist); 232 } 233 } 234 235 if(error) { 236 return NULL; 237 } 238 // TODO: cleanup on error 239 240 sstr_t file; 241 int ret; 242 char errbuf[512]; 243 244 if(!conf->chainfile.ptr) { 245 file = sstrdup(conf->certfile); 246 ret = SSL_CTX_use_certificate_file(ctx, file.ptr, SSL_FILETYPE_PEM); 247 free(file.ptr); 248 if(!ret) { 249 ERR_error_string(ERR_get_error(), errbuf); 250 log_ereport(LOG_MISCONFIG, "Cannot load ssl chain file: %s", errbuf); 251 return NULL; 252 } 253 } else { 254 file = sstrdup(conf->chainfile); 255 ret = SSL_CTX_use_certificate_chain_file(ctx, file.ptr); 256 free(file.ptr); 257 if(!ret) { 258 ERR_error_string(ERR_get_error(), errbuf); 259 log_ereport(LOG_MISCONFIG, "Cannot load ssl cert file: %s", errbuf); 260 return NULL; 261 } 262 } 263 264 file = sstrdup(conf->privkeyfile); 265 ret = SSL_CTX_use_PrivateKey_file(ctx, file.ptr, SSL_FILETYPE_PEM); 266 free(file.ptr); 267 if(!ret) { 268 ERR_error_string(ERR_get_error(), errbuf); 269 log_ereport(LOG_MISCONFIG, "Cannot load ssl key file: %s", errbuf); 270 return NULL; 271 } 272 273 // TODO: chain 274 listener->ssl->sslctx = ctx; 275 } 276 277 278 ucx_map_sstr_put(listener_map, listener->name, listener); 279 280 struct sockaddr_in servaddr; /* server address */ 281 282 /* init address structure */ 283 memset(&servaddr, 0, sizeof(servaddr)); 284 servaddr.sin_family = AF_INET; 285 servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 286 servaddr.sin_port = htons(conf->port); 287 288 /* create socket */ 289 if((listener->server_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) { 290 perror("Error: http_listener_new: socket"); 291 return NULL; 292 } 293 294 int o = 1; 295 setsockopt( 296 listener->server_socket, 297 SOL_SOCKET, SO_REUSEADDR, 298 &o, 299 sizeof(int)); 300 301 /* bind server socket to address */ 302 if(bind(listener->server_socket, (struct sockaddr*)&servaddr, sizeof(servaddr))){ 303 log_ereport(LOG_FAILURE, "http_listener_new: bind failed. Port: %d", conf->port); 304 return NULL; 305 } 306 307 /* create acceptors */ 308 listener->acceptors = calloc(listener->nacceptors, sizeof(void*)); 309 for (int i=0;i<listener->nacceptors;i++) { 310 listener->acceptors[i] = acceptor_new(listener); 311 } 312 313 return listener; 314 } 315 316 int http_listener_start(HttpListener *listener) { 317 if(listener->running) { 318 return 0; 319 } 320 log_ereport(LOG_INFORM, "start listener on port %d", listener->port); 321 322 if (listen(listener->server_socket, 256) == -1) { 323 log_ereport(LOG_FAILURE, "http_listener_start: listen failed"); 324 return -1; 325 } 326 327 /* start acceptor threads */ 328 for (int i=0;i<listener->nacceptors;i++) { 329 acceptor_start(listener->acceptors[i]); 330 } 331 332 return 0; 333 } 334 335 void http_listener_ref(HttpListener *listener) { 336 ws_atomic_inc32(&listener->ref); 337 } 338 339 void http_listener_unref(HttpListener *listener) { 340 uint32_t ref = ws_atomic_dec32(&listener->ref); 341 if(ref == 0) { 342 free(listener->acceptors); 343 // TODO: unref cfg 344 // TODO: unref session handler 345 free(listener); 346 } 347 } 348 349 350 351 Acceptor* acceptor_new(HttpListener *listener) { 352 Acceptor *acceptor = malloc(sizeof(Acceptor)); 353 acceptor->listener = listener; 354 return acceptor; 355 } 356 357 void acceptor_start(Acceptor *a) { 358 if(pthread_create( 359 &a->tid, 360 NULL, 361 (void*(*)(void*))acceptor_thread, 362 a) != 0) 363 { 364 perror("Error: acceptor_start: pthread_create"); 365 } 366 } 367 368 void* acceptor_thread(Acceptor *acceptor) { 369 WS_ASSERT(acceptor); 370 WS_ASSERT(acceptor->listener); 371 WS_ASSERT(acceptor->listener->session_handler); 372 WS_ASSERT(acceptor->listener->session_handler->enqueue_connection); 373 374 HttpListener *listener = acceptor->listener; 375 376 for (;;) { 377 /* accept connections */ 378 struct sockaddr_in ca; 379 socklen_t length = sizeof(ca); 380 int clientfd; 381 382 /* accept a connection */ 383 clientfd = accept( 384 listener->server_socket, 385 (struct sockaddr*)&ca, 386 &length); 387 if (clientfd == -1) { 388 perror("Error: acceptor_thread: accept"); 389 continue; 390 } 391 392 // check listener 393 HttpListener *ls = listener; 394 int acceptor_exit = 0; 395 while(ls->next) { 396 ls = ls->next; 397 acceptor_exit = 1; 398 } 399 400 /* create Connection object */ 401 Connection *conn = malloc(sizeof(Connection)); 402 conn->address = ca; 403 conn->fd = clientfd; 404 conn->listener = ls; 405 conn->ssl_accepted = 0; 406 if(ls->ssl) { 407 // SSL connections are always non-blocking 408 // set socket non blocking 409 int flags; 410 if((flags = fcntl(conn->fd, F_GETFL, 0)) == -1) { 411 flags = 0; 412 } 413 if(fcntl(conn->fd, F_SETFL, flags | O_NONBLOCK)) { 414 perror("Error: acceptor_thread: fcntl"); 415 // TODO: error 416 } 417 418 SSL *ssl = SSL_new(ls->ssl->sslctx); 419 SSL_set_fd(ssl, clientfd); 420 421 conn->ssl = ssl; 422 conn->read = connection_ssl_read; 423 conn->write = connection_ssl_write; 424 conn->close = connection_ssl_close; 425 } else { 426 conn->ssl = NULL; 427 conn->read = connection_read; 428 conn->write = connection_write; 429 conn->close = connection_close; 430 } 431 432 if(conn) { 433 cfg_ref(ls->cfg); 434 435 /* enqueue the connection */ 436 ls->session_handler->enqueue_connection( 437 ls->session_handler, 438 conn); 439 } 440 441 /* ready for new connection */ 442 443 if(acceptor_exit) { 444 // this acceptor is outdated 445 break; 446 } 447 } 448 449 http_listener_unref(listener->next); 450 http_listener_unref(listener); 451 452 return NULL; 453 } 454