|
|
@ -20,93 +20,6 @@
|
|
|
|
* Private Static Inline *
|
|
|
|
* Private Static Inline *
|
|
|
|
************************/
|
|
|
|
************************/
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Start the module as a server listening at module->port
|
|
|
|
|
|
|
|
* @param module
|
|
|
|
|
|
|
|
* @returns 0 on success, -1 on error
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
static inline int
|
|
|
|
|
|
|
|
module_listen(struct module *module)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Allocate a new TCP/IP socket, setting it to be non-blocking */
|
|
|
|
|
|
|
|
int socket_descriptor = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
|
|
|
|
|
|
|
|
if (unlikely(socket_descriptor < 0)) goto err_create_socket;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Socket should never have returned on fd 0, 1, or 2 */
|
|
|
|
|
|
|
|
assert(socket_descriptor != STDIN_FILENO);
|
|
|
|
|
|
|
|
assert(socket_descriptor != STDOUT_FILENO);
|
|
|
|
|
|
|
|
assert(socket_descriptor != STDERR_FILENO);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Configure the socket to allow multiple sockets to bind to the same host and port */
|
|
|
|
|
|
|
|
int optval = 1;
|
|
|
|
|
|
|
|
rc = setsockopt(socket_descriptor, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval));
|
|
|
|
|
|
|
|
if (unlikely(rc < 0)) goto err_set_socket_option;
|
|
|
|
|
|
|
|
optval = 1;
|
|
|
|
|
|
|
|
rc = setsockopt(socket_descriptor, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
|
|
|
|
|
|
|
|
if (unlikely(rc < 0)) goto err_set_socket_option;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Bind name [all addresses]:[module->port] to socket */
|
|
|
|
|
|
|
|
module->socket_descriptor = socket_descriptor;
|
|
|
|
|
|
|
|
module->socket_address.sin_family = AF_INET;
|
|
|
|
|
|
|
|
module->socket_address.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
|
|
|
|
|
|
module->socket_address.sin_port = htons((unsigned short)module->port);
|
|
|
|
|
|
|
|
rc = bind(socket_descriptor, (struct sockaddr *)&module->socket_address, sizeof(module->socket_address));
|
|
|
|
|
|
|
|
if (unlikely(rc < 0)) goto err_bind_socket;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Listen to the interface */
|
|
|
|
|
|
|
|
rc = listen(socket_descriptor, MODULE_MAX_PENDING_CLIENT_REQUESTS);
|
|
|
|
|
|
|
|
if (unlikely(rc < 0)) goto err_listen;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Set the socket descriptor and register with our global epoll instance to monitor for incoming HTTP
|
|
|
|
|
|
|
|
requests */
|
|
|
|
|
|
|
|
rc = listener_thread_register_module(module);
|
|
|
|
|
|
|
|
if (unlikely(rc < 0)) goto err_add_to_epoll;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rc = 0;
|
|
|
|
|
|
|
|
done:
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
err_add_to_epoll:
|
|
|
|
|
|
|
|
err_listen:
|
|
|
|
|
|
|
|
err_bind_socket:
|
|
|
|
|
|
|
|
module->socket_descriptor = -1;
|
|
|
|
|
|
|
|
err_set_socket_option:
|
|
|
|
|
|
|
|
close(socket_descriptor);
|
|
|
|
|
|
|
|
err_create_socket:
|
|
|
|
|
|
|
|
err:
|
|
|
|
|
|
|
|
debuglog("Socket Error: %s", strerror(errno));
|
|
|
|
|
|
|
|
rc = -1;
|
|
|
|
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************
|
|
|
|
|
|
|
|
* Public Methods
|
|
|
|
|
|
|
|
***************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Module Mega Teardown Function
|
|
|
|
|
|
|
|
* Closes the socket and dynamic library, and then frees the module
|
|
|
|
|
|
|
|
* Returns harmlessly if there are outstanding references
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* TODO: Untested Functionality. Unsure if this will work. Also, what about the module database? Do we
|
|
|
|
|
|
|
|
* need to do any cleanup there? Issue #17
|
|
|
|
|
|
|
|
* @param module - the module to teardown
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
|
|
module_free(struct module *module)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (module == NULL) return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Do not free if we still have oustanding references */
|
|
|
|
|
|
|
|
if (module->reference_count) return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
close(module->socket_descriptor);
|
|
|
|
|
|
|
|
sledge_abi_symbols_deinit(&module->abi);
|
|
|
|
|
|
|
|
free(module);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static inline int
|
|
|
|
static inline int
|
|
|
|
module_init(struct module *module, char *name, char *path, uint32_t stack_size, uint32_t relative_deadline_us,
|
|
|
|
module_init(struct module *module, char *name, char *path, uint32_t stack_size, uint32_t relative_deadline_us,
|
|
|
|
uint16_t port, uint32_t request_size, uint32_t response_size, uint8_t admissions_percentile,
|
|
|
|
uint16_t port, uint32_t request_size, uint32_t response_size, uint8_t admissions_percentile,
|
|
|
@ -193,6 +106,93 @@ err:
|
|
|
|
goto done;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************
|
|
|
|
|
|
|
|
* Public Methods
|
|
|
|
|
|
|
|
***************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Start the module as a server listening at module->port
|
|
|
|
|
|
|
|
* @param module
|
|
|
|
|
|
|
|
* @returns 0 on success, -1 on error
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
int
|
|
|
|
|
|
|
|
module_listen(struct module *module)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Allocate a new TCP/IP socket, setting it to be non-blocking */
|
|
|
|
|
|
|
|
int socket_descriptor = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
|
|
|
|
|
|
|
|
if (unlikely(socket_descriptor < 0)) goto err_create_socket;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Socket should never have returned on fd 0, 1, or 2 */
|
|
|
|
|
|
|
|
assert(socket_descriptor != STDIN_FILENO);
|
|
|
|
|
|
|
|
assert(socket_descriptor != STDOUT_FILENO);
|
|
|
|
|
|
|
|
assert(socket_descriptor != STDERR_FILENO);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Configure the socket to allow multiple sockets to bind to the same host and port */
|
|
|
|
|
|
|
|
int optval = 1;
|
|
|
|
|
|
|
|
rc = setsockopt(socket_descriptor, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval));
|
|
|
|
|
|
|
|
if (unlikely(rc < 0)) goto err_set_socket_option;
|
|
|
|
|
|
|
|
optval = 1;
|
|
|
|
|
|
|
|
rc = setsockopt(socket_descriptor, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
|
|
|
|
|
|
|
|
if (unlikely(rc < 0)) goto err_set_socket_option;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Bind name [all addresses]:[module->port] to socket */
|
|
|
|
|
|
|
|
module->socket_descriptor = socket_descriptor;
|
|
|
|
|
|
|
|
module->socket_address.sin_family = AF_INET;
|
|
|
|
|
|
|
|
module->socket_address.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
|
|
|
|
|
|
module->socket_address.sin_port = htons((unsigned short)module->port);
|
|
|
|
|
|
|
|
rc = bind(socket_descriptor, (struct sockaddr *)&module->socket_address, sizeof(module->socket_address));
|
|
|
|
|
|
|
|
if (unlikely(rc < 0)) goto err_bind_socket;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Listen to the interface */
|
|
|
|
|
|
|
|
rc = listen(socket_descriptor, MODULE_MAX_PENDING_CLIENT_REQUESTS);
|
|
|
|
|
|
|
|
if (unlikely(rc < 0)) goto err_listen;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Set the socket descriptor and register with our global epoll instance to monitor for incoming HTTP
|
|
|
|
|
|
|
|
requests */
|
|
|
|
|
|
|
|
rc = listener_thread_register_module(module);
|
|
|
|
|
|
|
|
if (unlikely(rc < 0)) goto err_add_to_epoll;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rc = 0;
|
|
|
|
|
|
|
|
done:
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
err_add_to_epoll:
|
|
|
|
|
|
|
|
err_listen:
|
|
|
|
|
|
|
|
err_bind_socket:
|
|
|
|
|
|
|
|
module->socket_descriptor = -1;
|
|
|
|
|
|
|
|
err_set_socket_option:
|
|
|
|
|
|
|
|
close(socket_descriptor);
|
|
|
|
|
|
|
|
err_create_socket:
|
|
|
|
|
|
|
|
err:
|
|
|
|
|
|
|
|
debuglog("Socket Error: %s", strerror(errno));
|
|
|
|
|
|
|
|
rc = -1;
|
|
|
|
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Module Mega Teardown Function
|
|
|
|
|
|
|
|
* Closes the socket and dynamic library, and then frees the module
|
|
|
|
|
|
|
|
* Returns harmlessly if there are outstanding references
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* TODO: Untested Functionality. Unsure if this will work. Also, what about the module database? Do we
|
|
|
|
|
|
|
|
* need to do any cleanup there? Issue #17
|
|
|
|
|
|
|
|
* @param module - the module to teardown
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
|
|
module_free(struct module *module)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (module == NULL) return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Do not free if we still have oustanding references */
|
|
|
|
|
|
|
|
if (module->reference_count) return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
close(module->socket_descriptor);
|
|
|
|
|
|
|
|
sledge_abi_symbols_deinit(&module->abi);
|
|
|
|
|
|
|
|
free(module);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Module Contructor
|
|
|
|
* Module Contructor
|
|
|
|
* Creates a new module, invokes initialize_tables to initialize the indirect table, and adds it to the module DB
|
|
|
|
* Creates a new module, invokes initialize_tables to initialize the indirect table, and adds it to the module DB
|
|
|
|