From fefd301279302de8c3c08ab49979206329178253 Mon Sep 17 00:00:00 2001
From: Philippe PITTOLI
Date: Mon, 8 Oct 2018 15:18:56 +0200
Subject: [PATCH] pending rewrite
---
core/communication.c | 29 +++++++--
core/communication.h | 24 ++------
core/error.h | 3 +
core/msg.c | 47 +++++++++++----
core/msg.h | 20 ++++---
core/usocket.c | 138 +++++++++++++++++++++++++++++++++----------
core/usocket.h | 40 +++++++++----
pong/app/pongd.c | 19 +++---
8 files changed, 221 insertions(+), 99 deletions(-)
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)