#include #include #include #include #include #include #include #include #ifdef __APPLE__ #include #endif #include #include "debug.h" #include "str-utils.h" #include "instance.h" #include "client.h" #include "server.h" /** * @brief Creates TCP server socket, binds to address and starts to listen. * @param server a pointer to #aisl_server_t instance. * @return #aisl_status_t code. */ static aisl_status_t aisl_server_open(aisl_server_t server) { int fd, s_opt = 1; fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); if (fd != -1) { setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&s_opt, sizeof(int)); #ifdef __APPLE__ ioctl(fd, FIONBIO, (char *)&s_opt); fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK); #endif s_opt = sizeof(struct sockaddr_in); if (bind(fd, (struct sockaddr *) &server->address, s_opt)==0) { if (listen(fd, SOMAXCONN) == 0) { server->fd = fd; return AISL_SUCCESS; } } close(fd); } return AISL_SYSCALL_ERROR; } /** * @brief Tries to accept a new client. * @param server a pointer to #aisl_server_t instance. * @param p_client a pointer to store #aisl_client_t instance pointer. * @return #aisl_status_t code. */ static aisl_status_t aisl_server_accept( aisl_server_t server, aisl_client_t * p_client ) { int fd; struct sockaddr_in addr; socklen_t len = sizeof(struct sockaddr_in); fd = accept(server->fd, (struct sockaddr *) &addr, &len); if (fd != -1) { int flags; DPRINTF("accepted fd=%d", fd); if ((flags = fcntl(fd, F_GETFL, 0)) != -1) { flags |= O_NONBLOCK; if (fcntl(fd, F_SETFL, flags) == 0) { return (!(*p_client = aisl_client_new(server, fd, &addr))) ? AISL_MALLOC_ERROR : AISL_SUCCESS; } } close(fd); } else if (errno == EWOULDBLOCK) return AISL_IDLE; return AISL_SYSCALL_ERROR; } /* Library Level ------------------------------------------------------------ */ aisl_status_t aisl_server_touch( aisl_server_t server, aisl_client_t * p_client ) { aisl_status_t result; if (server->fd == -1) { if ((result = aisl_server_open(server)) != AISL_IDLE) { aisl_raise( server->instance, server, ((result == AISL_SUCCESS) ? AISL_EVENT_SERVER_OPEN : AISL_EVENT_SERVER_ERROR), result ); } } else result = aisl_server_accept(server, p_client); return result; } int aisl_server_get_socket( aisl_server_t server ) { return server->fd; } aisl_server_t aisl_server_new(aisl_cfg_srv_t const cfg_srv, aisl_t instance) { aisl_server_t server; if ( (server = calloc(1, sizeof(struct aisl_server))) != NULL ) { server->instance = instance; server->fd = -1; server->address.sin_family = AF_INET; server->address.sin_addr.s_addr = inet_addr(cfg_srv->host); server->address.sin_port = htons(cfg_srv->port); server->ssl = cfg_srv->secure; } return server; } void aisl_server_free(aisl_server_t server) { if (server) { if ( server->fd != -1) { close(server->fd); server->fd=-1; } free(server); } } /* API Level ---------------------------------------------------------------- */ __attribute__ ((visibility ("default") )) void aisl_server_get_address( aisl_server_t server, struct sockaddr_in * address) { memcpy(address, &server->address, sizeof(struct sockaddr_in)); } #ifndef AISL_WITHOUT_SSL __attribute__ ((visibility ("default") )) bool aisl_server_get_ssl( aisl_server_t server ) { return server->ssl; } #endif