Obsolete
/
libipc-old
Archived
3
0
Fork 0
This repository has been archived on 2024-06-18. You can view files and clone it, but cannot push or open issues/pull-requests.
libipc-old/src/communication.c

563 lines
17 KiB
C
Raw Normal View History

2019-07-27 15:46:04 +02:00
#include <sys/select.h>
#include <unistd.h>
2016-12-17 18:00:04 +01:00
#include <stdio.h>
#include <errno.h> // error numbers
2019-06-03 21:25:59 +02:00
2020-06-27 04:45:43 +02:00
#include <poll.h>
2019-06-03 21:25:59 +02:00
#include <stdlib.h>
#include <string.h>
2019-07-27 15:46:04 +02:00
#include "ipc.h"
#include "utils.h"
2019-06-03 21:25:59 +02:00
2019-07-27 15:46:04 +02:00
// print structures
#include "message.h"
2020-06-28 01:13:48 +02:00
struct ipc_error
service_path (char *path, const char *sname)
{
T_R ((path == NULL), IPC_ERROR_SERVICE_PATH__NO_PATH);
T_R ((sname == NULL), IPC_ERROR_SERVICE_PATH__NO_SERVICE_NAME);
2019-06-03 21:25:59 +02:00
memset (path, 0, PATH_MAX);
2019-06-03 21:25:59 +02:00
char *rundir = getenv ("IPC_RUNDIR");
if (rundir == NULL)
rundir = RUNDIR;
2019-06-03 21:25:59 +02:00
2020-06-27 19:16:07 +02:00
snprintf (path, PATH_MAX - 1, "%s/%s", rundir, sname);
2019-07-27 15:46:04 +02:00
IPC_RETURN_NO_ERROR;
2019-06-03 21:25:59 +02:00
}
2020-06-27 19:16:07 +02:00
struct ipc_error ipc_ctx_init (struct ipc_ctx **ctx)
2016-05-26 18:27:59 +02:00
{
2020-06-27 19:16:07 +02:00
T_R ((ctx == NULL), IPC_ERROR_CTX_INIT__NO_CONTEXT_PARAM);
T_R ((*ctx != NULL), IPC_ERROR_CTX_INIT__CONTEXT_ALREADY_INIT);
*ctx = malloc(sizeof(struct ipc_ctx));
T_R ((*ctx == NULL), IPC_ERROR_CTX_INIT__MALLOC_CTX);
memset (ctx, 0, sizeof(struct ipc_ctx));
IPC_RETURN_NO_ERROR;
}
2020-06-28 15:40:02 +02:00
/**
* 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.
*/
2020-06-28 17:22:58 +02:00
struct ipc_error ipc_ctx_new_alloc (struct ipc_ctx *ctx)
2020-06-27 19:16:07 +02:00
{
2020-06-28 15:40:02 +02:00
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);
2020-06-28 17:22:58 +02:00
SECURE_BUFFER_HEAP_ALLOCATION_R (ctx->pollfd, sizeof (struct pollfd),, IPC_ERROR_ADD__MALLOC_POLLFD);
2020-06-28 15:40:02 +02:00
} else {
ctx->cinfos = realloc (ctx->cinfos, sizeof (struct ipc_connection_info) * ctx->size);
ctx->pollfd = realloc (ctx->pollfd, sizeof (struct pollfd ) * ctx->size);
}
2016-05-26 18:27:59 +02:00
2020-06-28 15:40:02 +02:00
T_R ((ctx->cinfos == NULL), IPC_ERROR_ADD__EMPTY_LIST);
T_R ((ctx->pollfd == NULL), IPC_ERROR_ADD__EMPTY_LIST);
2020-06-27 19:16:07 +02:00
2020-06-28 15:40:02 +02:00
// Clean the last entry.
2020-06-28 17:22:58 +02:00
memset (&ctx->cinfos[ctx->size -1], 0, sizeof (struct ipc_connection_info));
memset (&ctx->pollfd[ctx->size -1], 0, sizeof (struct pollfd));
2016-06-12 14:41:25 +02:00
2020-06-28 17:22:58 +02:00
IPC_RETURN_NO_ERROR;
2020-06-28 15:40:02 +02:00
}
2020-06-28 01:13:48 +02:00
2020-06-28 17:22:58 +02:00
struct ipc_error ipc_server_init (struct ipc_ctx **ctx, const char *sname)
2020-06-28 15:40:02 +02:00
{
T_R ((sname == NULL), IPC_ERROR_SERVER_INIT__NO_SERVER_NAME_PARAM);
2020-06-28 01:13:48 +02:00
2020-06-28 17:22:58 +02:00
ipc_ctx_init(ctx); // Allocate the context.
2019-07-27 15:46:04 +02:00
2020-06-28 17:22:58 +02:00
// Declaration and instanciation of the new connection (ipc_connection_info + pollfd).
2020-06-28 15:40:02 +02:00
SECURE_DECLARATION (struct ipc_connection_info, srv);
srv.type = IPC_CONNECTION_TYPE_SERVER;
SECURE_DECLARATION(struct pollfd, pollfd);
pollfd.events = POLLIN;
2019-07-27 15:46:04 +02:00
2020-06-28 17:22:58 +02:00
// Get the service path.
SECURE_BUFFER_DECLARATION (char, buf, PATH_MAX);
TEST_IPC_RR (service_path (buf, sname), "cannot get server path");
size_t s = strlen (buf);
if (s > PATH_MAX)
s = PATH_MAX;
2020-06-28 15:40:02 +02:00
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
2020-06-28 17:22:58 +02:00
// Socket initialisation for the service.
2020-06-28 15:40:02 +02:00
TEST_IPC_RETURN_ON_ERROR (usock_init (&pollfd.fd, srv.spath));
2019-07-27 15:46:04 +02:00
2020-06-28 01:13:48 +02:00
// Add the server to the listened file descriptors.
2020-06-28 17:22:58 +02:00
// ipc_add allocate memory then copy the data of srv and pollfd in ctx.
2020-06-28 15:40:02 +02:00
TEST_IPC_RR (ipc_add (*ctx, &srv, &pollfd), "cannot add the server in the context");
2020-06-28 01:13:48 +02:00
IPC_RETURN_NO_ERROR;
2019-07-27 15:46:04 +02:00
}
struct ipc_error ipc_write_fd (int fd, const struct ipc_message *m);
2019-07-27 15:46:04 +02:00
// when networkd is not working properly (or do not retrieve the service): srv->fd = 0
2020-06-28 15:40:02 +02:00
struct ipc_error ipc_contact_networkd (int *pfd, const char *sname)
2019-07-27 15:46:04 +02:00
{
2020-06-28 15:40:02 +02:00
T_R ((pfd == NULL), IPC_ERROR_CONTACT_NETWORKD__NO_FD_PARAM);
T_R ((sname == NULL), IPC_ERROR_CONTACT_NETWORKD__NO_SERVICE_NAME_PARAM);
2019-07-27 15:46:04 +02:00
char *networkvar = getenv ("IPC_NETWORK");
2019-07-27 15:46:04 +02:00
if (networkvar == NULL) {
2020-06-28 15:40:02 +02:00
*pfd = 0;
IPC_RETURN_NO_ERROR;
2018-10-08 15:18:56 +02:00
}
// TODO: is there another, more interesting way to do this?
// currently, IPC_NETWORK is shared with the network service
// in order to route requests over any chosen protocol stack
// ex: IPC_NETWORK="audio tor://some.example.com/audio ;pong tls://pong.example.com/pong"
2019-07-27 15:46:04 +02:00
// printf ("IPC_NETWORK: %s\n", networkvar);
SECURE_BUFFER_DECLARATION (char, columnthensname, BUFSIZ);
columnthensname[0] = ';';
memcpy (columnthensname + 1, sname, strlen (sname));
2019-07-27 15:46:04 +02:00
if (strncmp (networkvar, sname, strlen (sname)) != 0 && strstr (networkvar, columnthensname) == NULL) {
2019-07-27 15:46:04 +02:00
// printf ("sname %s not found\n", sname);
2020-06-28 18:05:28 +02:00
*pfd = 0;
IPC_RETURN_NO_ERROR;
2018-10-08 15:18:56 +02:00
}
2019-07-27 15:46:04 +02:00
2020-06-28 01:13:48 +02:00
// Get the service path.
SECURE_BUFFER_DECLARATION (char, buf, PATH_MAX);
2020-06-28 01:13:48 +02:00
TEST_IPC_RR (service_path (buf, "network"), "cannot get network service path");
2019-07-27 15:46:04 +02:00
int networkdfd = 0;
TEST_IPC_RETURN_ON_ERROR (usock_connect (&networkdfd, buf));
2019-07-27 15:46:04 +02:00
SECURE_DECLARATION (struct ipc_message, msg);
msg.type = MSG_TYPE_NETWORK_LOOKUP;
msg.user_type = MSG_TYPE_NETWORK_LOOKUP;
SECURE_BUFFER_DECLARATION (char, content, BUFSIZ);
2019-07-27 15:46:04 +02:00
snprintf (content, BUFSIZ, "%s;%s", sname, networkvar);
msg.length = strlen (content);
msg.payload = content;
TEST_IPC_RR (ipc_write_fd (networkdfd, &msg), "cannot send a message to networkd");
2019-07-27 15:46:04 +02:00
2020-06-28 15:40:02 +02:00
struct ipc_error ret = ipc_receive_fd (networkdfd, pfd);
if (ret.error_code == IPC_ERROR_NONE) {
2019-07-27 15:46:04 +02:00
usock_close (networkdfd);
2019-06-03 21:25:59 +02:00
}
2016-05-26 18:27:59 +02:00
2019-07-27 15:46:04 +02:00
return ret;
}
2020-06-28 01:13:48 +02:00
// Create context, contact networkd, connects to the service.
2020-06-28 17:22:58 +02:00
struct ipc_error ipc_connection (struct ipc_ctx **ctx, const char *sname)
{
2020-06-27 19:16:07 +02:00
T_R ((ctx == NULL), IPC_ERROR_CONNECTION__NO_CTX);
T_R ((sname == NULL), IPC_ERROR_CONNECTION__NO_SERVICE_NAME);
2019-07-27 15:46:04 +02:00
2020-06-28 15:40:02 +02:00
ipc_ctx_init(ctx); // Allocate memory for the context.
2020-06-28 01:13:48 +02:00
2020-06-28 15:40:02 +02:00
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;
2020-06-28 01:13:48 +02:00
2020-06-28 15:40:02 +02:00
TEST_IPC_P (ipc_contact_networkd (&pollfd.fd, sname), "error during networkd connection");
2019-07-27 15:46:04 +02:00
// if networkd did not initiate the connection
2020-06-28 15:40:02 +02:00
if (pollfd.fd <= 0) {
// gets the service path
SECURE_BUFFER_DECLARATION (char, buf, PATH_MAX);
2020-06-27 19:16:07 +02:00
TEST_IPC_RR (service_path (buf, sname), "cannot get server path");
2020-06-28 15:40:02 +02:00
TEST_IPC_RETURN_ON_ERROR (usock_connect (&pollfd.fd, buf));
}
2016-10-28 13:58:04 +02:00
2020-06-28 15:40:02 +02:00
// 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;
}
2020-06-28 17:22:58 +02:00
struct ipc_error ipc_close_all (struct ipc_ctx *ctx)
2016-05-26 18:27:59 +02:00
{
2020-06-28 17:22:58 +02:00
for (size_t i = 0 ; i < ctx->size ; i++) {
TEST_IPC_P (ipc_close (ctx, i), "cannot close a connection in handle_message");
}
2020-06-28 17:22:58 +02:00
IPC_RETURN_NO_ERROR;
2016-05-26 18:27:59 +02:00
}
2020-06-28 17:22:58 +02:00
struct ipc_error ipc_close (struct ipc_ctx *ctx, uint32_t index)
2019-06-03 21:25:59 +02:00
{
2020-06-28 17:22:58 +02:00
struct ipc_error ret = usock_close (ctx->pollfd[index].fd);
2020-06-28 18:05:28 +02:00
// TODO: verify that the close was OK??
if (ctx->cinfos[index].type == IPC_CONNECTION_TYPE_SERVER) {
ret = usock_remove (ctx->cinfos[index].spath);
if (ctx->cinfos[index].spath != NULL) {
free (ctx->cinfos[index].spath);
ctx->cinfos[index].spath = NULL;
2020-06-28 17:22:58 +02:00
}
}
return ret;
2016-05-26 18:27:59 +02:00
}
2020-06-28 17:22:58 +02:00
// New connection from a client.
struct ipc_error ipc_accept_add (struct ipc_event *event, struct ipc_ctx *ctx, uint32_t index)
2016-05-26 18:27:59 +02:00
{
2020-06-28 17:22:58 +02:00
T_R ((ctx == NULL), IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFOS_PARAM);
T_R ((index >= ctx->size), IPC_ERROR_HANDLE_NEW_CONNECTION__INCONSISTENT_INDEX);
// Memory reallocation.
ipc_ctx_new_alloc (ctx);
2016-12-20 23:36:00 +01:00
2020-06-28 17:22:58 +02:00
int server_fd = ctx->pollfd[index].fd;
int *client_fd = &ctx->pollfd[ctx->size -1].fd;
2016-12-20 23:36:00 +01:00
2020-06-28 17:22:58 +02:00
TEST_IPC_RR (usock_accept (server_fd, client_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;
ctx->size++;
2020-06-28 18:05:28 +02:00
// Set the event structure.
uint32_t client_index = ctx->size - 1;
IPC_EVENT_SET (event, IPC_EVENT_TYPE_CONNECTION, client_index, *client_fd, NULL);
2020-06-28 18:05:28 +02:00
IPC_RETURN_NO_ERROR;
2019-07-27 15:46:04 +02:00
}
2017-01-19 22:07:52 +01:00
2019-07-27 15:46:04 +02:00
// receive then format in an ipc_message structure
2020-06-28 17:22:58 +02:00
struct ipc_error ipc_read (const struct ipc_ctx *ctx, uint32_t index, struct ipc_message *m)
2019-07-27 15:46:04 +02:00
{
T_R ((m == NULL), IPC_ERROR_READ__NO_MESSAGE_PARAM);
2017-01-19 22:07:52 +01:00
char *buf = NULL;
size_t msize = IPC_MAX_MESSAGE_SIZE;
2020-06-28 17:22:58 +02:00
// On error or closed recipient, the buffer already freed.
TEST_IPC_RETURN_ON_ERROR (usock_recv (ctx->pollfd[index].fd, &buf, &msize));
TEST_IPC_RETURN_ON_ERROR_FREE (ipc_message_format_read (m, buf, msize), buf);
2019-07-27 15:46:04 +02:00
free (buf);
IPC_RETURN_NO_ERROR; // propagates ipc_message_format return
2017-01-19 22:07:52 +01:00
}
struct ipc_error ipc_write_fd (int fd, const struct ipc_message *m)
2018-10-28 17:09:35 +01:00
{
T_R ((m == NULL), IPC_ERROR_WRITE__NO_MESSAGE_PARAM);
2019-07-27 15:46:04 +02:00
char *buf = NULL;
size_t msize = 0;
ipc_message_format_write (m, &buf, &msize);
2019-07-27 15:46:04 +02:00
size_t nbytes_sent = 0;
TEST_IPC_RETURN_ON_ERROR_FREE (usock_send (fd, buf, msize, &nbytes_sent), buf);
2019-07-27 15:46:04 +02:00
if (buf != NULL) {
free (buf);
}
// what was sent != what should have been sent
T_R ((nbytes_sent != msize), IPC_ERROR_WRITE__NOT_ENOUGH_DATA);
2019-07-27 15:46:04 +02:00
IPC_RETURN_NO_ERROR;
2018-10-28 17:09:35 +01:00
}
2020-06-28 17:22:58 +02:00
// TODO: high level API, should be buffered, socket may not be usable for now.
struct ipc_error ipc_write (const struct ipc_ctx *ctx, uint32_t index, const struct ipc_message *m)
2016-12-22 21:48:35 +01:00
{
2020-06-28 17:22:58 +02:00
return ipc_write_fd (ctx->pollfd[index].fd, m);
}
2018-10-10 23:08:58 +02:00
2020-06-28 17:22:58 +02:00
/**
* Allocate memory then add a new connection to the context.
*/
struct ipc_error ipc_add ( struct ipc_ctx *ctx, struct ipc_connection_info *p, struct pollfd *pollfd)
2019-07-27 15:46:04 +02:00
{
2020-06-28 17:22:58 +02:00
T_R ((ctx == NULL), IPC_ERROR_ADD__NO_PARAM_CLIENTS);
T_R ((p == NULL), IPC_ERROR_ADD__NO_PARAM_CLIENT);
2019-07-27 15:46:04 +02:00
2020-06-28 15:40:02 +02:00
// Memory reallocation.
ipc_ctx_new_alloc (ctx);
2019-07-27 15:46:04 +02:00
2020-06-28 18:05:28 +02:00
ctx->cinfos[ctx->size - 1] = *p;
ctx->pollfd[ctx->size - 1] = *pollfd;
2019-07-27 15:46:04 +02:00
IPC_RETURN_NO_ERROR;
2019-07-27 15:46:04 +02:00
}
2020-06-28 18:05:28 +02:00
struct ipc_error ipc_del (struct ipc_ctx *ctx, uint32_t index)
2020-06-28 17:22:58 +02:00
{
2020-06-28 18:05:28 +02:00
T_R ((ctx == NULL), IPC_ERROR_DEL__NO_CLIENTS_PARAM);
T_R ((ctx->cinfos == NULL || ctx->pollfd == NULL), IPC_ERROR_DEL__EMPTY_LIST);
if (index >= ctx->size) {
IPC_RETURN_ERROR (IPC_ERROR_DEL__CANNOT_FIND_CLIENT);
}
if (ctx->cinfos[index].spath != NULL)
free (ctx->cinfos[index].spath);
ctx->size--;
if (ctx->size == 0) {
// free ctx->cinfos and ctx->pollfd
ipc_connections_free (ctx);
IPC_RETURN_NO_ERROR;
}
// The last element in the array replaces the removed one.
ctx->cinfos[index] = ctx->cinfos[ctx->size];
ctx->pollfd[index] = ctx->pollfd[ctx->size];
// Reallocation of the arrays. TODO: should be optimised someday.
ctx->cinfos = realloc (ctx->cinfos, sizeof (struct ipc_connection_info) * ctx->size);
ctx->pollfd = realloc (ctx->pollfd, sizeof (struct pollfd ) * ctx->size);
if (ctx->cinfos == NULL || ctx->pollfd == NULL) {
IPC_RETURN_ERROR (IPC_ERROR_DEL__EMPTIED_LIST);
2020-06-28 17:22:58 +02:00
}
2020-06-28 18:05:28 +02:00
IPC_RETURN_NO_ERROR;
2020-06-28 17:22:58 +02:00
}
void ipc_connections_free (struct ipc_ctx *ctx)
{
if (ctx->cinfos != NULL) {
free (ctx->cinfos);
2020-06-28 18:05:28 +02:00
free (ctx->pollfd);
2020-06-28 17:22:58 +02:00
ctx->cinfos = NULL;
2020-06-28 18:05:28 +02:00
ctx->pollfd = NULL;
2020-06-28 17:22:58 +02:00
}
if (ctx->switchdb.collection != NULL) {
free (ctx->switchdb.collection);
ctx->switchdb.collection = NULL;
}
2020-06-28 17:22:58 +02:00
ctx->size = 0;
}
// add an arbitrary file descriptor to read
struct ipc_error ipc_add_fd (struct ipc_ctx *ctx, int fd)
{
T_R ((ctx == NULL), IPC_ERROR_ADD_FD__NO_PARAM_CINFOS);
SECURE_DECLARATION (struct ipc_connection_info, cinfo);
cinfo.type = IPC_CONNECTION_TYPE_EXTERNAL;
SECURE_DECLARATION (struct pollfd, pollfd);
pollfd.fd = fd;
pollfd.events = POLLIN;
return ipc_add (ctx, &cinfo, &pollfd);
}
// remove a connection from its file descriptor
struct ipc_error ipc_del_fd (struct ipc_ctx *ctx, int fd)
{
T_R ((ctx == NULL), IPC_ERROR_DEL_FD__NO_PARAM_CINFOS);
T_R ((ctx->cinfos == NULL || ctx->pollfd), IPC_ERROR_DEL_FD__EMPTY_LIST);
for (size_t i = 0; i < ctx->size; i++) {
if (ctx->pollfd[i].fd == fd) {
2020-06-28 18:05:28 +02:00
return ipc_del (ctx, i);
2020-06-28 17:22:58 +02:00
}
}
IPC_RETURN_ERROR (IPC_ERROR_DEL_FD__CANNOT_FIND_CLIENT);
}
// TODO
struct ipc_error handle_writing_message (struct ipc_event *event, struct ipc_ctx *ctx, uint32_t index);
struct ipc_error handle_writing_message (struct ipc_event *event, struct ipc_ctx *ctx, uint32_t index)
{
for (size_t i = 0; ctx->tx.size ; i++) {
// TODO
}
IPC_EVENT_SET (event, IPC_EVENT_TYPE_TX, index, ctx->pollfd[index].fd, NULL);
IPC_RETURN_NO_ERROR;
}
2020-06-28 17:22:58 +02:00
2019-07-27 15:46:04 +02:00
// new message
struct ipc_error handle_new_message (struct ipc_event *event, struct ipc_ctx *ctx, int index)
2018-10-10 23:08:58 +02:00
{
// If the socket is associated to another one for networkd:
// read and write automatically and provide a new IPC_EVENT_TYPE indicating the switch.
if (ctx->switchdb.collection != NULL) {
int talkingfd = ctx->pollfd[index].fd;
int correspondingfd = ipc_switching_get (&ctx->switchdb, talkingfd);
2019-07-27 15:46:04 +02:00
if (correspondingfd != -1) {
char *buf = NULL;
size_t msize = 0;
{ /** Some macros use "ret" as a variable name, so this is to be sure. */
struct ipc_error ret = usock_recv (talkingfd, &buf, &msize);
if (ret.error_code != IPC_ERROR_NONE && ret.error_code != IPC_ERROR_CLOSED_RECIPIENT) {
if (buf != NULL)
free (buf);
IPC_EVENT_SET (event, IPC_EVENT_TYPE_ERROR, index, talkingfd, NULL)
return ret;
}
}
2019-07-27 15:46:04 +02:00
/** There is a message, send it to the corresponding fd **/
2019-07-27 15:46:04 +02:00
if (msize > 0) {
size_t nbytes_sent = 0;
TEST_IPC_RETURN_ON_ERROR_FREE (usock_send (correspondingfd, buf, msize, &nbytes_sent), buf);
2019-07-27 15:46:04 +02:00
if (nbytes_sent != msize) {
// LOG_ERROR ("wrote not enough data from %d to fd %d", talkingfd, correspondingfd);
IPC_EVENT_SET (event, IPC_EVENT_TYPE_ERROR, index, ctx->pollfd[index].fd, NULL);
IPC_RETURN_NO_ERROR; // FIXME: return something else, maybe?
2019-07-27 15:46:04 +02:00
}
// LOG_DEBUG ("received a message on fd %d => switch to fd %d", talkingfd, correspondingfd);
2019-07-27 15:46:04 +02:00
if (buf != NULL)
free (buf);
// Everything is OK: inform networkd of a successful transfer.
IPC_EVENT_SET (event, IPC_EVENT_TYPE_SWITCH, index, ctx->pollfd[index].fd, NULL);
IPC_RETURN_NO_ERROR;
} else if (msize == 0) {
2019-07-27 15:46:04 +02:00
int delfd;
2018-10-10 23:08:58 +02:00
delfd = ipc_switching_del (&ctx->switchdb, talkingfd);
2019-07-27 15:46:04 +02:00
if (delfd >= 0) {
close (delfd);
2020-06-28 15:40:02 +02:00
ipc_del_fd (ctx, delfd);
2019-07-27 15:46:04 +02:00
}
close (talkingfd);
2020-06-28 15:40:02 +02:00
ipc_del_fd (ctx, talkingfd);
2019-07-27 15:46:04 +02:00
#if 0
2019-07-27 15:46:04 +02:00
if (delfd >= 0) {
LOG_DEBUG ("disconnection of %d (and related fd %d)", talkingfd, delfd);
} else {
2019-07-27 15:46:04 +02:00
LOG_DEBUG ("disconnection of %d", talkingfd);
}
#endif
2019-07-27 15:46:04 +02:00
IPC_EVENT_SET (event, IPC_EVENT_TYPE_DISCONNECTION, index, ctx->pollfd[index].fd, NULL);
IPC_RETURN_ERROR (IPC_ERROR_CLOSED_RECIPIENT);
2019-07-27 15:46:04 +02:00
}
}
2018-10-10 23:08:58 +02:00
}
2019-07-27 15:46:04 +02:00
// no treatment of the socket if external socket
if (ctx->cinfos[index].type == IPC_CONNECTION_TYPE_EXTERNAL) {
IPC_EVENT_SET (event, IPC_EVENT_TYPE_EXTRA_SOCKET, index, ctx->pollfd[index].fd, NULL);
IPC_RETURN_NO_ERROR;
2018-10-10 23:08:58 +02:00
}
// listen to what they have to say (disconnection or message)
// then add a client to `event`, the ipc_event structure
SECURE_DECLARATION (struct ipc_error, ret);
struct ipc_message *m = NULL;
SECURE_BUFFER_HEAP_ALLOCATION_R (m, sizeof (struct ipc_message),, IPC_ERROR_HANDLE_MESSAGE__NOT_ENOUGH_MEMORY);
// current talking client
ret = ipc_read (ctx, index, m);
if (ret.error_code != IPC_ERROR_NONE && ret.error_code != IPC_ERROR_CLOSED_RECIPIENT) {
struct ipc_error rvalue = ret; // store the final return value
ipc_message_empty (m);
free (m);
// if there is a problem, just remove the client
TEST_IPC_P (ipc_close (ctx, index), "cannot close a connection in handle_message");
TEST_IPC_P (ipc_del (ctx, index), "cannot delete a connection in handle_message");
IPC_EVENT_SET (event, IPC_EVENT_TYPE_ERROR, index, ctx->pollfd[index].fd, NULL);
return rvalue;
}
2020-06-28 17:22:58 +02:00
2020-06-28 15:40:02 +02:00
// disconnection: close the client then delete it from ctx
if (ret.error_code == IPC_ERROR_CLOSED_RECIPIENT) {
TEST_IPC_P (ipc_close (ctx, index), "cannot close a connection on closed recipient in handle_message");
TEST_IPC_P (ipc_del (ctx, index), "cannot delete a connection on closed recipient in handle_message");
2018-10-28 17:09:35 +01:00
ipc_message_empty (m);
free (m);
2019-07-27 15:46:04 +02:00
IPC_EVENT_SET (event, IPC_EVENT_TYPE_DISCONNECTION, index, ctx->pollfd[index].fd, NULL);
2019-07-27 15:46:04 +02:00
// warning: do not forget to free the ipc_client structure
IPC_RETURN_NO_ERROR;
}
2018-10-28 17:09:35 +01:00
IPC_EVENT_SET (event, IPC_EVENT_TYPE_MESSAGE, index, ctx->pollfd[index].fd, m);
2020-06-28 15:40:02 +02:00
IPC_RETURN_NO_ERROR;
}
/* timer is in ms */
struct ipc_error ipc_events_loop (struct ipc_ctx *ctx, struct ipc_event *event, int *timer)
2020-06-27 04:45:43 +02:00
{
2020-06-28 15:40:02 +02:00
T_R ((ctx == NULL), IPC_ERROR_WAIT_EVENT__NO_CLIENTS_PARAM);
2020-06-27 04:45:43 +02:00
T_R ((event == NULL), IPC_ERROR_WAIT_EVENT__NO_EVENT_PARAM);
IPC_EVENT_CLEAN (event);
int32_t n;
2020-06-27 04:45:43 +02:00
if ((n = poll(ctx->pollfd, ctx->size, *timer)) < 0) {
printf("select error\n");
exit(1); // TODO FIXME
2020-06-27 04:45:43 +02:00
}
2020-06-28 15:40:02 +02:00
// Timeout.
if (n == 0) {
IPC_EVENT_SET (event, IPC_EVENT_TYPE_TIMER, 0, 0, NULL);
IPC_RETURN_NO_ERROR;
2020-06-28 15:40:02 +02:00
}
2020-06-27 04:45:43 +02:00
for (size_t i = 0; i <= ctx->size; i++) {
2020-06-27 19:16:07 +02:00
// Something to read or connection.
if (ctx->pollfd[i].revents & POLLIN) {
2020-06-27 04:45:43 +02:00
// In case there is something to read for the server socket: new client.
2020-06-28 15:40:02 +02:00
if (ctx->cinfos[i].type == IPC_CONNECTION_TYPE_SERVER) {
return ipc_accept_add (event, ctx, i);
2020-06-27 04:45:43 +02:00
}
return handle_new_message (event, ctx, i);
2020-06-27 04:45:43 +02:00
}
// Something can be sent.
if (ctx->pollfd[i].revents & POLLOUT) {
2020-06-28 15:40:02 +02:00
return handle_writing_message (event, ctx, i);
}
2020-06-27 19:16:07 +02:00
// Disconnection.
if (ctx->pollfd[i].revents & POLLHUP) {
/** IPC_EVENT_SET: event, type, index, fd, message */
IPC_EVENT_SET (event, IPC_EVENT_TYPE_DISCONNECTION, i, ctx->pollfd[i].fd, NULL);
return ipc_close (ctx, i);
2020-06-27 04:45:43 +02:00
}
2020-06-27 19:16:07 +02:00
} /** for loop: end of the message handling */
2020-06-27 04:45:43 +02:00
IPC_RETURN_NO_ERROR;
2019-07-27 15:46:04 +02:00
}