1 /**********************************************************
2 * File: qipc_server.c
3 * Created at Wed Apr 4 23:53:12 2001 by lev // lev@serebryakov.spb.ru
4 *
5 * $Id: qipc_server.c,v 1.5 2002/03/16 15:59:38 lev Exp $
6 **********************************************************/
7 #include "headers.h"
8 #include <sys/socket.h>
9 #include <netdb.h>
10 #include <netinet/in.h>
11
12 /* Some global variables */
13 static anylist_t *ip_lines;
14 static anylist_t *tty_lines;
15 static anylist_t *clients;
16 static int line_socket;
17 static int client_socket;
18
19 /* Static misc functions */
reset_txrx(txrxstate_t * txrx)20 static void reset_txrx(txrxstate_t *txrx)
21 {
22 memset(txrx,0,sizeof(*txrx));
23 txrx->phase = TXRX_PHASE_BEGIN;
24 txrx->filephase;
25 }
26
27
28 /*
29 * Support functions for anylist_t with uiclient_t
30 */
31 /* Allocate client record for anylist */
uiclient_alloc(void * key)32 al_item_t *uiclient_alloc(void *key)
33 {
34 uiclient_t *p;
35 if(!(p=xmalloc(sizeof(*p)))) return NULL;
36 memset(p,0,sizeof(*p));
37 p->socket = *((int*)key);
38 return (al_item_t*)p;
39 }
40
41 /* Free client record for anylist */
uiclient_free(al_item_t * i)42 void uiclient_free(al_item_t *i)
43 {
44 uiclient_t *p = (uiclient_t*)i;
45 if(!p) return;
46 shutdown(p->socket,3); close(p->socket);
47 xfree(p);
48 }
49
50 /* Compare client record with key for anylist */
uiclient_cmp(al_item_t * i,void * key)51 int uiclient_cmp(al_item_t *i, void *key)
52 {
53 uiclient_t *p = (uiclient_t*)i;
54 return p->socket != *((int*)key);
55 }
56
57 /*
58 * Support functions for anylist_t with line2ui_t
59 */
60 /* Allocate mapping record for anylist */
line2ui_alloc(void * key)61 al_item_t *line2ui_alloc(void *key)
62 {
63 line2ui_t *p;
64 if(!(p=xmalloc(sizeof(*p)))) return NULL;
65 memset(p,0,sizeof(*p));
66 p->client = (uiclient_t*)key;
67 return (al_item_t*)p;
68 }
69
70 /* Free mapping record for anylist */
line2ui_free(al_item_t * i)71 void line2ui_free(al_item_t *i)
72 {
73 line2ui_t *p = (line2ui_t*)i;
74 if(!p) return;
75 xfree(p);
76 }
77
78 /* Compare mapping record with key for anylist */
line2ui_cmp(al_item_t * i,void * key)79 int line2ui_cmp(al_item_t *i, void *key)
80 {
81 line2ui_t *p = (line2ui_t*)i;
82 return p->client != (uiclient_t*)key;
83 }
84
85 /*
86 * Support functions for anylist_t with linestate_t -- PID as key (IP lines)
87 */
88 /* Allocate line record for anylist */
ipline_alloc(void * key)89 al_item_t *ipline_alloc(void *key)
90 {
91 linestate_t *p;
92 if(!(p=xmalloc(sizeof(*p)))) return NULL;
93 memset(p,0,sizeof(*p));
94 p->pid = *((pid_t*)key);
95 p->phase = SESS_PHASE_NOPROC;
96 p->send.phase = p->recv.phase = TXRX_PHASE_BEGIN;
97 if(!(p->clients=al_new(lien2ui_alloc,line2ui_free,line2ui_cmp))) return NULL;
98 return (al_item_t*)p;
99 }
100
101 /* Free line record for anylist */
102 /* Use anyline_free() */
103
104 /* Compare client record with key for anylist */
ipline_cmp(al_item_t * i,void * key)105 int ipline_cmp(al_item_t *i, void *key)
106 {
107 linestate_t *p = (line2ui_t*)i;
108 return p->pid != *((pid_t*)key);
109 }
110
111 /*
112 * Support functions for anylist_t with linestate_t -- tty as key (TTY lines)
113 */
114 /* Allocate line record for anylist */
ttyline_alloc(void * key)115 al_item_t *ttyline_alloc(void *key)
116 {
117 linestate_t *p;
118 if(!(p=xmalloc(sizeof(*p)))) return NULL;
119 memset(p,0,sizeof(*p));
120 p->phase = SESS_PHASE_NOPROC;
121 p->send.phase = p->recv.phase = TXRX_PHASE_BEGIN;
122 if(!(p->tty=xstrdup((char*)key))) return NULL;
123 if(!(p->clients=al_new(lien2ui_alloc,line2ui_free,line2ui_cmp))) return NULL;
124 return (al_item_t*)p;
125 }
126
127 /* Free line record for anylist */
128 /* Use anyline_free() */
129
130 /* Compare client record with key for anylist */
ttyline_cmp(al_item_t * i,void * key)131 int ttyline_cmp(al_item_t *i, void *key)
132 {
133 linestate_t *p = (line2ui_t*)i;
134 return strcmp(p->tty,(char*)key);
135 }
136
137 /* Free any line in list */
anyline_free(al_item_t * i)138 void anyline_free(al_item_t *i)
139 {
140 linestate_t *p = (line2ui_t*)i;
141 int i;
142 if(!p) return;
143 nlfree(&p->remote);
144 if(p->tty) xfree(p->tty);
145 if(p->connect) xfree(p->connect);
146 if(p->cid) xfree(p->cid);
147 for(i=0;i<LOG_BUFFER_SIZE;i++) if(p->log_buffer[i]) xfree(p->log_buffer[i]);
148 if(p->clients) al_free(p->clients);
149 xfree(p);
150 }
151
152
153 /* Clear tty line -- delete all internal contents, but leave registartion and tty unchanged */
ttyline_clear(linestate_t * p)154 void ttyline_clear(linestate_t *p)
155 {
156 int i;
157 anylist_t *l;
158 CHAR *c;
159 if(!p) return;
160 nlfree(&p->remote);
161 if(p->connect) xfree(p->connect);
162 if(p->cid) xfree(p->cid);
163 for(i=0;i<LOG_BUFFER_SIZE;i++) if(p->log_buffer[i]) xfree(p->log_buffer[i]);
164 l = p->clients;
165 c = p->tty;
166 memset(p,0,sizeof(*p));
167 p->clients = l;
168 p->tty = c;
169 p->phase = SESS_PHASE_NOPROC;
170 p->send.phase = p->recv.phase = TXRX_PHASE_BEGIN;
171 }
172
set_all_opts(int s)173 static int set_all_opts(int s)
174 {
175 int x = 1;
176 if(!setsockopt(s,SOL_SOCKET,SO_REUSEADDR,&x,sizeof(x))) return -1;
177 if(!setsockopt(s,SOL_SOCKET,SO_REUSEPORT,&x,sizeof(x))) return -1;
178
179 x = fcntl(s,F_GETFL,0L);
180 if(x < 0) return -1;
181 x |= O_NONBLOCK;
182 if(fcntl(s,F_SETFL,x) < 0) return -1;
183 return 0;
184 }
185
186
server_init()187 int server_init()
188 {
189 struct sockaddr_in sin;
190 slist_t ports = NULL;
191
192 /* Allocate list for IP lines */
193 if(!(ip_lines=al_new(ipline_alloc,anyline_free,ipline_cmp)))return -1;
194 /* Allocate list fot TTY lines */
195 if(!(tty_lines=al_new(ttyline_alloc,ttyline_free,ttyline_cmp)))return -1;
196 /* Allocate list for clients */
197 if(!(clients=al_new(uiclient_alloc,uiclient_free,uiclient_cmp)))return -1;
198
199 /* Insert all TTY lines into list */
200 ports = cfgsl(CFG_PORT);
201 while(ports) {
202 al_finda(tty_lines,ports->str,NULL);
203 ports = ports->next;
204 }
205
206 /* Prepare and open sockets */
207 /* Common part */
208 sin.sin_len = sizeof(sin);
209 sin.sin_family = AF_INET;
210 sin.sin_port = htons(cfgi(CFG_MANAGERPORT));
211
212 /* UDP socket for lines. On loopback only for security reasons. */
213 sin.sin_addr.s_addr = INADDR_LOOPBACK;
214 line_socket = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
215 if(line_socket == -1) return -1;
216 if(!set_all_opts(line_socket)) return -1;
217 if(bind(line_socket,(struct sockaddr*)&sin,sizeof(sin))) return -1;
218
219
220 /* TCP socket for UIs. */
221 sin.sin_addr.s_addr = INADDR_ANY;
222 client_socket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
223 if(client_socket == -1) return -1;
224 if(!set_all_opts(client_socket)) return -1;
225 if(bind(client_socket,(struct sockaddr*)&sin,sizeof(sin))) return -1;
226 if(listen(client_socket,4)) return -1;
227
228 return 0;
229 }
230
server_delete_client(uiclient_t * client)231 void server_delete_client(uiclient_t *client)
232 {
233 linestate_t *line;
234
235 /* Delete client from TTY lines */
236 line = (linestat_t*) tty_lines->head;
237 while(line) {
238 al_delk(line->clients,(void*)client);
239 line = line->next;
240 }
241
242 /* Delete client from IP lines */
243 line = (linestat_t*) ip_lines->head;
244 while(line) {
245 al_delk(line->clients,(void*)client);
246 line = line->next;
247 }
248
249 /* Close socket */
250 shutdown(client->socket,3);
251 close(client->socket);
252
253 /* Delete client from global of clients */
254 al_deli(clients,(al_item_t*)client);
255 }
256
get_txrx_state(linestate_t * line,char d)257 static txrxstate_t *get_txrx_state(linestate_t *line, char d)
258 {
259 switch(toupper(d)) {
260 case 'R':
261 return &line->recv;
262 case 'S':
263 return &line->send;
264 default:
265 write_log("Invalid direction: '%c'",d);
266 return NULL;
267 }
268 }
269
evt_out_of_sequence(evtlam_t * evt)270 static void evt_out_of_sequence(evtlam_t *evt)
271 {
272 write_log("Out of sequence %02x event from '%16s'",evt->type,evt->tty[0]?evt->tty:'tcp');
273 }
274
evt_not_unpack(evtlam_t * evt)275 static void evt_not_unpack(evtlam_t *evt)
276 {
277 write_log("Could not unpack event %02x: %d bytes from '%16s'",evt->type,evt.fulllength,evt->tty[0]?evt->tty:'tcp');
278 }
279
server_process_line_event(linestate_t * line,evtlam_t * evt,struct sockaddr_in * sa)280 int server_process_line_event(linestate_t *line, evtlam_t *evt, struct sockaddr_in *sa)
281 {
282 char *pwd;
283 char c1,c2;
284 DWORD dw1,dw2,dw3,dw4;
285 char *s;
286 txrxstate_t *txrx;
287
288 /* First of all -- check PASSWORD */
289 pwd = cfgs(CFG_LINEPASSWORD);
290 if(memcmp(pwd,evt->password,sizeof(evt->password))) {
291 write_log("Invalid password from line %d from '%16s': '%8s'",evt->pid,evt->tty[0]?evt->tty:'tcp',evt->password);
292 return -1;
293 }
294
295 /* Check for PIDs */
296 if(line->pid && line->pid != evt->pid) {
297 write_log("Invalid PID: %d, was %d from '%16s'",evt->pid,line->pid,evt->tty[0]?evt->tty:'tcp');
298 if(!evt->tty[0]) al_deli(ip_lines,(al_item_t*)line);
299 else ttyline_clear(line);
300 return -1;
301 }
302
303 evt.fulllength -= sizeof(*evt);
304
305 /* Process event */
306 switch(evt->type) {
307 case EVTL2M_REGISTER: /* Register new line, set mode -- answer or call */
308 /* Signature: "c" -- [A]NSWER/[C]ALL. */
309 line->pid = evt->pid;
310 line->phase = SESS_PHASE_BEGIN;
311 memcpy(&line->from,sa,sizeof(line->from));
312 if(1!=unpack_ipc_packet(evt->data,evt.fulllength,"c",&line->mode)) {
313 evt_out_of_sequence(evt);
314 return -1;
315 }
316 line->mode = toupper(line->mode);
317 if(line->mode != 'A' && line->mode != 'C') {
318 write_log("Invalid call mode: '%c' from '%16s'",line->mode,evt->tty[0]?evt->tty:'tcp');
319 return -1;
320 }
321 break;
322 case EVTL2M_CLOSE: /* Unregister line and delete it */
323 /* Signature: "" */
324 if(!evt->tty[0]) al_deli(ip_lines,(al_item_t*)line);
325 else ttyline_clear(line);
326 break;
327 case EVTL2M_STAT_CONNECT: /* Modem connected, carrier detected. Speed and CID */
328 /* Signature: "dss" -- SPEED,CONNECT,CID*/
329 if(line->phase != SESS_PHASE_BEGIN) {
330 evt_out_of_sequence(evt);
331 return -1;
332 }
333 if(3!=unpack_ipc_packet(evt->data,evt.fulllength,"dss",&line->speed,&line->connect,&line->cid)) {
334 evt_not_unpack(evt);
335 return -1;
336 }
337 line->phase = SESS_PHASE_CONNECT;
338 break;
339 case EVTL2M_STAT_DETECTED: /* Mailer detected. Session type. */
340 /* Signature: "d" -- SESSION TYPE */
341 if(line->phase != SESS_PHASE_CONNECT) {
342 evt_out_of_sequence(evt);
343 return -1;
344 }
345 if(1!=unpack_ipc_packet(evt->data,evt.fulllength,"d",&line->type)) {
346 evt_not_unpack(evt);
347 return -1;
348 }
349 break;
350 case EVTL2M_STAT_DATAGOT: /* We know about remote node. node_t info */
351 /* Signature: "n" -- REMOTE NODE INFO */
352 if((line->mode == 'A' && line->phase != SESS_PHASE_CONNECT)
353 ||
354 (line->mode == 'C' && line->phase != SESS_PHASE_HSHAKEOUT)) {
355 evt_out_of_sequence(evt);
356 return -1;
357 }
358 if(1!=unpack_ipc_packet(evt->data,evt.fulllength,"n",&line->remote)) {
359 evt_not_unpack(evt);
360 return -1;
361 }
362 line->phase = SESS_PHASE_HSHAKEIN;
363 break;
364 case EVTL2M_STAT_DATASENT: /* Remote know about us */
365 /* Signature: "" */
366 if((line->mode == 'A' && line->phase != SESS_PHASE_HSHAKEIN)
367 ||
368 (line->mode == 'C' && line->phase != SESS_PHASE_CONNECT)) {
369 evt_out_of_sequence(evt);
370 return -1;
371 }
372 line->phase = SESS_PHASE_HSHAKEOUT;
373 break;
374 case EVTL2M_STAT_HANDSHAKED: /* Handshake finished. Protocols and options */
375 /* Signature: "dd" -- PROTOCOL,FINAL OPTIONS*/
376 if((line->mode == 'A' && line->phase != SESS_PHASE_HSHAKEOUT)
377 ||
378 (line->mode == 'C' && line->phase != SESS_PHASE_HSHAKEIN)) {
379 evt_out_of_sequence(evt);
380 return -1;
381 }
382 if(2!=unpack_ipc_packet(evt->data,evt.fulllength,"dd",&line->proto,&line->flags)) {
383 evt_not_unpack(evt);
384 return -1;
385 }
386 line->phase = SESS_PHASE_INPROCESS;
387 break;
388 case EVTL2M_BATCH_START: /* Batch starts */
389 /* Signature: "c" -- DIRECTION */
390 if(line->phase != SESS_PHASE_INPROCESS) {
391 evt_out_of_sequence(evt);
392 return -1;
393 }
394 if(1!=unpack_ipc_packet(evt->data,evt.fulllength,"c",&c1)) {
395 evt_not_unpack(evt);
396 return -1;
397 }
398 if(!(txrx = get_txrx_state(line,c1))) return -1;
399 if(txrx->phase != TXRX_PHASE_BEGIN && txrx->phase != TXRX_PHASE_EOT) {
400 evt_out_of_sequence(evt);
401 return -1;
402 }
403 txrx->phase = TXRX_PHASE_HSHAKE;
404 txrx->transferstarted = time(NULL);
405 break;
406 case EVTL2M_BATCH_HSHAKED: /* Batch handshaked */
407 /* Signature: "c" -- DIRECTION */
408 if(line->phase != SESS_PHASE_INPROCESS) {
409 evt_out_of_sequence(evt);
410 return -1;
411 }
412 if(1!=unpack_ipc_packet(evt->data,evt.fulllength,"c",&c1)) {
413 evt_not_unpack(evt);
414 return -1;
415 }
416 if(!(txrx = get_txrx_state(line,c1))) return -1;
417 if(txrx->phase != TXRX_PHASE_HSHAKE) {
418 evt_out_of_sequence(evt);
419 return -1;
420 }
421 txrx->phase = TXRX_PHASE_LOOP;
422 break;
423 case EVTL2M_BATCH_CLOSE: /* Batch finishing */
424 /* Signature: "c" -- DIRECTION */
425 if(line->phase != SESS_PHASE_INPROCESS) {
426 evt_out_of_sequence(evt);
427 return -1;
428 }
429 if(1!=unpack_ipc_packet(evt->data,evt.fulllength,"c",&c1)) {
430 evt_not_unpack(evt);
431 return -1;
432 }
433 if(!(txrx = get_txrx_state(line,c1))) return -1;
434 if(txrx->phase != TXRX_PHASE_LOOP) {
435 evt_out_of_sequence(evt);
436 return -1;
437 }
438 txrx->phase = TXRX_PHASE_FINISH;
439 break;
440 case EVTL2M_BATCH_CLOSED: /* Batch finished */
441 /* Signature: "c" -- DIRECTION */
442 if(line->phase != SESS_PHASE_INPROCESS) {
443 evt_out_of_sequence(evt);
444 return -1;
445 }
446 if(1!=unpack_ipc_packet(evt->data,evt.fulllength,"c",&c1)) {
447 evt_not_unpack(evt);
448 return -1;
449 }
450 if(!(txrx = get_txrx_state(line,c1))) return -1;
451 if(txrx->phase != TXRX_PHASE_FINISH) {
452 evt_out_of_sequence(evt);
453 return -1;
454 }
455 txrx->phase = TXRX_PHASE_EOT;
456 break;
457 case EVTL2M_BATCH_INFO: /* Batch info -- async */
458 /* Signature: "cdddd" -- DIRECTION,MAX BLOCK,CRC,FILES,TOTAL SIZE */
459 if(line->phase != SESS_PHASE_INPROCESS) {
460 evt_out_of_sequence(evt);
461 return -1;
462 }
463 if(5!=unpack_ipc_packet(evt->data,evt.fulllength,"cdddd",&c1,&dw1,&dw2,&dw3,&dw4)) {
464 evt_not_unpack(evt);
465 return -1;
466 }
467 if(!(txrx = get_txrx_state(line,c1))) return -1;
468 txrx->maxblock = dw1;
469 txrx->crcsize = dw2;
470 txrx->totalfiles = dw3;
471 txrx->totalsize = dw4;
472 break;
473 case EVTL2M_FILE_START: /* New file started */
474 /* Signature: "c" */
475 if(line->phase != SESS_PHASE_INPROCESS) {
476 evt_out_of_sequence(evt);
477 return -1;
478 }
479 if(1!=unpack_ipc_packet(evt->data,evt.fulllength,"c",&c1)) {
480 evt_not_unpack(evt);
481 return -1;
482 }
483 if(!(txrx = get_txrx_state(line,c1))) return -1;
484 if(txrx->phase != TXRX_PHASE_LOOP ||
485 txrx->filephase != TXRX_FILE_EOF) {
486 evt_out_of_sequence(evt);
487 return -1;
488 }
489 txrx->filephase = TXRX_FILE_HSHAKE;
490 txrx->filestarted = time(NULL);
491 break;
492 case EVTL2M_FILE_INFO: /* Info about new file sended/received */
493 /* Signature: "csddd" -- DIRECTION,NAME,CRC,SIZE,TIME */
494 if(line->phase != SESS_PHASE_INPROCESS) {
495 evt_out_of_sequence(evt);
496 return -1;
497 }
498 if(5!=unpack_ipc_packet(evt->data,evt.fulllength,"csddd",&c1,&s,&dw1,&dw2,&dw3)) {
499 evt_not_unpack(evt);
500 return -1;
501 }
502 if(!(txrx = get_txrx_state(line,c1))) return -1;
503 if(txrx->phase != TXRX_PHASE_LOOP) {
504 evt_out_of_sequence(evt);
505 return -1;
506 }
507 txrx->file = s;
508 txrx->crcsize = dw1;
509 txrx->filesize = dw2;
510 if(txrx->totalpos+txrx->filesize>txrx->totalsize)
511 txrx->totalsize = txrx->totalpos+txrx->filesize;
512 break;
513 case EVTL2M_FILE_DATA: /* FINFO Ok, start data exhcnage */
514 /* Signature: "cd" -- DIRECTION,POS */
515 if(line->phase != SESS_PHASE_INPROCESS) {
516 evt_out_of_sequence(evt);
517 return -1;
518 }
519 if(2!=unpack_ipc_packet(evt->data,evt.fulllength,"cd",&c1,&dw1)) {
520 evt_not_unpack(evt);
521 return -1;
522 }
523 if(!(txrx = get_txrx_state(line,c1))) return -1;
524 if(txrx->phase != TXRX_PHASE_LOOP ||
525 txrx->filephase != TXRX_FILE_HSHAKE) {
526 evt_out_of_sequence(evt);
527 return -1;
528 }
529 txrx->filephase = TXRX_FILE_DATA;
530 txrx->totalpos += dw1;
531 txrx->filepos = dw1;
532 break;
533 case EVTL2M_FILE_BLOCK: /* Block sended/received */
534 /* Signature: "cdd" -- DIRECTION,POS,SIZE */
535 if(line->phase != SESS_PHASE_INPROCESS) {
536 evt_out_of_sequence(evt);
537 return -1;
538 }
539 if(3!=unpack_ipc_packet(evt->data,evt.fulllength,"cdd",&c1,&dw1,&dw2)) {
540 evt_not_unpack(evt);
541 return -1;
542 }
543 if(!(txrx = get_txrx_state(line,c1))) return -1;
544 if(txrx->phase != TXRX_PHASE_LOOP ||
545 txrx->filephase != TXRX_FILE_DATA) {
546 evt_out_of_sequence(evt);
547 return -1;
548 }
549 txrx->totalpos -= txrx->filepos;
550 txrx->totalpos += dw1+dw2;
551 txrx->filepos += dw1+dw2;
552 txrx->curblock = dw2;
553 break;
554 case EVTL2M_FILE_REPOS: /* Repos */
555 /* Signature: "cd" -- DIRECTION,POS */
556 if(line->phase != SESS_PHASE_INPROCESS) {
557 evt_out_of_sequence(evt);
558 return -1;
559 }
560 if(2!=unpack_ipc_packet(evt->data,evt.fulllength,"cd",&c1,&dw1)) {
561 evt_not_unpack(evt);
562 return -1;
563 }
564 if(!(txrx = get_txrx_state(line,c1))) return -1;
565 if(txrx->phase != TXRX_PHASE_LOOP ||
566 txrx->filephase != TXRX_FILE_DATA) {
567 evt_out_of_sequence(evt);
568 return -1;
569 }
570 txrx->totalpos -= txrx->filepos;
571 txrx->totalpos += dw1;
572 txrx->filepos = dw1;
573 break;
574 case EVTL2M_FILE_END: /* End */
575 /* Signature: "cc" -- DIRECTION,REASON */
576 if(line->phase != SESS_PHASE_INPROCESS) {
577 evt_out_of_sequence(evt);
578 return -1;
579 }
580 if(1!=unpack_ipc_packet(evt->data,evt.fulllength,"cc",&c1,&c2)) {
581 evt_not_unpack(evt);
582 return -1;
583 }
584 if(!(txrx = get_txrx_state(line,c1))) return -1;
585 if(txrx->phase != TXRX_PHASE_LOOP) {
586 evt_out_of_sequence(evt);
587 return -1;
588 }
589 txrx->filephase = TXRX_FILE_EOF;
590 txrx->lastfilestat = c2;
591 break;
592 case EVTL2M_CHAT_INIT: /* Remote request for chat */
593 /* Signature: "" */
594
595 break;
596 case EVTL2M_CHAT_LINE: /* Chat string received */
597 /* Signature: "s" -- LINE */
598 break;
599 case EVTL2M_CHAT_CLOSE: /* Remote close chat */
600 /* Signature: "" */
601 break;
602 case EVTL2M_SLINE: /* Status line */
603 /* Signature: "s" -- LINE */
604 break;
605 case EVTL2M_LOG: /* Log string */
606 /* Signature: "s" -- LINE */
607 break;
608 default:
609 break;
610 }
611
612 return 0;
613 }
614
server_process_ui_event(uiclient_t * client,evtuam_t evt)615 int server_process_ui_event(uiclient_t *client, evtuam_t evt)
616 {
617 return 0;
618 }
619
server_dispatch_events(int usec)620 int server_dispatch_events(int usec)
621 {
622 struct sockaddr_in sa;
623 CHAR *buf;
624 fd_set rfds, efds;
625 struct timeval tv;
626 time_t st,ft;
627 int rc;
628 int ncl = 0;
629 uiclient_t *uic, *uic_tmp;
630 evtlam_t *levt;
631 evtuam_t *cevt;
632 linestate_t *line;
633
634
635 ft = time(NULL);
636 do {
637 st = ft;
638 FD_ZERO(&rfds);
639 FD_ZERO(&efds);
640 FD_SET(line_socket,&rfds);
641 FD_SET(client_socket,&rfds);
642 FD_SET(line_socket,&efds);
643 FD_SET(client_socket,&efds);
644
645 uic = (uiclient_t*)clients->head;
646 ncl = 0;
647 while(uic) {
648 ncl++;
649 FD_SET(uic->socket,&rfds);
650 FD_SET(uic->socket,&efds);
651 uic = uic->next;
652 }
653
654 tv.tv_sec = usec / 1000;
655 tv.tv_usec = usec % 1000;
656 rc = select(2+ncl,&rfds,NULL,&efds,&tv);
657 if(rc<0) return -1;
658 if(!rc) return 0;
659
660 /* Here is event from line */
661 if(FD_ISSET(rfds,line_socket)) {
662 levt = (evtlam_t*)receive_ipc_packet_udp(line_socket,&sa);
663 if(levt) {
664 UINT32 pid = levt->pid;
665 levt->pid = FETCH32(((BYTE*)&pid));
666 if(!levt->tty[0]) {
667 /* Find TCP line, andd new one if it is needed */
668 line = al_finda(ip_lines,levt->pid,NULL);
669 } else {
670 /* Find TTY line, add new one if it is needed */
671 line = al_finda(tty_lines,levt->tty,&rc);
672 if(!rc)
673 write_log("Strange: request from not-configured TTY line '%16s'",levt->tty);
674 }
675 server_process_line_event(line,levt,&sa);
676 xfree(levt);
677 }
678 }
679 /* Here is request for new client connection */
680 if(FD_ISSET(rfds,line_socket)) {
681 uic = xmalloc(sizeof(*uic));
682 if(uic) {
683 uic->socket = accept(client_socket,(struct sockaddr*)&sa,sizeof(sa));
684 if(uic->socket != -1) al_toend(clients,(al_item_t*)uic);
685 else xfree(uic);
686 }
687 }
688
689 /* Check all clients */
690 uic = (uiclient_t*)clients->head;
691 while(uic) {
692 if(FD_ISSET(efds,uic->socket)) { /* Error? Delete then this one */
693 uic_tmp = uic;
694 uic = uic->next;
695 server_delete_client(uic_tmp);
696 } else if(FD_ISSET(rfds,uic->socket)) { /* Process request */
697 cevt = (evtuam_t*)receive_ipc_packet_tcp(uic->socket);
698 if(cevt) {
699 server_process_ui_event(uic,cevt);
700 xfree(cevt);
701 }
702 uic = uic->next;
703 } else {
704 uic = uic->next;
705 }
706 }
707 /* Change process time */
708 ft = time(NULL);
709 usec -= (ft - st) * 1000;
710 } while(usec > 0);
711 return 0;
712 }
713
714