libipm: Add support for receiving file descriptors
This commit is contained in:
parent
8a71322fe4
commit
c9adb3a2a6
@ -32,6 +32,23 @@
|
||||
|
||||
const char *libipm_valid_type_chars = "ybnqiuxtsdhogB";
|
||||
|
||||
/*****************************************************************************/
|
||||
void
|
||||
libipm_msg_in_close_file_descriptors(struct trans *self)
|
||||
{
|
||||
struct libipm_priv *priv = (struct libipm_priv *)self->extra_data;
|
||||
if (priv != NULL)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = priv->in_fd_index ; i < priv->in_fd_count; ++i)
|
||||
{
|
||||
g_file_close(priv->in_fds[i]);
|
||||
}
|
||||
priv->in_fd_count = 0;
|
||||
priv->in_fd_index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************//**
|
||||
* Send function for a struct trans initialised with libipm_init_trans()
|
||||
*
|
||||
@ -60,6 +77,52 @@ libipm_trans_send_proc(struct trans *self, const char *data, int len)
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**************************************************************************//**
|
||||
* Receive function for a struct trans initialised with libipm_init_trans()
|
||||
*
|
||||
* @param trans Transport to receive on
|
||||
* @param data pointer to receive data buffer
|
||||
* @param len Length of data to read
|
||||
* @return As for read(2)
|
||||
*/
|
||||
static int
|
||||
libipm_trans_recv_proc(struct trans *self, char *data, int len)
|
||||
{
|
||||
int rv;
|
||||
struct libipm_priv *priv = (struct libipm_priv *)self->extra_data;
|
||||
if (priv != NULL && data == self->in_s->data)
|
||||
{
|
||||
/* We're receiving the message header */
|
||||
unsigned int fdcount;
|
||||
|
||||
/* Check there are no live file descriptors in the input
|
||||
* buffer from a previous message. This shouldn't happen, but
|
||||
* if by some chance it does, we could leak file descriptors */
|
||||
if (priv->in_fd_count > 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_WARNING, "Unconsumed file descriptors detected");
|
||||
libipm_msg_in_close_file_descriptors(self);
|
||||
}
|
||||
rv = g_sck_recv_fd_set(self->sck, data, len,
|
||||
priv->in_fds, MAX_FD_PER_MSG,
|
||||
&fdcount);
|
||||
if (fdcount > MAX_FD_PER_MSG)
|
||||
{
|
||||
LOG(LOG_LEVEL_WARNING,
|
||||
"%d file descriptors were discarded on recvmsg()",
|
||||
fdcount - MAX_FD_PER_MSG);
|
||||
fdcount = MAX_FD_PER_MSG;
|
||||
}
|
||||
priv->in_fd_count = fdcount;
|
||||
}
|
||||
else
|
||||
{
|
||||
rv = g_sck_recv(self->sck, data, len, 0);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************//**
|
||||
* Destructor for a struct trans initialised with libipm_init_trans()
|
||||
@ -71,6 +134,7 @@ libipm_trans_destructor(struct trans *trans)
|
||||
{
|
||||
struct libipm_priv *priv = (struct libipm_priv *)trans->extra_data;
|
||||
|
||||
libipm_msg_in_close_file_descriptors(trans);
|
||||
if (priv != NULL)
|
||||
{
|
||||
if ((priv->flags & LIBIPM_E_MSG_IN_ERASE_AFTER_USE) != 0 &&
|
||||
@ -113,6 +177,7 @@ libipm_init_trans(struct trans *trans,
|
||||
priv->msgno_to_str = msgno_to_str;
|
||||
|
||||
trans->trans_send = libipm_trans_send_proc;
|
||||
trans->trans_recv = libipm_trans_recv_proc;
|
||||
trans->extra_data = priv;
|
||||
trans->extra_destructor = libipm_trans_destructor;
|
||||
|
||||
|
@ -300,8 +300,8 @@ libipm_msg_in_peek_type(struct trans *trans);
|
||||
* 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)
|
||||
*
|
||||
@ -315,6 +315,9 @@ libipm_msg_in_peek_type(struct trans *trans);
|
||||
* returned. This pointer will only be valid until the next call to
|
||||
* libipm_msg_in_reset()
|
||||
*
|
||||
* The 'h' type can only be used where the underlying transport is a
|
||||
* UNIX domain socket.
|
||||
*
|
||||
* For the 'B' type, pass in the address of an initialised descriptor
|
||||
* containing the address and size of the object to copy the data
|
||||
* to. The size in the descriptor must match the size of the object
|
||||
@ -330,6 +333,9 @@ libipm_msg_in_parse(struct trans *trans, const char *format, ...);
|
||||
* If the LIBIPM_E_MSG_IN_ERASE_AFTER_USE flag is set for the transport,
|
||||
* the entire buffer is erased, and the flag is cleared
|
||||
*
|
||||
* Any file descriptors received from the other end but not parsed
|
||||
* by the application are closed.
|
||||
*
|
||||
* @param trans libipm transport
|
||||
*/
|
||||
void
|
||||
|
@ -61,6 +61,11 @@ struct libipm_priv
|
||||
int out_fds[MAX_FD_PER_MSG];
|
||||
unsigned short in_msgno;
|
||||
unsigned short in_param_count;
|
||||
/** Pointer to next fd to be consumed by the app */
|
||||
unsigned short in_fd_index;
|
||||
/** Number of fds in the incoming message */
|
||||
unsigned short in_fd_count;
|
||||
int in_fds[MAX_FD_PER_MSG];
|
||||
};
|
||||
|
||||
/**
|
||||
@ -71,4 +76,15 @@ struct libipm_priv
|
||||
*/
|
||||
extern const char *libipm_valid_type_chars;
|
||||
|
||||
/**
|
||||
* Close input file descriptors for an input message
|
||||
*
|
||||
* If file descriptors are read from the other end, but not passed to the
|
||||
* application, they must be closed to prevent file descriptor leaks
|
||||
*
|
||||
* @param trans Transport to close file descriptors for
|
||||
*/
|
||||
void
|
||||
libipm_msg_in_close_file_descriptors(struct trans *self);
|
||||
|
||||
#endif /* LIBIPM__PRIVATE_H */
|
||||
|
@ -460,6 +460,36 @@ extract_char_ptr_type(char c, struct trans *trans, va_list *argptr)
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************//**
|
||||
* Extract a file descriptor from the input stream
|
||||
*
|
||||
* @param c Type letter which triggered the call
|
||||
* @param trans libipm transport
|
||||
* @param argptr argptr to pointer to receive the value
|
||||
* @return != 0 for error
|
||||
*/
|
||||
static enum libipm_status
|
||||
extract_fd_type(char c, struct trans *trans, va_list *argptr)
|
||||
{
|
||||
enum libipm_status rv = E_LI_SUCCESS;
|
||||
struct libipm_priv *priv = (struct libipm_priv *)trans->extra_data;
|
||||
|
||||
/* File descriptor available? */
|
||||
if (priv->in_fd_index >= priv->in_fd_count)
|
||||
{
|
||||
log_parse_error(trans, "No file descriptors available");
|
||||
rv = E_LI_TOO_MANY_FDS;
|
||||
}
|
||||
else
|
||||
{
|
||||
int *tmp = va_arg(*argptr, int *);
|
||||
|
||||
*tmp = priv->in_fds[priv->in_fd_index++];
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**************************************************************************//**
|
||||
* Extract a fixed size block from the input stream
|
||||
*
|
||||
@ -588,6 +618,10 @@ libipm_msg_in_parsev(struct trans *trans, const char *format, va_list *argptr)
|
||||
rv = extract_char_ptr_type(c, trans, argptr);
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
rv = extract_fd_type(c, trans, argptr);
|
||||
break;
|
||||
|
||||
case 'B':
|
||||
rv = extract_fsb_type(c, trans, argptr);
|
||||
break;
|
||||
@ -650,6 +684,7 @@ libipm_msg_in_reset(struct trans *trans)
|
||||
}
|
||||
priv->in_msgno = 0;
|
||||
priv->in_param_count = 0;
|
||||
libipm_msg_in_close_file_descriptors(trans);
|
||||
}
|
||||
|
||||
trans->extra_flags = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user