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

514 lines
13 KiB
C
Raw Normal View History

2016-05-26 18:27:59 +02:00
#include "communication.h"
#include "utils.h"
2016-12-21 01:26:47 +01:00
#include "error.h"
2018-10-28 17:09:35 +01:00
#include "event.h"
#include <unistd.h>
2016-12-17 18:00:04 +01:00
#include <assert.h>
#include <stdio.h>
2016-09-11 14:37:41 +02:00
#include <errno.h>
2016-10-28 13:58:04 +02:00
2018-11-02 21:03:54 +01:00
void service_path (char *path, const char *sname, int32_t index, int32_t version)
{
2016-12-21 01:26:47 +01:00
assert (path != NULL);
assert (sname != NULL);
2016-12-17 18:00:04 +01:00
memset (path, 0, PATH_MAX);
snprintf (path, PATH_MAX, "%s/%s-%d-%d", RUNDIR, sname, index, version);
2016-06-12 12:38:43 +02:00
}
2018-11-02 21:03:54 +01:00
int32_t ipc_server_init (char **env
2018-10-04 00:30:47 +02:00
, struct ipc_service *srv, const char *sname)
2016-05-26 18:27:59 +02:00
{
2016-06-05 20:48:13 +02:00
if (srv == NULL)
2018-10-08 15:18:56 +02:00
return IPC_ERROR_WRONG_PARAMETERS;
2016-05-26 18:27:59 +02:00
2016-06-12 14:41:25 +02:00
// TODO
// use env parameters
2016-06-12 14:41:25 +02:00
// it will be useful to change some parameters transparently
// ex: to get resources from other machines, choosing the
// remote with environment variables
env = env;
2016-12-17 18:00:04 +01:00
// gets the service path
service_path (srv->spath, sname, srv->index, srv->version);
2016-06-13 09:47:19 +02:00
2018-11-02 21:03:54 +01:00
int32_t ret = usock_init (&srv->service_fd, srv->spath);
2018-10-08 15:18:56 +02:00
if (ret < 0) {
handle_err ("ipc_server_init", "usock_init ret < 0");
return -1;
}
return 0;
2016-05-26 18:27:59 +02:00
}
2018-11-02 21:03:54 +01:00
int32_t ipc_server_accept (struct ipc_service *srv, struct ipc_client *p)
{
2016-12-21 01:26:47 +01:00
assert (srv != NULL);
assert (p != NULL);
2018-11-02 21:03:54 +01:00
int32_t ret = usock_accept (srv->service_fd, &p->proc_fd);
2018-10-08 15:18:56 +02:00
if (ret < 0) {
handle_err ("ipc_server_accept", "usock_accept < 0");
return -1;
}
return 0;
}
2018-10-08 16:15:35 +02:00
// empty the srv structure
2018-11-02 21:03:54 +01:00
int32_t ipc_server_close (struct ipc_service *srv)
2016-05-26 18:27:59 +02:00
{
2016-12-17 18:00:04 +01:00
usock_close (srv->service_fd);
2018-11-02 21:03:54 +01:00
int32_t ret = usock_remove (srv->spath);
2018-10-08 16:15:35 +02:00
ipc_service_empty (srv);
return ret;
2016-05-26 18:27:59 +02:00
}
2018-11-02 21:03:54 +01:00
int32_t ipc_server_close_client (struct ipc_client *p)
{
return usock_close (p->proc_fd);
2016-05-26 21:56:43 +02:00
}
2018-11-02 21:03:54 +01:00
int32_t ipc_server_read (const struct ipc_client *p, struct ipc_message *m)
2016-05-26 21:56:43 +02:00
{
2018-10-03 21:52:11 +02:00
return ipc_message_read (p->proc_fd, m);
2016-05-26 18:27:59 +02:00
}
2018-11-02 21:03:54 +01:00
int32_t ipc_server_write (const struct ipc_client *p, const struct ipc_message *m)
{
2018-10-03 21:52:11 +02:00
return ipc_message_write (p->proc_fd, m);
}
2018-11-02 21:03:54 +01:00
int32_t ipc_application_connection (char **env
2018-10-08 16:15:35 +02:00
, struct ipc_service *srv, const char *sname)
{
// TODO
// use env parameters
// it will be useful to change some parameters transparently
// ex: to get resources from other machines, choosing the
// remote with environment variables
env = env;
2016-11-03 22:44:35 +01:00
2016-12-17 18:00:04 +01:00
assert (srv != NULL);
assert (sname != NULL);
2016-10-28 13:58:04 +02:00
2016-12-17 18:00:04 +01:00
if (srv == NULL) {
2016-10-28 13:58:04 +02:00
return -1;
2016-12-17 18:00:04 +01:00
}
2016-10-28 13:58:04 +02:00
2016-12-17 18:00:04 +01:00
// gets the service path
service_path (srv->spath, sname, srv->index, srv->version);
2018-11-02 21:03:54 +01:00
int32_t ret = usock_connect (&srv->service_fd, srv->spath);
2018-10-08 15:18:56 +02:00
if (ret < 0) {
handle_err ("ipc_application_connection", "usock_connect ret <= 0");
return -1;
}
2016-10-28 13:58:04 +02:00
return 0;
}
// close the socket
2018-11-02 21:03:54 +01:00
int32_t ipc_application_close (struct ipc_service *srv)
2016-05-26 18:27:59 +02:00
{
2016-12-17 18:00:04 +01:00
return usock_close (srv->service_fd);
2016-05-26 18:27:59 +02:00
}
2018-11-02 21:03:54 +01:00
int32_t ipc_application_read (struct ipc_service *srv, struct ipc_message *m)
2016-10-28 14:24:15 +02:00
{
2018-10-03 21:52:11 +02:00
return ipc_message_read (srv->service_fd, m);
2016-05-26 18:27:59 +02:00
}
2018-11-02 21:03:54 +01:00
int32_t ipc_application_write (struct ipc_service *srv, const struct ipc_message *m)
2016-05-26 18:27:59 +02:00
{
2018-10-03 21:52:11 +02:00
return ipc_message_write (srv->service_fd, m);
2016-10-28 13:58:04 +02:00
}
2016-12-20 23:36:00 +01:00
2017-01-19 22:07:52 +01:00
/*calculer le max filedescriptor*/
2018-11-02 21:03:54 +01:00
static int32_t get_max_fd_from_ipc_clients_ (struct ipc_clients *clients)
2017-01-19 22:07:52 +01:00
{
2018-11-02 21:03:54 +01:00
int32_t i;
int32_t max = 0;
2017-01-19 22:07:52 +01:00
for (i = 0; i < clients->size; i++ ) {
if (clients->clients[i]->proc_fd > max) {
max = clients->clients[i]->proc_fd;
2017-01-19 22:07:52 +01:00
}
}
return max;
}
2018-11-02 21:03:54 +01:00
static int32_t get_max_fd_from_ipc_services_ (struct ipc_services *services)
2018-10-28 17:09:35 +01:00
{
2018-11-02 21:03:54 +01:00
int32_t i;
int32_t max = 0;
2018-10-28 17:09:35 +01:00
for (i = 0; i < services->size; i++ ) {
if (services->services[i]->service_fd > max) {
max = services->services[i]->service_fd;
}
}
return max;
}
2016-12-22 21:48:35 +01:00
/*
2018-10-03 21:24:20 +02:00
* ipc_server_select prend en parametre
2018-10-04 01:22:50 +02:00
* * un tableau de client qu'on écoute
2016-12-22 21:48:35 +01:00
* * le service qui attend de nouvelles connexions
2018-10-04 01:22:50 +02:00
* * un tableau de client qui souhaitent parler
2016-12-22 21:48:35 +01:00
*
* 0 = OK
* -1 = error
2016-12-22 21:48:35 +01:00
*/
2018-11-02 21:03:54 +01:00
int32_t ipc_server_select (struct ipc_clients *clients, struct ipc_service *srv
, struct ipc_clients *active_clients, int32_t *new_connection)
2016-12-22 21:48:35 +01:00
{
*new_connection = 0;
assert (clients != NULL);
assert (active_clients != NULL);
2016-12-23 01:33:52 +01:00
// delete previous read active_clients array
2018-10-08 16:15:35 +02:00
ipc_clients_free (active_clients);
2016-12-23 01:33:52 +01:00
2018-11-02 21:03:54 +01:00
int32_t i, j;
2016-12-20 23:36:00 +01:00
/* master file descriptor list */
fd_set master;
fd_set readf;
/* maximum file descriptor number */
2018-11-02 21:03:54 +01:00
int32_t fdmax;
2016-12-20 23:36:00 +01:00
/* listening socket descriptor */
2018-11-02 21:03:54 +01:00
int32_t listener = srv->service_fd;
2016-12-20 23:36:00 +01:00
/* clear the master and temp sets */
FD_ZERO(&master);
FD_ZERO(&readf);
/* add the listener to the master set */
FD_SET(listener, &master);
for (i=0; i < clients->size; i++) {
FD_SET(clients->clients[i]->proc_fd, &master);
2016-12-20 23:36:00 +01:00
}
/* keep track of the biggest file descriptor */
2018-10-28 17:09:35 +01:00
fdmax = get_max_fd_from_ipc_clients_ (clients) > srv->service_fd ? get_max_fd_from_ipc_clients_ (clients) : srv->service_fd;
readf = master;
if(select(fdmax+1, &readf, NULL, NULL, NULL) == -1) {
perror("select");
return -1;
}
for (i = 0; i <= fdmax; i++) {
if (FD_ISSET(i, &readf)) {
if (i == listener) {
*new_connection = 1;
} else {
for(j = 0; j < clients->size; j++) {
if(i == clients->clients[j]->proc_fd ) {
ipc_clients_add (active_clients, clients->clients[j]);
}
}
}
}
}
return 0;
}
2018-10-10 23:08:58 +02:00
/*
* ipc_application_select prend en parametre
* * un tableau de server qu'on écoute
* * le service qui attend de nouvelles connexions
* * un tableau de client qui souhaitent parler
*
* 0 = OK
* -1 = error
*/
2018-11-02 21:03:54 +01:00
int32_t ipc_application_select (struct ipc_services *services, struct ipc_services *active_services)
2018-10-10 23:08:58 +02:00
{
assert (services != NULL);
assert (active_services != NULL);
// delete previous read active_services array
ipc_services_free (active_services);
2018-11-02 21:03:54 +01:00
int32_t i, j;
2018-10-10 23:08:58 +02:00
/* master file descriptor list */
fd_set master;
fd_set readf;
/* maximum file descriptor number */
2018-11-02 21:03:54 +01:00
int32_t fdmax;
2018-10-10 23:08:58 +02:00
/* clear the master and temp sets */
FD_ZERO(&master);
FD_ZERO(&readf);
for (i=0; i < services->size; i++) {
FD_SET(services->services[i]->service_fd, &master);
}
/* keep track of the biggest file descriptor */
2018-10-28 17:09:35 +01:00
fdmax = get_max_fd_from_ipc_services_ (services);
2018-10-10 23:08:58 +02:00
readf = master;
if(select(fdmax+1, &readf, NULL, NULL, NULL) == -1) {
perror("select");
return -1;
}
for (i = 0; i <= fdmax; i++) {
if (FD_ISSET(i, &readf)) {
for(j = 0; j < services->size; j++) {
if(i == services->services[j]->service_fd ) {
ipc_services_add (active_services, services->services[j]);
2018-10-10 23:08:58 +02:00
}
}
}
}
return 0;
}
2018-10-28 17:09:35 +01:00
2018-11-02 21:03:54 +01:00
int32_t handle_new_connection (struct ipc_service *srv
2018-10-28 17:09:35 +01:00
, struct ipc_clients *clients
, struct ipc_client **new_client)
{
*new_client = malloc(sizeof(struct ipc_client));
memset(*new_client, 0, sizeof(struct ipc_client));
if (ipc_server_accept (srv, *new_client) < 0) {
handle_error("server_accept < 0");
return 1;
} else {
2018-11-05 19:01:09 +01:00
// printf("new connection\n");
2018-10-28 17:09:35 +01:00
}
if (ipc_clients_add (clients, *new_client) < 0) {
handle_error("ipc_clients_add < 0");
2018-10-28 17:09:35 +01:00
return 1;
}
return 0;
}
2018-11-02 21:03:54 +01:00
int32_t ipc_service_poll_event (struct ipc_clients *clients, struct ipc_service *srv
2018-10-28 17:09:35 +01:00
, struct ipc_event *event)
{
assert (clients != NULL);
IPC_EVENT_CLEAN(event);
2018-11-02 21:03:54 +01:00
int32_t i, j;
2018-10-28 17:09:35 +01:00
/* master file descriptor list */
fd_set master;
fd_set readf;
/* maximum file descriptor number */
2018-11-02 21:03:54 +01:00
int32_t fdmax;
2018-10-28 17:09:35 +01:00
/* listening socket descriptor */
2018-11-02 21:03:54 +01:00
int32_t listener = srv->service_fd;
2018-10-28 17:09:35 +01:00
/* clear the master and temp sets */
FD_ZERO(&master);
FD_ZERO(&readf);
/* add the listener to the master set */
FD_SET(listener, &master);
for (i=0; i < clients->size; i++) {
FD_SET(clients->clients[i]->proc_fd, &master);
}
/* keep track of the biggest file descriptor */
fdmax = get_max_fd_from_ipc_clients_ (clients) > srv->service_fd ? get_max_fd_from_ipc_clients_ (clients) : srv->service_fd;
readf = master;
if(select(fdmax+1, &readf, NULL, NULL, NULL) == -1) {
perror("select");
return -1;
}
for (i = 0; i <= fdmax; i++) {
if (FD_ISSET(i, &readf)) {
if (i == listener) {
// connection
struct ipc_client *new_client = NULL;
handle_new_connection (srv, clients, &new_client);
IPC_EVENT_SET (event, IPC_EVENT_TYPE_CONNECTION, NULL, new_client);
return 0;
} else {
for(j = 0; j < clients->size; j++) {
if(i == clients->clients[j]->proc_fd ) {
// listen to what they have to say (disconnection or message)
// then add a client to `event`, the ipc_event structure
2018-11-02 21:03:54 +01:00
int32_t ret = 0;
2018-10-28 17:09:35 +01:00
struct ipc_message *m = NULL;
m = malloc (sizeof(struct ipc_message));
if (m == NULL) {
return IPC_ERROR_NOT_ENOUGH_MEMORY;
}
memset (m, 0, sizeof (struct ipc_message));
// current talking client
struct ipc_client *pc = clients->clients[j];
ret = ipc_server_read (pc, m);
if (ret < 0) {
2018-10-28 19:28:19 +01:00
handle_err ("ipc_service_poll_event", "ipc_server_read < 0");
2018-10-28 17:09:35 +01:00
ipc_message_empty (m);
free (m);
IPC_EVENT_SET(event, IPC_EVENT_TYPE_ERROR, NULL, pc);
return IPC_ERROR_READ;
}
// disconnection: close the client then delete it from clients
if (ret == 1) {
if (ipc_server_close_client (pc) < 0) {
2018-10-28 19:28:19 +01:00
handle_err( "ipc_service_poll_event", "ipc_server_close_client < 0");
2018-10-28 17:09:35 +01:00
}
if (ipc_clients_del (clients, pc) < 0) {
handle_err( "ipc_service_poll_event", "ipc_clients_del < 0");
2018-10-28 17:09:35 +01:00
}
ipc_message_empty (m);
free (m);
IPC_EVENT_SET(event, IPC_EVENT_TYPE_DISCONNECTION, NULL, pc);
// warning: do not forget to free the ipc_client structure
return 0;
}
// we received a new message from a client
IPC_EVENT_SET (event, IPC_EVENT_TYPE_MESSAGE, m, pc);
return 0;
}
}
}
}
}
return 0;
}
2018-11-02 21:03:54 +01:00
int32_t ipc_application_poll_event_ (struct ipc_services *services, struct ipc_event *event, int32_t interactive)
2018-10-28 17:09:35 +01:00
{
assert (services != NULL);
IPC_EVENT_CLEAN(event);
2018-11-02 21:03:54 +01:00
int32_t i, j;
/* master file descriptor list */
fd_set master;
fd_set readf;
/* maximum file descriptor number */
2018-11-02 21:03:54 +01:00
int32_t fdmax;
/* clear the master and temp sets */
FD_ZERO(&master);
FD_ZERO(&readf);
if (interactive) {
FD_SET(0, &master);
}
for (i=0; i < services->size; i++) {
FD_SET(services->services[i]->service_fd, &master);
}
/* keep track of the biggest file descriptor */
fdmax = get_max_fd_from_ipc_services_ (services);
readf = master;
if(select(fdmax+1, &readf, NULL, NULL, NULL) == -1) {
perror("select");
return -1;
}
for (i = 0; i <= fdmax; i++) {
if (FD_ISSET(i, &readf)) {
// interactive: input on stdin
if (i == 0) {
// XXX: by default, message type is 0
struct ipc_message *m = malloc (sizeof (struct ipc_message));
if (m == NULL) {
return IPC_ERROR_NOT_ENOUGH_MEMORY;
}
memset (m, 0, sizeof (struct ipc_message));
m->payload = malloc (IPC_MAX_MESSAGE_SIZE);
m->length = read(0, m->payload , IPC_MAX_MESSAGE_SIZE);
IPC_EVENT_SET(event, IPC_EVENT_TYPE_STDIN, m, NULL);
return 0;
}
for(j = 0; j < services->size; j++) {
if(i == services->services[j]->service_fd ) {
// listen to what they have to say (disconnection or message)
// then add a client to `event`, the ipc_event structure
2018-11-02 21:03:54 +01:00
int32_t ret = 0;
struct ipc_message *m = NULL;
m = malloc (sizeof(struct ipc_message));
if (m == NULL) {
return IPC_ERROR_NOT_ENOUGH_MEMORY;
}
memset (m, 0, sizeof (struct ipc_message));
// current talking client
struct ipc_service *ps = services->services[j];
ret = ipc_application_read (ps, m);
if (ret < 0) {
2018-10-28 19:28:19 +01:00
handle_err ("ipc_application_poll_event", "ipc_application_read < 0");
ipc_message_empty (m);
free (m);
IPC_EVENT_SET(event, IPC_EVENT_TYPE_ERROR, NULL, ps);
return IPC_ERROR_READ;
}
// disconnection: close the service
if (ret == 1) {
if (ipc_application_close (ps) < 0) {
2018-10-28 19:28:19 +01:00
handle_err( "ipc_application_poll_event", "ipc_application_close < 0");
}
if (ipc_services_del (services, ps) < 0) {
handle_err( "ipc_application_poll_event", "ipc_services_del < 0");
}
ipc_message_empty (m);
free (m);
IPC_EVENT_SET(event, IPC_EVENT_TYPE_DISCONNECTION, NULL, ps);
// warning: do not forget to free the ipc_client structure
return 0;
}
// we received a new message from a client
IPC_EVENT_SET (event, IPC_EVENT_TYPE_MESSAGE, m, ps);
return 0;
}
}
}
}
2018-10-28 17:09:35 +01:00
return 0;
}
2018-11-02 21:03:54 +01:00
int32_t ipc_application_poll_event (struct ipc_services *services, struct ipc_event *event) {
2018-10-28 19:28:19 +01:00
return ipc_application_poll_event_ (services, event, 0);
}
2018-11-02 21:03:54 +01:00
int32_t ipc_application_peek_event (struct ipc_services *services, struct ipc_event *event) {
2018-10-28 19:28:19 +01:00
return ipc_application_poll_event_ (services, event, 1);
}