ia64/xen-unstable

view tools/xcs/xcs.c @ 3966:0b9ff7354a95

bitkeeper revision 1.1236.1.47 (4225ff68LvKUt73k78dKjnXxsnQt7A)

Fix tools build. Clean up barrier defs.
Signed-off-by: Jerone Young <jyoung5@us.ibm.com>
Signed-off-by: Keir Fraser <keir.fraser@cl.cam.ac.uk>
author kaf24@scramble.cl.cam.ac.uk
date Wed Mar 02 18:01:12 2005 +0000 (2005-03-02)
parents 09c70b5f2e07
children 24703bde489b 2101e98387dd
line source
1 /* xcs.c
2 *
3 * xcs - Xen Control Switch
4 *
5 * Copyright (c) 2004, Andrew Warfield
6 */
8 /*
10 Things we need to select on in xcs:
12 1. Events arriving on /dev/evtchn
14 These will kick a function to read everything off the fd, and scan the
15 associated control message rings, resulting in notifications sent on
16 data channels to connected clients.
18 2. New TCP connections on XCS_PORT.
20 These will either be control (intially) or associated data connections.
22 Control connections will instantiate or rebind to an existing connnection
23 struct. The control channel is used to configure what events will be
24 received on an associated data channel. These two channels are split
25 out because the control channel is synchronous, all messages will return
26 a result from XCS. The data channel is effectively asynchronous, events
27 may arrive in the middle of a control message exchange. Additionally,
28 Having two TCP connections allows the client side to have a blocking
29 listen loop for data messages, while independently interacting on the
30 control channel at other places in the code.
32 Data connections attach to an existing control struct, using a session
33 id that is passed during the control connect. There is currently a
34 one-to-one relationship between data and control channels, but there
35 could just as easily be many data channels, if there were a set of
36 clients with identical interests, or if you wanted to trace an existing
37 client's data traffic.
39 3. Messages arriving on open TCP connections.
40 There are three types of open connections:
42 3a. Messages arriving on open control channel file descriptors.
44 [description of the control protocol here]
46 3b. Messages arriving on open data channel file descriptors.
48 [description of the data protocol here]
50 3c. Messages arriving on (new) unbound connections.
52 A connection must issue a XCS_CONNECT message to specify what
53 it is, after which the connection is moved into one of the above
54 two groups.
56 Additionally, we need a periodic timer to do housekeeping.
58 4. Every XCS_GC_INTERVAL seconds, we need to clean up outstanding state.
59 Specifically, we garbage collect any sessions (connection_t structs)
60 that have been unconnected for a period of time (XCS_SESSION_TIMEOUT),
61 and close any connections that have been openned, but not connected
62 as a control or data connection (XCS_UFD_TIMEOUT).
64 */
66 #include <stdlib.h>
67 #include <stdio.h>
68 #include <unistd.h>
69 #include <sys/time.h>
70 #include <sys/types.h>
71 #include <string.h>
72 #include <signal.h>
73 #include <sys/socket.h>
74 #include <sys/un.h>
75 #include <errno.h>
76 #include <malloc.h>
77 #include <fcntl.h>
78 #include "xcs.h"
80 #undef fd_max
81 #define fd_max(x,y) ((x) > (y) ? (x) : (y))
83 /* ------[ Control channel interfaces ]------------------------------------*/
85 static control_channel_t *cc_list[NR_EVENT_CHANNELS];
86 static int *dom_port_map = 0;
87 static int dom_port_map_size = 0;
89 static void map_dom_to_port(u32 dom, int port)
90 {
91 if (dom >= dom_port_map_size) {
92 dom_port_map = (int *)realloc(dom_port_map,
93 (dom + 256) * sizeof(dom_port_map[0]));
95 if (dom_port_map == NULL) {
96 perror("realloc(dom_port_map)");
97 exit(1);
98 }
100 for (; dom_port_map_size < dom + 10; dom_port_map_size++) {
101 dom_port_map[dom_port_map_size] = -1;
102 }
103 }
105 dom_port_map[dom] = port;
106 }
108 static int dom_to_port(u32 dom)
109 {
110 if (dom >= dom_port_map_size) return -1;
112 return dom_port_map[dom];
113 }
115 static void init_interfaces(void)
116 {
117 memset(cc_list, 0, sizeof cc_list);
118 }
120 static control_channel_t *add_interface(u32 dom, int local_port,
121 int remote_port)
122 {
123 control_channel_t *cc=NULL, *oldcc;
124 int ret;
126 if (cc_list[dom_to_port(dom)] != NULL)
127 {
128 return(cc_list[dom_to_port(dom)]);
129 }
131 if (cc_list[local_port] == NULL)
132 {
133 cc = ctrl_chan_new(dom, local_port, remote_port);
134 }
136 if (cc == NULL)
137 return NULL;
139 DPRINTF("added a new interface: dom: %u (l:%d,r:%d): %p\n",
140 dom, local_port, remote_port, cc);
141 DPRINTF("added a new interface: dom: %u (l:%d,r:%d): %p\n",
142 dom, cc->local_port, cc->remote_port, cc);
144 if ((ret = evtchn_bind(cc->local_port)) != 0)
145 {
146 DPRINTF("Got control interface, but couldn't bind evtchan!(%d)\n", ret);
147 ctrl_chan_free(cc);
148 return NULL;
149 }
151 if ( cc_list[cc->local_port] != NULL )
152 {
153 oldcc = cc_list[cc->local_port];
155 if ((oldcc->remote_dom != cc->remote_dom) ||
156 (oldcc->remote_port != cc->remote_port))
157 {
158 DPRINTF("CC conflict! (port: %d, old dom: %u, new dom: %u)\n",
159 cc->local_port, oldcc->remote_dom, cc->remote_dom);
160 map_dom_to_port(oldcc->remote_dom, -1);
161 ctrl_chan_free(cc_list[cc->local_port]);
162 }
163 }
165 cc_list[cc->local_port] = cc;
166 map_dom_to_port(cc->remote_dom, cc->local_port);
167 cc->type = CC_TYPE_INTERDOMAIN;
168 cc->ref_count = 0;
169 return cc;
170 }
172 control_channel_t *add_virq(int virq)
173 {
174 control_channel_t *cc;
175 int virq_port;
177 if (ctrl_chan_bind_virq(virq, &virq_port) == -1)
178 return NULL;
180 if ((cc_list[virq_port] != NULL) &&
181 (cc_list[virq_port]->type != CC_TYPE_VIRQ))
182 return NULL;
184 if ((cc_list[virq_port] != NULL) &&
185 (cc_list[virq_port]->type == CC_TYPE_VIRQ))
186 return cc_list[virq_port];
188 cc = (control_channel_t *)malloc(sizeof(control_channel_t));
189 if ( cc == NULL ) return NULL;
191 cc->type = CC_TYPE_VIRQ;
192 cc->local_port = virq_port;
193 cc->virq = virq;
195 return cc;
196 }
198 void get_interface(control_channel_t *cc)
199 {
200 if (cc != NULL)
201 cc->ref_count++;
202 }
204 void put_interface(control_channel_t *cc)
205 {
206 if (cc != NULL)
207 {
208 cc->ref_count--;
209 if (cc->ref_count <= 0)
210 {
211 DPRINTF("Freeing cc on port %d.\n", cc->local_port);
212 (void)evtchn_unbind(cc->local_port);
213 ctrl_chan_free(cc);
214 }
215 }
216 }
218 /* ------[ Simple helpers ]------------------------------------------------*/
220 /* listen_socket() is straight from paul sheer's useful select_tut manpage. */
221 static int listen_socket (char *listen_path)
222 {
223 struct sockaddr_un a;
224 int s;
225 int yes;
227 if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
228 {
229 perror ("socket");
230 return -1;
231 }
233 yes = 1;
235 memset (&a, 0, sizeof (a));
236 a.sun_family = AF_UNIX;
237 strcpy(a.sun_path, listen_path);
239 /* remove an old socket if it exists. */
240 unlink(listen_path);
242 if (bind(s, (struct sockaddr *) &a, sizeof (a)) < 0)
243 {
244 perror ("bind");
245 close (s);
246 return -1;
247 }
248 printf ("accepting connections on path %s\n", listen_path);
249 listen (s, 10);
250 return s;
251 }
253 /* ------[ Message handlers ]----------------------------------------------*/
255 #define NO_CHANGE 0
256 #define CONNECTED 1
257 #define DISCONNECTED 2
258 int handle_connect_msg( xcs_msg_t *msg, int fd )
259 {
260 xcs_connect_msg_t *cmsg = &msg->u.connect;
261 connection_t *con;
262 int ret = NO_CHANGE;
264 switch (msg->type)
265 {
266 case XCS_CONNECT_CTRL:
267 {
268 if ( cmsg->session_id == 0 )
269 {
270 con = connection_new();
271 if ( con == NULL)
272 {
273 msg->result = XCS_RSLT_FAILED;
274 break;
275 }
276 msg->result = XCS_RSLT_OK;
277 cmsg->session_id = con->id;
278 con->ctrl_fd = fd;
279 ret = CONNECTED;
280 DPRINTF("New control connection\n");
281 break;
282 }
284 con = get_con_by_session(cmsg->session_id);
285 if ( con == NULL )
286 {
287 msg->result = XCS_RSLT_BADSESSION;
288 break;
289 }
290 if ( con->ctrl_fd != -1 )
291 {
292 msg->result = XCS_RSLT_CONINUSE;
293 break;
294 }
295 con->ctrl_fd = fd;
296 msg->result = XCS_RSLT_OK;
297 ret = CONNECTED;
298 DPRINTF("Rebound to control connection\n");
299 break;
300 }
301 case XCS_CONNECT_DATA:
302 {
303 con = get_con_by_session(cmsg->session_id);
304 if ( con == NULL )
305 {
306 msg->result = XCS_RSLT_BADSESSION;
307 break;
308 }
309 if ( con->data_fd != -1 )
310 {
311 msg->result = XCS_RSLT_CONINUSE;
312 break;
313 }
314 con->data_fd = fd;
315 msg->result = XCS_RSLT_OK;
316 ret = CONNECTED;
317 DPRINTF("Attached data connection\n");
318 break;
320 }
321 case XCS_CONNECT_BYE:
322 {
323 close ( fd );
324 ret = DISCONNECTED;
325 break;
326 }
327 }
329 return ret;
330 }
332 int handle_control_message( connection_t *con, xcs_msg_t *msg )
333 {
334 int ret;
335 int reply_needed = 1;
337 DPRINTF("Got message, type %u.\n", msg->type);
339 switch (msg->type)
340 {
341 case XCS_MSG_BIND:
342 {
343 xcs_bind_msg_t *bmsg = &msg->u.bind;
345 if ( ! BIND_MSG_VALID(bmsg) )
346 {
347 msg->result = XCS_RSLT_BADREQUEST;
348 break;
349 }
351 ret = xcs_bind(con, bmsg->port, bmsg->type);
352 if (ret == 0) {
353 msg->result = XCS_RSLT_OK;
354 } else {
355 msg->result = XCS_RSLT_FAILED;
356 }
357 break;
358 }
359 case XCS_MSG_UNBIND:
360 {
361 xcs_bind_msg_t *bmsg = &msg->u.bind;
363 if ( ! BIND_MSG_VALID(bmsg) )
364 {
365 msg->result = XCS_RSLT_BADREQUEST;
366 break;
367 }
369 ret = xcs_unbind(con, bmsg->port, bmsg->type);
370 if (ret == 0) {
371 msg->result = XCS_RSLT_OK;
372 } else {
373 msg->result = XCS_RSLT_FAILED;
374 }
375 break;
376 }
377 case XCS_VIRQ_BIND:
378 {
379 control_channel_t *cc;
380 xcs_virq_msg_t *vmsg = &msg->u.virq;
381 if ( ! VIRQ_MSG_VALID(vmsg) )
382 {
383 msg->result = XCS_RSLT_BADREQUEST;
384 break;
385 }
387 cc = add_virq(vmsg->virq);
388 if (cc == NULL)
389 {
390 msg->result = XCS_RSLT_FAILED;
391 break;
392 }
393 ret = xcs_bind(con, cc->local_port, TYPE_VIRQ);
394 if (ret == 0) {
395 vmsg->port = cc->local_port;
396 msg->result = XCS_RSLT_OK;
397 } else {
398 msg->result = XCS_RSLT_FAILED;
399 }
400 break;
401 }
403 case XCS_CIF_NEW_CC:
404 {
405 control_channel_t *cc;
406 xcs_interface_msg_t *imsg = &msg->u.interface;
408 if ( ! INTERFACE_MSG_VALID(imsg) )
409 {
410 msg->result = XCS_RSLT_BADREQUEST;
411 break;
412 }
414 cc = add_interface(imsg->dom, imsg->local_port, imsg->remote_port);
415 if (cc != NULL) {
416 get_interface(cc);
417 msg->result = XCS_RSLT_OK;
418 imsg->local_port = cc->local_port;
419 imsg->remote_port = cc->remote_port;
420 } else {
421 msg->result = XCS_RSLT_FAILED;
422 }
423 break;
424 }
426 case XCS_CIF_FREE_CC:
427 {
428 control_channel_t *cc;
429 xcs_interface_msg_t *imsg = &msg->u.interface;
431 if ( ! INTERFACE_MSG_VALID(imsg) )
432 {
433 msg->result = XCS_RSLT_BADREQUEST;
434 break;
435 }
437 cc = add_interface(imsg->dom, imsg->local_port, imsg->remote_port);
438 if (cc != NULL) {
439 put_interface(cc);
440 }
441 msg->result = XCS_RSLT_OK;
442 break;
443 }
444 }
445 return reply_needed;
446 }
448 void handle_data_message( connection_t *con, xcs_msg_t *msg )
449 {
450 control_channel_t *cc;
451 xcs_control_msg_t *cmsg = &msg->u.control;
452 int port;
454 switch (msg->type)
455 {
456 case XCS_REQUEST:
457 if ( cmsg->remote_dom > MAX_DOMS )
458 break;
460 port = dom_to_port(cmsg->remote_dom);
461 if (port == -1) break;
462 cc = cc_list[port];
463 if ((cc != NULL) && ( cc->type == CC_TYPE_INTERDOMAIN ))
464 {
465 DPRINTF("DN:REQ: dom:%d port: %d type: %d\n",
466 cc->remote_dom, cc->local_port,
467 cmsg->msg.type);
468 ctrl_chan_write_request(cc, cmsg);
469 ctrl_chan_notify(cc);
470 } else {
471 DPRINTF("tried to send a REQ to a null cc\n.");
472 }
473 break;
475 case XCS_RESPONSE:
476 if ( cmsg->remote_dom > MAX_DOMS )
477 break;
479 port = dom_to_port(cmsg->remote_dom);
480 if (port == -1) break;
481 cc = cc_list[port];
482 if ((cc != NULL) && ( cc->type == CC_TYPE_INTERDOMAIN ))
483 {
484 DPRINTF("DN:RSP: dom:%d port: %d type: %d\n",
485 cc->remote_dom, cc->local_port,
486 cmsg->msg.type);
487 ctrl_chan_write_response(cc, cmsg);
488 ctrl_chan_notify(cc);
489 }
490 break;
492 case XCS_VIRQ:
493 if ( !(PORT_VALID(cmsg->local_port)) )
494 break;
496 cc = cc_list[cmsg->local_port];
498 if ((cc != NULL) && ( cc->type == CC_TYPE_VIRQ ))
499 {
500 DPRINTF("DN:VIRQ: virq: %d port: %d\n",
501 cc->virq, cc->local_port);
502 ctrl_chan_notify(cc);
503 }
504 break;
505 }
506 }
508 /* ------[ Control interface handler ]-------------------------------------*/
510 /* passed as a function pointer to the lookup. */
511 void send_kmsg(connection_t *c, void *arg)
512 {
513 xcs_msg_t *msg = (xcs_msg_t *)arg;
515 DPRINTF(" -> CONNECTION %d\n", c->data_fd);
516 if (c->data_fd > 0)
517 {
518 send(c->data_fd, msg, sizeof(xcs_msg_t), 0);
519 }
520 }
522 int handle_ctrl_if(void)
523 {
524 control_channel_t *cc;
525 control_msg_t *msg;
526 xcs_msg_t kmsg;
527 int chan, ret;
529 DPRINTF("Event thread kicked!\n");
530 again:
531 while ((chan = evtchn_read()) > 0)
532 {
533 evtchn_unmask(chan);
534 cc = cc_list[chan];
535 if (cc_list[chan] == NULL) {
536 DPRINTF("event from unknown channel (%d)\n", chan);
537 continue;
538 }
540 if ( cc_list[chan]->type == CC_TYPE_VIRQ )
541 {
542 DPRINTF("UP:VIRQ: virq:%d port: %d\n",
543 cc->virq, cc->local_port);
544 kmsg.type = XCS_VIRQ;
545 kmsg.u.control.local_port = cc->local_port;
546 xcs_lookup(cc->local_port, TYPE_VIRQ, send_kmsg, &kmsg);
547 continue;
548 }
550 while (ctrl_chan_request_to_read(cc))
551 {
552 msg = &kmsg.u.control.msg;
553 kmsg.type = XCS_REQUEST;
554 kmsg.u.control.remote_dom = cc->remote_dom;
555 kmsg.u.control.local_port = cc->local_port;
556 ret = ctrl_chan_read_request(cc, &kmsg.u.control);
557 DPRINTF("UP:REQ: dom:%d port: %d type: %d len: %d\n",
558 cc->remote_dom, cc->local_port,
559 msg->type, msg->length);
560 if (ret == 0)
561 xcs_lookup(cc->local_port, msg->type, send_kmsg, &kmsg);
562 }
564 while (ctrl_chan_response_to_read(cc))
565 {
566 msg = &kmsg.u.control.msg;
567 kmsg.type = XCS_RESPONSE;
568 kmsg.u.control.remote_dom = cc->remote_dom;
569 kmsg.u.control.local_port = cc->local_port;
570 ret = ctrl_chan_read_response(cc, &kmsg.u.control);
571 DPRINTF("UP:RSP: dom:%d port: %d type: %d len: %d\n",
572 cc->remote_dom, cc->local_port,
573 msg->type, msg->length);
574 if (ret == 0)
575 xcs_lookup(cc->local_port, msg->type, send_kmsg, &kmsg);
576 }
577 }
579 if (chan == -EINTR)
580 goto again;
582 return chan;
583 }
586 /* ------[ Main xcs code / big select loop ]-------------------------------*/
589 typedef struct unbound_fd_st {
590 int fd;
591 struct timeval born;
592 struct unbound_fd_st *next;
593 } unbound_fd_t;
595 /* This makes ufd point to the next entry in the list, so need to *
596 * break/continue if called while iterating. */
597 void delete_ufd(unbound_fd_t **ufd)
598 {
599 unbound_fd_t *del_ufd;
601 del_ufd = *ufd;
602 *ufd = (*ufd)->next;
603 free( del_ufd );
604 }
606 void gc_ufd_list( unbound_fd_t **ufd )
607 {
608 struct timeval now, delta;
610 gettimeofday(&now, NULL);
612 while ( *ufd != NULL )
613 {
614 timersub(&now, &(*ufd)->born, &delta);
615 if (delta.tv_sec > XCS_UFD_TIMEOUT)
616 {
617 DPRINTF("GC-UFD: closing fd: %d\n", (*ufd)->fd);
618 close((*ufd)->fd);
619 delete_ufd(ufd);
620 continue;
621 }
622 ufd = &(*ufd)->next;
623 }
624 }
626 int main (int argc, char *argv[])
627 {
628 int listen_fd, evtchn_fd;
629 unbound_fd_t *unbound_fd_list = NULL, **ufd;
630 struct timeval timeout = { XCS_GC_INTERVAL, 0 };
631 connection_t **con;
633 /* Initialize xc and event connections. */
634 if (ctrl_chan_init() != 0)
635 {
636 printf("Couldn't open conneciton to libxc.\n");
637 exit(-1);
638 }
640 if ((evtchn_fd = evtchn_open()) < 0)
641 {
642 printf("Couldn't open event channel driver interface.\n");
643 exit(-1);
644 }
646 /* Initialize control interfaces, bindings. */
647 init_interfaces();
648 init_bindings();
650 listen_fd = listen_socket(XCS_SUN_PATH);
652 /* detach from our controlling tty so that a shell does hang waiting for
653 stopped jobs. */
654 /* we should use getopt() here */
656 if (!(argc == 2 && !strcmp(argv[1], "-i"))) {
657 pid_t pid = fork();
658 int fd;
660 if (pid == -1) {
661 perror("fork()");
662 } else if (pid) {
663 exit(0);
664 }
666 setsid();
667 close(2);
668 close(1);
669 close(0);
670 fd = open("/dev/null", O_RDWR);
671 dup(fd);
672 dup(fd);
673 }
675 for (;;)
676 {
677 int n = 0, ret;
678 fd_set rd, wr, er;
679 FD_ZERO ( &rd );
680 FD_ZERO ( &wr );
681 FD_ZERO ( &er );
683 /* TCP listen fd: */
684 FD_SET ( listen_fd, &rd );
685 n = fd_max ( n, listen_fd );
687 /* Evtchn fd: */
688 FD_SET ( evtchn_fd, &rd );
689 n = fd_max ( n, evtchn_fd );
691 /* unbound connection fds: */
692 ufd = &unbound_fd_list;
693 while ((*ufd) != NULL)
694 {
695 FD_SET ( (*ufd)->fd, &rd );
696 n = fd_max ( n, (*ufd)->fd );
697 ufd = &(*ufd)->next;
698 }
700 /* control and data fds: */
701 con = &connection_list;
702 while ((*con) != NULL)
703 {
704 if ((*con)->ctrl_fd > 0)
705 {
706 FD_SET ( (*con)->ctrl_fd, &rd );
707 n = fd_max ( n, (*con)->ctrl_fd );
708 }
709 if ((*con)->data_fd > 0)
710 {
711 FD_SET ( (*con)->data_fd, &rd );
712 n = fd_max ( n, (*con)->data_fd );
713 }
714 con = &(*con)->next;
715 }
717 ret = select ( n + 1, &rd, &wr, &er, &timeout );
719 if ( (timeout.tv_sec == 0) && (timeout.tv_usec == 0) )
720 {
721 gc_ufd_list(&unbound_fd_list);
722 gc_connection_list();
723 timeout.tv_sec = XCS_GC_INTERVAL;
724 }
726 if ( (ret == -1) && (errno == EINTR) )
727 continue;
728 if ( ret < 0 )
729 {
730 perror ("select()");
731 exit(-1);
732 }
734 /* CASE 1: Events arriving on /dev/evtchn. */
736 if ( FD_ISSET (evtchn_fd, &rd ))
737 handle_ctrl_if();
739 /* CASE 2: New connection on the listen port. */
740 if ( FD_ISSET ( listen_fd, &rd ))
741 {
742 struct sockaddr_un remote_addr;
743 int size;
744 memset (&remote_addr, 0, sizeof (remote_addr));
745 size = sizeof remote_addr;
746 ret = accept(listen_fd, (struct sockaddr *)&remote_addr, &size);
747 if ( ret < 0 )
748 {
749 perror("accept()");
750 } else {
751 unbound_fd_t *new_ufd;
753 new_ufd = (unbound_fd_t *)malloc(sizeof(*new_ufd));
755 if (new_ufd != NULL)
756 {
757 gettimeofday(&new_ufd->born, NULL);
758 new_ufd->fd = ret;
759 new_ufd->next = unbound_fd_list;
760 unbound_fd_list = new_ufd;
761 } else {
762 perror("malloc unbound connection");
763 close(ret);
764 }
765 }
766 }
768 /* CASE 3a: Handle messages on control connections. */
770 con = &connection_list;
771 while ( *con != NULL )
772 {
773 if ( ((*con)->ctrl_fd > 0) && (FD_ISSET((*con)->ctrl_fd, &rd)) )
774 {
775 xcs_msg_t msg;
776 memset (&msg, 0, sizeof(msg));
777 ret = read( (*con)->ctrl_fd, &msg, sizeof(msg) );
779 if ( ret < 0 )
780 {
781 perror("reading ctrl fd.");
782 } else if ( ret == 0 )
783 {
784 DPRINTF("Control connection dropped.\n");
785 close ( (*con)->ctrl_fd );
786 (*con)->ctrl_fd = -1;
787 gettimeofday(&(*con)->disconnect_time, NULL);
788 } else
789 {
790 if ( ret != sizeof(msg) )
791 {
792 DPRINTF("Unexpected frame size!\n");
793 continue;
794 }
796 ret = handle_control_message( *con, &msg );
798 if ( ret == 1 )
799 send( (*con)->ctrl_fd, &msg, sizeof(msg), 0 );
800 }
801 }
802 con = &(*con)->next;
803 }
805 /* CASE 3b: Handle messages on data connections. */
807 con = &connection_list;
808 while ( *con != NULL )
809 {
810 if ( ((*con)->data_fd > 0) && (FD_ISSET((*con)->data_fd, &rd)) )
811 {
812 xcs_msg_t msg;
813 memset (&msg, 0, sizeof(msg));
814 ret = read( (*con)->data_fd, &msg, sizeof(msg) );
816 if ( ret < 0 )
817 {
818 perror("reading data fd.");
819 } else if ( ret == 0 )
820 {
821 DPRINTF("Data connection dropped.\n");
822 close ( (*con)->data_fd );
823 (*con)->data_fd = -1;
824 gettimeofday(&(*con)->disconnect_time, NULL);
825 } else
826 {
827 if ( ret != sizeof(msg) )
828 {
829 DPRINTF("Unexpected frame size!\n");
830 continue;
831 }
833 handle_data_message( *con, &msg );
834 }
835 }
836 con = &(*con)->next;
837 }
839 /* CASE 3c: Handle messages arriving on unbound connections. */
840 ufd = &unbound_fd_list;
841 while ((*ufd) != NULL)
842 {
843 if ( FD_ISSET( (*ufd)->fd, &rd ) )
844 {
845 xcs_msg_t msg;
846 memset (&msg, 0, sizeof(msg));
847 ret = read( (*ufd)->fd, &msg, sizeof(msg) );
849 if ( ret == 0 )
850 {
851 close ( (*ufd)->fd );
852 delete_ufd(ufd);
853 continue; /* we just advanced ufd */
854 } else {
855 if ( ret != sizeof(msg) )
856 {
857 DPRINTF("Unexpected frame size!\n");
858 continue;
859 }
861 ret = handle_connect_msg( &msg, (*ufd)->fd );
863 if ( (ret == CONNECTED) || (ret == NO_CHANGE) )
864 send( (*ufd)->fd, &msg, sizeof(msg), 0 );
866 if ( (ret = CONNECTED) || (ret = DISCONNECTED) )
867 {
868 delete_ufd( ufd );
869 continue;
870 }
871 }
872 }
873 ufd = &(*ufd)->next;
874 }
875 }
876 }