diff --git a/src/communication.c b/src/communication.c index 450d9dd..a5f8ca8 100644 --- a/src/communication.c +++ b/src/communication.c @@ -239,7 +239,7 @@ struct ipc_error ipc_accept_add (struct ipc_event *event, struct ipc_ctx *ctx, u // Set the event structure. uint32_t client_index = ctx->size - 1; - IPC_EVENT_SET (event, IPC_EVENT_TYPE_CONNECTION, NULL, client_index, *client_fd); + IPC_EVENT_SET (event, IPC_EVENT_TYPE_CONNECTION, client_index, *client_fd, NULL); IPC_RETURN_NO_ERROR; } @@ -341,15 +341,17 @@ struct ipc_error ipc_del (struct ipc_ctx *ctx, uint32_t index) void ipc_connections_free (struct ipc_ctx *ctx) { - // The close and close_all functions perform deep removal of structures. - ipc_close_all (ctx); - if (ctx->cinfos != NULL) { free (ctx->cinfos); free (ctx->pollfd); ctx->cinfos = NULL; ctx->pollfd = NULL; } + + if (ctx->switchdb.collection != NULL) { + free (ctx->switchdb.collection); + ctx->switchdb.collection = NULL; + } ctx->size = 0; } @@ -383,39 +385,51 @@ struct ipc_error ipc_del_fd (struct ipc_ctx *ctx, int fd) IPC_RETURN_ERROR (IPC_ERROR_DEL_FD__CANNOT_FIND_CLIENT); } -#if 0 + +// TODO +struct ipc_error handle_writing_message (struct ipc_event *event, struct ipc_ctx *ctx, uint32_t index); +struct ipc_error handle_writing_message (struct ipc_event *event, struct ipc_ctx *ctx, uint32_t index) +{ + + for (size_t i = 0; ctx->tx.size ; i++) { + // TODO + } + + IPC_EVENT_SET (event, IPC_EVENT_TYPE_TX, index, ctx->pollfd[index].fd, NULL); + IPC_RETURN_NO_ERROR; +} // new message -struct ipc_error handle_message ( - struct ipc_event *event - , struct ipc_ctx *ctx - , struct ipc_connection_info *pc, struct ipc_switchings *switchdb) +struct ipc_error handle_new_message (struct ipc_event *event, struct ipc_ctx *ctx, int index) { - // 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) { - int talkingfd = pc->pollfd.fd; - int correspondingfd = ipc_switching_get (switchdb, talkingfd); + + // If the socket is associated to another one for networkd: + // read and write automatically and provide a new IPC_EVENT_TYPE indicating the switch. + if (ctx->switchdb.collection != NULL) { + int talkingfd = ctx->pollfd[index].fd; + int correspondingfd = ipc_switching_get (&ctx->switchdb, talkingfd); 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)) ; + { /** Some macros use "ret" as a variable name, so this is to be sure. */ + struct ipc_error ret = usock_recv (talkingfd, &buf, &msize); + if (ret.error_code != IPC_ERROR_NONE && ret.error_code != IPC_ERROR_CLOSED_RECIPIENT) { + if (buf != NULL) + free (buf); + IPC_EVENT_SET (event, IPC_EVENT_TYPE_ERROR, index, talkingfd, NULL) + return ret; + } + } - /** TODO: there is a message, send it to the corresponding fd **/ + /** 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); if (nbytes_sent != msize) { // LOG_ERROR ("wrote not enough data from %d to fd %d", talkingfd, correspondingfd); - IPC_EVENT_SET (event, IPC_EVENT_TYPE_ERROR, NULL, pc); + IPC_EVENT_SET (event, IPC_EVENT_TYPE_ERROR, index, ctx->pollfd[index].fd, NULL); IPC_RETURN_NO_ERROR; // FIXME: return something else, maybe? } // LOG_DEBUG ("received a message on fd %d => switch to fd %d", talkingfd, correspondingfd); @@ -423,13 +437,13 @@ struct ipc_error handle_message ( if (buf != NULL) free (buf); - // everything is OK: inform networkd of a successful transfer - IPC_EVENT_SET (event, IPC_EVENT_TYPE_SWITCH, NULL, pc); + // Everything is OK: inform networkd of a successful transfer. + IPC_EVENT_SET (event, IPC_EVENT_TYPE_SWITCH, index, ctx->pollfd[index].fd, NULL); IPC_RETURN_NO_ERROR; } else if (msize == 0) { int delfd; - delfd = ipc_switching_del (switchdb, talkingfd); + delfd = ipc_switching_del (&ctx->switchdb, talkingfd); if (delfd >= 0) { close (delfd); ipc_del_fd (ctx, delfd); @@ -446,16 +460,18 @@ struct ipc_error handle_message ( } #endif - IPC_EVENT_SET (event, IPC_EVENT_TYPE_DISCONNECTION, NULL, pc); + IPC_EVENT_SET (event, IPC_EVENT_TYPE_DISCONNECTION, index, ctx->pollfd[index].fd, NULL); IPC_RETURN_ERROR (IPC_ERROR_CLOSED_RECIPIENT); } } } + // 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); + if (ctx->cinfos[index].type == IPC_CONNECTION_TYPE_EXTERNAL) { + IPC_EVENT_SET (event, IPC_EVENT_TYPE_EXTRA_SOCKET, index, ctx->pollfd[index].fd, NULL); IPC_RETURN_NO_ERROR; } + // 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); @@ -464,220 +480,83 @@ struct ipc_error handle_message ( 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); + ret = ipc_read (ctx, index, m); if (ret.error_code != IPC_ERROR_NONE && ret.error_code != IPC_ERROR_CLOSED_RECIPIENT) { struct ipc_error rvalue = ret; // store the final return value ipc_message_empty (m); free (m); // if there is a problem, just remove the client - TEST_IPC_P (ipc_close (pc), "cannot close a connection in handle_message"); - TEST_IPC_P (ipc_del (ctx, pc), "cannot delete a connection in handle_message"); + TEST_IPC_P (ipc_close (ctx, index), "cannot close a connection in handle_message"); + TEST_IPC_P (ipc_del (ctx, index), "cannot delete a connection in handle_message"); - IPC_EVENT_SET (event, IPC_EVENT_TYPE_ERROR, NULL, pc); + IPC_EVENT_SET (event, IPC_EVENT_TYPE_ERROR, index, ctx->pollfd[index].fd, NULL); return rvalue; } // disconnection: close the client then delete it from ctx 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 (ctx, pc), "cannot delete a connection on closed recipient in handle_message"); + TEST_IPC_P (ipc_close (ctx, index), "cannot close a connection on closed recipient in handle_message"); + TEST_IPC_P (ipc_del (ctx, index), "cannot delete a connection on closed recipient in handle_message"); ipc_message_empty (m); free (m); - IPC_EVENT_SET (event, IPC_EVENT_TYPE_DISCONNECTION, NULL, pc); + IPC_EVENT_SET (event, IPC_EVENT_TYPE_DISCONNECTION, index, ctx->pollfd[index].fd, NULL); // warning: do not forget to free the ipc_client structure IPC_RETURN_NO_ERROR; } - IPC_EVENT_SET (event, IPC_EVENT_TYPE_MESSAGE, m, pc); + IPC_EVENT_SET (event, IPC_EVENT_TYPE_MESSAGE, index, ctx->pollfd[index].fd, m); 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 -ipc_events_loop ( - struct ipc_ctx *ctx - , struct ipc_connection_info *cinfo // NULL for clients - , struct ipc_event *event - , struct ipc_switchings *switchdb - , struct ipc_messages *messages_to_send - , int *timer /* in ms */) +/* timer is in ms */ +struct ipc_error ipc_events_loop (struct ipc_ctx *ctx, struct ipc_event *event, int *timer) { T_R ((ctx == NULL), IPC_ERROR_WAIT_EVENT__NO_CLIENTS_PARAM); T_R ((event == NULL), IPC_ERROR_WAIT_EVENT__NO_EVENT_PARAM); IPC_EVENT_CLEAN (event); - int i, n, listenfd, client_fd, nread; - uid_t uid; + int32_t n; - // Generate the array of pollfd structure once, then use it each time. - // TODO: ça ailleurs: if ( (ctx->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: ctx->pollfd[0].fd = listenfd; - // TODO: ça ailleurs: ctx->pollfd[0].events = POLLIN; - - if ((n = poll(ctx->pollfd, ctx->size, *timer)) < 0) - { - log_sys("select error"); + if ((n = poll(ctx->pollfd, ctx->size, *timer)) < 0) { + printf("select error\n"); + exit(1); // TODO FIXME } - + // Timeout. if (n == 0) { - // TODO: timeout + IPC_EVENT_SET (event, IPC_EVENT_TYPE_TIMER, 0, 0, NULL); + IPC_RETURN_NO_ERROR; } - for (i = 0; i <= ctx->size; i++) { + for (size_t i = 0; i <= ctx->size; i++) { // Something to read or connection. - if (ctx->pollfd[i].revents & POLLIN) - { + if (ctx->pollfd[i].revents & POLLIN) { // In case there is something to read for the server socket: new client. if (ctx->cinfos[i].type == IPC_CONNECTION_TYPE_SERVER) { return ipc_accept_add (event, ctx, i); } - return handle_message (event, ctx, i, switchdb); + return handle_new_message (event, ctx, i); } - if (ctx->pollfd[i].revents & POLLOUT) - { + // Something can be sent. + if (ctx->pollfd[i].revents & POLLOUT) { return handle_writing_message (event, ctx, i); } - // TODO: in case there is an error that way?? - //if (ctx->cinfos[i].fd < 0) - // continue; - // Disconnection. - if (ctx->pollfd[i].revents & POLLHUP) - goto hungup; - else if (ctx->pollfd[i].revents & POLLIN) { - return handle_disconnection (event, ctx, i, switchdb); - /* read argument buffer from client */ - if ( (nread = read(client_fd, buf, MAXLINE)) < 0) - log_sys("read error on fd %d", client_fd); - else if (nread == 0) { -hungup: - log_msg("closed: uid %d, fd %d", client[i].uid, client_fd); - client_del(client_fd); /* client has closed conn */ - ctx->pollfd[i].fd = -1; - close(client_fd); - } else /* process client's rquest */ - request(buf, nread, client_fd, client[i].uid); + if (ctx->pollfd[i].revents & POLLHUP) { + /** IPC_EVENT_SET: event, type, index, fd, message */ + IPC_EVENT_SET (event, IPC_EVENT_TYPE_DISCONNECTION, i, ctx->pollfd[i].fd, NULL); + return ipc_close (ctx, i); } } /** for loop: end of the message handling */ - // from 0 to ctx->size - // if something to read - // if this is the server - // return handle_connection - // else - // from 0 to ctx->size - // if this is the right index in ctx->cinfos - // return handle_message (event, ctx, i, switchdb); - IPC_RETURN_NO_ERROR; } - -struct ipc_error ipc_wait_event_networkd ( - struct ipc_ctx *ctx - , struct ipc_connection_info *cinfo // NULL for clients - , struct ipc_event *event - , struct ipc_switchings *switchdb - , int *timer) -{ - T_R ((ctx == NULL), IPC_ERROR_WAIT_EVENT__NO_CLIENTS_PARAM); - T_R ((event == NULL), IPC_ERROR_WAIT_EVENT__NO_EVENT_PARAM); - - IPC_EVENT_CLEAN (event); - - size_t i, j; - /* master file descriptor list */ - fd_set master; - fd_set readf; - - /* clear the master and temp sets */ - FD_ZERO (&master); - FD_ZERO (&readf); - - /* maximum file descriptor number */ - /* keep track of the biggest file descriptor */ - int32_t fdmax = get_max_fd (ctx); - - /* listening socket descriptor */ - int32_t listener; - if (cinfo != NULL) { - listener = cinfo->pollfd.fd; - - /* add the listener to the master set */ - FD_SET (listener, &master); - - /* if listener is max fd */ - if (fdmax < listener) - fdmax = listener; - } - - for (i = 0; i < ctx->size; i++) { - FD_SET (ctx->cinfos[i]->pollfd.fd, &master); - } - - 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) { - *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, ctx, cinfo); - } else { - for (j = 0; j < ctx->size; j++) { - if (i == (size_t) ctx->cinfos[j]->pollfd.fd) { - return handle_message (event, ctx, ctx->cinfos[j], switchdb); - } - } - } - } - } - - IPC_RETURN_NO_ERROR; -} - -struct ipc_error ipc_wait_event ( - struct ipc_ctx *ctx - , struct ipc_connection_info *cinfo // NULL for clients - , struct ipc_event *event - , int *timer) -{ - return ipc_wait_event_networkd (ctx, cinfo, event, NULL, timer); -} -#endif diff --git a/src/ipc.h b/src/ipc.h index 732d512..1f8ea8b 100644 --- a/src/ipc.h +++ b/src/ipc.h @@ -73,13 +73,14 @@ enum msg_types { enum ipc_event_type { IPC_EVENT_TYPE_NOT_SET = 0 , IPC_EVENT_TYPE_ERROR = 1 - , IPC_EVENT_TYPE_EXTRA_SOCKET = 2 - , IPC_EVENT_TYPE_SWITCH = 3 - , 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 + , IPC_EVENT_TYPE_EXTRA_SOCKET = 2 // Message received from a non IPC socket. + , IPC_EVENT_TYPE_SWITCH = 3 // Message to send to a corresponding fd. + , IPC_EVENT_TYPE_CONNECTION = 4 // New user. + , IPC_EVENT_TYPE_DISCONNECTION = 5 // User disconnected. + , IPC_EVENT_TYPE_MESSAGE = 6 // New message. + , IPC_EVENT_TYPE_LOOKUP = 7 // Client asking for a service through ipcd. + , IPC_EVENT_TYPE_TIMER = 8 // Timeout in the poll(2) function. + , IPC_EVENT_TYPE_TX = 9 // Message sent. }; /** @@ -170,19 +171,19 @@ enum ipc_error_code { , IPC_ERROR_DIR_SETUP__DIRECTORY_NOT_WRITABLE = 84 , IPC_ERROR_DIRECTORY_SETUP__PATH_PARAM = 85 - , IPC_ERROR_SERVER_INIT__NOT_ENOUGH_MEMORY = 86 - , IPC_ERROR_CONNECTION__NOT_ENOUGH_MEMORY = 87 - , IPC_ERROR_CTX_INIT__NO_CONTEXT_PARAM = 88 - , IPC_ERROR_CTX_INIT__CONTEXT_ALREADY_INIT = 89 - , IPC_ERROR_ADD__MALLOC_POLLFD = 90 - , IPC_ERROR_ADD_MESSAGE_TO_SEND__EMPTY_LIST = 91 - , IPC_ERROR_ADD_MESSAGE_TO_SEND__MALLOC = 92 - , IPC_ERROR_ADD_MESSAGE_TO_SEND__NO_PARAM_MESSAGE = 93 - , IPC_ERROR_ADD_MESSAGE_TO_SEND__NO_PARAM_MESSAGES = 94 - , IPC_ERROR_CONNECTION__NO_CTX = 95 - , IPC_ERROR_CTX_INIT__MALLOC_CTX = 96 - , IPC_ERROR_CTX_INIT__MALLOC_POLLFD = 97 - , IPC_ERROR_CONTACT_NETWORKD__NO_FD_PARAM = 98 + , IPC_ERROR_SERVER_INIT__NOT_ENOUGH_MEMORY = 86 + , IPC_ERROR_CONNECTION__NOT_ENOUGH_MEMORY = 87 + , IPC_ERROR_CTX_INIT__NO_CONTEXT_PARAM = 88 + , IPC_ERROR_CTX_INIT__CONTEXT_ALREADY_INIT = 89 + , IPC_ERROR_ADD__MALLOC_POLLFD = 90 + , IPC_ERROR_ADD_MESSAGE_TO_SEND__EMPTY_LIST = 91 + , IPC_ERROR_ADD_MESSAGE_TO_SEND__MALLOC = 92 + , IPC_ERROR_ADD_MESSAGE_TO_SEND__NO_PARAM_MESSAGE = 93 + , IPC_ERROR_ADD_MESSAGE_TO_SEND__NO_PARAM_MESSAGES = 94 + , IPC_ERROR_CONNECTION__NO_CTX = 95 + , IPC_ERROR_CTX_INIT__MALLOC_CTX = 96 + , IPC_ERROR_CTX_INIT__MALLOC_POLLFD = 97 + , IPC_ERROR_CONTACT_NETWORKD__NO_FD_PARAM = 98 , IPC_ERROR_HANDLE_NEW_CONNECTION__INCONSISTENT_INDEX = 99 }; @@ -191,6 +192,16 @@ struct ipc_error { char error_message[BUFSIZ]; }; +struct ipc_switching { + int orig; + int dest; +}; + +struct ipc_switchings { + struct ipc_switching *collection; + size_t size; +}; + // get explanation about an error // This only returns the generic error based on its code. // Library's users have a more meaningful insight on the error @@ -202,6 +213,19 @@ struct ipc_connection_info { char *spath; // max size: PATH_MAX }; +struct ipc_message { + char type; + char user_type; + uint32_t length; + char *payload; + int fd; // File descriptor concerned about this message. +}; + +struct ipc_messages { + struct ipc_message *messages; + size_t size; +}; + /** * Context of the whole networking state. */ @@ -218,37 +242,32 @@ struct ipc_ctx { * Size of the connection list. */ size_t size; -}; - -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. + /** + * List of messages to send, once the fd are available. + */ + struct ipc_messages tx; + /** + * Relations between fd. + */ + struct ipc_switchings switchdb; }; struct ipc_event { enum ipc_event_type type; uint32_t index; int origin; - void *m; // message pointer + void *m; // message pointer }; /*** * ipc event macros **/ -#define IPC_EVENT_SET(pevent,type_,message_,index_, origin_fd_) {\ +#define IPC_EVENT_SET(pevent,type_,index_, origin_fd_,message_) {\ pevent->type = type_; \ - pevent->m = message_; \ pevent->index = index_; \ pevent->origin = origin_fd_; \ + pevent->m = message_; \ }; enum ipc_connection_types { @@ -335,16 +354,6 @@ struct ipc_error service_path (char *path, const char *sname); * networkd enumerations, structures and functions **/ -struct ipc_switching { - int orig; - int dest; -}; - -struct ipc_switchings { - struct ipc_switching *collection; - size_t size; -}; - struct networkd { int cpt; struct ipc_connection_info *srv; diff --git a/src/message.c b/src/message.c index cd679ec..c9d7ae2 100644 --- a/src/message.c +++ b/src/message.c @@ -163,7 +163,8 @@ struct ipc_error ipc_messages_add (struct ipc_messages *messages, struct ipc_me T_R ((messages->messages == NULL), IPC_ERROR_ADD_MESSAGE_TO_SEND__EMPTY_LIST); - messages->messages[messages->size - 1] = message; + // NOT A DEEP COPY. + messages->messages[messages->size - 1] = *message; IPC_RETURN_NO_ERROR; }