Bugfix (<= => <), better error message (send) and error management.
This commit is contained in:
parent
825e0c1b2c
commit
a99d5317b0
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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)
|
||||||
|
@ -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;
|
||||||
|
Reference in New Issue
Block a user