chiark / gitweb /
Cope with NNTP_MSGID_MAXLEN abolishment (replaced with NNTP_MAXLEN_MSGID)
[innduct.git] / innduct.h
1 /*
2  *  innduct
3  *  tailing reliable realtime streaming feeder for inn
4  *
5  *  Copyright (C) 2010 Ian Jackson <ijackson@chiark.greenend.org.uk>
6  * 
7  *  This program is free software: you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation, either version 3 of the License, or
10  *  (at your option) any later version.
11  * 
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  * 
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  *
20  *  (I believe that when you compile and link this as part of the inn2
21  *  build, with the Makefile runes I have provided, all the libraries
22  *  and files which end up included in innduct are licence-compatible
23  *  with GPLv3.  If not then please let me know.  -Ian Jackson.)
24  */
25
26 #ifndef INNDUCT_H
27 #define INNDUCT_H
28
29 #define _GNU_SOURCE 1
30
31 #include "config.h"
32 #include "storage.h"
33 #include "nntp.h"
34 #include "libinn.h"
35 #include "inndcomm.h"
36
37 #include "inn/list.h"
38 #include "inn/innconf.h"
39 #include "inn/messages.h"
40
41 #include <sys/uio.h>
42 #include <sys/types.h>
43 #include <sys/wait.h>
44 #include <sys/stat.h>
45 #include <sys/socket.h>
46 #include <sys/un.h>
47 #include <unistd.h>
48 #include <string.h>
49 #include <signal.h>
50 #include <stdio.h>
51 #include <errno.h>
52 #include <syslog.h>
53 #include <fcntl.h>
54 #include <stdarg.h>
55 #include <assert.h>
56 #include <stdlib.h>
57 #include <stddef.h>
58 #include <glob.h>
59 #include <time.h>
60 #include <math.h>
61 #include <ctype.h>
62 #include <limits.h>
63
64 #include <oop.h>
65 #include <oop-read.h>
66
67 /*----- general definitions, probably best not changed -----*/
68
69 #define CONNCHILD_ESTATUS_STREAM   24
70 #define CONNCHILD_ESTATUS_NOSTREAM 25
71
72 #define INNDCOMMCHILD_ESTATUS_FAIL     26
73 #define INNDCOMMCHILD_ESTATUS_NONESUCH 27
74
75 #define MAX_LINE_FEEDFILE (NNTP_MAXLEN_MSGID + sizeof(TOKEN)*2 + 10)
76 #define MAX_CLI_COMMAND 1000
77
78 #define VA                va_list al;  va_start(al,fmt)
79 #define PRINTF(f,a)       __attribute__((__format__(printf,f,a)))
80 #define NORET_PRINTF(f,a) __attribute__((__noreturn__,__format__(printf,f,a)))
81 #define NORET             __attribute__((__noreturn__))
82
83 #define NEW(ptr)              ((ptr)= zxmalloc(sizeof(*(ptr))))
84 #define NEW_DECL(type,ptr) type ptr = zxmalloc(sizeof(*(ptr)))
85
86 #define DUMPV(fmt,pfx,v) fprintf(f, " " #v "=" fmt, pfx v);
87
88 #define FOR_LIST_NODE(nodevar, list) \
89   for ((nodevar)=LIST_HEAD(list); (nodevar); (nodevar)=LIST_NEXT((nodevar)))
90
91 #define FOR_CONN(conn) FOR_LIST_NODE(conn, conns)
92
93 /*----- doubly linked lists -----*/
94
95 #define ISNODE(T)   struct node list_node
96 #define DEFLIST(T)                              \
97    typedef struct {                             \
98      union { struct list li; T *for_type; } u;  \
99      int count;                                 \
100    } T##List
101
102 #define NODE(n) (assert((void*)&(n)->list_node == (n)), &(n)->list_node)
103
104 #define LIST_CHECKCANHAVENODE(l,n) \
105   ((void)((n) == ((l).u.for_type))) /* just for the type check */
106
107 #define LIST_ADDSOMEHOW(l,n,list_addsomehow)    \
108  ( LIST_CHECKCANHAVENODE(l,n),                  \
109    list_addsomehow(&(l).u.li, NODE((n))),       \
110    (void)(l).count++                            \
111    )
112
113 #define LIST_REMSOMEHOW(l,list_remsomehow)      \
114  ( (typeof((l).u.for_type))                     \
115    ( (l).count                                  \
116      ? ( (l).count--,                           \
117          list_remsomehow(&(l).u.li) )           \
118      : 0                                        \
119      )                                          \
120    )
121
122
123 #define LIST_ADDHEAD(l,n) LIST_ADDSOMEHOW((l),(n),list_addhead)
124 #define LIST_ADDTAIL(l,n) LIST_ADDSOMEHOW((l),(n),list_addtail)
125 #define LIST_REMHEAD(l) LIST_REMSOMEHOW((l),list_remhead)
126 #define LIST_REMTAIL(l) LIST_REMSOMEHOW((l),list_remtail)
127
128 #define LIST_INIT(l) ((l).count=0, list_new(&(l).u.li))
129 #define LIST_HEAD(l) ((typeof((l).u.for_type))(list_head((struct list*)&(l))))
130 #define LIST_NEXT(n) ((typeof(n))list_succ(NODE((n))))
131 #define LIST_BACK(n) ((typeof(n))list_pred(NODE((n))))
132
133 #define LIST_REMOVE(l,n)                        \
134  ( LIST_CHECKCANHAVENODE(l,n),                  \
135    list_remove(NODE((n))),                      \
136    (void)(l).count--                            \
137    )
138
139 #define LIST_INSERT(l,n,pred)                                   \
140  ( LIST_CHECKCANHAVENODE(l,n),                                  \
141    LIST_CHECKCANHAVENODE(l,pred),                               \
142    list_insert((struct list*)&(l), NODE((n)), NODE((pred))),    \
143    (void)(l).count++                                            \
144    )
145
146 /*----- type predeclarations -----*/
147
148 typedef struct Conn Conn;
149 typedef struct Article Article;
150 typedef struct InputFile InputFile;
151 typedef struct XmitDetails XmitDetails;
152 typedef struct Filemon_Perfile Filemon_Perfile;
153 typedef enum StateMachineState StateMachineState;
154 typedef struct CliCommand CliCommand;
155
156 DEFLIST(Conn);
157 DEFLIST(Article);
158
159
160 /*----- configuration options -----*/
161
162 extern const char *sitename, *remote_host;
163 extern const char *feedfile, *path_run, *path_cli, *path_cli_dir;
164 extern int quiet_multiple, interactive, try_filemon, try_stream, port;
165 extern const char *inndconffile;
166
167 extern int max_connections, max_queue_per_conn, target_max_feedfile_size;
168 extern int period_seconds, filepoll_seconds, max_queue_per_ipf;
169 extern int connection_setup_timeout, inndcomm_flush_timeout;
170
171 extern double nocheck_thresh;
172 extern double nocheck_decay;
173
174 /* all these are initialised to seconds, and converted to periods in main */
175 extern int reconnect_delay_periods;
176 extern int flushfail_retry_periods;
177 extern int backlog_retry_minperiods;
178 extern int backlog_spontrescan_periods;
179 extern int spontaneous_flush_periods;
180 extern int max_separated_periods;
181 extern int need_activity_periods;
182 extern int stats_log_periods;
183 extern int lowvol_thresh;
184 extern int lowvol_periods;
185
186 extern double max_bad_data_ratio;
187 extern int max_bad_data_initial;
188
189
190 /*----- article states, and statistics -----*/
191
192 typedef enum {      /* in queue                 in conn->sent             */
193   art_Unchecked,    /*   not checked, not sent    checking                */
194   art_Wanted,       /*   checked, wanted          sent body as requested  */
195   art_Unsolicited,  /*   -                        sent body without check */
196   art_MaxState,
197 } ArtState;
198 extern const char *const artstate_names[]; /* xmit.c */
199
200 #define RESULT_COUNTS(RCS,RCN)                  \
201   RCS(sent)                                     \
202   RCS(accepted)                                 \
203   RCN(unwanted)                                 \
204   RCN(rejected)                                 \
205   RCN(deferred)                                 \
206   RCN(missing)                                  \
207   RCN(connretry)
208
209 #define RCI_TRIPLE_FMT_BASE "%d (id=%d,bod=%d,nc=%d)"
210 #define RCI_TRIPLE_VALS_BASE(counts,x)          \
211        counts[art_Unchecked] x                  \
212        + counts[art_Wanted] x                   \
213        + counts[art_Unsolicited] x,             \
214        counts[art_Unchecked] x                  \
215        , counts[art_Wanted] x                   \
216        , counts[art_Unsolicited] x
217
218 typedef enum {
219 #define RC_INDEX(x) RC_##x,
220   RESULT_COUNTS(RC_INDEX, RC_INDEX)
221   RCI_max
222 } ResultCountIndex;
223
224 typedef enum {
225   read_ok, read_blank, read_err, nooffer_missing,
226   ECI_max
227 } EventCountIndex;
228
229 /*----- transmission buffers -----*/
230
231 #define CONNIOVS 128
232
233 typedef enum {
234   xk_Const, xk_Artdata
235 } XmitKind;
236
237 struct XmitDetails {
238   XmitKind kind;
239   union {
240     ARTHANDLE *sm_art;
241   } info;
242 };
243
244
245 /*----- core operational data structure types -----*/
246
247 typedef struct {
248   int results[art_MaxState][RCI_max];
249   int events[ECI_max];
250 } Counts;
251
252 struct InputFile {
253   /* This is also an instance of struct oop_readable */
254   struct oop_readable readable; /* first */
255   oop_readable_call *readable_callback;
256   void *readable_callback_user;
257
258   int fd;
259   Filemon_Perfile *filemon;
260
261   oop_read *rd; /* non-0: reading; 0: constructing, or had EOF */
262   off_t offset;
263   int skippinglong, paused, fake_readable;
264
265   ArticleList queue;
266   long inprogress; /* includes queue.count and also articles in conns */
267   long autodefer; /* -1 means not doing autodefer */
268
269   Counts counts;
270   char path[];
271 };
272
273 struct Article {
274   ISNODE(Article);
275   ArtState state;
276   int midlen, missing;
277   InputFile *ipf;
278   TOKEN token;
279   off_t offset;
280   int blanklen;
281   char messageid[1];
282 };
283
284 struct Conn {
285   ISNODE(Conn);
286   int fd; /* may be 0, meaning closed (during construction/destruction) */
287   oop_read *rd; /* likewise */
288   int oopwriting; /* since on_fd is not idempotent */
289   int max_queue, stream;
290   const char *quitting;
291   int since_activity; /* periods */
292   ArticleList waiting; /* not yet told peer */
293   ArticleList priority; /* peer says send it now */
294   ArticleList sent; /* offered/transmitted - in xmit or waiting reply */
295   struct iovec xmit[CONNIOVS];
296   XmitDetails xmitd[CONNIOVS];
297   int xmitu;
298 };
299
300 #define SMS_LIST(X)                             \
301   X(NORMAL)                                     \
302   X(FLUSHING)                                   \
303   X(FLUSHFAILED)                                \
304   X(SEPARATED)                                  \
305   X(DROPPING)                                   \
306   X(DROPPED)
307
308 enum StateMachineState {
309 #define SMS_DEF_ENUM(s) sm_##s,
310   SMS_LIST(SMS_DEF_ENUM)
311 };
312
313 extern const char *sms_names[];
314
315 /*========== function declarations ==========*/
316
317 /*----- help.c -----*/
318
319 void syscrash(const char *fmt, ...) NORET_PRINTF(1,2);
320 void crash(const char *fmt, ...) NORET_PRINTF(1,2);
321 void info(const char *fmt, ...) PRINTF(1,2);
322 void dbg(const char *fmt, ...) PRINTF(1,2);
323
324 void logv(int sysloglevel, const char *pfx, int errnoval,
325           const char *fmt, va_list al) PRINTF(5,0);
326
327 char *mvasprintf(const char *fmt, va_list al) PRINTF(1,0);
328 char *masprintf(const char *fmt, ...) PRINTF(1,2);
329
330 int close_perhaps(int *fd);
331 void xclose(int fd, const char *what, const char *what2);
332 void xclose_perhaps(int *fd, const char *what, const char *what2);
333 pid_t xfork(const char *what); /* also runs postfork in child */
334 pid_t xfork_bare(const char *what);
335
336 void on_fd_read_except(int fd, oop_call_fd callback);
337 void cancel_fd_read_except(int fd);
338
339 void report_child_status(const char *what, int status);
340 int xwaitpid(pid_t *pid, const char *what);
341
342 void *zxmalloc(size_t sz);
343 void xunlink(const char *path, const char *what);
344 time_t xtime(void);
345 void xsigaction(int signo, const struct sigaction *sa);
346 void xsigsetdefault(int signo);
347 void raise_default(int signo) NORET;
348
349 void xgettimeofday(struct timeval *tv_r);
350 void xsetnonblock(int fd, int nonb);
351
352 void check_isreg(const struct stat *stab, const char *path,
353                         const char *what);
354 void xfstat(int fd, struct stat *stab_r, const char *what);
355 void xfstat_isreg(int fd, struct stat *stab_r,
356                   const char *path, const char *what);
357 void xlstat_isreg(const char *path, struct stat *stab,
358                   int *enoent_r /* 0 means ENOENT is fatal */,
359                   const char *what);
360 int samefile(const struct stat *a, const struct stat *b);
361
362 char *sanitise(const char *input, int len);
363
364 static inline int isewouldblock(int errnoval) {
365   return errnoval==EWOULDBLOCK || errnoval==EAGAIN;
366 }
367
368 #define INNLOGSETS(INNLOGSET)                   \
369   INNLOGSET(die,      "fatal",    LOG_ERR)      \
370   INNLOGSET(warn,     "warning",  LOG_WARNING)  \
371   INNLOGSET(notice,   "notice",   LOG_NOTICE)   \
372   INNLOGSET(debug,    "debug",    LOG_DEBUG)
373 #define INNLOGSET_DECLARE(fn, pfx, sysloglevel)                         \
374   void duct_log_##fn(int l, const char *fmt, va_list al, int errval)    \
375     PRINTF(3,0);
376 INNLOGSETS(INNLOGSET_DECLARE)
377
378 /*----- duct.c -----*/
379
380 void postfork(void);
381 void period(void);
382
383 /*----- cli.c -----*/
384
385 void cli_init(void);
386 void cli_stdio(void);
387
388 /*----- conn.c -----*/
389
390 void conn_closefd(Conn *conn, const char *msgprefix);
391 void check_idle_conns(void);
392 int conn_busy(Conn *conn);
393 void conn_dispose(Conn *conn);
394
395 void vconnfail(Conn *conn, const char *fmt, va_list al) PRINTF(2,0);
396 void connfail(Conn *conn, const char *fmt, ...)         PRINTF(2,3);
397
398 void notice_conns_more(const char *new_kind);
399 void notice_conns_fewer(void);
400 void notice_conns_stats(void);
401
402 int allow_connect_start(void);
403 void connect_start(void);
404
405 /*----- defer.c -----*/
406
407 void poll_backlog_file(void);
408 void search_backlog_file(void);
409 void open_defer(void);
410 void close_defer(void);
411
412 /*----- filemon.c -----*/
413
414 int filemon_method_init(void);
415 void filemon_method_dump_info(FILE *f);
416
417 void filemon_start(InputFile *ipf);
418 void filemon_stop(InputFile *ipf);
419
420 /*----- infile.c -----*/
421
422 void filepoll(void);
423
424 void inputfile_reading_start(InputFile *ipf);
425 void inputfile_reading_stop(InputFile *ipf);
426 void inputfile_reading_pause(InputFile *ipf);
427 void inputfile_reading_resume(InputFile *ipf);
428   /* pause and resume are idempotent, and no-op if not done _reading_start */
429
430 InputFile *open_input_file(const char *path);
431 void close_input_file(InputFile *ipf); /* does not free */
432 char *dbg_report_ipf(InputFile *ipf);
433
434 void tailing_make_readable(InputFile *ipf);
435
436 /*----- recv.c -----*/
437
438 extern const oop_rd_style peer_rd_style;
439 oop_rd_call peer_rd_ok, peer_rd_err;
440
441 void article_done(Article *art, int whichcount);
442
443 /*----- statemc.c -----*/
444
445 void statemc_check_flushing_done(void);
446 void statemc_check_backlog_done(void);
447
448 extern sig_atomic_t terminate_sig_flag;
449 void statemc_period_poll(void);
450 void statemc_lock(void);
451 void init_signals(void);
452 void statemc_init(void);
453 void showstats(void);
454
455 #define SMS(newstate, periods, why) \
456    (statemc_setstate(sm_##newstate,(periods),#newstate,(why)))
457 void statemc_setstate(StateMachineState newsms, int periods,
458                              const char *forlog, const char *why);
459
460 void statemc_start_flush(const char *why); /* Normal => Flushing */
461 void spawn_inndcomm_flush(const char *why); /* Moved => Flushing */
462 int trigger_flush_ok(const char *why /* 0 means timeout */);
463                                   /* => Flushing,FLUSHING, ret 1; or ret 0 */
464
465 void preterminate(void);
466
467 /*----- xmit.c -----*/
468
469 void inputfile_queue_check_expired(InputFile *ipf);
470 void check_assign_articles(void);
471 void queue_check_input_done(void);
472 void check_reading_pause_resume(InputFile *ipf);
473
474 void conn_maybe_write(Conn *conn);
475 void conn_make_some_xmits(Conn *conn);
476 void *conn_write_some_xmits(Conn *conn);
477
478 void xmit_free(XmitDetails *d);
479
480 int article_check_expired(Article *art /* must be queued, not conn */);
481 void article_autodefer(InputFile *ipf, Article *art);
482 void article_defer(Article *art /* not on a queue */, int whichcount);
483 void autodefer_input_file(InputFile *ipf);
484
485 /*----- external linkage for debug/dump only -----*/
486
487 extern pid_t connecting_child;
488 extern int connecting_fdpass_sock;
489 extern pid_t inndcomm_child;
490
491 /*========== general operational variables ==========*/
492
493 /* duct.c */
494 extern oop_source *loop;
495 extern ConnList conns;
496 extern char *path_lock, *path_flushing, *path_defer, *path_dump;
497 extern char *globpat_backlog;
498 extern pid_t self_pid;
499 extern int *lowvol_perperiod;
500 extern int lowvol_circptr;
501 extern int lowvol_total; /* does not include current period */
502 extern int until_stats_log;
503
504 /* statemc.c */
505 extern StateMachineState sms;
506 extern int until_flush;
507 extern InputFile *main_input_file, *flushing_input_file, *backlog_input_file;
508 extern Counts backlog_counts;
509 extern int backlog_counts_report;
510 extern FILE *defer;
511 extern int until_connect, until_backlog_nextscan;
512 extern double accept_proportion;
513 extern int nocheck, nocheck_reported, in_child;
514
515 /* help.c */
516 extern int simulate_flush;
517 extern int logv_use_syslog;
518 extern const char *logv_prefix;
519
520
521 #endif /*INNDUCT_H*/