chiark / gitweb /
wip split into multiple files and make compile
[inn-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
63 #include <oop.h>
64 #include <oop-read.h>
65
66 /*----- general definitions, probably best not changed -----*/
67
68 #define CONNCHILD_ESTATUS_STREAM   24
69 #define CONNCHILD_ESTATUS_NOSTREAM 25
70
71 #define INNDCOMMCHILD_ESTATUS_FAIL     26
72 #define INNDCOMMCHILD_ESTATUS_NONESUCH 27
73
74 #define MAX_LINE_FEEDFILE (NNTP_MSGID_MAXLEN + sizeof(TOKEN)*2 + 10)
75 #define MAX_CLI_COMMAND 1000
76
77 #define VA                va_list al;  va_start(al,fmt)
78 #define PRINTF(f,a)       __attribute__((__format__(printf,f,a)))
79 #define NORET_PRINTF(f,a) __attribute__((__noreturn__,__format__(printf,f,a)))
80 #define NORET             __attribute__((__noreturn__))
81
82 #define NEW(ptr)              ((ptr)= zxmalloc(sizeof(*(ptr))))
83 #define NEW_DECL(type,ptr) type ptr = zxmalloc(sizeof(*(ptr)))
84
85 #define DUMPV(fmt,pfx,v) fprintf(f, " " #v "=" fmt, pfx v);
86
87 #define FOR_CONN(conn) \
88   for ((conn)=LIST_HEAD(conns); (conn); (conn)=LIST_NEXT((conn)))
89
90 /*----- doubly linked lists -----*/
91
92 #define ISNODE(T)   struct node list_node
93 #define DEFLIST(T)                              \
94    typedef struct {                             \
95      union { struct list li; T *for_type; } u;  \
96      int count;                                 \
97    } T##List
98
99 #define NODE(n) (assert((void*)&(n)->list_node == (n)), &(n)->list_node)
100
101 #define LIST_CHECKCANHAVENODE(l,n) \
102   ((void)((n) == ((l).u.for_type))) /* just for the type check */
103
104 #define LIST_ADDSOMEHOW(l,n,list_addsomehow)    \
105  ( LIST_CHECKCANHAVENODE(l,n),                  \
106    list_addsomehow(&(l).u.li, NODE((n))),       \
107    (void)(l).count++                            \
108    )
109
110 #define LIST_REMSOMEHOW(l,list_remsomehow)      \
111  ( (typeof((l).u.for_type))                     \
112    ( (l).count                                  \
113      ? ( (l).count--,                           \
114          list_remsomehow(&(l).u.li) )           \
115      : 0                                        \
116      )                                          \
117    )
118
119
120 #define LIST_ADDHEAD(l,n) LIST_ADDSOMEHOW((l),(n),list_addhead)
121 #define LIST_ADDTAIL(l,n) LIST_ADDSOMEHOW((l),(n),list_addtail)
122 #define LIST_REMHEAD(l) LIST_REMSOMEHOW((l),list_remhead)
123 #define LIST_REMTAIL(l) LIST_REMSOMEHOW((l),list_remtail)
124
125 #define LIST_INIT(l) ((l).count=0, list_new(&(l).u.li))
126 #define LIST_HEAD(l) ((typeof((l).u.for_type))(list_head((struct list*)&(l))))
127 #define LIST_NEXT(n) ((typeof(n))list_succ(NODE((n))))
128 #define LIST_BACK(n) ((typeof(n))list_pred(NODE((n))))
129
130 #define LIST_REMOVE(l,n)                        \
131  ( LIST_CHECKCANHAVENODE(l,n),                  \
132    list_remove(NODE((n))),                      \
133    (void)(l).count--                            \
134    )
135
136 #define LIST_INSERT(l,n,pred)                                   \
137  ( LIST_CHECKCANHAVENODE(l,n),                                  \
138    LIST_CHECKCANHAVENODE(l,pred),                               \
139    list_insert((struct list*)&(l), NODE((n)), NODE((pred))),    \
140    (void)(l).count++                                            \
141    )
142
143 /*----- type predeclarations -----*/
144
145 typedef struct Conn Conn;
146 typedef struct Article Article;
147 typedef struct InputFile InputFile;
148 typedef struct XmitDetails XmitDetails;
149 typedef struct Filemon_Perfile Filemon_Perfile;
150 typedef enum StateMachineState StateMachineState;
151 typedef struct CliCommand CliCommand;
152
153 DEFLIST(Conn);
154 DEFLIST(Article);
155
156
157 /*----- configuration options -----*/
158 /* when changing defaults, remember to update the manpage */
159
160 static const char *sitename, *remote_host;
161 static const char *feedfile, *path_run, *path_cli, *path_cli_dir;
162 static int quiet_multiple=0;
163 static int interactive=0, try_filemon=1;
164 static int try_stream=1;
165 static int port=119;
166 static const char *inndconffile;
167
168 static int max_connections=10;
169 static int max_queue_per_conn=200;
170 static int target_max_feedfile_size=100000;
171 static int period_seconds=30;
172 static int filepoll_seconds=5;
173 static int max_queue_per_ipf=-1;
174
175 static int connection_setup_timeout=200;
176 static int inndcomm_flush_timeout=100;
177
178 static double nocheck_thresh= 95.0; /* converted from percentage by main */
179 static double nocheck_decay= 100; /* conv'd from articles to lambda by main */
180
181 /* all these are initialised to seconds, and converted to periods in main */
182 static int reconnect_delay_periods=1000;
183 static int flushfail_retry_periods=1000;
184 static int backlog_retry_minperiods=100;
185 static int backlog_spontrescan_periods=300;
186 static int spontaneous_flush_periods=100000;
187 static int max_separated_periods=2000;
188 static int need_activity_periods=1000;
189 static int lowvol_thresh=3;
190 static int lowvol_periods=1000;
191
192 static double max_bad_data_ratio= 1; /* conv'd from percentage by main */
193 static int max_bad_data_initial= 30;
194   /* in one corrupt 4096-byte block the number of newlines has
195    * mean 16 and standard deviation 3.99.  30 corresponds to z=+3.5 */
196
197
198 /*----- statistics -----*/
199
200 typedef enum {      /* in queue                 in conn->sent             */
201   art_Unchecked,    /*   not checked, not sent    checking                */
202   art_Wanted,       /*   checked, wanted          sent body as requested  */
203   art_Unsolicited,  /*   -                        sent body without check */
204   art_MaxState,
205 } ArtState;
206
207 static const char *const artstate_names[]=
208   { "Unchecked", "Wanted", "Unsolicited", 0 };
209
210 #define RESULT_COUNTS(RCS,RCN)                  \
211   RCS(sent)                                     \
212   RCS(accepted)                                 \
213   RCN(unwanted)                                 \
214   RCN(rejected)                                 \
215   RCN(deferred)                                 \
216   RCN(missing)                                  \
217   RCN(connretry)
218
219 #define RCI_TRIPLE_FMT_BASE "%d (id=%d,bod=%d,nc=%d)"
220 #define RCI_TRIPLE_VALS_BASE(counts,x)          \
221        counts[art_Unchecked] x                  \
222        + counts[art_Wanted] x                   \
223        + counts[art_Unsolicited] x,             \
224        counts[art_Unchecked] x                  \
225        , counts[art_Wanted] x                   \
226        , counts[art_Unsolicited] x
227
228 typedef enum {
229 #define RC_INDEX(x) RC_##x,
230   RESULT_COUNTS(RC_INDEX, RC_INDEX)
231   RCI_max
232 } ResultCountIndex;
233
234
235 /*----- transmission buffers -----*/
236
237 #define CONNIOVS 128
238
239 typedef enum {
240   xk_Const, xk_Artdata
241 } XmitKind;
242
243 struct XmitDetails {
244   XmitKind kind;
245   union {
246     ARTHANDLE *sm_art;
247   } info;
248 };
249
250
251 /*----- core operational data structure types -----*/
252
253 struct InputFile {
254   /* This is also an instance of struct oop_readable */
255   struct oop_readable readable; /* first */
256   oop_readable_call *readable_callback;
257   void *readable_callback_user;
258
259   int fd;
260   Filemon_Perfile *filemon;
261
262   oop_read *rd; /* non-0: reading; 0: constructing, or had EOF */
263   off_t offset;
264   int skippinglong, paused, fake_readable;
265
266   ArticleList queue;
267   long inprogress; /* includes queue.count and also articles in conns */
268   long autodefer; /* -1 means not doing autodefer */
269
270   int counts[art_MaxState][RCI_max];
271   int readcount_ok, readcount_blank, readcount_err, count_nooffer_missing;
272   char path[];
273 };
274
275 struct Article {
276   ISNODE(Article);
277   ArtState state;
278   int midlen, missing;
279   InputFile *ipf;
280   TOKEN token;
281   off_t offset;
282   int blanklen;
283   char messageid[1];
284 };
285
286 #define SMS_LIST(X)                             \
287   X(NORMAL)                                     \
288   X(FLUSHING)                                   \
289   X(FLUSHFAILED)                                \
290   X(SEPARATED)                                  \
291   X(DROPPING)                                   \
292   X(DROPPED)
293
294 enum StateMachineState {
295 #define SMS_DEF_ENUM(s) sm_##s,
296   SMS_LIST(SMS_DEF_ENUM)
297 };
298
299 extern const char *sms_names[];
300
301 /*========== function declarations ==========*/
302
303 /*----- help.c -----*/
304
305 static void syscrash(const char *fmt, ...) NORET_PRINTF(1,2);
306 static void crash(const char *fmt, ...) NORET_PRINTF(1,2);
307 static void info(const char *fmt, ...) PRINTF(1,2);
308 static void dbg(const char *fmt, ...) PRINTF(1,2);
309
310 void logv(int sysloglevel, const char *pfx, int errnoval,
311           const char *fmt, va_list al) PRINTF(5,0);
312
313 char *xvasprintf(const char *fmt, va_list al) PRINTF(1,0);
314 char *xasprintf(const char *fmt, ...) PRINTF(1,2);
315
316 int close_perhaps(int *fd);
317 void xclose(int fd, const char *what, const char *what2);
318 void xclose_perhaps(int *fd, const char *what, const char *what2);
319 pid_t xfork(const char *what);
320
321 static void on_fd_read_except(int fd, oop_call_fd callback);
322 void cancel_fd_read_except(int fd);
323
324 void report_child_status(const char *what, int status);
325 int xwaitpid(pid_t *pid, const char *what);
326
327 void *zxmalloc(size_t sz);
328 void xunlink(const char *path, const char *what);
329 time_t xtime(void);
330 void xsigaction(int signo, const struct sigaction *sa);
331 void xsigsetdefault(int signo);
332
333 void xgettimeofday(struct timeval *tv_r);
334 void xsetnonblock(int fd, int nonb);
335
336 void check_isreg(const struct stat *stab, const char *path,
337                         const char *what);
338 void xfstat(int fd, struct stat *stab_r, const char *what);
339 void xfstat_isreg(int fd, struct stat *stab_r,
340                   const char *path, const char *what);
341 void xlstat_isreg(const char *path, struct stat *stab,
342                   int *enoent_r /* 0 means ENOENT is fatal */,
343                   const char *what);
344 int samefile(const struct stat *a, const struct stat *b);
345
346 char *sanitise(const char *input, int len);
347
348 static inline int isewouldblock(int errnoval) {
349   return errnoval==EWOULDBLOCK || errnoval==EAGAIN;
350 }
351
352 /*----- innduct.c -----*/
353
354 void postfork(void);
355
356 /*----- conn.c -----*/
357
358 void conn_closefd(Conn *conn, const char *msgprefix);
359
360 /*----- defer.c -----*/
361
362 void poll_backlog_file(void);
363
364 /*----- infile.c -----*/
365
366 void filepoll(void);
367
368 /*----- statemc.c -----*/
369
370 sig_atomic_t terminate_sig_flag;
371
372 /*----- xmit.c -----*/
373
374 void inputfile_queue_check_expired(InputFile *ipf);
375
376 /*----- external linkage for debug/dump only -----*/
377
378 pid_t connecting_child;
379 pid_t inndcomm_child;
380
381 /*========== general operational variables ==========*/
382
383 /* innduct.c */
384 extern oop_source *loop;
385 extern ConnList conns;
386 extern char *path_lock, *path_flushing, *path_defer, *path_dump;
387 extern char *globpat_backlog;
388 extern pid_t self_pid;
389 extern int *lowvol_perperiod;
390 extern int lowvol_circptr;
391 extern int lowvol_total; /* does not include current period */
392
393 /* statemc.c */
394 extern StateMachineState sms;
395 extern int until_flush;
396 extern InputFile *main_input_file, *flushing_input_file, *backlog_input_file;
397 extern FILE *defer;
398 extern int until_connect, until_backlog_nextscan;
399 extern double accept_proportion;
400 extern int nocheck, nocheck_reported, in_child;
401
402 /* help.c */
403 extern int simulate_flush;
404 extern int logv_use_syslog;
405 extern const char *logv_prefix;
406
407
408 #endif /*INNDUCT_H*/