diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2010-09-02 10:04:45 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2010-09-02 11:24:50 +0300 |
commit | fbffe40a9758e084a98710e70f4c7b703cee315a (patch) | |
tree | abb469162bc2a59963c85996e8041d60e779bf18 | |
parent | 3e7ab184e897aad84f9f40c541d6b4e3654864d4 (diff) | |
download | mailutils-fbffe40a9758e084a98710e70f4c7b703cee315a.tar.gz mailutils-fbffe40a9758e084a98710e70f4c7b703cee315a.tar.bz2 |
Implement an ioctl for replace bottom-level transport layers in a stream chain.
* include/mailutils/stream.h (MU_IOCTL_SWAP_STREAM): New ioctl op.
(mu_stream_seterr): New function.
* include/mailutils/sys/stream.h (_MU_SWAP_FIRST_ONLY)
(_MU_SWAP_IOCTL_MUST_SUCCEED): New defines.
(_mu_stream_swap_streams): New proto.
* mailbox/amd.c (amd_body_stream_read): Always update *pnread.
* mailbox/errors (MU_ERR_NO_TRANSPORT): New error code.
* mailbox/stream.c (_stream_seterror): Rename to mu_stream_seterr,
remove static qualifier. All uses updated.
(_mu_stream_swap_streams): New function.
* mailbox/filter_iconv.c (_icvt_ioctl): Implement MU_IOCTL_SWAP_STREAM.
* mailbox/iostream.c (_iostream_ctl): Likewise.
* mailbox/xscript-stream.c (_xscript_ctl): Likewise.
* pop3d/extra.c (real_istream, real_ostream): Remove statics.
(pop3d_init_tls_server): Use MU_IOCTL_SWAP_STREAM to replace
bottom-level transport layers without recreating the entire stream
chain.
-rw-r--r-- | include/mailutils/stream.h | 5 | ||||
-rw-r--r-- | include/mailutils/sys/stream.h | 7 | ||||
-rw-r--r-- | libmu_auth/tls.c | 4 | ||||
-rw-r--r-- | mailbox/amd.c | 7 | ||||
-rw-r--r-- | mailbox/errors | 2 | ||||
-rw-r--r-- | mailbox/filter_iconv.c | 3 | ||||
-rw-r--r-- | mailbox/iostream.c | 5 | ||||
-rw-r--r-- | mailbox/stream.c | 118 | ||||
-rw-r--r-- | mailbox/xscript-stream.c | 7 | ||||
-rw-r--r-- | pop3d/extra.c | 66 |
10 files changed, 162 insertions, 62 deletions
diff --git a/include/mailutils/stream.h b/include/mailutils/stream.h index 431984066..d9d3b5b41 100644 --- a/include/mailutils/stream.h +++ b/include/mailutils/stream.h @@ -32,8 +32,6 @@ enum mu_buffer_type #define MU_SEEK_CUR 1 #define MU_SEEK_END 2 -#define MU_STREAM_NO_CHECK 0 /* for backward compatibility */ - #define MU_STREAM_READ 0x00000001 #define MU_STREAM_WRITE 0x00000002 #define MU_STREAM_RDWR (MU_STREAM_READ|MU_STREAM_WRITE) @@ -63,6 +61,7 @@ enum mu_buffer_type #define MU_IOCTL_ABRIDGE_SEEK MU_IOCTL_SET_SEEK_LIMITS #define MU_IOCTL_GET_SEEK_LIMITS 5 #define MU_IOCTL_SET_TRANSPORT 6 +#define MU_IOCTL_SWAP_STREAM 7 void mu_stream_ref (mu_stream_t stream); void mu_stream_unref (mu_stream_t stream); @@ -72,6 +71,8 @@ const char *mu_stream_strerror (mu_stream_t stream, int rc); int mu_stream_err (mu_stream_t stream); int mu_stream_last_error (mu_stream_t stream); void mu_stream_clearerr (mu_stream_t stream); +int mu_stream_seterr (struct _mu_stream *stream, int code, int perm); + int mu_stream_eof (mu_stream_t stream); int mu_stream_seek (mu_stream_t stream, mu_off_t offset, int whence, mu_off_t *pres); diff --git a/include/mailutils/sys/stream.h b/include/mailutils/sys/stream.h index 90de02f05..07bee7281 100644 --- a/include/mailutils/sys/stream.h +++ b/include/mailutils/sys/stream.h @@ -65,4 +65,11 @@ int mu_stream_write_unbuffered (mu_stream_t stream, const void *buf, size_t size, int full_write, size_t *pnwritten); +#define _MU_SWAP_FIRST_ONLY 0x01 +#define _MU_SWAP_IOCTL_MUST_SUCCEED 0x02 + +int _mu_stream_swap_streams (mu_stream_t stream, mu_stream_t *curtrans, + mu_stream_t *newtrans, int flags); + + #endif diff --git a/libmu_auth/tls.c b/libmu_auth/tls.c index f80912ce2..4ad23be6e 100644 --- a/libmu_auth/tls.c +++ b/libmu_auth/tls.c @@ -679,7 +679,7 @@ _mu_tls_stream_create (mu_stream_t *pstream, free (sp); return rc; } - + rc = _mu_tls_io_stream_create (&sp->transport[1], strout, MU_STREAM_WRITE | autoclose, sp); if (rc) @@ -688,7 +688,7 @@ _mu_tls_stream_create (mu_stream_t *pstream, free (sp->transport[0]); return rc; } - + mu_stream_set_buffer ((mu_stream_t) sp, mu_buffer_line, 1024); *pstream = (mu_stream_t) sp; return 0; diff --git a/mailbox/amd.c b/mailbox/amd.c index 2b88ffce2..06b92e2f7 100644 --- a/mailbox/amd.c +++ b/mailbox/amd.c @@ -1604,8 +1604,7 @@ amd_body_stream_read (mu_stream_t is, char *buffer, size_t buflen, if (buffer == NULL || buflen == 0) { - if (pnread) - *pnread = nread; + *pnread = nread; return 0; } @@ -1626,11 +1625,11 @@ amd_body_stream_read (mu_stream_t is, char *buffer, size_t buflen, { status = mu_stream_read (mhm->stream, buffer, nread, &nread); amdstr->off += nread; - if (pnread) - *pnread = nread; } } + *pnread = nread; + mu_monitor_unlock (mhm->amd->mailbox->monitor); #ifdef WITH_PTHREAD pthread_cleanup_pop (0); diff --git a/mailbox/errors b/mailbox/errors index 49910eee7..06eb98b48 100644 --- a/mailbox/errors +++ b/mailbox/errors @@ -83,3 +83,5 @@ MU_ERR_NO_INTERFACE _("No such interface") MU_ERR_BADOP _("Inappropriate operation for this mode") MU_ERR_BAD_FILENAME _("Badly formed file or directory name") MU_ERR_READ _("Read error") + +MU_ERR_NO_TRANSPORT _("Transport stream not set") diff --git a/mailbox/filter_iconv.c b/mailbox/filter_iconv.c index 9df8c4f23..93b9cb4ba 100644 --- a/mailbox/filter_iconv.c +++ b/mailbox/filter_iconv.c @@ -400,6 +400,9 @@ _icvt_ioctl (mu_stream_t stream, int code, void *ptr) ptrans[1] = NULL; break; + case MU_IOCTL_SWAP_STREAM: + return mu_stream_ioctl (s->transport, code, ptr); + default: return EINVAL; } diff --git a/mailbox/iostream.c b/mailbox/iostream.c index 0867c7d42..4267a8102 100644 --- a/mailbox/iostream.c +++ b/mailbox/iostream.c @@ -148,6 +148,11 @@ _iostream_ctl (struct _mu_stream *str, int op, void *arg) sp->transport[_MU_STREAM_INPUT] = (mu_stream_t) ptrans[0]; sp->transport[_MU_STREAM_OUTPUT] = (mu_stream_t) ptrans[1]; break; + + case MU_IOCTL_SWAP_STREAM: + if (!arg) + return EINVAL; + return _mu_stream_swap_streams (str, sp->transport, arg, 0); default: return EINVAL; diff --git a/mailbox/stream.c b/mailbox/stream.c index bf48b266b..70186f1cf 100644 --- a/mailbox/stream.c +++ b/mailbox/stream.c @@ -32,8 +32,8 @@ #include <mailutils/stream.h> #include <mailutils/sys/stream.h> -static int -_stream_seterror (struct _mu_stream *stream, int code, int perm) +int +mu_stream_seterr (struct _mu_stream *stream, int code, int perm) { stream->last_err = code; switch (code) @@ -236,7 +236,7 @@ mu_stream_open (mu_stream_t stream) int rc; if (stream->open && (rc = stream->open (stream))) - return _stream_seterror (stream, rc, 1); + return mu_stream_seterr (stream, rc, 1); stream->bytes_in = stream->bytes_out = 0; return 0; } @@ -286,10 +286,10 @@ mu_stream_seek (mu_stream_t stream, mu_off_t offset, int whence, mu_off_t size; if (!stream->seek) - return _stream_seterror (stream, ENOSYS, 0); + return mu_stream_seterr (stream, ENOSYS, 0); if (!(stream->flags & MU_STREAM_SEEK)) - return _stream_seterror (stream, EACCES, 1); + return mu_stream_seterr (stream, EACCES, 1); switch (whence) { @@ -308,12 +308,12 @@ mu_stream_seek (mu_stream_t stream, mu_off_t offset, int whence, case MU_SEEK_END: rc = mu_stream_size (stream, &size); if (rc) - return _stream_seterror (stream, rc, 1); + return mu_stream_seterr (stream, rc, 1); offset += size; break; default: - return _stream_seterror (stream, EINVAL, 1); + return mu_stream_seterr (stream, EINVAL, 1); } if (stream->buftype == mu_buffer_none @@ -326,7 +326,7 @@ mu_stream_seek (mu_stream_t stream, mu_off_t offset, int whence, if (rc == ESPIPE) return rc; if (rc) - return _stream_seterror (stream, rc, 1); + return mu_stream_seterr (stream, rc, 1); _stream_cleareof (stream); } @@ -352,7 +352,7 @@ mu_stream_skip_input_bytes (mu_stream_t stream, mu_off_t count, mu_off_t *pres) int rc; if (!(stream->flags & MU_STREAM_READ)) - return _stream_seterror (stream, EACCES, 1); + return mu_stream_seterr (stream, EACCES, 1); if (stream->buftype == mu_buffer_none) { @@ -426,7 +426,7 @@ mu_stream_set_buffer (mu_stream_t stream, enum mu_buffer_type type, if (stream->buffer == NULL) { stream->buftype = mu_buffer_none; - return _stream_seterror (stream, ENOMEM, 1); + return mu_stream_seterr (stream, ENOMEM, 1); } stream->bufsize = size; stream->cur = stream->buffer; @@ -444,10 +444,10 @@ mu_stream_read_unbuffered (mu_stream_t stream, void *buf, size_t size, size_t nread; if (!stream->read) - return _stream_seterror (stream, ENOSYS, 0); + return mu_stream_seterr (stream, ENOSYS, 0); if (!(stream->flags & MU_STREAM_READ)) - return _stream_seterror (stream, EACCES, 1); + return mu_stream_seterr (stream, EACCES, 1); if (stream->flags & _MU_STR_ERR) return stream->last_err; @@ -479,7 +479,7 @@ mu_stream_read_unbuffered (mu_stream_t stream, void *buf, size_t size, } if (size && rc) - rc = _stream_seterror (stream, rc, 0); + rc = mu_stream_seterr (stream, rc, 0); } else { @@ -490,7 +490,7 @@ mu_stream_read_unbuffered (mu_stream_t stream, void *buf, size_t size, stream->flags |= _MU_STR_EOF; stream->bytes_in += nread; } - _stream_seterror (stream, rc, rc != 0); + mu_stream_seterr (stream, rc, rc != 0); } stream->offset += nread; if (pnread) @@ -509,10 +509,10 @@ mu_stream_write_unbuffered (mu_stream_t stream, size_t nwritten; if (!stream->write) - return _stream_seterror (stream, ENOSYS, 0); + return mu_stream_seterr (stream, ENOSYS, 0); if (!(stream->flags & MU_STREAM_WRITE)) - return _stream_seterror (stream, EACCES, 1); + return mu_stream_seterr (stream, EACCES, 1); if (stream->flags & _MU_STR_ERR) return stream->last_err; @@ -555,7 +555,7 @@ mu_stream_write_unbuffered (mu_stream_t stream, stream->offset += nwritten; if (pnwritten) *pnwritten = nwritten; - _stream_seterror (stream, rc, rc != 0); + mu_stream_seterr (stream, rc, rc != 0); return rc; } @@ -861,9 +861,9 @@ mu_stream_size (mu_stream_t stream, mu_off_t *psize) int rc; if (!stream->size) - return _stream_seterror (stream, ENOSYS, 0); + return mu_stream_seterr (stream, ENOSYS, 0); rc = stream->size (stream, psize); - return _stream_seterror (stream, rc, rc != 0); + return mu_stream_seterr (stream, rc, rc != 0); } mu_off_t @@ -948,8 +948,88 @@ mu_stream_clr_flags (mu_stream_t stream, int fl) return 0; } +static void +swapstr (mu_stream_t stream, mu_stream_t *curstr, mu_stream_t *newstr) +{ + mu_stream_t tmp; + + tmp = *newstr; + *newstr = *curstr; + *curstr = tmp; + if (!(stream->flags & MU_STREAM_AUTOCLOSE)) + { + if (*newstr) + mu_stream_unref (*newstr); + if (tmp) + mu_stream_ref (tmp); + } + if (!tmp) + mu_stream_seterr (stream, MU_ERR_NO_TRANSPORT, 1); + else if (stream->last_err == MU_ERR_NO_TRANSPORT) + mu_stream_clearerr (stream); +} +static int +swapstr_recursive (mu_stream_t stream, mu_stream_t *curstr, + mu_stream_t *newstr, int flags) +{ + mu_stream_t strtab[2]; + int rc = ENOSYS; + if (*curstr == NULL && *newstr == NULL) + return 0; + + if (*curstr) + { + strtab[0] = *newstr; + strtab[1] = NULL; + rc = mu_stream_ioctl (*curstr, MU_IOCTL_SWAP_STREAM, strtab); + if (rc) + { + if ((flags & _MU_SWAP_IOCTL_MUST_SUCCEED) + || !(rc == ENOSYS || rc == EINVAL)) + return rc; + } + } + if (rc == 0) + *newstr = strtab[0]; + else + swapstr (stream, curstr, newstr); + return 0; +} + +/* CURTRANS[2] contains I/O transport streams used by STREAM, + NEWTRANS[2] contains another pair of streams. + This function swaps the items of these two arrays using the + MU_IOCTL_SWAP_STREAM ioctl. It is intended for use by STREAM's + ioctl method and is currently used by iostream.c */ + +int +_mu_stream_swap_streams (mu_stream_t stream, mu_stream_t *curtrans, + mu_stream_t *newtrans, int flags) +{ + int rc; + + rc = swapstr_recursive (stream, &curtrans[0], &newtrans[0], flags); + if (rc) + return rc; + if (flags & _MU_SWAP_FIRST_ONLY) + return 0; + rc = swapstr_recursive (stream, &curtrans[1], &newtrans[1], flags); + if (rc) + { + int rc1 = swapstr_recursive (stream, &curtrans[0], &newtrans[0], flags); + if (rc1) + { + mu_diag_output (MU_DIAG_CRIT, + _("restoring streams on %p failed: %s"), + stream, mu_strerror (rc1)); + abort (); + } + } + return rc; +} + diff --git a/mailbox/xscript-stream.c b/mailbox/xscript-stream.c index 8cadff2b1..34ad52378 100644 --- a/mailbox/xscript-stream.c +++ b/mailbox/xscript-stream.c @@ -176,7 +176,8 @@ _xscript_ctl (struct _mu_stream *str, int op, void *arg) { struct _mu_xscript_stream *sp = (struct _mu_xscript_stream *)str; mu_transport_t *ptrans; - + mu_stream_t strtab[2]; + switch (op) { case MU_IOCTL_GET_TRANSPORT: @@ -196,7 +197,9 @@ _xscript_ctl (struct _mu_stream *str, int op, void *arg) if (ptrans[1]) sp->logstr = (mu_stream_t) ptrans[1]; break; - + + case MU_IOCTL_SWAP_STREAM: + /* fall through */ default: return mu_stream_ioctl (sp->transport, op, arg); } diff --git a/pop3d/extra.c b/pop3d/extra.c index 183667a8c..c34e05ca4 100644 --- a/pop3d/extra.c +++ b/pop3d/extra.c @@ -126,14 +126,6 @@ pop3d_abquit (int reason) exit (code); } -/* Keeps the *real* output stream. Ostream is a RFC822 filter built over - real_ostream, or even over a TLS stream, which in turn is based on this - real_ostream. - FIXME: This is sorta kludge: we could use MU_IOCTL_GET_TRANSPORT call - to retrieve the bottom-level stream, if filter streams supported it. -*/ -static mu_stream_t real_istream, real_ostream; - void pop3d_setio (FILE *in, FILE *out) { @@ -147,20 +139,24 @@ pop3d_setio (FILE *in, FILE *out) if (mu_stdio_stream_create (&istream, fileno (in), MU_STREAM_READ | MU_STREAM_AUTOCLOSE)) pop3d_abquit (ERR_NO_IFILE); - real_istream = istream; mu_stream_set_buffer (istream, mu_buffer_line, 1024); - if (mu_stdio_stream_create (&str, fileno (out), + if (mu_stdio_stream_create (&ostream, fileno (out), MU_STREAM_WRITE | MU_STREAM_AUTOCLOSE)) pop3d_abquit (ERR_NO_OFILE); - real_ostream = str; - if (mu_filter_create (&ostream, str, "rfc822", MU_FILTER_ENCODE, - MU_STREAM_WRITE)) - pop3d_abquit (ERR_NO_IFILE); - mu_stream_set_buffer (ostream, mu_buffer_line, 1024); - if (mu_iostream_create (&iostream, istream, ostream)) + /* Combine the two streams into an I/O one. */ + if (mu_iostream_create (&str, istream, ostream)) pop3d_abquit (ERR_FILE); + + /* Convert all writes to CRLF form. + There is no need to convert reads, as the code ignores extra \r anyway. + This also installs an extra full buffering, which is needed for TLS + code (see below). */ + if (mu_filter_create (&iostream, str, "rfc822", MU_FILTER_ENCODE, + MU_STREAM_WRITE | MU_STREAM_RDTHRU)) + pop3d_abquit (ERR_NO_IFILE); + if (pop3d_transcript) { int rc; @@ -192,36 +188,40 @@ pop3d_setio (FILE *in, FILE *out) int pop3d_init_tls_server () { - mu_stream_t stream; + mu_stream_t tlsstream, stream[2]; int rc; - rc = mu_tls_server_stream_create (&stream, real_istream, real_ostream, 0); + stream[0] = stream[1] = NULL; + rc = mu_stream_ioctl (iostream, MU_IOCTL_SWAP_STREAM, stream); + if (rc) + { + mu_error (_("%s failed: %s"), "MU_IOCTL_SWAP_STREAM", + mu_stream_strerror (iostream, rc)); + return 1; + } + + rc = mu_tls_server_stream_create (&tlsstream, stream[0], stream[1], 0); if (rc) return 1; - rc = mu_stream_open (stream); + rc = mu_stream_open (tlsstream); if (rc) { mu_diag_output (MU_DIAG_ERROR, _("cannot open TLS stream: %s"), - mu_stream_strerror (stream, rc)); - mu_stream_destroy (&stream); + mu_stream_strerror (tlsstream, rc)); + mu_stream_destroy (&tlsstream); return 1; } + else + stream[0] = stream[1] = tlsstream; - if (mu_filter_create (&stream, stream, "rfc822", MU_FILTER_ENCODE, - MU_STREAM_WRITE | MU_STREAM_RDTHRU)) - pop3d_abquit (ERR_NO_IFILE); - - if (pop3d_transcript) + rc = mu_stream_ioctl (iostream, MU_IOCTL_SWAP_STREAM, stream); + if (rc) { - mu_transport_t trans[2]; - - trans[0] = (mu_transport_t) stream; - trans[1] = NULL; - mu_stream_ioctl (iostream, MU_IOCTL_SET_TRANSPORT, trans); + mu_error (_("%s failed: %s"), "MU_IOCTL_SWAP_STREAM", + mu_stream_strerror (iostream, rc)); + pop3d_abquit (ERR_IO); } - else - iostream = stream; return 0; } #endif |