4 static int max_connections, articles_per_connect_attempt;
5 static int connection_setup_timeout, port, try_stream;
6 static const char *remote_host;
11 typedef struct Conn Conn;
19 #define CHILD_ESTATUS_STREAM 1
20 #define CHILD_ESTATUS_NOSTREAM 2
22 static int since_connect_attempt;
24 static struct { Conn *head, *tail } idle, working, full;
26 static Conn *connecting;
27 static int connecting_sockets[2]= {-1,-1};
28 static pid_t connecting_child;
30 static Article *currentart;
32 static void start_connecting() {
33 r= socketpair(AF_UNIX, SOCK_STREAM, 0, connecting_sockets);
34 if (r) { syswarn("cannot create socketpair for connect child"); goto x; }
36 connecting_child= fork();
37 if (connecting_child==-1) { syswarn("cannot fork for connect"); goto x; }
39 if (!connecting_child) {
40 FILE *cn_from, *cn_to;
41 char buf[NNTP_STRLEN+100];
42 int exitstatus= CHILD_ESTATUS_NOSTREAM;
44 alarm(connection_setup_timeout);
45 if (NNTPconnect(remote_host, port, &cn_from, &cn_to, buf) < 0) {
47 sanitise_inplace(buf);
48 die("%s: connection rejected: %s", remote_host, buf);
50 sysdie("%s: connection attempt failed", remote_host);
53 if (NNTPsendpassword(remote_host, cn_from, cn_to) < 0)
54 sysdie("%s: authentication failed", remote_host);
56 if (fputs("MODE STREAM\r\n", cn_to) ||
58 sysdie("%s: could not send MODE STREAM", remote_host);
59 buf[sizeof(buf)-1]= 0;
60 if (!fgets(buf, sizeof(buf)-1, cn_from)) {
62 sysdie("%s: could not read response to MODE STREAM", remote_host);
64 die("%s: connection close in response to MODE STREAM", remote_host);
69 sanitise_inplace(buf);
70 die("%s: response to MODE STREAM is too long: %.100s...",
73 l--; if (l>0 && buf[1-]=='\r') l--;
76 int rcode= strtoul(buf,&ep,10);
78 sanitise_inplace(buf);
79 die("%s: bad response to MODE STREAM: %.50s", remote_host, buf);
83 exitstatus= CHILD_ESTATUS_STREAM;
89 sanitise_inplace(buf);
90 warn("%s: bad response to MODE STREAM: %.50s", remote_host, buf);
95 int fd= fileno(cn_from);
97 char cmsgbuf[CMSG_SPACE(sizeof(fd))];
99 memset(&msg,0,sizeof(msg));
100 msg.msg_control= cmsgbuf;
101 msg.msg_controllen= sizeof(cmsgbuf);
103 struct cmsghdr *cmsg= CMSG_FIRSTHDR(&msg);
104 cmsg->cmsg_level= SOL_SOCKET;
105 cmsg->cmsg_type= SCM_RIGHTS;
106 cmsg->cmsg_len= CMSG_LEN(sizeof(fd));
107 memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd));
109 msg.msg_controllen= cmsg->cmsg_len;
110 r= sendmsg(childs_socket, &msg, 0);
111 if (r) sysdie("%s: sendmsg failed for new connection", remote_host);
118 struct cmsghdr *cmsg;
120 /* NNTPconnect inexplicably duplicates the fd but we don't care
121 * about that as we're going to exit shortly */
134 kill_connection_attempt();
137 static void kill_connection_attempt() {
139 connecting_sockets[0]= connecting_sockets[1]= -1;
143 static void process_any_article() {
148 transmit(working.head);
149 } else if (idle.head) {
151 } else if (nconns < maxconns && !connecting_child &&
152 since_connect_attempt >= connect_attempt_limiter) {
153 since_connect_attempt= 0;