From: Stephan Bosch Date: Sat, 30 Apr 2016 10:50:53 +0000 (+0200) Subject: lib: Added ostream-unix for writing fd sockets via ostream. X-Git-Tag: 2.2.31.rc1~158 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=1472a6db72a5aeb7616316d243147bc1b32a34cf;p=thirdparty%2Fdovecot%2Fcore.git lib: Added ostream-unix for writing fd sockets via ostream. --- diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index b6cde6c588..88436bf924 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -116,6 +116,7 @@ liblib_la_SOURCES = \ ostream-hash.c \ ostream-null.c \ ostream-rawlog.c \ + ostream-unix.c \ pkcs5.c \ primes.c \ printf-format-fix.c \ @@ -255,6 +256,7 @@ headers = \ ostream-private.h \ ostream-null.h \ ostream-rawlog.h \ + ostream-unix.h \ pkcs5.h \ primes.h \ printf-format-fix.h \ diff --git a/src/lib/ostream-unix.c b/src/lib/ostream-unix.c new file mode 100644 index 0000000000..9280c90ee9 --- /dev/null +++ b/src/lib/ostream-unix.c @@ -0,0 +1,90 @@ +/* Copyright (c) 2015-2016 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "fdpass.h" +#include "ostream-file-private.h" +#include "ostream-unix.h" + +struct unix_ostream { + struct file_ostream fstream; + int write_fd; +}; + +static void +o_stream_unix_close(struct iostream_private *stream, bool close_parent) +{ + struct unix_ostream *ustream = (struct unix_ostream *)stream; + + if (ustream->write_fd != -1) + i_close_fd(&ustream->write_fd); + o_stream_file_close(stream, close_parent); +} + +static ssize_t o_stream_unix_writev(struct file_ostream *fstream, + const struct const_iovec *iov, + unsigned int iov_count) +{ + struct unix_ostream *ustream = (struct unix_ostream *)fstream; + size_t sent; + ssize_t ret; + + if (ustream->write_fd == -1) { + /* no fd */ + return o_stream_file_writev(fstream, iov, iov_count); + } + + /* send first iovec along with fd */ + if (iov_count == 0) + return 0; + i_assert(iov[0].iov_len > 0); + ret = fd_send(fstream->fd, ustream->write_fd, + iov[0].iov_base, iov[0].iov_len); + if (ret < 0) + return ret; + + /* update stream */ + sent = ret; + fstream->real_offset += sent; + + ustream->write_fd = -1; + + if (sent < iov[0].iov_len || iov_count == 1) { + /* caller will call us again to write the rest */ + return sent; + } + + /* send remaining iovecs */ + ret = o_stream_file_writev(fstream, &iov[1], iov_count-1); + if (ret < 0) + return (errno == EAGAIN || errno == EINTR ? (ssize_t)sent : ret); + sent += ret; + return sent; +} + +struct ostream *o_stream_create_unix(int fd, size_t max_buffer_size) +{ + struct unix_ostream *ustream; + struct ostream *output; + + i_assert(fd != -1); + + ustream = i_new(struct unix_ostream, 1); + ustream->write_fd = -1; + output = o_stream_create_file_common(&ustream->fstream, fd, + max_buffer_size, FALSE); + output->real_stream->iostream.close = o_stream_unix_close; + ustream->fstream.writev = o_stream_unix_writev; + + return output; +} + +bool o_stream_unix_write_fd(struct ostream *output, int fd) +{ + struct unix_ostream *ustream = + (struct unix_ostream *)output->real_stream; + + if (ustream->write_fd >= 0) + return FALSE; + ustream->write_fd = fd; + return TRUE; +} diff --git a/src/lib/ostream-unix.h b/src/lib/ostream-unix.h new file mode 100644 index 0000000000..849669b9c2 --- /dev/null +++ b/src/lib/ostream-unix.h @@ -0,0 +1,10 @@ +#ifndef OSTREAM_UNIX_H +#define OSTREAM_UNIX_H + +struct ostream *o_stream_create_unix(int fd, size_t max_buffer_size); +/* Write fd to UNIX socket along with the next outgoing data block. + Returns TRUE if fd is accepted, and FALSE if a previous fd still + needs to be sent. */ +bool o_stream_unix_write_fd(struct ostream *output, int fd); + +#endif