add logging of PC92A ip addresses
[spider.git] / src / sel.c
1 /*
2  * sel.c
3  * 
4  * util routines for do the various select activities
5  * 
6  * Copyright 1996 (c) D-J Koopman
7  * 
8  * $Header$
9  */
10  
11
12 static char rcsid[] = "$Id$";
13
14 #include <sys/time.h>
15 #include <sys/types.h>
16 #include <unistd.h>
17 #include <stdlib.h>
18 #include <time.h>
19 #include <string.h>
20 #include <errno.h>
21
22 #include "chain.h"
23 #include "sel.h"
24
25 sel_t *sel;                                                        /* the array of selectors */
26 int sel_max;                                               /* the maximum no of selectors */
27 int sel_top;                                               /* the last selector in use */
28 int sel_inuse;                                             /* the no of selectors in use */
29 time_t sel_systime;                                        /* the unix time now */
30 struct timeval sel_tv;                             /* the current timeout for select */
31
32 /*
33  * initialise the selector system, no is the no of slots to reserve
34  */
35
36 void sel_init(int no, long sec, long usec)
37 {
38         sel = malloc(sizeof(sel_t) * no);
39         if (!sel)
40                 die("no room in sel_init");
41         memset(sel, 0, sizeof(sel_t) * no);
42         sel_max = no;
43         sel_inuse = sel_top = 0;
44         if (sec == 0 && usec == 0) 
45                 usec = 10000;
46         sel_tv.tv_sec = sec;
47         sel_tv.tv_usec = usec;
48 }
49
50 /*
51  * open and initialise a selector slot, you are expected to deal with the
52  * actual opening and setting up of the device itself
53  */
54
55 sel_t *sel_open(int cnum, void *fcb, char *name, int (*handler)(), int sort, int flags)
56 {
57         int i;
58         sel_t *sp;
59         
60         /* get a free slot */
61         for (i = 0; i < sel_max; ++i) {
62                 sp = &sel[i];
63                 if (sp->sort == 0)
64                         break;
65         }
66         if (i >= sel_max)
67                 die("there are no more sel slots available (max %d)", sel_max);
68         
69         /* fill in the blanks */
70         sp->cnum = cnum;
71         sp->fcb = fcb;
72         sp->name = strdup(name);
73         sp->handler = handler;
74         sp->sort = sort;
75         sp->flags = flags;
76         sp->msgbase = chain_new();
77         sp->err = 0;
78         ++sel_inuse;
79         if (sel_top < (sp - sel) + 1)
80                 sel_top = (sp - sel) + 1;
81         return sp;
82 }
83
84 /* 
85  * post a close handler for this connection, to do special things
86  * in the event of this cnum closing, the default is just to close
87  */
88
89 void sel_closehandler(sel_t *sp, void (*handler)())
90 {
91         sp->closehandler = handler;
92 }
93
94 /*
95  * close (and thus clear down) a slot, it is assumed that you have done whatever
96  * you need to do to close the actual device already
97  */
98
99 void sel_close(sel_t *sp)
100 {
101         if (sp->sort) {
102                 if (sp->closehandler) {
103                         (sp->closehandler)(sp);
104                 } else {
105                         close(sp->cnum);
106                 }
107                 chain_flush(sp->msgbase);
108                 free(sp->msgbase);
109                 free(sp->name);
110                 memset(sp, 0, sizeof(sel_t));
111                 if (sel_top == (sp - sel) + 1)
112                         --sel_top;
113                 --sel_inuse;
114         }
115 }
116
117 /*
118  * this actually runs the (de)multiplexor, it simply listens to the various cnums 
119  * presents the events to the handler which has to deal with them
120  */
121
122 void sel_run()
123 {
124         int i, r, max = 0;
125         struct timeval tv;
126         fd_set infd;
127         fd_set outfd;
128         fd_set errfd;
129         sel_t *sp;
130         
131         /* first set up the parameters for the select according to the slots registered */
132         FD_ZERO(&infd);
133         FD_ZERO(&outfd);
134         FD_ZERO(&errfd);
135         tv = sel_tv;
136         
137         for (i = 0; i < sel_top; ++i) {
138                 sp = &sel[i];
139                 if (sp->sort && !sp->err) {
140                         if (sp->flags & SEL_INPUT)
141                                 FD_SET(sp->cnum, &infd);
142                         if (sp->flags & SEL_OUTPUT)
143                                 FD_SET(sp->cnum, &outfd);
144                         if (sp->flags & SEL_ERROR)
145                                 FD_SET(sp->cnum, &errfd);
146                         if (sp->cnum > max)
147                                 max = sp->cnum;
148                 }
149         }
150         
151         /* now do the select */
152         r = select(max + 1, &infd, &outfd, &errfd, &tv);
153
154         if (r < 0) {
155                 if (errno != EINTR)
156                         die("Error during select (%d)", errno);
157                 return;
158         }
159
160         /* if there is anything to do, pass it on to the appropriate handler */
161         if (r > 0) {
162                 int in, out, err;
163                 int hr;
164                 
165                 for (i = 0; i < sel_top; ++i) {
166                         sp = &sel[i];
167                         if (sp->sort) {
168                                 in = FD_ISSET(sp->cnum, &infd);
169                                 out = FD_ISSET(sp->cnum, &outfd);
170                                 err = FD_ISSET(sp->cnum, &errfd);
171                                 if (in || out || err) {
172                                         hr = (sp->handler)(sp, in, out, err);
173                                         
174                                         /* if this is positive, close this selector */
175                                         if (hr)
176                                                 sel_close(sp);
177                                         else {
178                                                 FD_CLR(sp->cnum, &infd);
179                                                 FD_CLR(sp->cnum, &outfd);
180                                                 FD_CLR(sp->cnum, &errfd);
181                                         }
182                                 }
183                         }
184                 }
185         }
186         
187         time(&sel_systime);                                /* note the time, for general purpuse use */
188 }
189
190 /*
191  * get/set error flag - -1 simply gets the flag, 0 or 1 sets the flag
192  * 
193  * in all cases the old setting of the flag is returned
194  */
195
196 int sel_error(sel_t *sp, int err)
197 {
198         int r = sp->err;
199         if (err >= 0)
200                 sp->err = err;
201         return r;
202 }
203
204 /*
205  * $Log$
206  * Revision 1.5  2002-01-27 15:35:33  minima
207  * try to fix EOF on standard input problems
208  *
209  * Revision 1.4  2000/07/20 14:16:00  minima
210  * can use Sourceforge now!
211  * added user->qra cleaning
212  * added 4 digit qra to user broadcast dxspots if available
213  *
214  * Revision 1.3  2000/03/30 22:51:14  djk
215  * fixed connect code in client.pl so it doesn't falsely recognise /spider
216  * /src/client as a 'client' directive.
217  * Tidied up the C client a bit
218  *
219  * Revision 1.2  2000/03/26 14:22:59  djk
220  * removed some irrelevant log info
221  *
222  * Revision 1.1  2000/03/26 00:03:30  djk
223  * first cut of client
224  *
225  * Revision 1.1  1997/01/03 23:44:31  djk
226  * initial workings
227  *
228  *
229  */