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