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

762 lines
22 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));
2020-06-28 01:13:48 +02:00
// (*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);
2020-06-27 19:16:07 +02:00
IPC_RETURN_NO_ERROR;
}
2020-06-28 01:13:48 +02:00
struct ipc_error
ipc_server_init (char **env, struct ipc_ctx **ctx, const char *sname)
2020-06-27 19:16:07 +02:00
{
T_R ((env == NULL), IPC_ERROR_SERVER_INIT__NO_ENVIRONMENT_PARAM);
T_R ((sname == NULL), IPC_ERROR_SERVER_INIT__NO_SERVER_NAME_PARAM);
2016-05-26 18:27:59 +02:00
2020-06-27 19:16:07 +02:00
ipc_ctx_init(ctx);
2019-07-27 15:46:04 +02:00
#if 0
// For server init, no need for networkd evaluation
2016-06-12 14:41:25 +02:00
// 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++) {
2019-07-27 15:46:04 +02:00
// TODO: check for every IPC_NETWORK_* environment variable
}
#endif
2016-06-12 14:41:25 +02:00
2020-06-28 01:13:48 +02:00
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);
2020-06-27 19:16:07 +02:00
TEST_IPC_RR (service_path (buf, sname), "cannot get server path");
2016-06-13 09:47:19 +02:00
// gets the service path
if (srv->spath != NULL) {
free (srv->spath);
srv->spath = NULL;
}
2019-07-27 15:46:04 +02:00
size_t s = strlen (buf);
2019-07-27 15:46:04 +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
2019-07-27 15:46:04 +02:00
2020-06-27 04:45:43 +02:00
TEST_IPC_RETURN_ON_ERROR (usock_init (&srv->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.
TEST_IPC_RR (ipc_add (ctx, srv), "cannot add the server in the context");
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
struct ipc_error ipc_contact_networkd (struct ipc_connection_info *srv, const char *sname)
2019-07-27 15:46:04 +02:00
{
T_R ((srv == NULL), IPC_ERROR_CONTACT_NETWORKD__NO_SERVER_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-27 04:45:43 +02:00
srv->pollfd.fd = 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-27 04:45:43 +02:00
srv->pollfd.fd = 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-27 04:45:43 +02:00
struct ipc_error ret = ipc_receive_fd (networkdfd, &srv->pollfd.fd);
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-27 19:16:07 +02:00
struct ipc_error ipc_connection (char **env, struct ipc_ctx **ctx, const char *sname)
{
2020-06-27 19:16:07 +02:00
T_R ((env == NULL), IPC_ERROR_CONNECTION__NO_ENVIRONMENT_PARAM);
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-27 19:16:07 +02:00
ipc_ctx_init(ctx);
2020-06-28 01:13:48 +02:00
struct ipc_connection_info *srv = NULL;
SECURE_BUFFER_HEAP_ALLOCATION_R (srv, sizeof (struct ipc_connection_info),,
IPC_ERROR_CONNECTION__NOT_ENOUGH_MEMORY);
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");
2019-07-27 15:46:04 +02:00
// if networkd did not initiate the connection
2020-06-27 04:45:43 +02:00
if (srv->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-27 04:45:43 +02:00
TEST_IPC_RETURN_ON_ERROR (usock_connect (&srv->pollfd.fd, buf));
}
2016-10-28 13:58:04 +02:00
IPC_RETURN_NO_ERROR;
}
struct ipc_error ipc_server_close (struct ipc_connection_info *srv)
2016-05-26 18:27:59 +02:00
{
2020-06-27 04:45:43 +02:00
usock_close (srv->pollfd.fd);
struct ipc_error ret = usock_remove (srv->spath);
if (srv->spath != NULL) {
free (srv->spath);
srv->spath = NULL;
}
return ret;
2016-05-26 18:27:59 +02:00
}
struct ipc_error ipc_close (struct ipc_connection_info *p)
2019-06-03 21:25:59 +02:00
{
2020-06-27 04:45:43 +02:00
return usock_close (p->pollfd.fd);
2016-05-26 18:27:59 +02:00
}
2020-06-27 04:45:43 +02:00
struct ipc_error ipc_accept (
struct ipc_connection_info *srv
, struct ipc_connection_info *p)
2016-05-26 18:27:59 +02:00
{
T_R ((srv == NULL), IPC_ERROR_ACCEPT__NO_SERVICE_PARAM);
T_R ((p == NULL), IPC_ERROR_ACCEPT__NO_CLIENT_PARAM);
2016-12-20 23:36:00 +01:00
2020-06-28 01:13:48 +02:00
TEST_IPC_RR (usock_accept (srv->pollfd.fd, &p->pollfd.fd), "cannot accept IPC connection");
2020-06-27 04:45:43 +02:00
p->pollfd.events = POLLIN; // Tell to poll(2) to watch for incoming data from this fd.
p->type = IPC_CONNECTION_TYPE_IPC;
2016-12-20 23:36:00 +01: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
struct ipc_error ipc_read (const struct ipc_connection_info *p, 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;
2019-07-27 15:46:04 +02:00
// on error or closed recipient, the buffer already freed
2020-06-27 04:45:43 +02:00
TEST_IPC_RETURN_ON_ERROR (usock_recv (p->pollfd.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
}
struct ipc_error ipc_write (const struct ipc_connection_info *p, const struct ipc_message *m)
2016-12-22 21:48:35 +01:00
{
2020-06-27 04:45:43 +02:00
return ipc_write_fd (p->pollfd.fd, m);
}
2018-10-10 23:08:58 +02:00
2020-06-27 04:45:43 +02:00
// New connection from a client.
2020-06-27 19:16:07 +02:00
struct ipc_error
handle_connection (struct ipc_event *event
, struct ipc_ctx *cinfos
2020-06-27 04:45:43 +02:00
, struct ipc_connection_info *cinfo)
2019-07-27 15:46:04 +02:00
{
2020-06-28 01:13:48 +02:00
T_R ((cinfo == NULL), IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFO_PARAM);
T_R ((cinfos == NULL), IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFOS_PARAM);
2019-07-27 15:46:04 +02:00
struct ipc_connection_info *new_client = NULL;
2019-07-27 15:46:04 +02:00
2020-06-27 04:45:43 +02:00
SECURE_BUFFER_HEAP_ALLOCATION_R (new_client, sizeof (struct ipc_connection_info),,
IPC_ERROR_HANDLE_NEW_CONNECTION__MALLOC);
2020-06-27 19:16:07 +02:00
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");
2019-07-27 15:46:04 +02:00
IPC_EVENT_SET (event, IPC_EVENT_TYPE_CONNECTION, NULL, new_client);
IPC_RETURN_NO_ERROR;
2019-07-27 15:46:04 +02:00
}
// new message
2020-06-27 04:45:43 +02:00
struct ipc_error handle_message (
struct ipc_event *event
2020-06-27 19:16:07 +02:00
, struct ipc_ctx *cinfos
, struct ipc_connection_info *pc, struct ipc_switchings *switchdb)
2018-10-10 23:08:58 +02:00
{
2019-07-27 15:46:04 +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 (switchdb != NULL) {
2020-06-27 04:45:43 +02:00
int talkingfd = pc->pollfd.fd;
2019-07-27 15:46:04 +02:00
int correspondingfd = ipc_switching_get (switchdb, talkingfd);
if (correspondingfd != -1) {
char *buf = NULL;
size_t msize = 0;
TEST_IPC_T_P_I_R (
/* function to test */ usock_recv (talkingfd, &buf, &msize)
, /* error condition */ ret.error_code != IPC_ERROR_NONE
&& ret.error_code != IPC_ERROR_CLOSED_RECIPIENT
, /* to do on error */ if (buf != NULL) free (buf);
IPC_EVENT_SET (event, IPC_EVENT_TYPE_ERROR, NULL, pc)
, /* return function */ return (ret)) ;
2019-07-27 15:46:04 +02:00
/** TODO: there is a message, send it to the corresponding fd **/
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);
2019-07-27 15:46:04 +02:00
IPC_EVENT_SET (event, IPC_EVENT_TYPE_ERROR, NULL, pc);
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, NULL, pc);
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
2019-07-27 15:46:04 +02:00
delfd = ipc_switching_del (switchdb, talkingfd);
if (delfd >= 0) {
close (delfd);
ipc_del_fd (cinfos, delfd);
}
close (talkingfd);
ipc_del_fd (cinfos, talkingfd);
#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, NULL, pc);
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 (pc->type == IPC_CONNECTION_TYPE_EXTERNAL) {
IPC_EVENT_SET (event, IPC_EVENT_TYPE_EXTRA_SOCKET, NULL, pc);
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 (pc, 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 (pc), "cannot close a connection in handle_message");
TEST_IPC_P (ipc_del (cinfos, 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
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");
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, NULL, pc);
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, m, pc);
IPC_RETURN_NO_ERROR;
2018-10-28 17:09:35 +01:00
}
2020-06-27 19:16:07 +02:00
struct ipc_error
ipc_events_loop (
struct ipc_ctx *cinfos
2020-06-27 04:45:43 +02:00
, struct ipc_connection_info *cinfo // NULL for clients
, struct ipc_event *event
, struct ipc_switchings *switchdb
, struct ipc_messages *messages_to_send
2020-06-27 19:16:07 +02:00
, int *timer /* in ms */)
2020-06-27 04:45:43 +02:00
{
T_R ((cinfos == 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 {
2020-06-27 19:16:07 +02:00
// struct pollfd *pollfd;
2020-06-27 04:45:43 +02:00
// char type; // server, client, arbitrary fd
// char *spath; // max size: PATH_MAX
// };
2020-06-27 19:16:07 +02:00
// struct ipc_ctx {
2020-06-27 04:45:43 +02:00
// struct ipc_connection_info **cinfos;
2020-06-27 19:16:07 +02:00
// struct ipc_connection_info *pollfd;
2020-06-27 04:45:43 +02:00
// 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]
2020-06-27 19:16:07 +02:00
int i, n, listenfd, client_fd, nread;
2020-06-27 04:45:43 +02:00
char buf[MAXLINE];
uid_t uid;
// Generate the array of pollfd structure once, then use it each time.
2020-06-27 19:16:07 +02:00
// TODO: ça ailleurs: if ( (cinfos->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;
2020-06-27 04:45:43 +02:00
2020-06-27 19:16:07 +02:00
if ((n = poll(cinfos->pollfd, cinfos->size, INFTIM)) < 0)
2020-06-27 04:45:43 +02:00
{
log_sys("select error");
}
for (i = 0; i <= cinfos->size; i++) {
2020-06-27 19:16:07 +02:00
// Something to read or connection.
if (cinfos->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.
if (cinfo != NULL && i == cinfo->pollfd) {
return handle_connection (event, cinfos, cinfo);
}
2020-06-27 19:16:07 +02:00
if (i == (size_t) cinfos->cinfos[j]->pollfd.fd) {
return handle_message (event, cinfos, cinfos->cinfos[j], switchdb);
2020-06-27 04:45:43 +02:00
}
}
2020-06-27 19:16:07 +02:00
// if ((client_fd = cinfos->cinfos[i].fd) < 0)
// continue;
// Timeout.
/** TODO: timeout */
// Disconnection.
if (cinfos->pollfd[i].revents & POLLHUP)
2020-06-27 04:45:43 +02:00
goto hungup;
2020-06-27 19:16:07 +02:00
else if (cinfos->pollfd[i].revents & POLLIN) {
return handle_message (event, cinfos, cinfos->cinfos[j], switchdb);
2020-06-27 04:45:43 +02:00
/* read argument buffer from client */
2020-06-27 19:16:07 +02:00
if ( (nread = read(client_fd, buf, MAXLINE)) < 0)
log_sys("read error on fd %d", client_fd);
2020-06-27 04:45:43 +02:00
else if (nread == 0) {
hungup:
2020-06-27 19:16:07 +02:00
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;
close(client_fd);
2020-06-27 04:45:43 +02:00
} else /* process client's rquest */
2020-06-27 19:16:07 +02:00
request(buf, nread, client_fd, client[i].uid);
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
2020-06-27 19:16:07 +02:00
// from 0 to cinfos->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);
2020-06-27 04:45:43 +02:00
IPC_RETURN_NO_ERROR;
}
struct ipc_error ipc_wait_event_networkd (
2020-06-27 19:16:07 +02:00
struct ipc_ctx *cinfos
2020-06-27 04:45:43 +02:00
, struct ipc_connection_info *cinfo // NULL for clients
, struct ipc_event *event
, struct ipc_switchings *switchdb
2020-06-27 19:16:07 +02:00
, int *timer)
2018-10-28 17:09:35 +01:00
{
T_R ((cinfos == 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);
2019-06-03 21:25:59 +02:00
IPC_EVENT_CLEAN (event);
2019-06-03 21:25:59 +02:00
size_t i, j;
/* master file descriptor list */
fd_set master;
fd_set readf;
2018-10-28 17:09:35 +01:00
/* clear the master and temp sets */
FD_ZERO (&master);
FD_ZERO (&readf);
2018-10-28 17:09:35 +01:00
/* maximum file descriptor number */
/* keep track of the biggest file descriptor */
int32_t fdmax = get_max_fd (cinfos);
2019-06-03 21:25:59 +02:00
/* listening socket descriptor */
int32_t listener;
if (cinfo != NULL) {
2020-06-27 04:45:43 +02:00
listener = cinfo->pollfd.fd;
2019-06-03 21:25:59 +02:00
/* add the listener to the master set */
FD_SET (listener, &master);
2019-06-03 21:25:59 +02:00
/* if listener is max fd */
if (fdmax < listener)
fdmax = listener;
}
2019-06-03 21:25:59 +02:00
for (i = 0; i < cinfos->size; i++) {
2020-06-27 04:45:43 +02:00
FD_SET (cinfos->cinfos[i]->pollfd.fd, &master);
}
2018-10-28 17:09:35 +01:00
readf = master;
struct timeval *ptimeout = NULL;
SECURE_DECLARATION (struct timeval, timeout);
if (timer != NULL && *timer > 0.0) {
timeout.tv_sec = (long) *timer;
timeout.tv_usec = (long) ((long)((*timer) * 1000000) % 1000000);
ptimeout = &timeout;
}
T_PERROR_RIPC ((select (fdmax + 1, &readf, NULL, NULL, ptimeout) == -1), "select", IPC_ERROR_WAIT_EVENT__SELECT);
if (ptimeout != NULL) {
2020-06-27 19:16:07 +02:00
*timer = timeout.tv_sec + (timeout.tv_usec / 1000000.0);
if (*timer == 0) {
IPC_EVENT_SET (event, IPC_EVENT_TYPE_TIMER, NULL, NULL);
IPC_RETURN_NO_ERROR;
}
}
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);
} else {
for (j = 0; j < cinfos->size; j++) {
2020-06-27 04:45:43 +02:00
if (i == (size_t) cinfos->cinfos[j]->pollfd.fd) {
return handle_message (event, cinfos, cinfos->cinfos[j], switchdb);
}
}
}
}
}
2019-07-27 15:46:04 +02:00
IPC_RETURN_NO_ERROR;
2019-07-27 15:46:04 +02:00
}
2018-10-28 17:09:35 +01:00
2020-06-27 04:45:43 +02:00
struct ipc_error ipc_wait_event (
2020-06-27 19:16:07 +02:00
struct ipc_ctx *cinfos
, struct ipc_connection_info *cinfo // NULL for clients
2020-06-27 19:16:07 +02:00
, struct ipc_event *event
, int *timer)
2019-07-27 15:46:04 +02:00
{
return ipc_wait_event_networkd (cinfos, cinfo, event, NULL, timer);
2018-10-28 17:09:35 +01:00
}
2020-06-27 04:45:43 +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.
*/
struct ipc_error ipc_add (
2020-06-27 19:16:07 +02:00
struct ipc_ctx *cinfos
2020-06-27 04:45:43 +02:00
, struct ipc_connection_info *p)
2018-10-28 17:09:35 +01:00
{
T_R ((cinfos == NULL), IPC_ERROR_ADD__NO_PARAM_CLIENTS);
2020-06-28 01:13:48 +02:00
T_R ((p == NULL), IPC_ERROR_ADD__NO_PARAM_CLIENT);
cinfos->size++;
2020-06-27 04:45:43 +02:00
// In case this is the first allocation.
2020-06-27 19:16:07 +02:00
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);
2020-06-27 19:16:07 +02:00
cinfos->pollfd = realloc (cinfos->pollfd, sizeof (struct pollfd ) * cinfos->size);
}
T_R ((cinfos->cinfos == NULL), IPC_ERROR_ADD__EMPTY_LIST);
2020-06-27 19:16:07 +02:00
cinfos->cinfos[cinfos->size - 1] = p;
2020-06-28 01:13:48 +02:00
cinfos->pollfd[cinfos->size - 1] = &p->pollfd;
2020-06-27 19:16:07 +02:00
IPC_RETURN_NO_ERROR;
2019-06-03 21:25:59 +02:00
}
2020-06-27 04:45:43 +02:00
struct ipc_error ipc_del (
2020-06-27 19:16:07 +02:00
struct ipc_ctx *cinfos
2020-06-27 04:45:43 +02:00
, struct ipc_connection_info *p)
2019-06-03 21:25:59 +02:00
{
2020-06-27 04:45:43 +02:00
T_R ((cinfos == 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);
size_t i;
for (i = 0; i < cinfos->size; i++) {
2020-06-27 04:45:43 +02:00
// 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) {
2020-06-27 04:45:43 +02:00
// 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);
} else {
cinfos->cinfos = realloc (cinfos->cinfos, sizeof (struct ipc_connection_info) * cinfos->size);
if (cinfos->cinfos == NULL) {
IPC_RETURN_ERROR (IPC_ERROR_DEL__EMPTIED_LIST);
}
}
IPC_RETURN_NO_ERROR;
}
}
2019-07-27 15:46:04 +02:00
IPC_RETURN_ERROR (IPC_ERROR_DEL__CANNOT_FIND_CLIENT);
2019-06-03 21:25:59 +02:00
}
2020-06-27 19:16:07 +02:00
void ipc_connections_close (struct ipc_ctx *cinfos)
2019-06-03 21:25:59 +02:00
{
if (cinfos->cinfos != NULL) {
for (size_t i = 0; i < cinfos->size; i++) {
ipc_close (cinfos->cinfos[i]);
free (cinfos->cinfos[i]);
}
free (cinfos->cinfos);
cinfos->cinfos = NULL;
}
cinfos->size = 0;
2019-06-03 21:25:59 +02:00
}
2020-06-27 19:16:07 +02:00
void ipc_connections_free (struct ipc_ctx *cinfos)
2019-06-03 21:25:59 +02:00
{
if (cinfos->cinfos != NULL) {
for (size_t i = 0; i < cinfos->size; i++) {
free (cinfos->cinfos[i]);
}
free (cinfos->cinfos);
cinfos->cinfos = NULL;
}
cinfos->size = 0;
2019-06-03 21:25:59 +02:00
}
// add an arbitrary file descriptor to read
2020-06-27 19:16:07 +02:00
struct ipc_error ipc_add_fd (struct ipc_ctx *cinfos, int fd)
2019-06-03 21:25:59 +02:00
{
T_R ((cinfos == NULL), IPC_ERROR_ADD_FD__NO_PARAM_CINFOS);
struct ipc_connection_info *cinfo = NULL;
SECURE_BUFFER_HEAP_ALLOCATION_R (cinfo, sizeof (struct ipc_connection_info),,
IPC_ERROR_ADD_FD__NOT_ENOUGH_MEMORY);
2019-06-03 21:25:59 +02:00
2020-06-28 01:13:48 +02:00
cinfo->type = IPC_CONNECTION_TYPE_EXTERNAL;
2019-06-03 21:25:59 +02:00
return ipc_add (cinfos, cinfo);
}
// remove a connection from its file descriptor
2020-06-27 19:16:07 +02:00
struct ipc_error ipc_del_fd (struct ipc_ctx *cinfos, int fd)
{
T_R ((cinfos == NULL), IPC_ERROR_DEL_FD__NO_PARAM_CINFOS);
T_R ((cinfos->cinfos == NULL), IPC_ERROR_DEL_FD__EMPTY_LIST);
2020-06-28 01:13:48 +02:00
for (size_t i = 0; i < cinfos->size; i++) {
2020-06-27 04:45:43 +02:00
if (cinfos->cinfos[i]->pollfd.fd == fd) {
2020-06-28 01:13:48 +02:00
2020-06-27 04:45:43 +02:00
cinfos->cinfos[i]->pollfd.fd = -1;
free (cinfos->cinfos[i]);
2020-06-28 01:13:48 +02:00
cinfos->pollfd[i] = NULL;
cinfos->size--;
2020-06-28 01:13:48 +02:00
if (cinfos->size == 0) {
// free cinfos->cinfos
ipc_connections_free (cinfos);
} else {
cinfos->cinfos[i] = cinfos->cinfos[cinfos->size];
2020-06-28 01:13:48 +02:00
cinfos->pollfd[i] = cinfos->pollfd[cinfos->size];
cinfos->cinfos = realloc (cinfos->cinfos, sizeof (struct ipc_connection_info) * cinfos->size);
2020-06-28 01:13:48 +02:00
cinfos->pollfd = realloc (cinfos->pollfd, sizeof (struct pollfd ) * cinfos->size);
2020-06-28 01:13:48 +02:00
if (cinfos->cinfos == NULL || cinfos->pollfd == NULL) {
IPC_RETURN_ERROR (IPC_ERROR_DEL_FD__EMPTIED_LIST);
}
}
2019-06-03 21:25:59 +02:00
IPC_RETURN_NO_ERROR;
}
}
IPC_RETURN_ERROR (IPC_ERROR_DEL_FD__CANNOT_FIND_CLIENT);
}