diff --git a/core/communication.c b/core/communication.c index 032c932..2ff42ff 100644 --- a/core/communication.c +++ b/core/communication.c @@ -1,5 +1,4 @@ #include "communication.h" -#include "usocket.h" #include "utils.h" #include "error.h" @@ -19,7 +18,7 @@ int ipc_server_init (int argc, char **argv, char **env , struct ipc_service *srv, const char *sname) { if (srv == NULL) - return ER_PARAMS; + return IPC_ERROR_WRONG_PARAMETERS; // TODO // use the argc, argv and env parameters @@ -34,7 +33,13 @@ int ipc_server_init (int argc, char **argv, char **env // gets the service path service_path (srv->spath, sname, srv->index, srv->version); - return usock_init (&srv->service_fd, srv->spath); + int ret = usock_init (&srv->service_fd, srv->spath); + if (ret < 0) { + handle_err ("ipc_server_init", "usock_init ret < 0"); + return -1; + } + + return 0; } int ipc_server_accept (struct ipc_service *srv, struct ipc_client *p) @@ -42,8 +47,13 @@ int ipc_server_accept (struct ipc_service *srv, struct ipc_client *p) assert (srv != NULL); assert (p != NULL); - usock_accept (srv->service_fd, &p->proc_fd); + int ret = usock_accept (srv->service_fd, &p->proc_fd); + if (ret < 0) { + handle_err ("ipc_server_accept", "usock_accept < 0"); + return -1; + } +#if 0 struct ipc_message m_con; memset (&m_con, 0, sizeof (struct ipc_message)); ipc_server_read (p, &m_con); @@ -55,6 +65,7 @@ int ipc_server_accept (struct ipc_service *srv, struct ipc_client *p) ipc_message_format_ack (&m_ack, NULL, 0); ipc_server_write (p, &m_ack); ipc_message_free (&m_ack); +#endif return 0; } @@ -106,8 +117,13 @@ int ipc_application_connection (int argc, char **argv, char **env // gets the service path service_path (srv->spath, sname, srv->index, srv->version); - usock_connect (&srv->service_fd, srv->spath); + int ret = usock_connect (&srv->service_fd, srv->spath); + if (ret < 0) { + handle_err ("ipc_application_connection", "usock_connect ret <= 0"); + return -1; + } +#if 0 // send connection string and receive acknowledgement struct ipc_message m_con; memset (&m_con, 0, sizeof (struct ipc_message)); @@ -130,10 +146,12 @@ int ipc_application_connection (int argc, char **argv, char **env assert (m_ack.type == MSG_TYPE_ACK); assert (m_ack.length == 0); ipc_message_free (&m_ack); +#endif return 0; } +#if 0 // send a CLOSE message then close the socket int ipc_application_close (struct ipc_service *srv) { @@ -146,6 +164,7 @@ int ipc_application_close (struct ipc_service *srv) return usock_close (srv->service_fd); } +#endif int ipc_application_read (struct ipc_service *srv, struct ipc_message *m) { diff --git a/core/communication.h b/core/communication.h index 92f2543..24d8401 100644 --- a/core/communication.h +++ b/core/communication.h @@ -11,26 +11,10 @@ #define COMMUNICATION_VERSION 1 -#define ER_MEM_ALLOC 100 -#define ER_PARAMS 101 - -#define TMPDIR "/run/ipc/" - -#define PATH_MAX 4096 - -#define IPC_MESSAGE_CONNECTION 0 -#define IPC_MESSAGE_DATA 1 -#define IPC_MESSAGE_DATA_AND_CONNECTION 2 -#define IPC_MESSAGE_SERVICE_STOP 3 - -struct ipc_service { - unsigned int version; - unsigned int index; - char spath[PATH_MAX]; - int service_fd; -}; - - +#define IPC_WITH_UNIX_SOCKETS +#ifdef IPC_WITH_UNIX_SOCKETS +#include "usocket.h" +#endif // SERVICE // srv->version and srv->index must be already set diff --git a/core/error.h b/core/error.h index c06b0e8..38d8383 100644 --- a/core/error.h +++ b/core/error.h @@ -3,6 +3,9 @@ #include "logger.h" +#define IPC_ERROR_NOT_ENOUGH_MEMORY 100 +#define IPC_ERROR_WRONG_PARAMETERS 101 + #define handle_error(msg) \ do { log_error (msg); exit(EXIT_FAILURE); } while (0) diff --git a/core/msg.c b/core/msg.c index 9d80572..ef3a135 100644 --- a/core/msg.c +++ b/core/msg.c @@ -73,6 +73,7 @@ int ipc_message_format_write (const struct ipc_message *m, char **buf, size_t *m return 0; } +// 1 on a recipient socket close int ipc_message_read (int fd, struct ipc_message *m) { assert (m != NULL); @@ -82,9 +83,15 @@ int ipc_message_read (int fd, struct ipc_message *m) int ret = usock_recv (fd, &buf, &msize); if (ret < 0) { + // on error, buffer already freed handle_err ("msg_read", "usock_recv"); - return ret; + return -1; } + + // closed recipient, buffer already freed + if (ret == 1) { + return 1; + } if (ipc_message_format_read (m, buf, msize) < 0) { return -1; @@ -99,15 +106,26 @@ int ipc_message_write (int fd, const struct ipc_message *m) assert (m != NULL); char *buf = NULL; - size_t msize = 0; + ssize_t msize = 0; ipc_message_format_write (m, &buf, &msize); - int ret = usock_send (fd, buf, msize); + ssize_t nbytes_sent = 0; + int ret = usock_send (fd, buf, msize, &nbytes_sent); if (ret < 0) { - handle_err ("msg_write", "usock_send"); - return ret; + if (buf != NULL) + free (buf); + handle_err ("msg_write", "usock_send ret < 0"); + return -1; } + // what was sent != what should have been sent + if (nbytes_sent != msize) { + if (buf != NULL) + free (buf); + handle_err ("msg_write", "usock_send did not send enough data"); + return -1; + } + if (buf != NULL) free (buf); @@ -134,8 +152,11 @@ int ipc_message_format (struct ipc_message *m, char type, const char *payload, s if (m->payload != NULL) { free (m->payload); } - // FIXME: test malloc + m->payload = malloc (length); + if (m->payload == NULL) { + return IPC_ERROR_NOT_ENOUGH_MEMORY; + } memset (m->payload, 0, length); } @@ -145,27 +166,29 @@ int ipc_message_format (struct ipc_message *m, char type, const char *payload, s return 0; } -int ipc_message_format_con (struct ipc_message *m, const char *payload, size_t length) -{ - return ipc_message_format (m, MSG_TYPE_CON, payload, length); -} - int ipc_message_format_data (struct ipc_message *m, const char *payload, size_t length) { return ipc_message_format (m, MSG_TYPE_DATA, payload, length); } +#if 0 + +int ipc_message_format_con (struct ipc_message *m, const char *payload, size_t length) +{ + return ipc_message_format (m, MSG_TYPE_CON, payload, length); +} int ipc_message_format_ack (struct ipc_message *m, const char *payload, size_t length) { return ipc_message_format (m, MSG_TYPE_ACK, payload, length); } +#endif int ipc_message_format_server_close (struct ipc_message *m) { return ipc_message_format (m, MSG_TYPE_SERVER_CLOSE, NULL, 0); } -int ipc_message_free (struct ipc_message *m) +int ipc_message_empty (struct ipc_message *m) { assert (m != NULL); diff --git a/core/msg.h b/core/msg.h index 459e965..d3c5574 100644 --- a/core/msg.h +++ b/core/msg.h @@ -5,12 +5,13 @@ #include #include -#define MSG_TYPE_CLOSE 0 -#define MSG_TYPE_CON 1 -#define MSG_TYPE_ERR 2 -#define MSG_TYPE_ACK 3 -#define MSG_TYPE_DATA 4 -#define MSG_TYPE_SERVER_CLOSE 5 +// FIXME, removed messages types: MSG_TYPE_CON, MSG_TYPE_CLOSE, MSG_TYPE_ACK +// this implies an underlying communication that is always correctly handled by the system +// (currently: unix sockets) + +#define MSG_TYPE_SERVER_CLOSE 0 +#define MSG_TYPE_ERR 1 +#define MSG_TYPE_DATA 2 struct ipc_message { char type; @@ -24,16 +25,17 @@ int ipc_message_format_read (struct ipc_message *m, const char *buf, size_t msiz int ipc_message_format_write (const struct ipc_message *m, char **buf, size_t *msize); // read a structure msg from fd +// 1 on a recipient socket close int ipc_message_read (int fd, struct ipc_message *m); // write a structure msg to fd int ipc_message_write (int fd, const struct ipc_message *m); -int ipc_message_format_con (struct ipc_message *m, const char *payload, size_t length); +// int ipc_message_format_con (struct ipc_message *m, const char *payload, size_t length); int ipc_message_format_data (struct ipc_message *m, const char *payload, size_t length); -int ipc_message_format_ack (struct ipc_message *m, const char *payload, size_t length); +// int ipc_message_format_ack (struct ipc_message *m, const char *payload, size_t length); int ipc_message_format_server_close (struct ipc_message *m); -int ipc_message_free (struct ipc_message *m); +int ipc_message_empty (struct ipc_message *m); void ipc_message_print (const struct ipc_message *m); #endif diff --git a/core/usocket.c b/core/usocket.c index c5deb2c..d37ea95 100644 --- a/core/usocket.c +++ b/core/usocket.c @@ -8,54 +8,119 @@ #include #include -int usock_send (const int fd, const char *buf, const int msize) +int usock_send (const int fd, const char *buf, ssize_t len, ssize_t *sent) { - // print_hexa ("msg send", (unsigned char *)buf, msize); - // fflush(stdout); - ssize_t ret = 0; - //printf ("%ld bytes to write\n", msize); - ret = send (fd, buf, msize, 0); - if (ret <= 0) + //printf ("%ld bytes to write\n", len); + ret = send (fd, buf, len, 0); + if (ret <= 0) { handle_err ("usock_send", "send ret <= 0"); - return (int) ret; + return -1; + } + *sent = ret; + return 0; } -int usock_recv (const int fd, char **buf, size_t *msize) +int usock_recv (const int fd, char **buf, ssize_t *len) { assert(buf != NULL); - assert(msize != NULL); + assert(len != NULL); + + ssize_t ret = 0; if (buf == NULL) { handle_err ("usock_recv", "buf == NULL"); return -1; } - if (msize == NULL) { - handle_err ("usock_recv", "msize == NULL"); + if (len == NULL) { + handle_err ("usock_recv", "len == NULL"); return -1; } if (*buf == NULL) { // do not allocate too much memory - if (*msize > BUFSIZ) - handle_err ("usock_recv", "msize > BUFSIZ"); - if (*msize == 0) - *msize = BUFSIZ; - *buf = malloc ((*msize < BUFSIZ) ? *msize : BUFSIZ); + if (*len > BUFSIZ) + handle_err ("usock_recv", "len > BUFSIZ"); + if (*len == 0) + *len = BUFSIZ; + *buf = malloc ((*len < BUFSIZ) ? *len : BUFSIZ); } - int ret = 0; - ret = recv (fd, *buf, *msize, 0); + ret = recv (fd, *buf, *len, 0); if (ret < 0) { + if (*buf != NULL) + free (*buf); + handle_err ("usock_recv", "recv ret < 0"); - *msize = 0; - return ret; + perror("recv"); + *len = 0; + + switch (ret) { + + // The receive buffer pointer(s) point outside the process's address space. + case EFAULT: + handle_err ("usock_recv", "critical error: use of unallocated memory, quitting..."); + exit (1); + + // Invalid argument passed. + case EINVAL: + handle_err ("usock_recv", "critical error: invalid arguments to read(2), quitting..."); + exit (1); + + // Could not allocate memory for recvmsg(). + case ENOMEM: + handle_err ("usock_recv", "critical error: cannot allocate memory, quitting..."); + exit (1); + + // The argument sockfd is an invalid descriptor. + case EBADF: + handle_err ("usock_recv", "critical error: invalid descriptor, quitting..."); + exit (1); + + // The file descriptor sockfd does not refer to a socket. + case ENOTSOCK: + handle_err ("usock_recv", "critical error: fd is not a socket, quitting..."); + exit (1); + + // The socket is associated with a connection-oriented protocol and has not + // been connected (see connect(2) and accept(2)). + case ENOTCONN: + handle_err ("usock_recv", "critical error: read(2) on a non connected socket, quitting..."); + exit (1); + + // EWOULDBLOCK + case EAGAIN: + + // A remote host refused to allow the network connection + // (typically because it is not running the requested service). + case ECONNREFUSED: + + // The receive was interrupted by delivery of a signal before + // any data were available; see signal(7). + case EINTR: + + default: + handle_err ("usock_recv", "unsupported error"); + ; + } + return -1; } - *msize = (size_t) ret; - // print_hexa ("msg recv", (unsigned char *)*buf, *msize); + + *len = ret; + + // 1 on none byte received, indicates a closed recipient + if (ret == 0) { + if (*buf != NULL) { + free (*buf); + *buf = NULL; + } + return 1; + } + + // print_hexa ("msg recv", (unsigned char *)*buf, *len); // fflush(stdout); - return ret; + return 0; } int usock_connect (int *fd, const char *path) @@ -87,12 +152,12 @@ int usock_connect (int *fd, const char *path) memset(&my_addr, 0, sizeof(struct sockaddr_un)); my_addr.sun_family = AF_UNIX; - strncpy(my_addr.sun_path, path, strlen (path)); + strncpy(my_addr.sun_path, path, (strlen (path) < PATH_MAX) ? strlen(path) : PATH_MAX); peer_addr_size = sizeof(struct sockaddr_un); if(connect(sfd, (struct sockaddr *) &my_addr, peer_addr_size) == -1) { handle_err ("usock_connect", "connect == -1"); - perror("connect()"); + perror("connect"); exit(errno); } @@ -139,13 +204,13 @@ int usock_init (int *fd, const char *path) if (bind (sfd, (struct sockaddr *) &my_addr, peer_addr_size) == -1) { handle_err ("usock_init", "bind == -1"); - perror("bind()"); + perror("bind"); return -1; } if (listen (sfd, LISTEN_BACKLOG) == -1) { handle_err ("usock_init", "listen == -1"); - perror("listen()"); + perror("listen"); return -1; } @@ -170,7 +235,7 @@ int usock_accept (int fd, int *pfd) *pfd = accept (fd, (struct sockaddr *) &peer_addr, &peer_addr_size); if (*pfd < 0) { handle_err ("usock_accept", "accept < 0"); - perror("listen()"); + perror("listen"); return -1; } @@ -179,13 +244,22 @@ int usock_accept (int fd, int *pfd) int usock_close (int fd) { - int ret; - ret = close (fd); + int ret = 0; + + ret = fsync (fd); + if (ret < 0) { + handle_err ("usock_close", "fsync ret < 0"); + perror ("closing"); + return -1; + } + + ret = close (fd); if (ret < 0) { handle_err ("usock_close", "close ret < 0"); perror ("closing"); + return -1; } - return ret; + return 0; } int usock_remove (const char *path) diff --git a/core/usocket.h b/core/usocket.h index 0ce6ec1..7e8d09f 100644 --- a/core/usocket.h +++ b/core/usocket.h @@ -7,28 +7,42 @@ #define LISTEN_BACKLOG 128 -// same as recv(2) -int usock_send (int fd, const char *buf, const int m_size); +#define TMPDIR "/run/ipc/" +#define PATH_MAX 4096 -// same as send(2) -// if msize == NULL => -1 -// if buf == NULL => -1 -// if *buf == NULL => allocation of *msize bytes -int usock_recv (int fd, char **buf, size_t *msize); +struct ipc_service { + unsigned int version; + unsigned int index; + char spath[PATH_MAX]; + int service_fd; +}; -// same as close(2) +/** + * for all functions: 0 ok, < 0 not ok + */ + +// input: len = max buf size +// output: *sent = nb received bytes +int usock_send (const int fd, const char *buf, ssize_t len, ssize_t *sent); + +// -1 on msize == NULL or buf == NULL +// -1 on unsupported errors from read(2) +// exit on most errors from read(2) +// +// allocation of *len bytes on *buf == NULL +// +// output: *len = nb sent bytes +int usock_recv (int fd, char **buf, ssize_t *len); + +// -1 on close(2) < 0 int usock_close (int fd); // same as connect(2) -// if fd == NULL => -1 +// -1 on fd == NULL int usock_connect (int *fd, const char *path); -// if not ok => -1 -// if ok => 0 int usock_init (int *fd, const char *path); -// if not ok => -1 -// if ok => 0 int usock_accept (int fd, int *pfd); // same as unlink(2) diff --git a/pong/app/pongd.c b/pong/app/pongd.c index f290207..6de090b 100644 --- a/pong/app/pongd.c +++ b/pong/app/pongd.c @@ -33,17 +33,19 @@ void handle_new_connection (struct ipc_clients *clients) void handle_new_msg (struct ipc_clients *clients, struct ipc_clients *clients_talking) { + int ret = 0; struct ipc_message m; memset (&m, 0, sizeof (struct ipc_message)); - int i; + int i = 0; for (i = 0; i < clients_talking->size; i++) { // printf ("loop handle_new_msg\n"); - if (ipc_server_read (clients_talking->clients[i], &m) < 0) { + ret = ipc_server_read (clients_talking->clients[i], &m); + if (ret < 0) { handle_error("server_read < 0"); } // close the client then delete it from the client array - if (m.type == MSG_TYPE_CLOSE) { + if (ret == 1) { cpt--; printf ("disconnection => %d client(s) remaining\n", cpt); @@ -117,11 +119,12 @@ void main_loop () /* * service ping-pong * - * 1. creates the named pipe /tmp/, then listens - * 2. opens the named pipes in & out - * 3. talks with the (test) program - * 4. closes the test program named pipes - * 5. removes the named pipe /tmp/ + * 1. creates the unix socket /run/ipc/.sock, then listens + * 2. listen for new clients + * 3. then accept a new client, and send back everything it sends + * 4. close any client that closes its socket + * + * and finally, stop the program once a client sends a SERVER CLOSE command */ int main(int argc, char * argv[], char **env)