chiark / gitweb /
WIP
authorIan Jackson <ian@liberator.(none)>
Fri, 27 Nov 2009 15:26:12 +0000 (15:26 +0000)
committerIan Jackson <ian@liberator.(none)>
Fri, 27 Nov 2009 15:26:12 +0000 (15:26 +0000)
.gitignore [new file with mode: 0644]
backends/innduct.c [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..b25c15b
--- /dev/null
@@ -0,0 +1 @@
+*~
diff --git a/backends/innduct.c b/backends/innduct.c
new file mode 100644 (file)
index 0000000..9be77ee
--- /dev/null
@@ -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();
+  } 
+}