2019-07-27 15:46:04 +02:00
|
|
|
#include <sys/select.h>
|
2018-10-28 18:12:17 +01:00
|
|
|
#include <unistd.h>
|
2016-12-17 18:00:04 +01:00
|
|
|
|
2016-05-30 01:54:19 +02:00
|
|
|
#include <stdio.h>
|
2020-01-01 12:11:34 +01:00
|
|
|
#include <errno.h> // error numbers
|
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"
|
2019-06-12 15:02:43 +02:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
struct ipc_error service_path (char *path, const char *sname, int32_t index, int32_t version)
|
2016-12-15 00:28:42 +01:00
|
|
|
{
|
2020-01-01 12:11:34 +01:00
|
|
|
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
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
memset (path, 0, PATH_MAX);
|
2019-06-03 21:25:59 +02:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
char *rundir = getenv ("IPC_RUNDIR");
|
|
|
|
if (rundir == NULL)
|
|
|
|
rundir = RUNDIR;
|
2019-06-03 21:25:59 +02:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
snprintf (path, PATH_MAX - 1, "%s/%s-%d-%d", rundir, sname, index, version);
|
2019-07-27 15:46:04 +02:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
IPC_RETURN_NO_ERROR;
|
2019-06-03 21:25:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static int32_t get_max_fd (struct ipc_connection_infos *cinfos)
|
|
|
|
{
|
2020-01-01 12:11:34 +01:00
|
|
|
size_t i;
|
|
|
|
int32_t max = 0;
|
2019-06-03 21:25:59 +02:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
for (i = 0; i < cinfos->size; i++) {
|
|
|
|
if (cinfos->cinfos[i]->fd > max) {
|
|
|
|
max = cinfos->cinfos[i]->fd;
|
|
|
|
}
|
|
|
|
}
|
2019-06-03 21:25:59 +02:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
return max;
|
2016-06-12 12:38:43 +02:00
|
|
|
}
|
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
struct ipc_error ipc_server_init (char **env, struct ipc_connection_info *srv, const char *sname)
|
2016-05-26 18:27:59 +02:00
|
|
|
{
|
2020-01-01 12:11:34 +01:00
|
|
|
T_R ((env == NULL), IPC_ERROR_SERVER_INIT__NO_ENVIRONMENT_PARAM);
|
|
|
|
T_R ((srv == NULL), IPC_ERROR_SERVER_INIT__NO_SERVICE_PARAM);
|
|
|
|
T_R ((sname == NULL), IPC_ERROR_SERVER_INIT__NO_SERVER_NAME_PARAM);
|
2016-05-26 18:27:59 +02:00
|
|
|
|
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
|
|
|
|
2020-01-01 12:11:34 +01: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-01-01 12:11:34 +01:00
|
|
|
// gets the service path
|
|
|
|
SECURE_BUFFER_DECLARATION (char, buf, PATH_MAX);
|
|
|
|
TEST_IPC_RR (service_path (buf, sname, srv->index, srv->version), "cannot get server path");
|
2016-06-13 09:47:19 +02:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
// gets the service path
|
|
|
|
if (srv->spath != NULL) {
|
|
|
|
free (srv->spath);
|
|
|
|
srv->spath = NULL;
|
|
|
|
}
|
2019-07-27 15:46:04 +02:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
size_t s = strlen (buf);
|
2019-07-27 15:46:04 +02:00
|
|
|
|
2020-01-01 12:11:34 +01: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-01-01 12:11:34 +01:00
|
|
|
TEST_IPC_RETURN_ON_ERROR (usock_init (&srv->fd, srv->spath));
|
2019-07-27 15:46:04 +02:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
IPC_RETURN_NO_ERROR;
|
2019-07-27 15:46:04 +02:00
|
|
|
}
|
|
|
|
|
2020-01-01 12:11:34 +01: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-01-01 12:11:34 +01:00
|
|
|
struct ipc_error ipc_contact_networkd (struct ipc_connection_info *srv, const char *sname)
|
2019-07-27 15:46:04 +02:00
|
|
|
{
|
2020-01-01 12:11:34 +01: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
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
char *networkvar = getenv ("IPC_NETWORK");
|
2019-07-27 15:46:04 +02:00
|
|
|
if (networkvar == NULL) {
|
|
|
|
srv->fd = 0;
|
2020-01-01 12:11:34 +01:00
|
|
|
IPC_RETURN_NO_ERROR;
|
2018-10-08 15:18:56 +02:00
|
|
|
}
|
2020-01-01 12:11:34 +01: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] = ';';
|
2020-01-01 12:11:34 +01:00
|
|
|
memcpy (columnthensname + 1, sname, strlen (sname));
|
2019-07-27 15:46:04 +02:00
|
|
|
|
2020-01-01 12:11:34 +01: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);
|
|
|
|
srv->fd = 0;
|
2020-01-01 12:11:34 +01:00
|
|
|
IPC_RETURN_NO_ERROR;
|
2018-10-08 15:18:56 +02:00
|
|
|
}
|
2019-07-27 15:46:04 +02:00
|
|
|
// printf ("(;)sname %s found\n", sname);
|
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
// gets the service path
|
|
|
|
SECURE_BUFFER_DECLARATION (char, buf, PATH_MAX);
|
|
|
|
TEST_IPC_RR (service_path (buf, "network", 0, 0), "cannot get network service path");
|
2019-07-27 15:46:04 +02:00
|
|
|
|
|
|
|
int networkdfd = 0;
|
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
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;
|
2016-12-19 19:20:27 +01:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
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;
|
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
TEST_IPC_RR (ipc_write_fd (networkdfd, &msg), "cannot send a message to networkd");
|
2019-07-27 15:46:04 +02:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
struct ipc_error ret = ipc_receive_fd (networkdfd, &srv->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;
|
2016-12-19 18:16:38 +01:00
|
|
|
}
|
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
struct ipc_error ipc_connection (char **env, struct ipc_connection_info *srv, const char *sname)
|
2016-06-10 01:21:04 +02:00
|
|
|
{
|
2020-01-01 12:11:34 +01:00
|
|
|
T_R ((env == NULL), IPC_ERROR_CONNECTION__NO_ENVIRONMENT_PARAM);
|
|
|
|
T_R ((srv == NULL), IPC_ERROR_CONNECTION__NO_SERVER);
|
|
|
|
T_R ((sname == NULL), IPC_ERROR_CONNECTION__NO_SERVICE_NAME);
|
2019-07-27 15:46:04 +02:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
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
|
|
|
|
if (srv->fd <= 0) {
|
2020-01-01 12:11:34 +01:00
|
|
|
// gets the service path
|
|
|
|
SECURE_BUFFER_DECLARATION (char, buf, PATH_MAX);
|
|
|
|
TEST_IPC_RR (service_path (buf, sname, srv->index, srv->version), "cannot get server path");
|
|
|
|
TEST_IPC_RETURN_ON_ERROR (usock_connect (&srv->fd, buf));
|
|
|
|
}
|
2016-10-28 13:58:04 +02:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
IPC_RETURN_NO_ERROR;
|
2016-06-10 01:21:04 +02:00
|
|
|
}
|
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
struct ipc_error ipc_server_close (struct ipc_connection_info *srv)
|
2016-05-26 18:27:59 +02:00
|
|
|
{
|
2020-01-01 12:11:34 +01:00
|
|
|
usock_close (srv->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
|
|
|
}
|
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
struct ipc_error ipc_close (struct ipc_connection_info *p)
|
2019-06-03 21:25:59 +02:00
|
|
|
{
|
2020-01-01 12:11:34 +01:00
|
|
|
return usock_close (p->fd);
|
2016-05-26 18:27:59 +02:00
|
|
|
}
|
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
struct ipc_error ipc_accept (struct ipc_connection_info *srv, struct ipc_connection_info *p)
|
2016-05-26 18:27:59 +02:00
|
|
|
{
|
2020-01-01 12:11:34 +01: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-01-01 12:11:34 +01:00
|
|
|
TEST_IPC_RR (usock_accept (srv->fd, &p->fd), "cannot accept IPC connection");
|
|
|
|
p->type = IPC_CONNECTION_TYPE_IPC;
|
2016-12-20 23:36:00 +01:00
|
|
|
|
2020-01-01 12:11:34 +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
|
2020-01-01 12:11:34 +01:00
|
|
|
struct ipc_error ipc_read (const struct ipc_connection_info *p, struct ipc_message *m)
|
2019-07-27 15:46:04 +02:00
|
|
|
{
|
2020-01-01 12:11:34 +01:00
|
|
|
T_R ((m == NULL), IPC_ERROR_READ__NO_MESSAGE_PARAM);
|
2017-01-19 22:07:52 +01:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
char *buf = NULL;
|
|
|
|
size_t msize = IPC_MAX_MESSAGE_SIZE;
|
2019-06-12 15:02:43 +02:00
|
|
|
|
2019-07-27 15:46:04 +02:00
|
|
|
// on error or closed recipient, the buffer already freed
|
2020-01-01 12:11:34 +01:00
|
|
|
TEST_IPC_RETURN_ON_ERROR (usock_recv (p->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);
|
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
IPC_RETURN_NO_ERROR; // propagates ipc_message_format return
|
2017-01-19 22:07:52 +01:00
|
|
|
}
|
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
struct ipc_error ipc_write_fd (int fd, const struct ipc_message *m)
|
2018-10-28 17:09:35 +01:00
|
|
|
{
|
2020-01-01 12:11:34 +01:00
|
|
|
T_R ((m == NULL), IPC_ERROR_WRITE__NO_MESSAGE_PARAM);
|
2019-07-27 15:46:04 +02:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
char *buf = NULL;
|
|
|
|
size_t msize = 0;
|
|
|
|
ipc_message_format_write (m, &buf, &msize);
|
2019-07-27 15:46:04 +02:00
|
|
|
|
2020-01-01 12:11:34 +01: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
|
|
|
|
2020-01-01 12:11:34 +01: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
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
IPC_RETURN_NO_ERROR;
|
2018-10-28 17:09:35 +01:00
|
|
|
}
|
|
|
|
|
2020-01-01 12:11:34 +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
|
|
|
{
|
2019-07-27 15:46:04 +02:00
|
|
|
return ipc_write_fd (p->fd, m);
|
2018-10-05 22:33:43 +02:00
|
|
|
}
|
2018-10-10 23:08:58 +02:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
struct ipc_error handle_new_connection (struct ipc_connection_info *cinfo, struct ipc_connection_infos *cinfos
|
|
|
|
, struct ipc_connection_info **new_client)
|
2019-07-27 15:46:04 +02:00
|
|
|
{
|
2020-01-01 12:11:34 +01: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
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
SECURE_BUFFER_HEAP_ALLOCATION_R (*new_client, sizeof (struct ipc_connection_info),,
|
|
|
|
IPC_ERROR_HANDLE_NEW_CONNECTION__MALLOC);
|
2019-07-27 15:46:04 +02:00
|
|
|
|
2020-01-01 12:11:34 +01: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
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
IPC_RETURN_NO_ERROR;
|
2019-07-27 15:46:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// new connection from a client
|
2020-01-01 12:11:34 +01:00
|
|
|
struct ipc_error handle_connection (struct ipc_event *event, struct ipc_connection_infos *cinfos
|
|
|
|
, struct ipc_connection_info *cinfo)
|
2019-07-27 15:46:04 +02:00
|
|
|
{
|
2020-01-01 12:11:34 +01:00
|
|
|
// connection
|
|
|
|
struct ipc_connection_info *new_client = NULL;
|
2019-07-27 15:46:04 +02:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
TEST_IPC_RR (handle_new_connection (cinfo, cinfos, &new_client), "cannot add new client");
|
2019-07-27 15:46:04 +02:00
|
|
|
|
2020-01-01 12:11:34 +01: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-01-01 12:11:34 +01:00
|
|
|
struct ipc_error handle_message (struct ipc_event *event, struct ipc_connection_infos *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
|
2020-01-01 12:11:34 +01:00
|
|
|
if (switchdb != NULL) {
|
2019-07-27 15:46:04 +02:00
|
|
|
int talkingfd = pc->fd;
|
|
|
|
int correspondingfd = ipc_switching_get (switchdb, talkingfd);
|
|
|
|
if (correspondingfd != -1) {
|
|
|
|
char *buf = NULL;
|
|
|
|
size_t msize = 0;
|
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
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;
|
2020-01-01 12:11:34 +01:00
|
|
|
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) {
|
2020-01-01 12:11:34 +01:00
|
|
|
// 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);
|
2020-01-01 12:11:34 +01:00
|
|
|
IPC_RETURN_NO_ERROR; // FIXME: return something else, maybe?
|
2019-07-27 15:46:04 +02:00
|
|
|
}
|
2020-01-01 12:11:34 +01: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);
|
2020-01-01 12:11:34 +01:00
|
|
|
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);
|
|
|
|
|
2020-01-01 12:11:34 +01: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);
|
2020-01-01 12:11:34 +01:00
|
|
|
} else {
|
2019-07-27 15:46:04 +02:00
|
|
|
LOG_DEBUG ("disconnection of %d", talkingfd);
|
|
|
|
}
|
2020-01-01 12:11:34 +01:00
|
|
|
#endif
|
2019-07-27 15:46:04 +02:00
|
|
|
|
2020-01-01 12:11:34 +01: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);
|
2020-01-01 12:11:34 +01:00
|
|
|
IPC_RETURN_NO_ERROR;
|
2018-10-10 23:08:58 +02:00
|
|
|
}
|
2020-01-01 12:11:34 +01: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
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
ipc_message_empty (m);
|
|
|
|
free (m);
|
2019-07-27 15:46:04 +02:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
IPC_EVENT_SET (event, IPC_EVENT_TYPE_DISCONNECTION, NULL, pc);
|
2019-07-27 15:46:04 +02:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
// warning: do not forget to free the ipc_client structure
|
|
|
|
IPC_RETURN_NO_ERROR;
|
|
|
|
}
|
2018-10-28 17:09:35 +01:00
|
|
|
|
2020-01-01 12:11:34 +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-01-01 12:11:34 +01:00
|
|
|
struct ipc_error ipc_wait_event_networkd (struct ipc_connection_infos *cinfos
|
|
|
|
, struct ipc_connection_info *cinfo // NULL for clients
|
|
|
|
, struct ipc_event *event, struct ipc_switchings *switchdb
|
|
|
|
, long *timer)
|
2018-10-28 17:09:35 +01:00
|
|
|
{
|
2020-01-01 12:11:34 +01:00
|
|
|
T_R ((cinfos == NULL), IPC_ERROR_WAIT_EVENT__NO_CLIENTS_PARAM);
|
|
|
|
T_R ((event == NULL), IPC_ERROR_WAIT_EVENT__NO_EVENT_PARAM);
|
2019-06-03 21:25:59 +02:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
IPC_EVENT_CLEAN (event);
|
2019-06-03 21:25:59 +02:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
size_t i, j;
|
|
|
|
/* master file descriptor list */
|
|
|
|
fd_set master;
|
|
|
|
fd_set readf;
|
2018-10-28 17:09:35 +01:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
/* clear the master and temp sets */
|
|
|
|
FD_ZERO (&master);
|
|
|
|
FD_ZERO (&readf);
|
2018-10-28 17:09:35 +01:00
|
|
|
|
2020-01-01 12:11:34 +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
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
/* listening socket descriptor */
|
|
|
|
int32_t listener;
|
|
|
|
if (cinfo != NULL) {
|
|
|
|
listener = cinfo->fd;
|
2019-06-03 21:25:59 +02:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
/* add the listener to the master set */
|
|
|
|
FD_SET (listener, &master);
|
2019-06-03 21:25:59 +02:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
/* if listener is max fd */
|
|
|
|
if (fdmax < listener)
|
|
|
|
fdmax = listener;
|
|
|
|
}
|
2019-06-03 21:25:59 +02:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
for (i = 0; i < cinfos->size; i++) {
|
|
|
|
FD_SET (cinfos->cinfos[i]->fd, &master);
|
|
|
|
}
|
2018-10-28 17:09:35 +01:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
readf = master;
|
2019-10-26 18:17:20 +02:00
|
|
|
|
|
|
|
struct timeval *ptimeout = NULL;
|
|
|
|
SECURE_DECLARATION (struct timeval, timeout);
|
|
|
|
|
|
|
|
if (timer != NULL && *timer > 0) {
|
|
|
|
timeout.tv_sec = *timer;
|
|
|
|
ptimeout = &timeout;
|
|
|
|
}
|
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
T_PERROR_RIPC ((select (fdmax + 1, &readf, NULL, NULL, ptimeout) == -1), "select", IPC_ERROR_WAIT_EVENT__SELECT);
|
2019-10-26 18:17:20 +02:00
|
|
|
|
|
|
|
if (ptimeout != NULL) {
|
|
|
|
*timer = timeout.tv_sec;
|
|
|
|
if (*timer == 0) {
|
2020-01-01 12:11:34 +01:00
|
|
|
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++) {
|
|
|
|
if (i == (size_t) cinfos->cinfos[j]->fd) {
|
|
|
|
return handle_message (event, cinfos, cinfos->cinfos[j], switchdb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-10-26 18:17:20 +02:00
|
|
|
}
|
|
|
|
}
|
2019-07-27 15:46:04 +02:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
IPC_RETURN_NO_ERROR;
|
2019-07-27 15:46:04 +02:00
|
|
|
}
|
2018-10-28 17:09:35 +01:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
struct ipc_error ipc_wait_event (struct ipc_connection_infos *cinfos
|
|
|
|
, struct ipc_connection_info *cinfo // NULL for clients
|
|
|
|
, struct ipc_event *event, long *timer)
|
2019-07-27 15:46:04 +02:00
|
|
|
{
|
2019-10-26 18:17:20 +02:00
|
|
|
return ipc_wait_event_networkd (cinfos, cinfo, event, NULL, timer);
|
2018-10-28 17:09:35 +01:00
|
|
|
}
|
|
|
|
|
2019-06-03 21:25:59 +02:00
|
|
|
// store and remove only pointers on allocated structures
|
2020-01-01 12:11:34 +01:00
|
|
|
struct ipc_error ipc_add (struct ipc_connection_infos *cinfos, struct ipc_connection_info *p)
|
2018-10-28 17:09:35 +01:00
|
|
|
{
|
2020-01-01 12:11:34 +01:00
|
|
|
T_R ((cinfos == NULL), IPC_ERROR_ADD__NO_PARAM_CLIENTS);
|
|
|
|
T_R ((p == NULL), IPC_ERROR_ADD__NO_PARAM_CLIENT);
|
|
|
|
|
|
|
|
cinfos->size++;
|
|
|
|
if (cinfos->size == 1 && cinfos->cinfos == NULL) {
|
|
|
|
// first allocation
|
|
|
|
SECURE_BUFFER_HEAP_ALLOCATION_R (cinfos->cinfos, sizeof (struct ipc_connection_info),,
|
|
|
|
IPC_ERROR_ADD__MALLOC);
|
|
|
|
} else {
|
|
|
|
cinfos->cinfos = realloc (cinfos->cinfos, sizeof (struct ipc_connection_info) * cinfos->size);
|
|
|
|
}
|
|
|
|
|
|
|
|
T_R ((cinfos->cinfos == NULL), IPC_ERROR_ADD__EMPTY_LIST);
|
|
|
|
|
|
|
|
cinfos->cinfos[cinfos->size - 1] = p;
|
|
|
|
IPC_RETURN_NO_ERROR;
|
2019-06-03 21:25:59 +02:00
|
|
|
}
|
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
struct ipc_error ipc_del (struct ipc_connection_infos *cinfos, struct ipc_connection_info *p)
|
2019-06-03 21:25:59 +02:00
|
|
|
{
|
2019-07-27 15:46:04 +02:00
|
|
|
T_R ((cinfos == NULL), IPC_ERROR_DEL__NO_CLIENTS_PARAM);
|
2020-01-01 12:11:34 +01:00
|
|
|
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++) {
|
|
|
|
if (cinfos->cinfos[i] == p) {
|
|
|
|
// TODO: possible memory leak if the ipc_connection_info is not 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);
|
|
|
|
}
|
|
|
|
}
|
2018-10-28 18:12:17 +01:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
IPC_RETURN_NO_ERROR;
|
|
|
|
}
|
|
|
|
}
|
2019-07-27 15:46:04 +02:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
IPC_RETURN_ERROR (IPC_ERROR_DEL__CANNOT_FIND_CLIENT);
|
2019-06-03 21:25:59 +02:00
|
|
|
}
|
2018-10-28 18:12:17 +01:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
void ipc_connections_close (struct ipc_connection_infos *cinfos)
|
2019-06-03 21:25:59 +02:00
|
|
|
{
|
2020-01-01 12:11:34 +01: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
|
|
|
}
|
2018-10-28 18:12:17 +01:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
void ipc_connections_free (struct ipc_connection_infos *cinfos)
|
2019-06-03 21:25:59 +02:00
|
|
|
{
|
2020-01-01 12:11:34 +01: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
|
|
|
}
|
|
|
|
|
|
|
|
// create the client service structure
|
2020-01-01 12:11:34 +01:00
|
|
|
struct ipc_error ipc_connection_gen (struct ipc_connection_info *cinfo
|
|
|
|
, uint32_t index, uint32_t version
|
|
|
|
, int fd, char type)
|
2019-06-03 21:25:59 +02:00
|
|
|
{
|
2020-01-01 12:11:34 +01:00
|
|
|
T_R ((cinfo == NULL), IPC_ERROR_CONNECTION_GEN__NO_CINFO);
|
2019-06-03 21:25:59 +02:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
cinfo->type = type;
|
|
|
|
cinfo->version = version;
|
|
|
|
cinfo->index = index;
|
|
|
|
cinfo->fd = fd;
|
2019-06-03 21:25:59 +02:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
IPC_RETURN_NO_ERROR;
|
2019-06-03 21:25:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// add an arbitrary file descriptor to read
|
2020-01-01 12:11:34 +01:00
|
|
|
struct ipc_error ipc_add_fd (struct ipc_connection_infos *cinfos, int fd)
|
2019-06-03 21:25:59 +02:00
|
|
|
{
|
2020-01-01 12:11:34 +01:00
|
|
|
T_R ((cinfos == NULL), IPC_ERROR_ADD_FD__NO_PARAM_CINFOS);
|
2018-10-28 18:12:17 +01:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
struct ipc_connection_info *cinfo = NULL;
|
2019-06-12 15:02:43 +02:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
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-01-01 12:11:34 +01:00
|
|
|
ipc_connection_gen (cinfo, 0, 0, fd, IPC_CONNECTION_TYPE_EXTERNAL);
|
2019-06-03 21:25:59 +02:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
return ipc_add (cinfos, cinfo);
|
2019-06-12 15:02:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// remove a connection from its file descriptor
|
2020-01-01 12:11:34 +01:00
|
|
|
struct ipc_error ipc_del_fd (struct ipc_connection_infos *cinfos, int fd)
|
2019-06-12 15:02:43 +02:00
|
|
|
{
|
2020-01-01 12:11:34 +01:00
|
|
|
T_R ((cinfos == NULL), IPC_ERROR_DEL_FD__NO_PARAM_CINFOS);
|
|
|
|
T_R ((cinfos->cinfos == NULL), IPC_ERROR_DEL_FD__EMPTY_LIST);
|
|
|
|
|
|
|
|
size_t i;
|
|
|
|
for (i = 0; i < cinfos->size; i++) {
|
|
|
|
if (cinfos->cinfos[i]->fd == fd) {
|
2020-01-28 13:42:19 +01:00
|
|
|
cinfos->cinfos[i]->fd = -1;
|
2020-01-01 12:11:34 +01:00
|
|
|
free (cinfos->cinfos[i]);
|
|
|
|
cinfos->size--;
|
|
|
|
if (cinfos->size == 0) {
|
|
|
|
// free cinfos->cinfos
|
|
|
|
ipc_connections_free (cinfos);
|
|
|
|
} else {
|
|
|
|
cinfos->cinfos[i] = cinfos->cinfos[cinfos->size];
|
|
|
|
cinfos->cinfos = realloc (cinfos->cinfos, sizeof (struct ipc_connection_info) * cinfos->size);
|
|
|
|
|
|
|
|
if (cinfos->cinfos == NULL) {
|
|
|
|
IPC_RETURN_ERROR (IPC_ERROR_DEL_FD__EMPTIED_LIST);
|
|
|
|
}
|
|
|
|
}
|
2019-06-03 21:25:59 +02:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
IPC_RETURN_NO_ERROR;
|
|
|
|
}
|
|
|
|
}
|
2018-10-28 18:12:17 +01:00
|
|
|
|
2020-01-01 12:11:34 +01:00
|
|
|
IPC_RETURN_ERROR (IPC_ERROR_DEL_FD__CANNOT_FIND_CLIENT);
|
2018-10-28 18:12:17 +01:00
|
|
|
}
|