/* * src/instance.c * * Copyright (C) 2019 Ilja KartaĊĦov * * Project homepage: https://lowenware.com/aisl/ * */ #include #include #include #include #include #include #include #ifndef AISL_WITHOUT_SSL #include #endif #include "debug.h" #include "str-utils.h" #include "buffer.h" #include "client.h" #include "server.h" //#include "globals.h" #include "stream.h" #include "instance.h" #ifndef AISL_WITHOUT_SSL static uint32_t m_instances = 0; static const aisl_ssl_t aisl_new_ssl( aisl_t instance, const aisl_cfg_ssl_t cfg_ssl) { SSL_CTX * ssl_ctx = NULL; aisl_ssl_t * list = instance->ssl, ssl; /* lookup for existing contexts */ while( (ssl = *list) ) { if (ssl->key_file && strcmp(ssl->key_file, cfg_ssl->key_file)==0 && ssl->crt_file && strcmp(ssl->crt_file, cfg_ssl->crt_file)==0 ) { ssl_ctx = ssl->ctx; break; } list++; } ssl = aisl_ssl_new( cfg_ssl->host, cfg_ssl->key_file, cfg_ssl->crt_file, ssl_ctx ); if (ssl) { if ( !ssl_ctx && !aisl_ssl_get_ctx(ssl, (void*) instance)) { aisl_ssl_free(ssl); ssl = NULL; } } return ssl; } #endif /* Initialization functions */ __attribute__ ((visibility ("default") )) aisl_t aisl_new( aisl_cfg_t cfg ) { aisl_t instance; /* allocate root structure */ if ( !(instance = calloc(1, sizeof(struct aisl))) ) goto finally; /* allocate servers */ if ( !(instance->srv = calloc(cfg->srv_cnt+1, sizeof(aisl_server_t))) ) goto release; for (int i=0; isrv_cnt; i++) { DPRINTF("new srv %d", i); if (!(instance->srv[i] = aisl_server_new(&cfg->srv[i], instance))) goto release; } #ifndef AISL_WITHOUT_SSL if ((m_instances++) == 0) { SSL_load_error_strings(); OpenSSL_add_ssl_algorithms(); } if ( !(instance->ssl = calloc(cfg->ssl_cnt+1, sizeof(aisl_ssl_t))) ) goto release; for (int i=0; issl_cnt; i++) { DPRINTF("new ssl %d", i); if (!(instance->ssl[i] = aisl_new_ssl(instance, &cfg->ssl[i]))) goto release; } #endif if ( list_init(&instance->client_spool, cfg->client_spool_size) == -1 ) goto release; instance->accept_limit = cfg->client_accept_limit; instance->silence_timeout = cfg->client_silence_timeout; instance->callback = cfg->callback; instance->p_ctx = cfg->p_ctx; goto finally; release: aisl_free(instance); instance = NULL; finally: return instance; } __attribute__ ((visibility ("default") )) void aisl_free( aisl_t instance ) { if (instance->srv) { aisl_server_t * srv = instance->srv; while (*srv) { aisl_server_free(*srv); srv++; } free(instance->srv); } list_release(&instance->client_spool, (list_destructor_t) aisl_client_free ); #ifndef AISL_WITHOUT_SSL if (instance->ssl) { aisl_ssl_t * ssl = instance->ssl; while (*ssl) { aisl_ssl_free(*ssl); ssl++; } free(instance->ssl); } if ((--m_instances) == 0) { EVP_cleanup(); } #endif free(instance); } #ifndef AISL_WITHOUT_SSL SSL_CTX * aisl_get_ssl_ctx( aisl_t instance, const char * host ) { aisl_ssl_t * list = instance->ssl, ssl; if (host) { while ( (ssl = *list) ) { if (str_cmpi(ssl->host, host) == 0) { return ssl->ctx; } list++; } } return NULL; } #endif void aisl_raise_evt( aisl_t instance, aisl_evt_t const evt ) { #ifdef AISL_WITHOUT_STRINGIFIERS DPRINTF("! %d", evt->code); #else DPRINTF("! %s", aisl_evt_code_to_string(evt->code)); #endif if (instance->callback) instance->callback(evt, instance->p_ctx); } void aisl_raise( aisl_t instance, void * source, aisl_evt_code_t code, aisl_status_t status ) { struct aisl_evt evt; evt.source = source; evt.code = code; evt.status = status; aisl_raise_evt(instance, &evt); } __attribute__ ((visibility ("default") )) aisl_status_t aisl_run_cycle( aisl_t instance ) { aisl_status_t result = AISL_IDLE; aisl_server_t * list = instance->srv, srv; aisl_client_t cli; while ( (srv = *list) ) { cli = NULL; if (aisl_server_touch(srv, &cli) != AISL_IDLE) result = AISL_SUCCESS; if (cli) { DPRINTF("Accepted %p", (void*)cli); if ( list_append(&instance->client_spool, cli) == -1 ) aisl_client_free(cli); } list++; } for (int32_t i=0; i < instance->client_spool.count; i++) { cli = LIST_INDEX(instance->client_spool, i); if (aisl_client_touch(cli, instance->silence_timeout) != AISL_IDLE) result = AISL_SUCCESS; /* if (aisl_client_is_timed_out( c, instance->silence_timeout ) ) aisl_raise( instance, c, AISL_EVENT_CLIENT_TIMEOUT ); */ if ( !aisl_client_is_online(cli) ) { aisl_client_free( cli ); list_remove_index(&instance->client_spool, i); } } return result; } __attribute__ ((visibility ("default") )) aisl_status_t aisl_sleep( aisl_t instance, uint32_t usec ) { int maxfd=0, sd; size_t i; struct timeval timeout = {0,usec}; memset(&timeout, 0, sizeof(struct timeval)); timeout.tv_usec = usec; fd_set fs; FD_ZERO (&fs); aisl_server_t * list = instance->srv, srv; while ( (srv = *list) ) { sd = aisl_server_get_socket(srv); if (sd != -1) { FD_SET(sd, &fs); if (sd > maxfd) maxfd = sd; } list++; } for (i=0; iclient_spool.count; i++) { aisl_client_t c = LIST_INDEX(instance->client_spool, i); sd = aisl_client_get_socket(c); if (sd != -1) { FD_SET(sd, &fs); if (sd > maxfd) maxfd = sd; } } switch ( select(maxfd+1, &fs, NULL, NULL, &timeout) ) { case -1: return AISL_SYSCALL_ERROR; case 0: return AISL_IDLE; default: return AISL_SUCCESS; } }