Archived
3
0

Bugfix (<= => <), better error message (send) and error management.

This commit is contained in:
Karchnu 2020-11-06 21:17:01 +01:00
parent 825e0c1b2c
commit a99d5317b0
4 changed files with 126 additions and 16 deletions

View File

@ -204,7 +204,7 @@ struct ipc_error ipc_close_all (struct ipc_ctx *ctx)
T_R ((ctx == NULL), IPC_ERROR_CLOSE_ALL__NO_CTX_PARAM); T_R ((ctx == NULL), IPC_ERROR_CLOSE_ALL__NO_CTX_PARAM);
for (size_t i = 0 ; i < ctx->size ; i++) { for (size_t i = 0 ; i < ctx->size ; i++) {
TEST_IPC_P (ipc_close (ctx, i), "cannot close a connection in handle_message"); TEST_IPC_P (ipc_close (ctx, i), "cannot close a connection in ipc_close_all");
} }
IPC_RETURN_NO_ERROR; IPC_RETURN_NO_ERROR;
@ -526,6 +526,10 @@ struct ipc_error ipc_wait_event (struct ipc_ctx *ctx, struct ipc_event *event, i
IPC_EVENT_CLEAN (event); IPC_EVENT_CLEAN (event);
// By default, everything is alright.
SECURE_DECLARATION(struct ipc_error, final_return);
final_return.error_code = IPC_ERROR_NONE;
int32_t n = 0; int32_t n = 0;
for (size_t i = 0; i < ctx->size; i++) { for (size_t i = 0; i < ctx->size; i++) {
@ -533,7 +537,9 @@ struct ipc_error ipc_wait_event (struct ipc_ctx *ctx, struct ipc_event *event, i
ctx->pollfd[i].events = POLLIN; ctx->pollfd[i].events = POLLIN;
} }
// For each message to send…
for (size_t i = 0; i < ctx->tx.size; i++) { for (size_t i = 0; i < ctx->tx.size; i++) {
// … verify that its destination is available for message exchange.
for (size_t y = 0; y < ctx->size; y++) { for (size_t y = 0; y < ctx->size; y++) {
if (ctx->pollfd[y].fd == ctx->tx.messages[i].fd) { if (ctx->pollfd[y].fd == ctx->tx.messages[i].fd) {
ctx->pollfd[y].events |= POLLOUT; ctx->pollfd[y].events |= POLLOUT;
@ -584,7 +590,12 @@ struct ipc_error ipc_wait_event (struct ipc_ctx *ctx, struct ipc_event *event, i
IPC_RETURN_NO_ERROR; IPC_RETURN_NO_ERROR;
} }
for (size_t i = 0; i <= ctx->size; i++) { for (size_t i = 0; i < ctx->size; i++) {
// Whatever happens, we have the fd and the index in event.
event->index = i;
event->origin = ctx->pollfd[i].fd;
// Something to read or connection. // Something to read or connection.
if (ctx->pollfd[i].revents & POLLIN || ctx->cinfos[i].more_to_read == 1) { if (ctx->pollfd[i].revents & POLLIN || ctx->cinfos[i].more_to_read == 1) {
@ -593,21 +604,25 @@ struct ipc_error ipc_wait_event (struct ipc_ctx *ctx, struct ipc_event *event, i
// 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 (ctx->cinfos[i].type == IPC_CONNECTION_TYPE_SERVER) { if (ctx->cinfos[i].type == IPC_CONNECTION_TYPE_SERVER) {
return ipc_accept_add (event, ctx, i); final_return = ipc_accept_add (event, ctx, i);
goto wait_event_exit;
} }
// fd is switched: using callbacks for IO operations. // fd is switched: using callbacks for IO operations.
if (ctx->cinfos[i].type == IPC_CONNECTION_TYPE_SWITCHED) { if (ctx->cinfos[i].type == IPC_CONNECTION_TYPE_SWITCHED) {
return handle_switched_message (event, ctx, i); final_return = handle_switched_message (event, ctx, i);
goto wait_event_exit;
} }
// No treatment of the socket if external socket: the libipc user should handle IO operations. // No treatment of the socket if external socket: the libipc user should handle IO operations.
if (ctx->cinfos[i].type == IPC_CONNECTION_TYPE_EXTERNAL) { if (ctx->cinfos[i].type == IPC_CONNECTION_TYPE_EXTERNAL) {
IPC_EVENT_SET (event, IPC_EVENT_TYPE_EXTRA_SOCKET, i, ctx->pollfd[i].fd, NULL); IPC_EVENT_SET (event, IPC_EVENT_TYPE_EXTRA_SOCKET, i, ctx->pollfd[i].fd, NULL);
IPC_RETURN_NO_ERROR; // Default: return no error.
goto wait_event_exit;
} }
return handle_new_message (event, ctx, i); final_return = handle_new_message (event, ctx, i);
goto wait_event_exit;
} }
// Something can be sent. // Something can be sent.
@ -616,20 +631,46 @@ struct ipc_error ipc_wait_event (struct ipc_ctx *ctx, struct ipc_event *event, i
// fd is switched: using callbacks for IO operations. // fd is switched: using callbacks for IO operations.
if (ctx->cinfos[i].type == IPC_CONNECTION_TYPE_SWITCHED) { if (ctx->cinfos[i].type == IPC_CONNECTION_TYPE_SWITCHED) {
return handle_writing_switched_message (event, ctx, i); final_return = handle_writing_switched_message (event, ctx, i);
goto wait_event_exit;
} }
return handle_writing_message (event, ctx, i); final_return = handle_writing_message (event, ctx, i);
goto wait_event_exit;
} }
// Disconnection. // Disconnection.
if (ctx->pollfd[i].revents & POLLHUP) { if (ctx->pollfd[i].revents & POLLHUP) {
/** IPC_EVENT_SET: event, type, index, fd, message */ /** IPC_EVENT_SET: event, type, index, fd, message */
IPC_EVENT_SET (event, IPC_EVENT_TYPE_DISCONNECTION, i, ctx->pollfd[i].fd, NULL); IPC_EVENT_SET (event, IPC_EVENT_TYPE_DISCONNECTION, i, ctx->pollfd[i].fd, NULL);
return ipc_close (ctx, i); final_return = ipc_close (ctx, i);
goto wait_event_exit;
}
if (ctx->pollfd[i].revents & POLLERR) {
printf ("POLLERR: PROBLEM WITH fd %d\n", ctx->pollfd[i].fd);
IPC_EVENT_SET (event, IPC_EVENT_TYPE_ERROR, i, ctx->pollfd[i].fd, NULL);
goto wait_event_exit;
}
if (ctx->pollfd[i].revents & POLLNVAL) {
printf ("POLLNVAL: INVALID fd %d\n", ctx->pollfd[i].fd);
IPC_EVENT_SET (event, IPC_EVENT_TYPE_ERROR, i, ctx->pollfd[i].fd, NULL);
goto wait_event_exit;
} }
} /** for loop: end of the message handling */ } /** for loop: end of the message handling */
IPC_RETURN_NO_ERROR; printf ("END OF THE LOOP WITHOUT GOTO!\n");
wait_event_exit:
/** TODO: tests on event, it has to be filled. */
if (event->type == 0) {
printf ("EVENT TYPE NOT FILLED! code: %d, error_message: %s\n"
, final_return.error_code
, final_return.error_message);
}
return final_return;
} }

View File

@ -316,6 +316,8 @@ struct ipc_event {
#define IPC_EVENT_CLEAN(pevent) {\ #define IPC_EVENT_CLEAN(pevent) {\
pevent->type = IPC_EVENT_TYPE_NOT_SET;\ pevent->type = IPC_EVENT_TYPE_NOT_SET;\
pevent->origin = 0;\
pevent->index = 0;\
if (pevent->m != NULL) {\ if (pevent->m != NULL) {\
ipc_message_empty (pevent->m);\ ipc_message_empty (pevent->m);\
free(pevent->m);\ free(pevent->m);\
@ -376,7 +378,7 @@ void ipc_messages_free (struct ipc_messages *);
// Switch cases macros // Switch cases macros
// print on error // print on error
#define ERROR_CASE(e,f,m) case e : { fprintf (stderr, "function %s: %s", f, m); } break; #define ERROR_CASE(e,f,m) case e : { fprintf (stderr, "function %s: %s\n", f, m); } break;
/*** /***
* non public functions * non public functions
@ -400,6 +402,7 @@ struct ipc_error service_path (char *path, const char *sname);
**/ **/
void ipc_ctx_switching_add (struct ipc_ctx *ctx, int orig, int dest); void ipc_ctx_switching_add (struct ipc_ctx *ctx, int orig, int dest);
int ipc_ctx_switching_del (struct ipc_ctx *ctx, int fd);
void ipc_switching_add (struct ipc_switchings *is, int orig, int dest); void ipc_switching_add (struct ipc_switchings *is, int orig, int dest);
int ipc_switching_del (struct ipc_switchings *is, int fd); int ipc_switching_del (struct ipc_switchings *is, int fd);
int ipc_switching_get (struct ipc_switchings *is, int fd); int ipc_switching_get (struct ipc_switchings *is, int fd);

View File

@ -118,6 +118,11 @@ void ipc_switching_add (struct ipc_switchings *is, int orig, int dest)
// printf ("ipc_switching_add END: switchdb has %ld entries\n", is->size); // printf ("ipc_switching_add END: switchdb has %ld entries\n", is->size);
} }
int ipc_ctx_switching_del (struct ipc_ctx *ctx, int fd)
{
return ipc_switching_del (&ctx->switchdb, fd);
}
int ipc_switching_del (struct ipc_switchings *is, int fd) int ipc_switching_del (struct ipc_switchings *is, int fd)
{ {
for (size_t i = 0; i < is->size; i++) { for (size_t i = 0; i < is->size; i++) {
@ -355,13 +360,14 @@ struct ipc_error fd_switching_read (struct ipc_event *event, struct ipc_ctx *ctx
* NOTE: In any other case, the fd is, or should be closed. * NOTE: In any other case, the fd is, or should be closed.
*/ */
// 1. close and remove both fd from switchdb // 1. remove both fd from switchdb
close (sw->dest); // Client and servers should be closed by the libipc user application.
ipc_del_fd (ctx, sw->dest); // close (sw->dest);
// Should not close the client: it's the job of the libipc user application.
// XXX: this may be normal, but should be documented.
// close (talkingfd); // close (talkingfd);
ipc_del_fd (ctx, sw->dest);
ipc_del_fd (ctx, talkingfd); ipc_del_fd (ctx, talkingfd);
ipc_switching_del (&ctx->switchdb, talkingfd); ipc_switching_del (&ctx->switchdb, talkingfd);
// 2. set event (either error or disconnection) // 2. set event (either error or disconnection)

View File

@ -24,6 +24,66 @@ struct ipc_error usock_send (const int32_t fd, const char *buf, size_t len, size
{ {
ssize_t ret = 0; ssize_t ret = 0;
ret = send (fd, buf, len, MSG_NOSIGNAL); ret = send (fd, buf, len, MSG_NOSIGNAL);
if (ret <= 0)
{
// TODO: Check for errno.
// Some choice could be made.
switch (errno) {
// The receive buffer pointer(s) point outside the process's address space.
ERROR_CASE (EACCES, "usock_send", "write permission is denied");
// The socket is marked nonblocking and the requested operation would block.
// POSIX.1-2001 allows either error to be returned for this case, and does not
// require these constants to have the same value, so a portable application
// should check for both possibilities.
case (EWOULDBLOCK) :
ERROR_CASE (EAGAIN, "usock_send", "socket marked as nonblocking, but requested operation would block");
ERROR_CASE (EAGAIN, "usock_send", "socket not previously bound to an address and all ports are in use");
ERROR_CASE (EALREADY, "usock_send", "another Fast Open is in progress");
ERROR_CASE (EBADF, "usock_send", "sockfd is not a valid open file descriptor");
ERROR_CASE (ECONNRESET, "usock_send", "Connection reset by peer.");
ERROR_CASE (EDESTADDRREQ, "usock_send", "socket not connection-mode, and no peer address is set.");
ERROR_CASE (EFAULT, "usock_send", "an invalid user space address was specified for an argument");
// See signal(7).
ERROR_CASE (EINTR, "usock_send", "a signal occurred before any data was transmitted");
ERROR_CASE (EINVAL, "usock_send", "invalid argument passed");
// This error should not happen, and the recipient specification may be ignored.
ERROR_CASE (EISCONN, "usock_send", "connection-mode socket was already connected but a recipient was specified");
// The socket type requires that message be sent atomically, and the size of the message to be sent made this impossible.
ERROR_CASE (EMSGSIZE, "usock_send", "cannot send a message of that size");
// This generally indicates that the interface has stopped sending, but
// may be caused by transient congestion. (Normally, this does not occur in Linux.
// Packets are just silently dropped when a device queue overflows.)
ERROR_CASE (ENOBUFS, "usock_send", "the output queue for the network interface was full");
ERROR_CASE (ENOMEM, "usock_send", "no memory available");
ERROR_CASE (ENOTCONN, "usock_send", "the socket is not connected, and no target has been given");
// Should not happen in libipc (watch out for libipc user application).
ERROR_CASE (ENOTSOCK, "usock_send", "the file descriptor sockfd does not refer to a socket");
// Should not happen in libipc.
ERROR_CASE (EOPNOTSUPP, "usock_send", "some bit in the flags argument is inappropriate for the socket type");
// In this case, the process will also receive a SIGPIPE unless MSG_NOSIGNAL is set.
ERROR_CASE (EPIPE, "usock_send", "the local end has been shut down on a connection oriented socket");
}
}
T_R ((ret <= 0), IPC_ERROR_USOCK_SEND); T_R ((ret <= 0), IPC_ERROR_USOCK_SEND);
*sent = ret; *sent = ret;
IPC_RETURN_NO_ERROR; IPC_RETURN_NO_ERROR;