aisl/src/server.c

196 lines
3.7 KiB
C

#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <netdb.h>
#include <fcntl.h>
#ifdef __APPLE__
#include <sys/ioctl.h>
#endif
#include <openssl/ssl.h>
#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