|
|
|
@ -41,15 +41,41 @@ struct ipc_error ipc_ctx_init (struct ipc_ctx **ctx)
|
|
|
|
|
T_R ((*ctx == NULL), IPC_ERROR_CTX_INIT__MALLOC_CTX);
|
|
|
|
|
memset (ctx, 0, sizeof(struct ipc_ctx));
|
|
|
|
|
|
|
|
|
|
// (*ctx)->cinfos = malloc(sizeof(struct ));
|
|
|
|
|
// T_R (((*ctx)->pollfd == NULL), IPC_ERROR_CTX_INIT__MALLOC_POLLFD);
|
|
|
|
|
//
|
|
|
|
|
// (*ctx)->pollfd = malloc(sizeof(struct pollfd));
|
|
|
|
|
// T_R (((*ctx)->pollfd == NULL), IPC_ERROR_CTX_INIT__MALLOC_POLLFD);
|
|
|
|
|
|
|
|
|
|
IPC_RETURN_NO_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* PERFORMANCE POINT:
|
|
|
|
|
* Realloc is performed at each new user. There is plenty of room for improvement,
|
|
|
|
|
* for example by managing allocations of thousands of structures at once.
|
|
|
|
|
* WARNING: Store and remove only pointers on allocated structures.
|
|
|
|
|
*/
|
|
|
|
|
struct ipc_error
|
|
|
|
|
ipc_ctx_new_alloc (struct ipc_ctx *ctx)
|
|
|
|
|
{
|
|
|
|
|
ctx->size++;
|
|
|
|
|
|
|
|
|
|
// Memory could be not allocated, yet.
|
|
|
|
|
if (ctx->size == 1 && ctx->cinfos == NULL && ctx->pollfd == NULL) {
|
|
|
|
|
SECURE_BUFFER_HEAP_ALLOCATION_R (ctx->cinfos, sizeof (struct ipc_connection_info),,
|
|
|
|
|
IPC_ERROR_ADD__MALLOC);
|
|
|
|
|
SECURE_BUFFER_HEAP_ALLOCATION_R (ctx->pollfd, sizeof (struct pollfd),,
|
|
|
|
|
IPC_ERROR_ADD__MALLOC_POLLFD);
|
|
|
|
|
} else {
|
|
|
|
|
ctx->cinfos = realloc (ctx->cinfos, sizeof (struct ipc_connection_info) * ctx->size);
|
|
|
|
|
ctx->pollfd = realloc (ctx->pollfd, sizeof (struct pollfd ) * ctx->size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
T_R ((ctx->cinfos == NULL), IPC_ERROR_ADD__EMPTY_LIST);
|
|
|
|
|
T_R ((ctx->pollfd == NULL), IPC_ERROR_ADD__EMPTY_LIST);
|
|
|
|
|
|
|
|
|
|
// Clean the last entry.
|
|
|
|
|
memset (ctx->cinfos[ctx-size -1], 0, sizeof (struct ipc_connection_info));
|
|
|
|
|
memset (ctx->pollfd[ctx-size -1], 0, sizeof (struct pollfd));
|
|
|
|
|
|
|
|
|
|
IPC_RETURN_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct ipc_error
|
|
|
|
|
ipc_server_init (char **env, struct ipc_ctx **ctx, const char *sname)
|
|
|
|
|
{
|
|
|
|
@ -58,46 +84,25 @@ ipc_server_init (char **env, struct ipc_ctx **ctx, const char *sname)
|
|
|
|
|
|
|
|
|
|
ipc_ctx_init(ctx);
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
// For server init, no need for networkd evaluation
|
|
|
|
|
|
|
|
|
|
// TODO: loop over environment variables
|
|
|
|
|
// any IPC_NETWORK_* should be shared with the network service
|
|
|
|
|
// in order to route requests over any chosen protocol stack
|
|
|
|
|
// ex: IPC_NETWORK_AUDIO="tor://some.example.com/"
|
|
|
|
|
for (size_t i = 0; env[i] != NULL; i++) {
|
|
|
|
|
// TODO: check for every IPC_NETWORK_* environment variable
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
struct ipc_connection_info *srv = NULL;
|
|
|
|
|
|
|
|
|
|
// Initialize the server IPC structure.
|
|
|
|
|
SECURE_BUFFER_HEAP_ALLOCATION_R (srv, sizeof (struct ipc_connection_info),,
|
|
|
|
|
IPC_ERROR_SERVER_INIT__NOT_ENOUGH_MEMORY);
|
|
|
|
|
|
|
|
|
|
srv->type = IPC_CONNECTION_TYPE_SERVER;
|
|
|
|
|
|
|
|
|
|
// gets the service path
|
|
|
|
|
SECURE_BUFFER_DECLARATION (char, buf, PATH_MAX);
|
|
|
|
|
TEST_IPC_RR (service_path (buf, sname), "cannot get server path");
|
|
|
|
|
|
|
|
|
|
// gets the service path
|
|
|
|
|
if (srv->spath != NULL) {
|
|
|
|
|
free (srv->spath);
|
|
|
|
|
srv->spath = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t s = strlen (buf);
|
|
|
|
|
|
|
|
|
|
SECURE_BUFFER_HEAP_ALLOCATION_R (srv->spath, s + 1,, IPC_ERROR_SERVER_INIT__MALLOC);
|
|
|
|
|
memcpy (srv->spath, buf, s);
|
|
|
|
|
srv->spath[s] = '\0'; // to be sure
|
|
|
|
|
SECURE_DECLARATION (struct ipc_connection_info, srv);
|
|
|
|
|
srv.type = IPC_CONNECTION_TYPE_SERVER;
|
|
|
|
|
SECURE_DECLARATION(struct pollfd, pollfd);
|
|
|
|
|
pollfd.events = POLLIN;
|
|
|
|
|
|
|
|
|
|
TEST_IPC_RETURN_ON_ERROR (usock_init (&srv->pollfd.fd, srv->spath));
|
|
|
|
|
SECURE_BUFFER_HEAP_ALLOCATION_R (srv.spath, s + 1,, IPC_ERROR_SERVER_INIT__MALLOC);
|
|
|
|
|
memcpy (srv.spath, buf, s);
|
|
|
|
|
srv.spath[s] = '\0'; // to be sure
|
|
|
|
|
|
|
|
|
|
TEST_IPC_RETURN_ON_ERROR (usock_init (&pollfd.fd, srv.spath));
|
|
|
|
|
|
|
|
|
|
// Add the server to the listened file descriptors.
|
|
|
|
|
TEST_IPC_RR (ipc_add (ctx, srv), "cannot add the server in the context");
|
|
|
|
|
TEST_IPC_RR (ipc_add (*ctx, &srv, &pollfd), "cannot add the server in the context");
|
|
|
|
|
|
|
|
|
|
IPC_RETURN_NO_ERROR;
|
|
|
|
|
}
|
|
|
|
@ -105,14 +110,14 @@ ipc_server_init (char **env, struct ipc_ctx **ctx, const char *sname)
|
|
|
|
|
struct ipc_error ipc_write_fd (int fd, const struct ipc_message *m);
|
|
|
|
|
|
|
|
|
|
// when networkd is not working properly (or do not retrieve the service): srv->fd = 0
|
|
|
|
|
struct ipc_error ipc_contact_networkd (struct ipc_connection_info *srv, const char *sname)
|
|
|
|
|
struct ipc_error ipc_contact_networkd (int *pfd, const char *sname)
|
|
|
|
|
{
|
|
|
|
|
T_R ((srv == NULL), IPC_ERROR_CONTACT_NETWORKD__NO_SERVER_PARAM);
|
|
|
|
|
T_R ((pfd == NULL), IPC_ERROR_CONTACT_NETWORKD__NO_FD_PARAM);
|
|
|
|
|
T_R ((sname == NULL), IPC_ERROR_CONTACT_NETWORKD__NO_SERVICE_NAME_PARAM);
|
|
|
|
|
|
|
|
|
|
char *networkvar = getenv ("IPC_NETWORK");
|
|
|
|
|
if (networkvar == NULL) {
|
|
|
|
|
srv->pollfd.fd = 0;
|
|
|
|
|
*pfd = 0;
|
|
|
|
|
IPC_RETURN_NO_ERROR;
|
|
|
|
|
}
|
|
|
|
|
// TODO: is there another, more interesting way to do this?
|
|
|
|
@ -128,7 +133,7 @@ struct ipc_error ipc_contact_networkd (struct ipc_connection_info *srv, const ch
|
|
|
|
|
|
|
|
|
|
if (strncmp (networkvar, sname, strlen (sname)) != 0 && strstr (networkvar, columnthensname) == NULL) {
|
|
|
|
|
// printf ("sname %s not found\n", sname);
|
|
|
|
|
srv->pollfd.fd = 0;
|
|
|
|
|
*fd = 0;
|
|
|
|
|
IPC_RETURN_NO_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -152,7 +157,7 @@ struct ipc_error ipc_contact_networkd (struct ipc_connection_info *srv, const ch
|
|
|
|
|
|
|
|
|
|
TEST_IPC_RR (ipc_write_fd (networkdfd, &msg), "cannot send a message to networkd");
|
|
|
|
|
|
|
|
|
|
struct ipc_error ret = ipc_receive_fd (networkdfd, &srv->pollfd.fd);
|
|
|
|
|
struct ipc_error ret = ipc_receive_fd (networkdfd, pfd);
|
|
|
|
|
if (ret.error_code == IPC_ERROR_NONE) {
|
|
|
|
|
usock_close (networkdfd);
|
|
|
|
|
}
|
|
|
|
@ -167,27 +172,26 @@ struct ipc_error ipc_connection (char **env, struct ipc_ctx **ctx, const char *s
|
|
|
|
|
T_R ((ctx == NULL), IPC_ERROR_CONNECTION__NO_CTX);
|
|
|
|
|
T_R ((sname == NULL), IPC_ERROR_CONNECTION__NO_SERVICE_NAME);
|
|
|
|
|
|
|
|
|
|
ipc_ctx_init(ctx);
|
|
|
|
|
ipc_ctx_init(ctx); // Allocate memory for the context.
|
|
|
|
|
|
|
|
|
|
struct ipc_connection_info *srv = NULL;
|
|
|
|
|
SECURE_BUFFER_HEAP_ALLOCATION_R (srv, sizeof (struct ipc_connection_info),,
|
|
|
|
|
IPC_ERROR_CONNECTION__NOT_ENOUGH_MEMORY);
|
|
|
|
|
SECURE_DECLARATION(struct ipc_connection_info, srv);
|
|
|
|
|
srv.type = IPC_CONNECTION_TYPE_IPC; // Data received on the socket = messages, not new clients.
|
|
|
|
|
SECURE_DECLARATION(struct pollfd, pollfd);
|
|
|
|
|
pollfd.events = POLLIN;
|
|
|
|
|
|
|
|
|
|
srv->type = IPC_CONNECTION_TYPE_IPC;
|
|
|
|
|
|
|
|
|
|
// Add the server to the listened file descriptors.
|
|
|
|
|
TEST_IPC_RR (ipc_add (ctx, srv), "cannot add the server in the context");
|
|
|
|
|
|
|
|
|
|
TEST_IPC_P (ipc_contact_networkd (srv, sname), "error during networkd connection");
|
|
|
|
|
TEST_IPC_P (ipc_contact_networkd (&pollfd.fd, sname), "error during networkd connection");
|
|
|
|
|
|
|
|
|
|
// if networkd did not initiate the connection
|
|
|
|
|
if (srv->pollfd.fd <= 0) {
|
|
|
|
|
if (pollfd.fd <= 0) {
|
|
|
|
|
// gets the service path
|
|
|
|
|
SECURE_BUFFER_DECLARATION (char, buf, PATH_MAX);
|
|
|
|
|
TEST_IPC_RR (service_path (buf, sname), "cannot get server path");
|
|
|
|
|
TEST_IPC_RETURN_ON_ERROR (usock_connect (&srv->pollfd.fd, buf));
|
|
|
|
|
TEST_IPC_RETURN_ON_ERROR (usock_connect (&pollfd.fd, buf));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add the server to the listened file descriptors.
|
|
|
|
|
TEST_IPC_RR (ipc_add (*ctx, &srv, &pollfd), "cannot add the server in the context");
|
|
|
|
|
|
|
|
|
|
IPC_RETURN_NO_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -265,20 +269,20 @@ struct ipc_error ipc_write (const struct ipc_connection_info *p, const struct ip
|
|
|
|
|
|
|
|
|
|
// New connection from a client.
|
|
|
|
|
struct ipc_error
|
|
|
|
|
handle_connection (struct ipc_event *event
|
|
|
|
|
, struct ipc_ctx *cinfos
|
|
|
|
|
, struct ipc_connection_info *cinfo)
|
|
|
|
|
ipc_accept_add (struct ipc_event *event, struct ipc_ctx *ctx, uint32_t i)
|
|
|
|
|
{
|
|
|
|
|
T_R ((cinfo == NULL), IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFO_PARAM);
|
|
|
|
|
T_R ((cinfos == NULL), IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFOS_PARAM);
|
|
|
|
|
T_R ((ctx == NULL), IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFOS_PARAM);
|
|
|
|
|
T_R ((i >= ctx->size), IPC_ERROR_HANDLE_NEW_CONNECTION__INCONSISTENT_INDEX);
|
|
|
|
|
|
|
|
|
|
struct ipc_connection_info *new_client = NULL;
|
|
|
|
|
// Memory reallocation.
|
|
|
|
|
ipc_ctx_new_alloc (ctx);
|
|
|
|
|
|
|
|
|
|
SECURE_BUFFER_HEAP_ALLOCATION_R (new_client, sizeof (struct ipc_connection_info),,
|
|
|
|
|
IPC_ERROR_HANDLE_NEW_CONNECTION__MALLOC);
|
|
|
|
|
TEST_IPC_RR (usock_accept (ctx->pollfd[i].fd, &ctx->pollfd[ctx->size -1].fd), "cannot accept IPC connection");
|
|
|
|
|
ctx->pollfd[ctx->size -1].events = POLLIN; // Tell to poll(2) to watch for incoming data from this fd.
|
|
|
|
|
ctx->cinfos[ctx->size -1].type = IPC_CONNECTION_TYPE_IPC;
|
|
|
|
|
|
|
|
|
|
TEST_IPC_RR (ipc_accept (cinfo, new_client), "cannot accept the client during handle_new_connection");
|
|
|
|
|
TEST_IPC_RR (ipc_add (cinfos, new_client), "cannot add the new accepted client");
|
|
|
|
|
struct ipc_connection_info *new_client = &ctx->cinfos[ctx->size];
|
|
|
|
|
ctx->size++;
|
|
|
|
|
|
|
|
|
|
IPC_EVENT_SET (event, IPC_EVENT_TYPE_CONNECTION, NULL, new_client);
|
|
|
|
|
IPC_RETURN_NO_ERROR;
|
|
|
|
@ -287,7 +291,7 @@ handle_connection (struct ipc_event *event
|
|
|
|
|
// new message
|
|
|
|
|
struct ipc_error handle_message (
|
|
|
|
|
struct ipc_event *event
|
|
|
|
|
, struct ipc_ctx *cinfos
|
|
|
|
|
, struct ipc_ctx *ctx
|
|
|
|
|
, struct ipc_connection_info *pc, struct ipc_switchings *switchdb)
|
|
|
|
|
{
|
|
|
|
|
// if the socket is associated to another one for networkd
|
|
|
|
@ -331,11 +335,11 @@ struct ipc_error handle_message (
|
|
|
|
|
delfd = ipc_switching_del (switchdb, talkingfd);
|
|
|
|
|
if (delfd >= 0) {
|
|
|
|
|
close (delfd);
|
|
|
|
|
ipc_del_fd (cinfos, delfd);
|
|
|
|
|
ipc_del_fd (ctx, delfd);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
close (talkingfd);
|
|
|
|
|
ipc_del_fd (cinfos, talkingfd);
|
|
|
|
|
ipc_del_fd (ctx, talkingfd);
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
if (delfd >= 0) {
|
|
|
|
@ -371,15 +375,15 @@ struct ipc_error handle_message (
|
|
|
|
|
|
|
|
|
|
// if there is a problem, just remove the client
|
|
|
|
|
TEST_IPC_P (ipc_close (pc), "cannot close a connection in handle_message");
|
|
|
|
|
TEST_IPC_P (ipc_del (cinfos, pc), "cannot delete a connection in handle_message");
|
|
|
|
|
TEST_IPC_P (ipc_del (ctx, pc), "cannot delete a connection in handle_message");
|
|
|
|
|
|
|
|
|
|
IPC_EVENT_SET (event, IPC_EVENT_TYPE_ERROR, NULL, pc);
|
|
|
|
|
return rvalue;
|
|
|
|
|
}
|
|
|
|
|
// disconnection: close the client then delete it from cinfos
|
|
|
|
|
// disconnection: close the client then delete it from ctx
|
|
|
|
|
if (ret.error_code == IPC_ERROR_CLOSED_RECIPIENT) {
|
|
|
|
|
TEST_IPC_P (ipc_close (pc), "cannot close a connection on closed recipient in handle_message");
|
|
|
|
|
TEST_IPC_P (ipc_del (cinfos, pc), "cannot delete a connection on closed recipient in handle_message");
|
|
|
|
|
TEST_IPC_P (ipc_del (ctx, pc), "cannot delete a connection on closed recipient in handle_message");
|
|
|
|
|
|
|
|
|
|
ipc_message_empty (m);
|
|
|
|
|
free (m);
|
|
|
|
@ -394,111 +398,75 @@ struct ipc_error handle_message (
|
|
|
|
|
IPC_RETURN_NO_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
|
struct ipc_error
|
|
|
|
|
handle_writing_message (struct ipc_event *events, struct ipc_ctx *ctx, uint32_t i);
|
|
|
|
|
struct ipc_error
|
|
|
|
|
handle_writing_message (struct ipc_event *events, struct ipc_ctx *ctx, uint32_t i)
|
|
|
|
|
{
|
|
|
|
|
IPC_RETURN_NO_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct ipc_error
|
|
|
|
|
ipc_events_loop (
|
|
|
|
|
struct ipc_ctx *cinfos
|
|
|
|
|
struct ipc_ctx *ctx
|
|
|
|
|
, struct ipc_connection_info *cinfo // NULL for clients
|
|
|
|
|
, struct ipc_event *event
|
|
|
|
|
, struct ipc_switchings *switchdb
|
|
|
|
|
, struct ipc_messages *messages_to_send
|
|
|
|
|
, int *timer /* in ms */)
|
|
|
|
|
{
|
|
|
|
|
T_R ((cinfos == NULL), IPC_ERROR_WAIT_EVENT__NO_CLIENTS_PARAM);
|
|
|
|
|
T_R ((ctx == NULL), IPC_ERROR_WAIT_EVENT__NO_CLIENTS_PARAM);
|
|
|
|
|
T_R ((event == NULL), IPC_ERROR_WAIT_EVENT__NO_EVENT_PARAM);
|
|
|
|
|
|
|
|
|
|
IPC_EVENT_CLEAN (event);
|
|
|
|
|
|
|
|
|
|
// struct ipc_connection_info {
|
|
|
|
|
// struct pollfd *pollfd;
|
|
|
|
|
// char type; // server, client, arbitrary fd
|
|
|
|
|
// char *spath; // max size: PATH_MAX
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
// struct ipc_ctx {
|
|
|
|
|
// struct ipc_connection_info **cinfos;
|
|
|
|
|
// struct ipc_connection_info *pollfd;
|
|
|
|
|
// size_t size;
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
// struct ipc_event {
|
|
|
|
|
// enum ipc_event_type type;
|
|
|
|
|
// struct ipc_connection_info *origin;
|
|
|
|
|
// void *m; // message pointer
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
// enum ipc_event_type {
|
|
|
|
|
// IPC_EVENT_TYPE_NOT_SET = 0
|
|
|
|
|
// , IPC_EVENT_TYPE_ERROR = 1
|
|
|
|
|
// , IPC_EVENT_TYPE_EXTRA_SOCKET = 2 // Message coming from a non-IPC fd.
|
|
|
|
|
// , IPC_EVENT_TYPE_SWITCH = 3 // Message coming from a switched fd.
|
|
|
|
|
// , IPC_EVENT_TYPE_CONNECTION = 4
|
|
|
|
|
// , IPC_EVENT_TYPE_DISCONNECTION = 5
|
|
|
|
|
// , IPC_EVENT_TYPE_MESSAGE = 6
|
|
|
|
|
// , IPC_EVENT_TYPE_LOOKUP = 7
|
|
|
|
|
// , IPC_EVENT_TYPE_TIMER = 8
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
// struct ipc_messages {
|
|
|
|
|
// struct ipc_message **messages;
|
|
|
|
|
// size_t size;
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
// struct ipc_message {
|
|
|
|
|
// char type;
|
|
|
|
|
// char user_type;
|
|
|
|
|
// uint32_t length;
|
|
|
|
|
// char *payload;
|
|
|
|
|
// int fd; // File descriptor concerned about this message.
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
// struct pollfd {
|
|
|
|
|
// int fd; /* file descriptor */
|
|
|
|
|
// short events; /* requested events */
|
|
|
|
|
// short revents; /* returned events */
|
|
|
|
|
// };
|
|
|
|
|
// [struct pollfd]
|
|
|
|
|
|
|
|
|
|
int i, n, listenfd, client_fd, nread;
|
|
|
|
|
char buf[MAXLINE];
|
|
|
|
|
uid_t uid;
|
|
|
|
|
|
|
|
|
|
// Generate the array of pollfd structure once, then use it each time.
|
|
|
|
|
// TODO: ça ailleurs: if ( (cinfos->pollfd = malloc(sizeof(struct pollfd))) == NULL)
|
|
|
|
|
// TODO: ça ailleurs: if ( (ctx->pollfd = malloc(sizeof(struct pollfd))) == NULL)
|
|
|
|
|
// TODO: ça ailleurs: err_sys("malloc error");
|
|
|
|
|
// TODO: ça ailleurs: client_add(listenfd, 0); /* we use [0] for listenfd */
|
|
|
|
|
// TODO: ça ailleurs: cinfos->pollfd[0].fd = listenfd;
|
|
|
|
|
// TODO: ça ailleurs: cinfos->pollfd[0].events = POLLIN;
|
|
|
|
|
// TODO: ça ailleurs: ctx->pollfd[0].fd = listenfd;
|
|
|
|
|
// TODO: ça ailleurs: ctx->pollfd[0].events = POLLIN;
|
|
|
|
|
|
|
|
|
|
if ((n = poll(cinfos->pollfd, cinfos->size, INFTIM)) < 0)
|
|
|
|
|
if ((n = poll(ctx->pollfd, ctx->size, *timer)) < 0)
|
|
|
|
|
{
|
|
|
|
|
log_sys("select error");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i <= cinfos->size; i++) {
|
|
|
|
|
// Timeout.
|
|
|
|
|
if (n == 0) {
|
|
|
|
|
// TODO: timeout
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i <= ctx->size; i++) {
|
|
|
|
|
// Something to read or connection.
|
|
|
|
|
if (cinfos->pollfd[i].revents & POLLIN)
|
|
|
|
|
if (ctx->pollfd[i].revents & POLLIN)
|
|
|
|
|
{
|
|
|
|
|
// In case there is something to read for the server socket: new client.
|
|
|
|
|
if (cinfo != NULL && i == cinfo->pollfd) {
|
|
|
|
|
return handle_connection (event, cinfos, cinfo);
|
|
|
|
|
if (ctx->cinfos[i].type == IPC_CONNECTION_TYPE_SERVER) {
|
|
|
|
|
return ipc_accept_add (event, ctx, i);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (i == (size_t) cinfos->cinfos[j]->pollfd.fd) {
|
|
|
|
|
return handle_message (event, cinfos, cinfos->cinfos[j], switchdb);
|
|
|
|
|
}
|
|
|
|
|
return handle_message (event, ctx, i, switchdb);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if ((client_fd = cinfos->cinfos[i].fd) < 0)
|
|
|
|
|
if (ctx->pollfd[i].revents & POLLOUT)
|
|
|
|
|
{
|
|
|
|
|
return handle_writing_message (event, ctx, i);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: in case there is an error that way??
|
|
|
|
|
//if (ctx->cinfos[i].fd < 0)
|
|
|
|
|
// continue;
|
|
|
|
|
|
|
|
|
|
// Timeout.
|
|
|
|
|
/** TODO: timeout */
|
|
|
|
|
|
|
|
|
|
// Disconnection.
|
|
|
|
|
if (cinfos->pollfd[i].revents & POLLHUP)
|
|
|
|
|
if (ctx->pollfd[i].revents & POLLHUP)
|
|
|
|
|
goto hungup;
|
|
|
|
|
else if (cinfos->pollfd[i].revents & POLLIN) {
|
|
|
|
|
return handle_message (event, cinfos, cinfos->cinfos[j], switchdb);
|
|
|
|
|
else if (ctx->pollfd[i].revents & POLLIN) {
|
|
|
|
|
return handle_disconnection (event, ctx, i, switchdb);
|
|
|
|
|
/* read argument buffer from client */
|
|
|
|
|
if ( (nread = read(client_fd, buf, MAXLINE)) < 0)
|
|
|
|
|
log_sys("read error on fd %d", client_fd);
|
|
|
|
@ -506,7 +474,7 @@ ipc_events_loop (
|
|
|
|
|
hungup:
|
|
|
|
|
log_msg("closed: uid %d, fd %d", client[i].uid, client_fd);
|
|
|
|
|
client_del(client_fd); /* client has closed conn */
|
|
|
|
|
cinfos->pollfd[i].fd = -1;
|
|
|
|
|
ctx->pollfd[i].fd = -1;
|
|
|
|
|
close(client_fd);
|
|
|
|
|
} else /* process client's rquest */
|
|
|
|
|
request(buf, nread, client_fd, client[i].uid);
|
|
|
|
@ -514,26 +482,27 @@ hungup:
|
|
|
|
|
|
|
|
|
|
} /** for loop: end of the message handling */
|
|
|
|
|
|
|
|
|
|
// from 0 to cinfos->size
|
|
|
|
|
// from 0 to ctx->size
|
|
|
|
|
// if something to read
|
|
|
|
|
// if this is the server
|
|
|
|
|
// return handle_connection
|
|
|
|
|
// else
|
|
|
|
|
// from 0 to cinfos->size
|
|
|
|
|
// if this is the right index in cinfos->cinfos
|
|
|
|
|
// return handle_message (event, cinfos, cinfos->cinfos[j], switchdb);
|
|
|
|
|
// from 0 to ctx->size
|
|
|
|
|
// if this is the right index in ctx->cinfos
|
|
|
|
|
// return handle_message (event, ctx, i, switchdb);
|
|
|
|
|
|
|
|
|
|
IPC_RETURN_NO_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
struct ipc_error ipc_wait_event_networkd (
|
|
|
|
|
struct ipc_ctx *cinfos
|
|
|
|
|
struct ipc_ctx *ctx
|
|
|
|
|
, struct ipc_connection_info *cinfo // NULL for clients
|
|
|
|
|
, struct ipc_event *event
|
|
|
|
|
, struct ipc_switchings *switchdb
|
|
|
|
|
, int *timer)
|
|
|
|
|
{
|
|
|
|
|
T_R ((cinfos == NULL), IPC_ERROR_WAIT_EVENT__NO_CLIENTS_PARAM);
|
|
|
|
|
T_R ((ctx == NULL), IPC_ERROR_WAIT_EVENT__NO_CLIENTS_PARAM);
|
|
|
|
|
T_R ((event == NULL), IPC_ERROR_WAIT_EVENT__NO_EVENT_PARAM);
|
|
|
|
|
|
|
|
|
|
IPC_EVENT_CLEAN (event);
|
|
|
|
@ -549,7 +518,7 @@ struct ipc_error ipc_wait_event_networkd (
|
|
|
|
|
|
|
|
|
|
/* maximum file descriptor number */
|
|
|
|
|
/* keep track of the biggest file descriptor */
|
|
|
|
|
int32_t fdmax = get_max_fd (cinfos);
|
|
|
|
|
int32_t fdmax = get_max_fd (ctx);
|
|
|
|
|
|
|
|
|
|
/* listening socket descriptor */
|
|
|
|
|
int32_t listener;
|
|
|
|
@ -564,8 +533,8 @@ struct ipc_error ipc_wait_event_networkd (
|
|
|
|
|
fdmax = listener;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < cinfos->size; i++) {
|
|
|
|
|
FD_SET (cinfos->cinfos[i]->pollfd.fd, &master);
|
|
|
|
|
for (i = 0; i < ctx->size; i++) {
|
|
|
|
|
FD_SET (ctx->cinfos[i]->pollfd.fd, &master);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readf = master;
|
|
|
|
@ -592,11 +561,11 @@ struct ipc_error ipc_wait_event_networkd (
|
|
|
|
|
for (i = 0; i <= (size_t) fdmax; i++) {
|
|
|
|
|
if (FD_ISSET (i, &readf)) {
|
|
|
|
|
if (cinfo != NULL && i == (size_t) listener) {
|
|
|
|
|
return handle_connection (event, cinfos, cinfo);
|
|
|
|
|
return handle_connection (event, ctx, cinfo);
|
|
|
|
|
} else {
|
|
|
|
|
for (j = 0; j < cinfos->size; j++) {
|
|
|
|
|
if (i == (size_t) cinfos->cinfos[j]->pollfd.fd) {
|
|
|
|
|
return handle_message (event, cinfos, cinfos->cinfos[j], switchdb);
|
|
|
|
|
for (j = 0; j < ctx->size; j++) {
|
|
|
|
|
if (i == (size_t) ctx->cinfos[j]->pollfd.fd) {
|
|
|
|
|
return handle_message (event, ctx, ctx->cinfos[j], switchdb);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -605,73 +574,60 @@ struct ipc_error ipc_wait_event_networkd (
|
|
|
|
|
|
|
|
|
|
IPC_RETURN_NO_ERROR;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
struct ipc_error ipc_wait_event (
|
|
|
|
|
struct ipc_ctx *cinfos
|
|
|
|
|
struct ipc_ctx *ctx
|
|
|
|
|
, struct ipc_connection_info *cinfo // NULL for clients
|
|
|
|
|
, struct ipc_event *event
|
|
|
|
|
, int *timer)
|
|
|
|
|
{
|
|
|
|
|
return ipc_wait_event_networkd (cinfos, cinfo, event, NULL, timer);
|
|
|
|
|
return ipc_wait_event_networkd (ctx, cinfo, event, NULL, timer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* PERFORMANCE POINT:
|
|
|
|
|
* Realloc is performed at each new user. There is plenty of room for improvement,
|
|
|
|
|
* for example by managing allocations of thousands of structures at once.
|
|
|
|
|
* WARNING: Store and remove only pointers on allocated structures.
|
|
|
|
|
* Allocate memory then add a new connection to the context.
|
|
|
|
|
*/
|
|
|
|
|
struct ipc_error ipc_add (
|
|
|
|
|
struct ipc_ctx *cinfos
|
|
|
|
|
, struct ipc_connection_info *p)
|
|
|
|
|
struct ipc_error
|
|
|
|
|
ipc_add (
|
|
|
|
|
struct ipc_ctx *ctx
|
|
|
|
|
, struct ipc_connection_info *p
|
|
|
|
|
, struct pollfd *pollfd)
|
|
|
|
|
{
|
|
|
|
|
T_R ((cinfos == NULL), IPC_ERROR_ADD__NO_PARAM_CLIENTS);
|
|
|
|
|
T_R ((ctx == NULL), IPC_ERROR_ADD__NO_PARAM_CLIENTS);
|
|
|
|
|
T_R ((p == NULL), IPC_ERROR_ADD__NO_PARAM_CLIENT);
|
|
|
|
|
|
|
|
|
|
cinfos->size++;
|
|
|
|
|
// In case this is the first allocation.
|
|
|
|
|
if (cinfos->size == 1) {
|
|
|
|
|
if (cinfos->cinfos == NULL && cinfos->pollfd == NULL) {
|
|
|
|
|
SECURE_BUFFER_HEAP_ALLOCATION_R (cinfos->cinfos, sizeof (struct ipc_connection_info),,
|
|
|
|
|
IPC_ERROR_ADD__MALLOC);
|
|
|
|
|
SECURE_BUFFER_HEAP_ALLOCATION_R (cinfos->pollfd, sizeof (struct pollfd),,
|
|
|
|
|
IPC_ERROR_ADD__MALLOC_POLLFD);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
cinfos->cinfos = realloc (cinfos->cinfos, sizeof (struct ipc_connection_info) * cinfos->size);
|
|
|
|
|
cinfos->pollfd = realloc (cinfos->pollfd, sizeof (struct pollfd ) * cinfos->size);
|
|
|
|
|
}
|
|
|
|
|
// Memory reallocation.
|
|
|
|
|
ipc_ctx_new_alloc (ctx);
|
|
|
|
|
|
|
|
|
|
T_R ((cinfos->cinfos == NULL), IPC_ERROR_ADD__EMPTY_LIST);
|
|
|
|
|
|
|
|
|
|
cinfos->cinfos[cinfos->size - 1] = p;
|
|
|
|
|
cinfos->pollfd[cinfos->size - 1] = &p->pollfd;
|
|
|
|
|
memcpy (ctx->cinfos[ctx->size - 1], p , sizeof (struct ipc_connection_info));
|
|
|
|
|
memcpy (ctx->pollfd[ctx->size - 1], pollfd, sizeof (struct pollfd));
|
|
|
|
|
|
|
|
|
|
IPC_RETURN_NO_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct ipc_error ipc_del (
|
|
|
|
|
struct ipc_ctx *cinfos
|
|
|
|
|
struct ipc_ctx *ctx
|
|
|
|
|
, struct ipc_connection_info *p)
|
|
|
|
|
{
|
|
|
|
|
T_R ((cinfos == NULL), IPC_ERROR_DEL__NO_CLIENTS_PARAM);
|
|
|
|
|
T_R ((ctx == NULL), IPC_ERROR_DEL__NO_CLIENTS_PARAM);
|
|
|
|
|
T_R ((p == NULL), IPC_ERROR_DEL__NO_CLIENT_PARAM);
|
|
|
|
|
T_R ((cinfos->cinfos == NULL), IPC_ERROR_DEL__EMPTY_LIST);
|
|
|
|
|
T_R ((ctx->cinfos == NULL), IPC_ERROR_DEL__EMPTY_LIST);
|
|
|
|
|
|
|
|
|
|
size_t i;
|
|
|
|
|
for (i = 0; i < cinfos->size; i++) {
|
|
|
|
|
for (i = 0; i < ctx->size; i++) {
|
|
|
|
|
// WARNING: The test is performed on the pointers of both structures,
|
|
|
|
|
// this is efficient but it doesn't work if the p structure is a copy.
|
|
|
|
|
if (cinfos->cinfos[i] == p) {
|
|
|
|
|
if (ctx->cinfos[i] == p) {
|
|
|
|
|
// TODO: possible memory leak if the ipc_connection_info is not deeply free'ed.
|
|
|
|
|
cinfos->cinfos[i] = cinfos->cinfos[cinfos->size - 1];
|
|
|
|
|
cinfos->size--;
|
|
|
|
|
if (cinfos->size == 0) {
|
|
|
|
|
ipc_connections_free (cinfos);
|
|
|
|
|
ctx->cinfos[i] = ctx->cinfos[ctx->size - 1];
|
|
|
|
|
ctx->size--;
|
|
|
|
|
if (ctx->size == 0) {
|
|
|
|
|
ipc_connections_free (ctx);
|
|
|
|
|
} else {
|
|
|
|
|
cinfos->cinfos = realloc (cinfos->cinfos, sizeof (struct ipc_connection_info) * cinfos->size);
|
|
|
|
|
ctx->cinfos = realloc (ctx->cinfos, sizeof (struct ipc_connection_info) * ctx->size);
|
|
|
|
|
|
|
|
|
|
if (cinfos->cinfos == NULL) {
|
|
|
|
|
if (ctx->cinfos == NULL) {
|
|
|
|
|
IPC_RETURN_ERROR (IPC_ERROR_DEL__EMPTIED_LIST);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -683,72 +639,72 @@ struct ipc_error ipc_del (
|
|
|
|
|
IPC_RETURN_ERROR (IPC_ERROR_DEL__CANNOT_FIND_CLIENT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ipc_connections_close (struct ipc_ctx *cinfos)
|
|
|
|
|
void ipc_connections_close (struct ipc_ctx *ctx)
|
|
|
|
|
{
|
|
|
|
|
if (cinfos->cinfos != NULL) {
|
|
|
|
|
for (size_t i = 0; i < cinfos->size; i++) {
|
|
|
|
|
ipc_close (cinfos->cinfos[i]);
|
|
|
|
|
free (cinfos->cinfos[i]);
|
|
|
|
|
if (ctx->cinfos != NULL) {
|
|
|
|
|
for (size_t i = 0; i < ctx->size; i++) {
|
|
|
|
|
ipc_close (ctx->cinfos[i]);
|
|
|
|
|
free (ctx->cinfos[i]);
|
|
|
|
|
}
|
|
|
|
|
free (cinfos->cinfos);
|
|
|
|
|
cinfos->cinfos = NULL;
|
|
|
|
|
free (ctx->cinfos);
|
|
|
|
|
ctx->cinfos = NULL;
|
|
|
|
|
}
|
|
|
|
|
cinfos->size = 0;
|
|
|
|
|
ctx->size = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ipc_connections_free (struct ipc_ctx *cinfos)
|
|
|
|
|
void ipc_connections_free (struct ipc_ctx *ctx)
|
|
|
|
|
{
|
|
|
|
|
if (cinfos->cinfos != NULL) {
|
|
|
|
|
for (size_t i = 0; i < cinfos->size; i++) {
|
|
|
|
|
free (cinfos->cinfos[i]);
|
|
|
|
|
if (ctx->cinfos != NULL) {
|
|
|
|
|
for (size_t i = 0; i < ctx->size; i++) {
|
|
|
|
|
free (ctx->cinfos[i]);
|
|
|
|
|
}
|
|
|
|
|
free (cinfos->cinfos);
|
|
|
|
|
cinfos->cinfos = NULL;
|
|
|
|
|
free (ctx->cinfos);
|
|
|
|
|
ctx->cinfos = NULL;
|
|
|
|
|
}
|
|
|
|
|
cinfos->size = 0;
|
|
|
|
|
ctx->size = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// add an arbitrary file descriptor to read
|
|
|
|
|
struct ipc_error ipc_add_fd (struct ipc_ctx *cinfos, int fd)
|
|
|
|
|
struct ipc_error ipc_add_fd (struct ipc_ctx *ctx, int fd)
|
|
|
|
|
{
|
|
|
|
|
T_R ((cinfos == NULL), IPC_ERROR_ADD_FD__NO_PARAM_CINFOS);
|
|
|
|
|
T_R ((ctx == NULL), IPC_ERROR_ADD_FD__NO_PARAM_CINFOS);
|
|
|
|
|
|
|
|
|
|
struct ipc_connection_info *cinfo = NULL;
|
|
|
|
|
SECURE_DECLARATION (struct ipc_connection_info, cinfo);
|
|
|
|
|
cinfo.type = IPC_CONNECTION_TYPE_EXTERNAL;
|
|
|
|
|
|
|
|
|
|
SECURE_BUFFER_HEAP_ALLOCATION_R (cinfo, sizeof (struct ipc_connection_info),,
|
|
|
|
|
IPC_ERROR_ADD_FD__NOT_ENOUGH_MEMORY);
|
|
|
|
|
SECURE_DECLARATION (struct pollfd, pollfd);
|
|
|
|
|
pollfd.fd = fd;
|
|
|
|
|
pollfd.events = POLLIN;
|
|
|
|
|
|
|
|
|
|
cinfo->type = IPC_CONNECTION_TYPE_EXTERNAL;
|
|
|
|
|
|
|
|
|
|
return ipc_add (cinfos, cinfo);
|
|
|
|
|
return ipc_add (ctx, &cinfo, &pollfd);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// remove a connection from its file descriptor
|
|
|
|
|
struct ipc_error ipc_del_fd (struct ipc_ctx *cinfos, int fd)
|
|
|
|
|
struct ipc_error ipc_del_fd (struct ipc_ctx *ctx, int fd)
|
|
|
|
|
{
|
|
|
|
|
T_R ((cinfos == NULL), IPC_ERROR_DEL_FD__NO_PARAM_CINFOS);
|
|
|
|
|
T_R ((cinfos->cinfos == NULL), IPC_ERROR_DEL_FD__EMPTY_LIST);
|
|
|
|
|
T_R ((ctx == NULL), IPC_ERROR_DEL_FD__NO_PARAM_CINFOS);
|
|
|
|
|
T_R ((ctx->cinfos == NULL), IPC_ERROR_DEL_FD__EMPTY_LIST);
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < cinfos->size; i++) {
|
|
|
|
|
for (size_t i = 0; i < ctx->size; i++) {
|
|
|
|
|
|
|
|
|
|
if (cinfos->cinfos[i]->pollfd.fd == fd) {
|
|
|
|
|
if (ctx->cinfos[i]->pollfd.fd == fd) {
|
|
|
|
|
|
|
|
|
|
cinfos->cinfos[i]->pollfd.fd = -1;
|
|
|
|
|
free (cinfos->cinfos[i]);
|
|
|
|
|
cinfos->pollfd[i] = NULL;
|
|
|
|
|
cinfos->size--;
|
|
|
|
|
ctx->cinfos[i]->pollfd.fd = -1;
|
|
|
|
|
free (ctx->cinfos[i]);
|
|
|
|
|
ctx->pollfd[i] = NULL;
|
|
|
|
|
ctx->size--;
|
|
|
|
|
|
|
|
|
|
if (cinfos->size == 0) {
|
|
|
|
|
// free cinfos->cinfos
|
|
|
|
|
ipc_connections_free (cinfos);
|
|
|
|
|
if (ctx->size == 0) {
|
|
|
|
|
// free ctx->cinfos
|
|
|
|
|
ipc_connections_free (ctx);
|
|
|
|
|
} else {
|
|
|
|
|
cinfos->cinfos[i] = cinfos->cinfos[cinfos->size];
|
|
|
|
|
cinfos->pollfd[i] = cinfos->pollfd[cinfos->size];
|
|
|
|
|
ctx->cinfos[i] = ctx->cinfos[ctx->size];
|
|
|
|
|
ctx->pollfd[i] = ctx->pollfd[ctx->size];
|
|
|
|
|
|
|
|
|
|
cinfos->cinfos = realloc (cinfos->cinfos, sizeof (struct ipc_connection_info) * cinfos->size);
|
|
|
|
|
cinfos->pollfd = realloc (cinfos->pollfd, sizeof (struct pollfd ) * cinfos->size);
|
|
|
|
|
ctx->cinfos = realloc (ctx->cinfos, sizeof (struct ipc_connection_info) * ctx->size);
|
|
|
|
|
ctx->pollfd = realloc (ctx->pollfd, sizeof (struct pollfd ) * ctx->size);
|
|
|
|
|
|
|
|
|
|
if (cinfos->cinfos == NULL || cinfos->pollfd == NULL) {
|
|
|
|
|
if (ctx->cinfos == NULL || ctx->pollfd == NULL) {
|
|
|
|
|
IPC_RETURN_ERROR (IPC_ERROR_DEL_FD__EMPTIED_LIST);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|