callbacks
parent
ff9d6ed2b8
commit
98a1389376
|
@ -177,14 +177,13 @@ struct ipc_error ipc_read (const struct ipc_ctx *ctx, uint32_t index, struct ipc
|
||||||
{
|
{
|
||||||
T_R ((m == NULL), IPC_ERROR_READ__NO_MESSAGE_PARAM);
|
T_R ((m == NULL), IPC_ERROR_READ__NO_MESSAGE_PARAM);
|
||||||
|
|
||||||
char *buf = NULL;
|
|
||||||
size_t msize = IPC_MAX_MESSAGE_SIZE;
|
size_t msize = IPC_MAX_MESSAGE_SIZE;
|
||||||
|
SECURE_BUFFER_DECLARATION (char, buf, msize);
|
||||||
|
char *pbuf = buf;
|
||||||
|
|
||||||
// On error or closed recipient, the buffer already freed.
|
// On error or closed recipient, the buffer already freed.
|
||||||
TEST_IPC_RETURN_ON_ERROR (usock_recv (ctx->pollfd[index].fd, &buf, &msize));
|
TEST_IPC_RETURN_ON_ERROR (usock_recv (ctx->pollfd[index].fd, &pbuf, &msize));
|
||||||
TEST_IPC_RETURN_ON_ERROR_FREE (ipc_message_format_read (m, buf, msize), buf);
|
TEST_IPC_RETURN_ON_ERROR (ipc_message_format_read (m, buf, msize));
|
||||||
|
|
||||||
free (buf);
|
|
||||||
|
|
||||||
IPC_RETURN_NO_ERROR; // propagates ipc_message_format return
|
IPC_RETURN_NO_ERROR; // propagates ipc_message_format return
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,6 +85,14 @@ enum ipc_event_type {
|
||||||
, IPC_EVENT_TYPE_TX = 9 // Message sent.
|
, IPC_EVENT_TYPE_TX = 9 // Message sent.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// For IO callbacks (switching).
|
||||||
|
enum ipccb {
|
||||||
|
IPC_CB_NO_ERROR = 0
|
||||||
|
, IPC_CB_FD_CLOSING = 1
|
||||||
|
, IPC_CB_FD_ERROR = 2
|
||||||
|
, IPC_CB_PARSING_ERROR = 3
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Error codes.
|
* Error codes.
|
||||||
* libipc tend to use unique error codes in the whole library, allowing easier debugging.
|
* libipc tend to use unique error codes in the whole library, allowing easier debugging.
|
||||||
|
|
157
src/network.c
157
src/network.c
|
@ -138,6 +138,28 @@ int ipc_switching_del (struct ipc_switchings *is, int fd)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 0 = fd is origin
|
||||||
|
* 1 = fd is dest
|
||||||
|
* -1 = not found
|
||||||
|
*/
|
||||||
|
int ipc_switching_get_ (const struct ipc_switchings *is
|
||||||
|
, int fd
|
||||||
|
, struct ipc_switching *s)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < is->size; i++) {
|
||||||
|
if (is->collection[i].orig == fd) {
|
||||||
|
*s = is->collection[i];
|
||||||
|
return 0;
|
||||||
|
} else if (is->collection[i].dest == fd) {
|
||||||
|
*s = is->collection[i];
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
int ipc_switching_get (struct ipc_switchings *is, int fd)
|
int ipc_switching_get (struct ipc_switchings *is, int fd)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < is->size; i++) {
|
for (size_t i = 0; i < is->size; i++) {
|
||||||
|
@ -163,74 +185,117 @@ void ipc_switching_free (struct ipc_switchings *is)
|
||||||
is->size = 0;
|
is->size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
enum ipccb
|
||||||
* switching_messages allows to send messages from a fd to another.
|
default_cb_in(int fd, struct ipc_message *m)
|
||||||
*/
|
|
||||||
struct ipc_error fd_switching (struct ipc_event *event, struct ipc_ctx *ctx, int index)
|
|
||||||
{
|
{
|
||||||
// If the socket is associated to another one for ipcd:
|
// TODO: fix buffer size for switching messages
|
||||||
// read and write automatically and provide a new IPC_EVENT_TYPE indicating the switch.
|
size_t msize = 4096;
|
||||||
T_R ((ctx->switchdb.size == 0), IPC_ERROR_FD_SWITCHING__NO_FD_RECORD);
|
char buf[msize];
|
||||||
|
char *pbuf = buf;
|
||||||
|
|
||||||
int talkingfd = ctx->pollfd[index].fd;
|
// By default, usock_read (a wrapper around read(2)) is used.
|
||||||
int correspondingfd = ipc_switching_get (&ctx->switchdb, talkingfd);
|
|
||||||
|
|
||||||
T_R ((correspondingfd == -1), IPC_ERROR_FD_SWITCHING__NO_FD_RECORD);
|
|
||||||
|
|
||||||
char *buf = NULL;
|
|
||||||
size_t msize = 0;
|
|
||||||
|
|
||||||
{ /** Some macros use "ret" as a variable name, so this is to be sure. */
|
{ /** Some macros use "ret" as a variable name, so this is to be sure. */
|
||||||
struct ipc_error ret = usock_recv (talkingfd, &buf, &msize);
|
struct ipc_error ret = usock_recv (fd, &pbuf, &msize);
|
||||||
if (ret.error_code != IPC_ERROR_NONE && ret.error_code != IPC_ERROR_CLOSED_RECIPIENT) {
|
if (ret.error_code != IPC_ERROR_NONE) {
|
||||||
if (buf != NULL)
|
if (ret.error_code == IPC_ERROR_CLOSED_RECIPIENT) {
|
||||||
free (buf);
|
return IPC_CB_FD_CLOSING;
|
||||||
IPC_EVENT_SET (event, IPC_EVENT_TYPE_ERROR, index, talkingfd, NULL)
|
}
|
||||||
return ret;
|
return IPC_CB_FD_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** There is a message, send it to the corresponding fd **/
|
/** There is a message, send it to the corresponding fd **/
|
||||||
if (msize > 0) {
|
if (msize > 0) {
|
||||||
size_t nbytes_sent = 0;
|
struct ipc_error ret = ipc_message_format_read (m, buf, msize);
|
||||||
TEST_IPC_RETURN_ON_ERROR_FREE (usock_send (correspondingfd, buf, msize, &nbytes_sent), buf);
|
if (ret.error_code != IPC_ERROR_NONE) {
|
||||||
|
return IPC_CB_PARSING_ERROR;
|
||||||
if (nbytes_sent != msize) {
|
}
|
||||||
// LOG_ERROR ("wrote not enough data from %d to fd %d", talkingfd, correspondingfd);
|
return IPC_CB_NO_ERROR;
|
||||||
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);
|
|
||||||
|
|
||||||
if (buf != NULL)
|
// By default, if msize <= 0 the fd should be closed.
|
||||||
free (buf);
|
return IPC_CB_FD_CLOSING;
|
||||||
|
}
|
||||||
|
|
||||||
// Everything is OK: inform ipcd of a successful transfer.
|
enum ipccb
|
||||||
|
default_cb_out(int fd, struct ipc_message *m)
|
||||||
|
{
|
||||||
|
printf("TODO: default_cb_out\n");
|
||||||
|
return IPC_CB_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* switching_messages allows to send messages from a fd to another.
|
||||||
|
*/
|
||||||
|
struct ipc_error fd_switching (struct ipc_event *event, struct ipc_ctx *ctx, int index)
|
||||||
|
{
|
||||||
|
printf ("fd_switching\n");
|
||||||
|
|
||||||
|
// If the socket is associated to another one for ipcd:
|
||||||
|
// read and write automatically and provide a new IPC_EVENT_TYPE indicating the switch.
|
||||||
|
T_R ((ctx->switchdb.size == 0), IPC_ERROR_FD_SWITCHING__NO_FD_RECORD);
|
||||||
|
|
||||||
|
int talkingfd = ctx->pollfd[index].fd;
|
||||||
|
struct ipc_switching sw;
|
||||||
|
struct ipc_message m;
|
||||||
|
|
||||||
|
enum ipccb r;
|
||||||
|
int is_valid = 0;
|
||||||
|
|
||||||
|
is_valid = ipc_switching_get_ (&ctx->switchdb, talkingfd, &sw);
|
||||||
|
|
||||||
|
T_R ((is_valid == -1), IPC_ERROR_FD_SWITCHING__NO_FD_RECORD);
|
||||||
|
|
||||||
|
if (sw.orig == talkingfd) {
|
||||||
|
if (sw.orig_in == NULL) {
|
||||||
|
r = default_cb_in (talkingfd, &m);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
r = (*sw.orig_in)(talkingfd, &m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (sw.dest_in == NULL) {
|
||||||
|
r = default_cb_in (talkingfd, &m);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
r = (*sw.dest_in)(talkingfd, &m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Message reception OK: reading the message and put it in the list of messages to send.
|
||||||
|
if (r == IPC_CB_NO_ERROR) {
|
||||||
|
// In case of message reception:
|
||||||
|
// 1. put the message in the list to be sent
|
||||||
|
ipc_write (ctx, &m);
|
||||||
|
// 2. set event IPC_EVENT_TYPE_SWITCH, inform ipcd of a successful reception.
|
||||||
IPC_EVENT_SET (event, IPC_EVENT_TYPE_SWITCH, index, ctx->pollfd[index].fd, NULL);
|
IPC_EVENT_SET (event, IPC_EVENT_TYPE_SWITCH, index, ctx->pollfd[index].fd, NULL);
|
||||||
|
// 3. IPC_RETURN_NO_ERROR
|
||||||
IPC_RETURN_NO_ERROR;
|
IPC_RETURN_NO_ERROR;
|
||||||
} else if (msize == 0) {
|
}
|
||||||
int delfd;
|
|
||||||
|
|
||||||
delfd = ipc_switching_del (&ctx->switchdb, talkingfd);
|
/**
|
||||||
|
* NOTE: In any other case, the fd is, or should be closed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 1. close and remove both fd from switchdb
|
||||||
|
int delfd = ipc_switching_del (&ctx->switchdb, talkingfd);
|
||||||
if (delfd >= 0) {
|
if (delfd >= 0) {
|
||||||
close (delfd);
|
close (delfd);
|
||||||
ipc_del_fd (ctx, delfd);
|
ipc_del_fd (ctx, delfd);
|
||||||
}
|
}
|
||||||
|
|
||||||
close (talkingfd);
|
close (talkingfd);
|
||||||
ipc_del_fd (ctx, talkingfd);
|
ipc_del_fd (ctx, talkingfd);
|
||||||
|
|
||||||
#if 0
|
// 2. set event (either error or disconnection)
|
||||||
if (delfd >= 0) {
|
if (r == IPC_CB_FD_CLOSING) {
|
||||||
LOG_DEBUG ("disconnection of %d (and related fd %d)", talkingfd, delfd);
|
|
||||||
} else {
|
|
||||||
LOG_DEBUG ("disconnection of %d", talkingfd);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
IPC_EVENT_SET (event, IPC_EVENT_TYPE_DISCONNECTION, index, talkingfd, NULL);
|
IPC_EVENT_SET (event, IPC_EVENT_TYPE_DISCONNECTION, index, talkingfd, NULL);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
IPC_EVENT_SET (event, IPC_EVENT_TYPE_ERROR, index, talkingfd, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. return IPC_ERROR_CLOSED_RECIPIENT
|
||||||
IPC_RETURN_ERROR (IPC_ERROR_CLOSED_RECIPIENT);
|
IPC_RETURN_ERROR (IPC_ERROR_CLOSED_RECIPIENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPC_RETURN_NO_ERROR;
|
|
||||||
}
|
|
||||||
|
|
Reference in New Issue