diff --git a/libipm/libipm.c b/libipm/libipm.c index aadb3687..953d9893 100644 --- a/libipm/libipm.c +++ b/libipm/libipm.c @@ -32,6 +32,35 @@ const char *libipm_valid_type_chars = "ybnqiuxtsdhogB"; +/**************************************************************************//** + * Send function for a struct trans initialised with libipm_init_trans() + * + * @param trans Transport to send on + * @param data pointer to data to send + * @param len Length of data to send + * @return As for write(2) + */ +static int +libipm_trans_send_proc(struct trans *self, const char *data, int len) +{ + int rv; + struct libipm_priv *priv = (struct libipm_priv *)self->extra_data; + if (priv != NULL && data == self->out_s->data) + { + /* We're sending the message header. Send any file descriptors + * as ancillary data */ + rv = g_sck_send_fd_set(self->sck, data, len, + priv->out_fds, priv->out_fd_count); + } + else + { + rv = g_sck_send(self->sck, data, len, 0); + } + + return rv; +} + + /**************************************************************************//** * Destructor for a struct trans initialised with libipm_init_trans() * @@ -83,6 +112,7 @@ libipm_init_trans(struct trans *trans, priv->facility = facility; priv->msgno_to_str = msgno_to_str; + trans->trans_send = libipm_trans_send_proc; trans->extra_data = priv; trans->extra_destructor = libipm_trans_destructor; diff --git a/libipm/libipm.h b/libipm/libipm.h index f74d967d..8c3fbdd7 100644 --- a/libipm/libipm.h +++ b/libipm/libipm.h @@ -67,6 +67,7 @@ enum libipm_status E_LI_UNIMPLEMENTED_TYPE, /***< Specified type code is unimplemented */ E_LI_UNEXPECTED_TYPE, /***< Encountered unexpected type on input */ E_LI_BUFFER_OVERFLOW, /***< End of buffer reached unexpectedly */ + E_LI_TOO_MANY_FDS, /***< Too many file descriptors encountered */ E_LI_BAD_VALUE, /***< Specified (or incoming) value is out of range */ E_LI_BAD_HEADER, /***< Bad incoming message header */ E_LI_TRANSPORT_ERROR /***< Error detected at the transport level */ @@ -154,14 +155,17 @@ libipm_msg_out_init(struct trans *trans, unsigned short msgno, * x |int64_t | Signed (two's complement) 64-bit integer * t |uint64_t | Unsigned 64-bit integer * s |char * | NULL-terminated string + * h |int | File descriptor * d | - | (reserved) - * h | - | (reserved) * o | - | (reserved) * g | - | (reserved) * * For the 'b' type, only values 0 and 1 are allowed. Other values * generate an error. * + * The 'h' type can only be used where the underlying transport is a + * UNIX domain socket. + * * The following additions to the D-Bus type system are also supported:- * * Char |C Type | Description diff --git a/libipm/libipm_private.h b/libipm/libipm_private.h index 7cc5a77b..bb8c8ef3 100644 --- a/libipm/libipm_private.h +++ b/libipm/libipm_private.h @@ -39,7 +39,12 @@ enum /** * Size of libipm header */ - HEADER_SIZE = 12 + HEADER_SIZE = 12, + + /** + * Max number of file descriptors in a message + */ + MAX_FD_PER_MSG = 8 }; /** @@ -52,6 +57,8 @@ struct libipm_priv const char *(*msgno_to_str)(unsigned short msgno); unsigned short out_msgno; unsigned short out_param_count; + unsigned short out_fd_count; + int out_fds[MAX_FD_PER_MSG]; unsigned short in_msgno; unsigned short in_param_count; }; diff --git a/libipm/libipm_send.c b/libipm/libipm_send.c index 5a2aa1a9..ad04b0ca 100644 --- a/libipm/libipm_send.c +++ b/libipm/libipm_send.c @@ -306,6 +306,47 @@ append_char_ptr_type(char c, struct trans *trans, va_list *argptr) return rv; } +/**************************************************************************//** + * Add a file descriptor to the output stream + * + * @param c Type letter which triggered the call + * @param trans libipm transport + * @param argptr Pointer to value in argument stack (promoted to int) + * @return != 0 for error + */ +static enum libipm_status +append_fd_type(char c, va_list *argptr, struct trans *trans) +{ + enum libipm_status rv = E_LI_SUCCESS; + struct stream *s = trans->out_s; + struct libipm_priv *priv = (struct libipm_priv *)trans->extra_data; + int fd = va_arg(*argptr, int); + if (fd < 0) + { + log_append_error(trans, "File descriptor cannot be < 0"); + rv = E_LI_PROGRAM_ERROR; + } + else if (!s_check_rem_out(s, 1)) + { + log_append_error(trans, + "Not enough space in output buffer for '%c'", c); + rv = E_LI_BUFFER_OVERFLOW; + } + else if (priv->out_fd_count >= MAX_FD_PER_MSG) + { + log_append_error(trans, + "Too many file descriptors for '%c'", c); + rv = E_LI_TOO_MANY_FDS; + } + else + { + out_uint8(s, c); + priv->out_fds[priv->out_fd_count++] = fd; + } + + return rv; +} + /**************************************************************************//** * Append a fixed size block to the output stream * @@ -405,6 +446,10 @@ libipm_msg_out_appendv(struct trans *trans, const char *format, va_list *argptr) rv = append_char_ptr_type(c, trans, argptr); break; + case 'h': + rv = append_fd_type(c, argptr, trans); + break; + case 'B': rv = append_fsb_type(c, trans, argptr); break; @@ -441,6 +486,7 @@ init_output_buffer(struct trans *trans, unsigned short msgno) priv->out_msgno = msgno; priv->out_param_count = 0; + priv->out_fd_count = 0; } /*****************************************************************************/