From 30fa5460d4490f2f8edbaeab242f9f97c4576900 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Fri, 27 Nov 2009 15:26:12 +0000 Subject: [PATCH 1/1] WIP --- .gitignore | 1 + backends/innduct.c | 156 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 157 insertions(+) create mode 100644 .gitignore create mode 100644 backends/innduct.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b25c15b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*~ diff --git a/backends/innduct.c b/backends/innduct.c new file mode 100644 index 0000000..9be77ee --- /dev/null +++ b/backends/innduct.c @@ -0,0 +1,156 @@ +/* + */ + +static int max_connections, articles_per_connect_attempt; +static int connection_setup_timeout, port, try_stream; +static const char *remote_host; + +struct Article { +}; + +typedef struct Conn Conn; +struct Conn { + Conn *next, *back; + int fd; + Article *queue; +}; + + +#define CHILD_ESTATUS_STREAM 1 +#define CHILD_ESTATUS_NOSTREAM 2 + +static int since_connect_attempt; +static int nconns; +static struct { Conn *head, *tail } idle, working, full; + +static Conn *connecting; +static int connecting_sockets[2]= {-1,-1}; +static pid_t connecting_child; + +static Article *currentart; + +static void start_connecting() { + r= socketpair(AF_UNIX, SOCK_STREAM, 0, connecting_sockets); + if (r) { syswarn("cannot create socketpair for connect child"); goto x; } + + connecting_child= fork(); + if (connecting_child==-1) { syswarn("cannot fork for connect"); goto x; } + + if (!connecting_child) { + FILE *cn_from, *cn_to; + char buf[NNTP_STRLEN+100]; + int exitstatus= CHILD_ESTATUS_NOSTREAM; + + alarm(connection_setup_timeout); + if (NNTPconnect(remote_host, port, &cn_from, &cn_to, buf) < 0) { + if (buf[0]) { + sanitise_inplace(buf); + die("%s: connection rejected: %s", remote_host, buf); + } else { + sysdie("%s: connection attempt failed", remote_host); + } + } + if (NNTPsendpassword(remote_host, cn_from, cn_to) < 0) + sysdie("%s: authentication failed", remote_host); + if (try_stream) { + if (fputs("MODE STREAM\r\n", cn_to) || + fflush(cn_to)) + sysdie("%s: could not send MODE STREAM", remote_host); + buf[sizeof(buf)-1]= 0; + if (!fgets(buf, sizeof(buf)-1, cn_from)) { + if (ferror(cn_from)) + sysdie("%s: could not read response to MODE STREAM", remote_host); + else + die("%s: connection close in response to MODE STREAM", remote_host); + } + int l= strlen(buf); + assert(l>=1); + if (buf[-1]!='\n') { + sanitise_inplace(buf); + die("%s: response to MODE STREAM is too long: %.100s...", + remote_host, buf); + } + l--; if (l>0 && buf[1-]=='\r') l--; + buf[l]= 0; + char *ep; + int rcode= strtoul(buf,&ep,10); + if (ep != buf[3]) { + sanitise_inplace(buf); + die("%s: bad response to MODE STREAM: %.50s", remote_host, buf); + } + switch (rcode) { + case 203: + exitstatus= CHILD_ESTATUS_STREAM; + break; + case 480: + case 500: + break; + default: + sanitise_inplace(buf); + warn("%s: bad response to MODE STREAM: %.50s", remote_host, buf); + exitstatus= 2; + break; + } + } + int fd= fileno(cn_from); + + char cmsgbuf[CMSG_SPACE(sizeof(fd))]; + struct msghdr msg; + memset(&msg,0,sizeof(msg)); + msg.msg_control= cmsgbuf; + msg.msg_controllen= sizeof(cmsgbuf); + + struct cmsghdr *cmsg= CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level= SOL_SOCKET; + cmsg->cmsg_type= SCM_RIGHTS; + cmsg->cmsg_len= CMSG_LEN(sizeof(fd)); + memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd)); + + msg.msg_controllen= cmsg->cmsg_len; + r= sendmsg(childs_socket, &msg, 0); + if (r) sysdie("%s: sendmsg failed for new connection", remote_host); + + _exit(exitstatus); + } + + on_fd(loop, + + struct cmsghdr *cmsg; + + /* NNTPconnect inexplicably duplicates the fd but we don't care + * about that as we're going to exit shortly */ + + + + + warn(" + + syswarn(" + int e= errno; + sanitise(buf); + syswarn(" + + x: + kill_connection_attempt(); +} + +static void kill_connection_attempt() { + fixme; + connecting_sockets[0]= connecting_sockets[1]= -1; + connecting_child= 0; +} + +static void process_any_article() { + if (!currentart) + return; + + if (working.head) { + transmit(working.head); + } else if (idle.head) { + transmit(idle.head); + } else if (nconns < maxconns && !connecting_child && + since_connect_attempt >= connect_attempt_limiter) { + since_connect_attempt= 0; + connect_start(); + } +} -- 2.30.2