Obsolete
/
libipc-old
Archived
3
0
Fork 0
pollfd
Karchnu 2020-06-28 15:40:02 +02:00
parent 05d483a712
commit 44992e940c
4 changed files with 209 additions and 277 deletions

View File

@ -155,10 +155,6 @@ int main (int argc, char *argv[], char *env[])
srv = malloc (sizeof (struct ipc_connection_info)); srv = malloc (sizeof (struct ipc_connection_info));
memset (srv, 0, sizeof (struct ipc_connection_info)); memset (srv, 0, sizeof (struct ipc_connection_info));
// index and version should be filled
srv->index = 0;
srv->version = 0;
if (argc == 4) if (argc == 4)
non_interactive (atoi(argv[1]), (size_t) atoi(argv[2]), argv[3], env); non_interactive (atoi(argv[1]), (size_t) atoi(argv[2]), argv[3], env);
else else

View File

@ -22,9 +22,8 @@
/** /**
****************************************************************************** ******************************************************************************
* Overview of the main loop: * Overview of the main loop:
* 1. "clients" pointer declaration (struct ipc_ctx). * 1. "ctx" pointer declaration (struct ipc_ctx).
* 1. ipc_init (&clients) * 1. ipc_server_init (env, ctx, SERVICE_NAME)
* 1. ipc_server_init (env, srv, SERVICE_NAME)
****************************************************************************** ******************************************************************************
*/ */
@ -32,8 +31,7 @@ int cpt = 0;
int verbosity = 1; int verbosity = 1;
struct ipc_connection_info *srv = NULL; struct ipc_ctx *ctx = NULL;
struct ipc_ctx *clients = NULL;
void main_loop () void main_loop ()
{ {
@ -41,26 +39,20 @@ void main_loop ()
double timer = base_timer; double timer = base_timer;
SECURE_DECLARATION (struct ipc_error, ret); SECURE_DECLARATION (struct ipc_error, ret);
/** TODO: should return something */
ipc_init (&clients);
// clients = malloc (sizeof (struct ipc_ctx));
// memset (clients, 0, sizeof (struct ipc_ctx));
SECURE_DECLARATION (struct ipc_event, event); SECURE_DECLARATION (struct ipc_event, event);
event.type = IPC_EVENT_TYPE_NOT_SET; event.type = IPC_EVENT_TYPE_NOT_SET;
while (1) { while (1) {
// ipc_wait_event provides one event at a time // ipc_wait_event provides one event at a time
// warning: event->m is free'ed if not NULL // warning: event->m is free'ed if not NULL
TEST_IPC_WAIT_EVENT_Q (ipc_wait_event (clients, srv, &event, &timer), EXIT_FAILURE); TEST_IPC_WAIT_EVENT_Q (ipc_wait_event (ctx, srv, &event, &timer), EXIT_FAILURE);
switch (event.type) { switch (event.type) {
case IPC_EVENT_TYPE_CONNECTION: case IPC_EVENT_TYPE_CONNECTION:
{ {
cpt++; cpt++;
if (verbosity > 1) { if (verbosity > 1) {
printf ("connection: %d clients connected, new client is %d\n", cpt, (event.origin)->fd); printf ("connection: %d ctx connected, new client is %d\n", cpt, (event.origin)->fd);
} }
}; };
break; break;
@ -68,7 +60,7 @@ void main_loop ()
{ {
cpt--; cpt--;
if (verbosity > 1) { if (verbosity > 1) {
printf ("disconnection: %d clients remaining\n", cpt); printf ("disconnection: %d ctx remaining\n", cpt);
} }
// free the ipc_client structure // free the ipc_client structure
@ -106,7 +98,7 @@ void main_loop ()
{ {
cpt--; cpt--;
fprintf (stderr, "a problem happened with client %d (now disconnected)", (event.origin)->fd); fprintf (stderr, "a problem happened with client %d (now disconnected)", (event.origin)->fd);
fprintf (stderr, ", %d clients remaining\n", cpt); fprintf (stderr, ", %d ctx remaining\n", cpt);
// free the ipc_client structure // free the ipc_client structure
free (event.origin); free (event.origin);
@ -127,17 +119,17 @@ void exit_program (int signal)
{ {
printf ("Quitting, signal: %d\n", signal); printf ("Quitting, signal: %d\n", signal);
// free remaining clients // free remaining ctx
for (size_t i = 0; i < clients->size; i++) { for (size_t i = 0; i < ctx->size; i++) {
struct ipc_connection_info *cli = clients->cinfos[i]; struct ipc_connection_info *cli = ctx->cinfos[i];
if (cli != NULL) { if (cli != NULL) {
free (cli); free (cli);
} }
clients->cinfos[i] = NULL; ctx->cinfos[i] = NULL;
} }
ipc_connections_free (clients); ipc_connections_free (ctx);
free (clients); free (ctx);
// the application will shut down, and close the service // the application will shut down, and close the service
struct ipc_error ret = ipc_server_close (srv); struct ipc_error ret = ipc_server_close (srv);
@ -150,7 +142,7 @@ void exit_program (int signal)
} }
/* /*
* service ping-pong: send back everything sent by the clients * service ping-pong: send back everything sent by the ctx
* stop the program on SIG{TERM,INT,ALRM,USR{1,2},HUP} signals * stop the program on SIG{TERM,INT,ALRM,USR{1,2},HUP} signals
*/ */
@ -165,32 +157,21 @@ int main (int argc, char *argv[], char **env)
printf ("pid = %d\n", getpid ()); printf ("pid = %d\n", getpid ());
srv = malloc (sizeof (struct ipc_connection_info)); struct ipc_error ret = ipc_server_init (env, &ctx, PONGD_SERVICE_NAME);
if (srv == NULL) {
exit (EXIT_FAILURE);
}
memset (srv, 0, sizeof (struct ipc_connection_info));
srv->type = '\0';
srv->index = 0;
srv->version = 0;
srv->fd = 0;
srv->spath = NULL;
struct ipc_error ret = ipc_server_init (env, srv, PONGD_SERVICE_NAME);
if (ret.error_code != IPC_ERROR_NONE) { if (ret.error_code != IPC_ERROR_NONE) {
PRINTERR (ret, "server init"); PRINTERR (ret, "server init");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
printf ("Listening on %s.\n", srv->spath); printf ("Listening on %s.\n", ctx->cinfos[0].spath);
printf ("MAIN: server created\n"); printf ("MAIN: server created\n");
signal (SIGHUP, exit_program); signal (SIGHUP, exit_program);
signal (SIGALRM, exit_program); signal (SIGALRM, exit_program);
signal (SIGUSR1, exit_program); signal (SIGUSR1, exit_program);
signal (SIGUSR2, exit_program); signal (SIGUSR2, exit_program);
signal (SIGTERM, exit_program); signal (SIGTERM, exit_program);
signal (SIGINT, exit_program); signal (SIGINT, exit_program);
// the service will loop until the end of time, or a signal // the service will loop until the end of time, or a signal
main_loop (); main_loop ();

View File

@ -41,15 +41,41 @@ struct ipc_error ipc_ctx_init (struct ipc_ctx **ctx)
T_R ((*ctx == NULL), IPC_ERROR_CTX_INIT__MALLOC_CTX); T_R ((*ctx == NULL), IPC_ERROR_CTX_INIT__MALLOC_CTX);
memset (ctx, 0, sizeof(struct ipc_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; 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 struct ipc_error
ipc_server_init (char **env, struct ipc_ctx **ctx, const char *sname) 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); 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 // gets the service path
SECURE_BUFFER_DECLARATION (char, buf, PATH_MAX); SECURE_BUFFER_DECLARATION (char, buf, PATH_MAX);
TEST_IPC_RR (service_path (buf, sname), "cannot get server path"); 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); size_t s = strlen (buf);
SECURE_BUFFER_HEAP_ALLOCATION_R (srv->spath, s + 1,, IPC_ERROR_SERVER_INIT__MALLOC); SECURE_DECLARATION (struct ipc_connection_info, srv);
memcpy (srv->spath, buf, s); srv.type = IPC_CONNECTION_TYPE_SERVER;
srv->spath[s] = '\0'; // to be sure 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. // 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; 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); 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 // 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); T_R ((sname == NULL), IPC_ERROR_CONTACT_NETWORKD__NO_SERVICE_NAME_PARAM);
char *networkvar = getenv ("IPC_NETWORK"); char *networkvar = getenv ("IPC_NETWORK");
if (networkvar == NULL) { if (networkvar == NULL) {
srv->pollfd.fd = 0; *pfd = 0;
IPC_RETURN_NO_ERROR; IPC_RETURN_NO_ERROR;
} }
// TODO: is there another, more interesting way to do this? // 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) { if (strncmp (networkvar, sname, strlen (sname)) != 0 && strstr (networkvar, columnthensname) == NULL) {
// printf ("sname %s not found\n", sname); // printf ("sname %s not found\n", sname);
srv->pollfd.fd = 0; *fd = 0;
IPC_RETURN_NO_ERROR; 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"); 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) { if (ret.error_code == IPC_ERROR_NONE) {
usock_close (networkdfd); 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 ((ctx == NULL), IPC_ERROR_CONNECTION__NO_CTX);
T_R ((sname == NULL), IPC_ERROR_CONNECTION__NO_SERVICE_NAME); 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_DECLARATION(struct ipc_connection_info, srv);
SECURE_BUFFER_HEAP_ALLOCATION_R (srv, sizeof (struct ipc_connection_info),, srv.type = IPC_CONNECTION_TYPE_IPC; // Data received on the socket = messages, not new clients.
IPC_ERROR_CONNECTION__NOT_ENOUGH_MEMORY); SECURE_DECLARATION(struct pollfd, pollfd);
pollfd.events = POLLIN;
srv->type = IPC_CONNECTION_TYPE_IPC; TEST_IPC_P (ipc_contact_networkd (&pollfd.fd, sname), "error during networkd connection");
// 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");
// if networkd did not initiate the connection // if networkd did not initiate the connection
if (srv->pollfd.fd <= 0) { if (pollfd.fd <= 0) {
// gets the service path // gets the service path
SECURE_BUFFER_DECLARATION (char, buf, PATH_MAX); SECURE_BUFFER_DECLARATION (char, buf, PATH_MAX);
TEST_IPC_RR (service_path (buf, sname), "cannot get server path"); 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; 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. // New connection from a client.
struct ipc_error struct ipc_error
handle_connection (struct ipc_event *event ipc_accept_add (struct ipc_event *event, struct ipc_ctx *ctx, uint32_t i)
, struct ipc_ctx *cinfos
, struct ipc_connection_info *cinfo)
{ {
T_R ((cinfo == NULL), IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFO_PARAM); T_R ((ctx == NULL), IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFOS_PARAM);
T_R ((cinfos == 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),, TEST_IPC_RR (usock_accept (ctx->pollfd[i].fd, &ctx->pollfd[ctx->size -1].fd), "cannot accept IPC connection");
IPC_ERROR_HANDLE_NEW_CONNECTION__MALLOC); 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"); struct ipc_connection_info *new_client = &ctx->cinfos[ctx->size];
TEST_IPC_RR (ipc_add (cinfos, new_client), "cannot add the new accepted client"); ctx->size++;
IPC_EVENT_SET (event, IPC_EVENT_TYPE_CONNECTION, NULL, new_client); IPC_EVENT_SET (event, IPC_EVENT_TYPE_CONNECTION, NULL, new_client);
IPC_RETURN_NO_ERROR; IPC_RETURN_NO_ERROR;
@ -287,7 +291,7 @@ handle_connection (struct ipc_event *event
// new message // new message
struct ipc_error handle_message ( struct ipc_error handle_message (
struct ipc_event *event struct ipc_event *event
, struct ipc_ctx *cinfos , struct ipc_ctx *ctx
, struct ipc_connection_info *pc, struct ipc_switchings *switchdb) , struct ipc_connection_info *pc, struct ipc_switchings *switchdb)
{ {
// if the socket is associated to another one for networkd // 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); delfd = ipc_switching_del (switchdb, talkingfd);
if (delfd >= 0) { if (delfd >= 0) {
close (delfd); close (delfd);
ipc_del_fd (cinfos, delfd); ipc_del_fd (ctx, delfd);
} }
close (talkingfd); close (talkingfd);
ipc_del_fd (cinfos, talkingfd); ipc_del_fd (ctx, talkingfd);
#if 0 #if 0
if (delfd >= 0) { if (delfd >= 0) {
@ -371,15 +375,15 @@ struct ipc_error handle_message (
// if there is a problem, just remove the client // 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_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); IPC_EVENT_SET (event, IPC_EVENT_TYPE_ERROR, NULL, pc);
return rvalue; 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) { 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_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); ipc_message_empty (m);
free (m); free (m);
@ -394,111 +398,75 @@ struct ipc_error handle_message (
IPC_RETURN_NO_ERROR; 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 struct ipc_error
ipc_events_loop ( ipc_events_loop (
struct ipc_ctx *cinfos struct ipc_ctx *ctx
, struct ipc_connection_info *cinfo // NULL for clients , struct ipc_connection_info *cinfo // NULL for clients
, struct ipc_event *event , struct ipc_event *event
, struct ipc_switchings *switchdb , struct ipc_switchings *switchdb
, struct ipc_messages *messages_to_send , struct ipc_messages *messages_to_send
, int *timer /* in ms */) , 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); T_R ((event == NULL), IPC_ERROR_WAIT_EVENT__NO_EVENT_PARAM);
IPC_EVENT_CLEAN (event); 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; int i, n, listenfd, client_fd, nread;
char buf[MAXLINE];
uid_t uid; uid_t uid;
// Generate the array of pollfd structure once, then use it each time. // 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: err_sys("malloc error");
// TODO: ça ailleurs: client_add(listenfd, 0); /* we use [0] for listenfd */ // TODO: ça ailleurs: client_add(listenfd, 0); /* we use [0] for listenfd */
// TODO: ça ailleurs: cinfos->pollfd[0].fd = listenfd; // TODO: ça ailleurs: ctx->pollfd[0].fd = listenfd;
// TODO: ça ailleurs: cinfos->pollfd[0].events = POLLIN; // 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"); log_sys("select error");
} }
// Timeout.
if (n == 0) {
// TODO: timeout
}
for (i = 0; i <= cinfos->size; i++) { for (i = 0; i <= ctx->size; i++) {
// Something to read or connection. // 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. // In case there is something to read for the server socket: new client.
if (cinfo != NULL && i == cinfo->pollfd) { if (ctx->cinfos[i].type == IPC_CONNECTION_TYPE_SERVER) {
return handle_connection (event, cinfos, cinfo); return ipc_accept_add (event, ctx, i);
} }
if (i == (size_t) cinfos->cinfos[j]->pollfd.fd) { return handle_message (event, ctx, i, switchdb);
return handle_message (event, cinfos, cinfos->cinfos[j], switchdb);
}
} }
// if ((client_fd = cinfos->cinfos[i].fd) < 0) if (ctx->pollfd[i].revents & POLLOUT)
// continue; {
return handle_writing_message (event, ctx, i);
}
// Timeout. // TODO: in case there is an error that way??
/** TODO: timeout */ //if (ctx->cinfos[i].fd < 0)
// continue;
// Disconnection. // Disconnection.
if (cinfos->pollfd[i].revents & POLLHUP) if (ctx->pollfd[i].revents & POLLHUP)
goto hungup; goto hungup;
else if (cinfos->pollfd[i].revents & POLLIN) { else if (ctx->pollfd[i].revents & POLLIN) {
return handle_message (event, cinfos, cinfos->cinfos[j], switchdb); return handle_disconnection (event, ctx, i, switchdb);
/* read argument buffer from client */ /* read argument buffer from client */
if ( (nread = read(client_fd, buf, MAXLINE)) < 0) if ( (nread = read(client_fd, buf, MAXLINE)) < 0)
log_sys("read error on fd %d", client_fd); log_sys("read error on fd %d", client_fd);
@ -506,7 +474,7 @@ ipc_events_loop (
hungup: hungup:
log_msg("closed: uid %d, fd %d", client[i].uid, client_fd); log_msg("closed: uid %d, fd %d", client[i].uid, client_fd);
client_del(client_fd); /* client has closed conn */ client_del(client_fd); /* client has closed conn */
cinfos->pollfd[i].fd = -1; ctx->pollfd[i].fd = -1;
close(client_fd); close(client_fd);
} else /* process client's rquest */ } else /* process client's rquest */
request(buf, nread, client_fd, client[i].uid); request(buf, nread, client_fd, client[i].uid);
@ -514,26 +482,27 @@ hungup:
} /** for loop: end of the message handling */ } /** for loop: end of the message handling */
// from 0 to cinfos->size // from 0 to ctx->size
// if something to read // if something to read
// if this is the server // if this is the server
// return handle_connection // return handle_connection
// else // else
// from 0 to cinfos->size // from 0 to ctx->size
// if this is the right index in cinfos->cinfos // if this is the right index in ctx->cinfos
// return handle_message (event, cinfos, cinfos->cinfos[j], switchdb); // return handle_message (event, ctx, i, switchdb);
IPC_RETURN_NO_ERROR; IPC_RETURN_NO_ERROR;
} }
#if 0
struct ipc_error ipc_wait_event_networkd ( 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_connection_info *cinfo // NULL for clients
, struct ipc_event *event , struct ipc_event *event
, struct ipc_switchings *switchdb , struct ipc_switchings *switchdb
, int *timer) , 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); T_R ((event == NULL), IPC_ERROR_WAIT_EVENT__NO_EVENT_PARAM);
IPC_EVENT_CLEAN (event); IPC_EVENT_CLEAN (event);
@ -549,7 +518,7 @@ struct ipc_error ipc_wait_event_networkd (
/* maximum file descriptor number */ /* maximum file descriptor number */
/* keep track of the biggest file descriptor */ /* keep track of the biggest file descriptor */
int32_t fdmax = get_max_fd (cinfos); int32_t fdmax = get_max_fd (ctx);
/* listening socket descriptor */ /* listening socket descriptor */
int32_t listener; int32_t listener;
@ -564,8 +533,8 @@ struct ipc_error ipc_wait_event_networkd (
fdmax = listener; fdmax = listener;
} }
for (i = 0; i < cinfos->size; i++) { for (i = 0; i < ctx->size; i++) {
FD_SET (cinfos->cinfos[i]->pollfd.fd, &master); FD_SET (ctx->cinfos[i]->pollfd.fd, &master);
} }
readf = master; readf = master;
@ -592,11 +561,11 @@ struct ipc_error ipc_wait_event_networkd (
for (i = 0; i <= (size_t) fdmax; i++) { for (i = 0; i <= (size_t) fdmax; i++) {
if (FD_ISSET (i, &readf)) { if (FD_ISSET (i, &readf)) {
if (cinfo != NULL && i == (size_t) listener) { if (cinfo != NULL && i == (size_t) listener) {
return handle_connection (event, cinfos, cinfo); return handle_connection (event, ctx, cinfo);
} else { } else {
for (j = 0; j < cinfos->size; j++) { for (j = 0; j < ctx->size; j++) {
if (i == (size_t) cinfos->cinfos[j]->pollfd.fd) { if (i == (size_t) ctx->cinfos[j]->pollfd.fd) {
return handle_message (event, cinfos, cinfos->cinfos[j], switchdb); return handle_message (event, ctx, ctx->cinfos[j], switchdb);
} }
} }
} }
@ -605,73 +574,60 @@ struct ipc_error ipc_wait_event_networkd (
IPC_RETURN_NO_ERROR; IPC_RETURN_NO_ERROR;
} }
#endif
struct ipc_error ipc_wait_event ( struct ipc_error ipc_wait_event (
struct ipc_ctx *cinfos struct ipc_ctx *ctx
, struct ipc_connection_info *cinfo // NULL for clients , struct ipc_connection_info *cinfo // NULL for clients
, struct ipc_event *event , struct ipc_event *event
, int *timer) , int *timer)
{ {
return ipc_wait_event_networkd (cinfos, cinfo, event, NULL, timer); return ipc_wait_event_networkd (ctx, cinfo, event, NULL, timer);
} }
/** /**
* PERFORMANCE POINT: * Allocate memory then add a new connection to the context.
* 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 ( struct ipc_error
struct ipc_ctx *cinfos ipc_add (
, struct ipc_connection_info *p) 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); T_R ((p == NULL), IPC_ERROR_ADD__NO_PARAM_CLIENT);
cinfos->size++; // Memory reallocation.
// In case this is the first allocation. ipc_ctx_new_alloc (ctx);
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);
}
T_R ((cinfos->cinfos == NULL), IPC_ERROR_ADD__EMPTY_LIST); memcpy (ctx->cinfos[ctx->size - 1], p , sizeof (struct ipc_connection_info));
memcpy (ctx->pollfd[ctx->size - 1], pollfd, sizeof (struct pollfd));
cinfos->cinfos[cinfos->size - 1] = p;
cinfos->pollfd[cinfos->size - 1] = &p->pollfd;
IPC_RETURN_NO_ERROR; IPC_RETURN_NO_ERROR;
} }
struct ipc_error ipc_del ( struct ipc_error ipc_del (
struct ipc_ctx *cinfos struct ipc_ctx *ctx
, struct ipc_connection_info *p) , 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 ((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; 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, // 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. // 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. // TODO: possible memory leak if the ipc_connection_info is not deeply free'ed.
cinfos->cinfos[i] = cinfos->cinfos[cinfos->size - 1]; ctx->cinfos[i] = ctx->cinfos[ctx->size - 1];
cinfos->size--; ctx->size--;
if (cinfos->size == 0) { if (ctx->size == 0) {
ipc_connections_free (cinfos); ipc_connections_free (ctx);
} else { } 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); 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); 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) { if (ctx->cinfos != NULL) {
for (size_t i = 0; i < cinfos->size; i++) { for (size_t i = 0; i < ctx->size; i++) {
ipc_close (cinfos->cinfos[i]); ipc_close (ctx->cinfos[i]);
free (cinfos->cinfos[i]); free (ctx->cinfos[i]);
} }
free (cinfos->cinfos); free (ctx->cinfos);
cinfos->cinfos = NULL; 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) { if (ctx->cinfos != NULL) {
for (size_t i = 0; i < cinfos->size; i++) { for (size_t i = 0; i < ctx->size; i++) {
free (cinfos->cinfos[i]); free (ctx->cinfos[i]);
} }
free (cinfos->cinfos); free (ctx->cinfos);
cinfos->cinfos = NULL; ctx->cinfos = NULL;
} }
cinfos->size = 0; ctx->size = 0;
} }
// add an arbitrary file descriptor to read // 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),, SECURE_DECLARATION (struct pollfd, pollfd);
IPC_ERROR_ADD_FD__NOT_ENOUGH_MEMORY); pollfd.fd = fd;
pollfd.events = POLLIN;
cinfo->type = IPC_CONNECTION_TYPE_EXTERNAL; return ipc_add (ctx, &cinfo, &pollfd);
return ipc_add (cinfos, cinfo);
} }
// remove a connection from its file descriptor // 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 ((ctx == NULL), IPC_ERROR_DEL_FD__NO_PARAM_CINFOS);
T_R ((cinfos->cinfos == NULL), IPC_ERROR_DEL_FD__EMPTY_LIST); 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; ctx->cinfos[i]->pollfd.fd = -1;
free (cinfos->cinfos[i]); free (ctx->cinfos[i]);
cinfos->pollfd[i] = NULL; ctx->pollfd[i] = NULL;
cinfos->size--; ctx->size--;
if (cinfos->size == 0) { if (ctx->size == 0) {
// free cinfos->cinfos // free ctx->cinfos
ipc_connections_free (cinfos); ipc_connections_free (ctx);
} else { } else {
cinfos->cinfos[i] = cinfos->cinfos[cinfos->size]; ctx->cinfos[i] = ctx->cinfos[ctx->size];
cinfos->pollfd[i] = cinfos->pollfd[cinfos->size]; ctx->pollfd[i] = ctx->pollfd[ctx->size];
cinfos->cinfos = realloc (cinfos->cinfos, sizeof (struct ipc_connection_info) * cinfos->size); ctx->cinfos = realloc (ctx->cinfos, sizeof (struct ipc_connection_info) * ctx->size);
cinfos->pollfd = realloc (cinfos->pollfd, sizeof (struct pollfd ) * cinfos->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); IPC_RETURN_ERROR (IPC_ERROR_DEL_FD__EMPTIED_LIST);
} }
} }

View File

@ -196,7 +196,6 @@ struct ipc_error {
const char *ipc_errors_get (enum ipc_error_code e); const char *ipc_errors_get (enum ipc_error_code e);
struct ipc_connection_info { struct ipc_connection_info {
struct pollfd pollfd;
char type; // server, client, arbitrary fd char type; // server, client, arbitrary fd
char *spath; // max size: PATH_MAX char *spath; // max size: PATH_MAX
}; };
@ -330,7 +329,7 @@ void ipc_connection_print (struct ipc_connection_info *cinfo);
void ipc_connections_print (struct ipc_ctx *cinfos); void ipc_connections_print (struct ipc_ctx *cinfos);
struct ipc_error ipc_accept (struct ipc_connection_info *srv, struct ipc_connection_info *p); struct ipc_error ipc_accept (struct ipc_connection_info *srv, struct ipc_connection_info *p);
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);
struct ipc_error service_path (char *path, const char *sname); struct ipc_error service_path (char *path, const char *sname);
/*** /***