libipc-old/src/ipc.h

594 lines
21 KiB
C

#ifndef __IPC_H__
#define __IPC_H__
#include <stdint.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h> // error numbers
#include <time.h>
#include <poll.h>
/***
* global defaults
**/
#define RUNDIR "/run/ipc/"
#define PATH_MAX 4096
#define IPC_HEADER_SIZE 6
// #define __IPC_BASE_SIZE 500000 // 500 KB
#define __IPC_BASE_SIZE 2000000 // 2 MB, plenty enough space for messages
#define IPC_MAX_MESSAGE_SIZE __IPC_BASE_SIZE-IPC_HEADER_SIZE
#define IPC_VERSION 4
#if ! defined(IPC_WITHOUT_ERRORS) && ! defined(IPC_WITH_ERRORS)
#define IPC_WITH_ERRORS 2
#endif
#define IPC_WITH_UNIX_SOCKETS
#ifdef IPC_WITH_UNIX_SOCKETS
#include "usocket.h"
#endif
/***
* structures and enumerations
**/
enum msg_types {
MSG_TYPE_SERVER_CLOSE = 0
, MSG_TYPE_ERR = 1
, MSG_TYPE_DATA = 2
, MSG_TYPE_NETWORK_LOOKUP = 3
};
/**
* Event types.
* In the main event loop, servers and clients can receive connections,
* disconnections, errors or messages from their pairs. They also can
* set a timer so the loop will allow a periodic routine (sending ping
* messages for websockets, for instance).
*
**
*
* A few other events can occur.
*
* Extra socket
* The main loop waiting for an event can be used as an unique entry
* point for socket management. libipc users can register sockets via
* ipc_add_fd allowing them to trigger an event, so events unrelated
* to libipc are managed the same way.
* Switch
* libipc can be used to create protocol-related programs, such as a
* websocket proxy allowing libipc services to be accessible online.
* To help those programs (with TCP-complient sockets), two sockets
* can be bound together, each message coming from one end will be
* automatically transfered to the other socket and a Switch event
* will be triggered.
* Look Up
* When a client establishes a connection to a service, it asks the
* ipc daemon (ipcd) to locate the service and establish a connection
* to it. This is a lookup.
*/
enum ipc_event_type {
IPC_EVENT_TYPE_NOT_SET = 0
, IPC_EVENT_TYPE_ERROR = 1
, IPC_EVENT_TYPE_EXTRA_SOCKET = 2 // Message received from a non IPC socket.
, IPC_EVENT_TYPE_SWITCH = 3 // Message to send to a corresponding fd.
, IPC_EVENT_TYPE_CONNECTION = 4 // New user.
, IPC_EVENT_TYPE_DISCONNECTION = 5 // User disconnected.
, IPC_EVENT_TYPE_MESSAGE = 6 // New message.
, IPC_EVENT_TYPE_LOOKUP = 7 // Client asking for a service through ipcd.
, IPC_EVENT_TYPE_TIMER = 8 // Timeout in the poll(2) function.
, IPC_EVENT_TYPE_TX = 9 // Message sent.
};
// For IO callbacks (switching).
enum ipccb {
IPC_CB_NO_ERROR = 0 // No error. A message was generated.
, IPC_CB_FD_CLOSING = 1 // The fd is closing.
, IPC_CB_FD_ERROR = 2 // Generic error.
, IPC_CB_PARSING_ERROR = 3 // The message was read but with errors.
, IPC_CB_IGNORE = 4 // The message should be ignored (protocol specific).
};
/**
* Error codes.
* libipc tend to use unique error codes in the whole library, allowing easier debugging.
*/
enum ipc_error_code {
IPC_ERROR_NONE = 0
, IPC_ERROR_HANDLE_MESSAGE__NOT_ENOUGH_MEMORY = 3
, IPC_ERROR_CLOSED_RECIPIENT = 4
, IPC_ERROR_SERVICE_PATH__NO_PATH = 5
, IPC_ERROR_SERVICE_PATH__NO_SERVICE_NAME = 6
, IPC_ERROR_SERVER_INIT__NO_ENVIRONMENT_PARAM = 7
, IPC_ERROR_SERVER_INIT__NO_SERVICE_PARAM = 8
, IPC_ERROR_SERVER_INIT__NO_SERVER_NAME_PARAM = 9
, IPC_ERROR_SERVER_INIT__MALLOC = 10
, IPC_ERROR_WRITE__NO_MESSAGE_PARAM = 11
, IPC_ERROR_WRITE_FD__NOT_ENOUGH_DATA = 12
, IPC_ERROR_READ__NO_MESSAGE_PARAM = 13
, IPC_ERROR_CONNECTION__NO_SERVICE_NAME = 15
, IPC_ERROR_CONNECTION__NO_ENVIRONMENT_PARAM = 16
, IPC_ERROR_ACCEPT__NO_SERVICE_PARAM = 18
, IPC_ERROR_ACCEPT__NO_CLIENT_PARAM = 19
, IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFO_PARAM = 20
, IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFOS_PARAM = 21
, IPC_ERROR_WAIT_EVENT__SELECT = 22
, IPC_ERROR_WAIT_EVENT__NO_CLIENTS_PARAM = 23
, IPC_ERROR_WAIT_EVENT__NO_EVENT_PARAM = 24
, IPC_ERROR_HANDLE_NEW_CONNECTION__MALLOC = 25
, IPC_ERROR_ADD__EMPTY_LIST = 26
, IPC_ERROR_ADD__NO_PARAM_CLIENTS = 27
, IPC_ERROR_ADD__NO_PARAM_CLIENT = 28
, IPC_ERROR_ADD__MALLOC = 29
, IPC_ERROR_ADD_FD__NO_PARAM_CINFOS = 30
, IPC_ERROR_ADD_FD__NOT_ENOUGH_MEMORY = 31
, IPC_ERROR_DEL_FD__NO_PARAM_CINFOS = 32
, IPC_ERROR_DEL_FD__EMPTIED_LIST = 33
, IPC_ERROR_DEL_FD__EMPTY_LIST = 34
, IPC_ERROR_DEL_FD__CANNOT_FIND_CLIENT = 35
, IPC_ERROR_CONTACT_IPCD__NO_SERVICE_NAME_PARAM = 36
, IPC_ERROR_CONTACT_IPCD__NO_SERVER_PARAM = 37
, IPC_ERROR_DEL__EMPTY_LIST = 38
, IPC_ERROR_DEL__EMPTIED_LIST = 39
, IPC_ERROR_DEL__CANNOT_FIND_CLIENT = 40
, IPC_ERROR_DEL__NO_CLIENTS_PARAM = 41
, IPC_ERROR_DEL__NO_CLIENT_PARAM = 42
, IPC_ERROR_USOCK_SEND = 43
, IPC_ERROR_USOCK_CONNECT__SOCKET = 44
, IPC_ERROR_USOCK_CONNECT__WRONG_FILE_DESCRIPTOR = 45
, IPC_ERROR_USOCK_CONNECT__EMPTY_PATH = 46
, IPC_ERROR_USOCK_CONNECT__CONNECT = 47
, IPC_ERROR_USOCK_CLOSE = 48
, IPC_ERROR_USOCK_REMOVE__UNLINK = 49
, IPC_ERROR_USOCK_REMOVE__NO_FILE = 50
, IPC_ERROR_USOCK_INIT__EMPTY_FILE_DESCRIPTOR = 51
, IPC_ERROR_USOCK_INIT__WRONG_FILE_DESCRIPTOR = 52
, IPC_ERROR_USOCK_INIT__EMPTY_PATH = 53
, IPC_ERROR_USOCK_INIT__BIND = 54
, IPC_ERROR_USOCK_INIT__LISTEN = 55
, IPC_ERROR_USOCK_ACCEPT__PATH_FILE_DESCRIPTOR = 56
, IPC_ERROR_USOCK_ACCEPT = 57
, IPC_ERROR_USOCK_RECV__NO_BUFFER = 58
, IPC_ERROR_USOCK_RECV__NO_LENGTH = 59
, IPC_ERROR_USOCK_RECV = 60
, IPC_ERROR_USOCK_RECV__UNRECOGNIZED_ERROR = 61
, IPC_ERROR_USOCK_RECV__HEAP_ALLOCATION = 62
, IPC_ERROR_USOCK_RECV__MESSAGE_SIZE = 63
, IPC_ERROR_RECEIVE_FD__NO_PARAM_FD = 64
, IPC_ERROR_RECEIVE_FD__RECVMSG = 65
, IPC_ERROR_PROVIDE_FD__SENDMSG = 66
, IPC_ERROR_MESSAGE_FORMAT_WRITE__MESSAGE_LENGTH = 67
, IPC_ERROR_MESSAGE_FORMAT__MESSAGE_SIZE = 68
, IPC_ERROR_MESSAGE_FORMAT__NO_MESSAGE_PARAM = 69
, IPC_ERROR_MESSAGE_FORMAT__INCONSISTENT_PARAMS = 70
, IPC_ERROR_MESSAGE_FORMAT__HEAP_ALLOCATION = 71
, IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MESSAGE = 72
, IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MSIZE = 73
, IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_BUFFER = 74
, IPC_ERROR_MESSAGE_FORMAT_READ__EMPTY_MESSAGE = 75
, IPC_ERROR_MESSAGE_FORMAT_READ__EMPTY_BUFFER = 76
, IPC_ERROR_MESSAGE_FORMAT_READ__PARAM_MESSAGE_SIZE = 77
, IPC_ERROR_MESSAGE_FORMAT_READ__READ_MESSAGE_SIZE = 78
, IPC_ERROR_MESSAGE_FORMAT_READ__MESSAGE_TOO_LONG = 79
, IPC_ERROR_MESSAGE_EMPTY__EMPTY_MESSAGE_LIST = 80
, IPC_ERROR_MKDIR__CANNOT_CREATE_DIR = 81
, IPC_ERROR_MKDIR__NAME_TOO_LONG = 82
, IPC_ERROR_DIR_SETUP__NOT_A_DIRECTORY = 83
, IPC_ERROR_DIR_SETUP__DIRECTORY_NOT_WRITABLE = 84
, IPC_ERROR_DIRECTORY_SETUP__PATH_PARAM = 85
, IPC_ERROR_SERVER_INIT__NOT_ENOUGH_MEMORY = 86
, IPC_ERROR_CONNECTION__NOT_ENOUGH_MEMORY = 87
, IPC_ERROR_CTX_INIT__NO_CONTEXT_PARAM = 88
, IPC_ERROR_CTX_INIT__CONTEXT_ALREADY_INIT = 89
, IPC_ERROR_ADD__MALLOC_POLLFD = 90
, IPC_ERROR_ADD_MESSAGE_TO_SEND__EMPTY_LIST = 91
, IPC_ERROR_ADD_MESSAGE_TO_SEND__MALLOC = 92
, IPC_ERROR_ADD_MESSAGE_TO_SEND__NO_PARAM_MESSAGE = 93
, IPC_ERROR_ADD_MESSAGE_TO_SEND__NO_PARAM_MESSAGES = 94
, IPC_ERROR_CONNECTION__NO_CTX = 95
, IPC_ERROR_CTX_INIT__MALLOC_CTX = 96
, IPC_ERROR_CTX_INIT__MALLOC_POLLFD = 97
, IPC_ERROR_CONTACT_IPCD__NO_FD_PARAM = 98
, IPC_ERROR_HANDLE_NEW_CONNECTION__INCONSISTENT_INDEX = 99
, IPC_ERROR_DEL_MESSAGE_TO_SEND__NO_PARAM_MESSAGES = 100
, IPC_ERROR_MESSAGE_DEL__INDEX_ERROR = 101
, IPC_ERROR_MESSAGE_DEL__EMPTY_LIST = 102
, IPC_ERROR_ADD__NO_PARAM_POLLFD = 103
, IPC_ERROR_WRITE__FD_NOT_FOUND = 104
, IPC_ERROR_ADD__NOT_ENOUGH_MEMORY = 105
, IPC_ERROR_WAIT_EVENT__POLL = 106
, IPC_ERROR_FD_SWITCHING__NO_FD_RECORD = 107
, IPC_ERROR_CLOSE_ALL__NO_CTX_PARAM = 108
, IPC_ERROR_CLOSE__NO_CTX_PARAM = 109
};
struct ipc_error {
enum ipc_error_code error_code;
char error_message[BUFSIZ];
};
// get explanation about an error
// This only returns the generic error based on its code.
// Library's users have a more meaningful insight on the error
// with the error_message string in the ipc_error structure.
const char *ipc_errors_get (enum ipc_error_code e);
enum ipc_connection_type {
IPC_CONNECTION_TYPE_IPC = 0
, IPC_CONNECTION_TYPE_EXTERNAL = 1
/** Messages received = new connections. */
, IPC_CONNECTION_TYPE_SERVER = 2
/** IO operations should go through registered callbacks. */
, IPC_CONNECTION_TYPE_SWITCHED = 3
};
struct ipc_connection_info {
enum ipc_connection_type type;
short int more_to_read;
char *spath; // max size: PATH_MAX
};
struct ipc_message {
char type; // Internal message type.
char user_type; // User-defined message type.
int fd; // File descriptor concerned about this message.
uint32_t length; // Payload length.
char *payload;
};
struct ipc_messages {
struct ipc_message *messages;
size_t size;
};
struct ipc_switching {
int orig;
int dest;
enum ipccb (*orig_in) (int origin_fd, struct ipc_message *m, short int *more_to_read);
enum ipccb (*orig_out) (int origin_fd, struct ipc_message *m);
enum ipccb (*dest_in) (int origin_fd, struct ipc_message *m, short int *more_to_read);
enum ipccb (*dest_out) (int origin_fd, struct ipc_message *m);
};
struct ipc_switchings {
struct ipc_switching *collection;
size_t size;
};
void ipc_message_copy (struct ipc_message *m
, uint32_t fd
, uint8_t type
, uint8_t utype
, char *payload
, uint32_t paylen);
struct ipc_error ipc_messages_del (struct ipc_messages *messages, uint32_t index);
/**
* Context of the whole networking state.
*/
struct ipc_ctx {
/**
* Keep track of connections.
*/
struct ipc_connection_info *cinfos;
/**
* List of "pollfd" structures within cinfos, so we can pass it to poll(2).
*/
struct pollfd *pollfd;
/**
* Size of the connection list.
*/
size_t size;
/**
* List of messages to send, once the fd are available.
*/
struct ipc_messages tx;
/**
* Relations between fd.
*/
struct ipc_switchings switchdb;
};
struct ipc_event {
enum ipc_event_type type;
uint32_t index;
int origin;
void *m; // message pointer
};
/***
* ipc event macros
**/
#define IPC_EVENT_SET(pevent,type_,index_, origin_fd_,message_) {\
pevent->type = type_; \
pevent->index = index_; \
pevent->origin = origin_fd_; \
pevent->m = message_; \
};
#define IPC_EVENT_CLEAN(pevent) {\
pevent->type = IPC_EVENT_TYPE_NOT_SET;\
pevent->origin = 0;\
pevent->index = 0;\
if (pevent->m != NULL) {\
ipc_message_empty (pevent->m);\
free(pevent->m);\
pevent->m = NULL;\
}\
};
/**
* main public functions
**/
struct ipc_error ipc_wait_event (struct ipc_ctx *, struct ipc_event *, int *timer);
struct ipc_error ipc_server_init (struct ipc_ctx *ctx, const char *sname);
struct ipc_error ipc_connection (struct ipc_ctx *ctx, const char *sname, int *fd);
struct ipc_error ipc_connection_switched (struct ipc_ctx *ctx, const char *sname, int clientfd, int *serverfd);
struct ipc_error ipc_close (struct ipc_ctx *ctx, uint32_t index);
struct ipc_error ipc_close_all (struct ipc_ctx *ctx);
void ipc_ctx_free (struct ipc_ctx *ctx);
struct ipc_error ipc_read (const struct ipc_ctx *, uint32_t index, struct ipc_message *m);
struct ipc_error ipc_read_fd (int32_t fd, struct ipc_message *m);
struct ipc_error ipc_write (struct ipc_ctx *, const struct ipc_message *m);
struct ipc_error fd_switching_read (struct ipc_event *event, struct ipc_ctx *ctx, int index);
struct ipc_error fd_switching_write (struct ipc_event *event, struct ipc_ctx *ctx, int index);
// store and remove only pointers on allocated structures
struct ipc_error ipc_add (struct ipc_ctx *, struct ipc_connection_info *, struct pollfd *);
struct ipc_error ipc_del (struct ipc_ctx *, uint32_t index);
// add an arbitrary file descriptor to read
struct ipc_error ipc_add_fd (struct ipc_ctx *ctx, int fd);
// add a switched file descriptor to read
struct ipc_error ipc_add_fd_switched (struct ipc_ctx *ctx, int fd);
struct ipc_error ipc_del_fd (struct ipc_ctx *ctx, int fd);
/***
* message functions
**/
uint32_t ipc_message_raw_serialize (char *buffer, char type, char user_type, char *message, uint32_t message_size);
// used to create msg structure from buffer
struct ipc_error ipc_message_format_read (struct ipc_message *m, const char *buf, size_t msize);
// used to create buffer from msg structure
struct ipc_error ipc_message_format_write (const struct ipc_message *m, char **buf, size_t * msize);
struct ipc_error ipc_message_format (struct ipc_message *m, char type, char utype, const char *payload, size_t length);
struct ipc_error ipc_message_format_data (struct ipc_message *m, char utype, const char *payload, size_t length);
struct ipc_error ipc_message_format_server_close (struct ipc_message *m);
struct ipc_error ipc_message_empty (struct ipc_message *m);
struct ipc_error ipc_messages_add (struct ipc_messages *, const struct ipc_message *);
void ipc_messages_free (struct ipc_messages *);
// Switch cases macros
// print on error
#define ERROR_CASE(e,f,m) case e : { fprintf (stderr, "function %s: %s\n", f, m); } break;
/***
* non public functions
**/
struct ipc_error ipc_write_fd (int fd, const struct ipc_message *m);
struct ipc_error ipc_ctx_init (struct ipc_ctx **);
struct ipc_error ipc_ctx_new_alloc (struct ipc_ctx *ctx);
struct ipc_error service_path (char *path, const char *sname);
struct ipc_error handle_writing_message (struct ipc_event *event, struct ipc_ctx *ctx, uint32_t index);
void ipc_ctx_print (struct ipc_ctx *ctx);
// Last parameter is the index for the server fd in the context structure.
struct ipc_error ipc_accept_add (struct ipc_event *event, struct ipc_ctx *ctx, uint32_t index);
struct ipc_error ipc_contact_ipcd (int *pfd, const char *sname);
struct ipc_error service_path (char *path, const char *sname);
/***
* ipcd enumerations, structures and functions
**/
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);
int ipc_switching_del (struct ipc_switchings *is, int fd);
int ipc_switching_get (struct ipc_switchings *is, int fd);
void ipc_switching_free (struct ipc_switchings *is);
void ipc_switching_callbacks_ (struct ipc_ctx *ctx, int fd
, enum ipccb (*cb_in )(int fd, struct ipc_message *m, short int *more_to_read));
void ipc_switching_callbacks (
struct ipc_ctx *ctx
, int fd
, enum ipccb (*cb_in )(int fd, struct ipc_message *m, short int *more_to_read)
, enum ipccb (*cb_out)(int fd, struct ipc_message *m));
int ipc_ctx_fd_type (struct ipc_ctx *ctx, int fd, enum ipc_connection_type type);
void ipc_switching_print (struct ipc_switchings *is);
struct ipc_error ipc_receive_fd (int sock, int *fd);
struct ipc_error ipc_provide_fd (int sock, int fd);
/***
* grooming macros
**/
#define SECURE_DECLARATION(t,v) t v; memset(&v,0,sizeof(t));
#define SECURE_BUFFER_DECLARATION(type,name,size) type name[size]; memset(&name, 0, sizeof(type) * size);
#define SECURE_BUFFER_HEAP_ALLOCATION(p,len,instr,r)\
{ p = malloc (len); if (p == NULL) { instr; r; } ; memset(p, 0, len); }
#define SECURE_BUFFER_HEAP_ALLOCATION_R(p,len,instr,r) SECURE_BUFFER_HEAP_ALLOCATION(p,len,instr, IPC_RETURN_ERROR(r); )
#define SECURE_BUFFER_HEAP_ALLOCATION_R_NULL(p,len,instr) SECURE_BUFFER_HEAP_ALLOCATION(p,len,instr, return NULL; )
#define SECURE_BUFFER_HEAP_ALLOCATION_Q(p,len,instr,r) SECURE_BUFFER_HEAP_ALLOCATION(p,len,instr, exit(r))
// Test macros, requiring the variable `enum ipc_error_code ret`
// one macro to rule them all!
// 1. function to test
// 2. Test IPC error based (test itself)
// 3. Instructions to exec on failure
// 4. Return something
#define TEST_IPC_T_P_I_R(function_to_test, test, instr, r) \
{\
struct ipc_error ret = function_to_test;\
if (test) {\
instr;\
r;\
}\
}
// R = return r param
// RR = return "ret" variable
// RV = return void
// Q = quit
// I = additionnal instructions before returning on error
#define TEST_IPC_T_I_P_Q(f,t,instr,err,r) TEST_IPC_T_P_I_R(f, t, instr, exit(r))
#define TEST_IPC_T_I_RR(f,t,instr) TEST_IPC_T_P_I_R(f, t, instr, return ret)
#define TEST_IPC_I_RR(f,instr) TEST_IPC_T_P_I_R(f, ret.error_code != IPC_ERROR_NONE, instr, return ret)
// Tests macros, do not require `enum ipc_error_code ret` variable
// test => return error code
#define T_R(t,r) if t { IPC_RETURN_ERROR(r); }
#define T_R_NULL(t) if t { return NULL; }
#define T_R_NOTHING(t) if t { return ; }
// test => perror then return (for system functions)
#define T_PERROR_R(t,m,r) if t { perror(m); return (r); }
// test => perror then exit (for system functions)
#define T_PERROR_Q(t,m,r) if t { perror(m); exit(r); }
#define T_PERROR_RIPC(t,m,r) if t { perror(m); IPC_RETURN_ERROR(r); }
#define TEST_IPC_QUIT_ON_ERROR(function_to_test,ec) {\
struct ipc_error ret = function_to_test;\
if (ret.error_code != IPC_ERROR_NONE) {\
fprintf(stderr, "%s\n", ret.error_message);\
exit(ec);\
}\
}
#define TEST_IPC_RETURN_ON_ERROR_FREE(function_to_test, buffer_to_free) {\
struct ipc_error ret = function_to_test; \
if (ret.error_code != IPC_ERROR_NONE) {\
if (buffer_to_free != NULL) {\
free(buffer_to_free); \
}\
return ret;\
}\
}
#define TEST_IPC_RETURN_ON_ERROR(function_to_test) {\
struct ipc_error ret = function_to_test;\
if (ret.error_code != IPC_ERROR_NONE) {\
return ret;\
}\
}
#define TEST_IPC_RETURN_ON_ERROR_FREE(function_to_test, buffer_to_free) {\
struct ipc_error ret = function_to_test; \
if (ret.error_code != IPC_ERROR_NONE) {\
if (buffer_to_free != NULL) {\
free(buffer_to_free); \
}\
return ret;\
}\
}
// formatted version of TEST_IPC_RR
#define TEST_IPC_RR_F(function_to_test, format, ...) {\
struct ipc_error ret = function_to_test;\
if (ret.error_code != IPC_ERROR_NONE) { \
error_message_format (ret.error_message + strlen(ret.error_message) \
, "blocking error" \
, ":" __FILE__ ":" format \
, ##__VA_ARGS__ ); \
return ret;\
}\
}
// TODO: ret already contains error message, append the error_message
// TODO: currently, error message is not what it should be
#define TEST_IPC_RR(function_to_test, err_message) \
TEST_IPC_RR_F(function_to_test, "%s", err_message)
// same as TEST_IPC_RR but do not return
// Also: print the error right away.
#define TEST_IPC_P(function_to_test, err_message) {\
struct ipc_error ret = function_to_test;\
if (ret.error_code != IPC_ERROR_NONE) {\
error_message_format (ret.error_message + strlen(ret.error_message) \
, "non blocking error" \
, ":" __FILE__ "%s:%s" \
, err_message );\
\
fprintf (stderr, "%s\n", ret.error_message);\
}\
}
#define IPC_RETURN_NO_ERROR { \
SECURE_DECLARATION (struct ipc_error, ret); \
ret.error_code = IPC_ERROR_NONE; \
return ret; \
}
#define IPC_FILL_DEFAULT_ERROR_MESSAGE(error_message_ptr,error_code) { \
const char *estr = ipc_errors_get (error_code); \
snprintf(error_message_ptr, BUFSIZ, "%s", estr); \
}
#define IPC_RETURN_ERROR(ec_) \
SECURE_DECLARATION(struct ipc_error, ret);\
IPC_FILL_DEFAULT_ERROR_MESSAGE(ret.error_message, ec_);\
ret.error_code = ec_;\
return ret;
#define IPC_RETURN_ERROR_FORMAT(v,format,...) { \
SECURE_DECLARATION (struct ipc_error, ret); \
ret.error_code = v; \
error_message_format (ret.error_message \
, "blocking error" \
, format \
, ##__VA_ARGS__ ); \
return ret; \
}
#define TEST_IPC_Q(f,e) {\
struct ipc_error ret = f; \
if (ret.error_code != IPC_ERROR_NONE) { \
fprintf(stderr, "%s", ret.error_message); \
exit(e); \
} \
}
#define TEST_IPC_WAIT_EVENT_RR(f, r) { \
struct ipc_error ret = f; \
if (ret.error_code != IPC_ERROR_NONE && \
ret.error_code != IPC_ERROR_CLOSED_RECIPIENT) { \
return ret; \
} \
}
#define TEST_IPC_WAIT_EVENT_Q(f, r) { \
struct ipc_error ret = f; \
if (ret.error_code != IPC_ERROR_NONE && \
ret.error_code != IPC_ERROR_CLOSED_RECIPIENT) { \
exit(r); \
} \
}
#endif