2 * Copyright (c) 1998,1999,2000
3 * Traakan, Inc., Los Altos, CA
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice unmodified, this list of conditions, and the following
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * ndmis_connect_status transitions
38 * Event relative to ------ before ------ ------ after -------
39 * "mine" end point MINE PEER REMO MINE PEER REMO
40 * ====================================================================
41 * LISTEN/LOCAL IDLE IDLE IDLE LISTEN IDLE EXCLUDE
42 * LISTEN/TCP IDLE IDLE IDLE LISTEN REMOTE LISTEN
44 * CONNECT/LOCAL IDLE LISTEN EXCLUDE CONN'ED ACC'ED EXCLUDE
45 * CONNECT/TCP IDLE IDLE IDLE CONN'ED REMOTE CONN'ED
47 * tcp_accept() LISTEN REMOTE LISTEN ACC'ED REMOTE ACC'ED
54 END ========== LOCAL ============ END
62 #include "ndmagents.h"
66 ndmis_reinit_remote (struct ndm_session *sess)
68 struct ndm_image_stream *is = &sess->plumb.image_stream;
70 NDMOS_MACRO_ZEROFILL(&is->remote);
72 ndmchan_initialize (&is->remote.listen_chan, "image-stream-listen");
73 ndmchan_initialize (&is->remote.sanity_chan, "image-stream-sanity");
74 ndmchan_initialize (&is->chan, "image-stream");
75 ndmchan_setbuf (&is->chan, is->buf, sizeof is->buf);
82 * Initialization and Cleanup
83 ****************************************************************
86 /* Initialize -- Set data structure to know value, ignore current value */
88 ndmis_initialize (struct ndm_session *sess)
90 struct ndm_image_stream *is = &sess->plumb.image_stream;
92 NDMOS_MACRO_ZEROFILL(is);
93 NDMOS_MACRO_ZEROFILL (&is->chan);
95 ndmis_reinit_remote (sess);
97 is->data_ep.name = "DATA";
98 is->tape_ep.name = "TAPE";
104 /* Commission -- Get agent ready. Entire session has been initialize()d */
106 ndmis_commission (struct ndm_session *sess)
111 /* Decommission -- Discard agent */
113 ndmis_decommission (struct ndm_session *sess)
118 /* Belay -- Cancel partially issued activation/start */
120 ndmis_belay (struct ndm_session *sess)
129 * Semantic actions -- called from ndma_dispatch()
130 ****************************************************************
134 ndmis_audit_data_listen (struct ndm_session *sess,
135 ndmp9_addr_type addr_type, char *reason)
137 struct ndm_image_stream *is = &sess->plumb.image_stream;
138 struct ndmis_end_point *mine_ep = &is->data_ep;
139 struct ndmis_end_point *peer_ep = &is->tape_ep;
141 return ndmis_audit_ep_listen (sess, addr_type, reason,
146 ndmis_audit_tape_listen (struct ndm_session *sess,
147 ndmp9_addr_type addr_type, char *reason)
149 struct ndm_image_stream *is = &sess->plumb.image_stream;
150 struct ndmis_end_point *mine_ep = &is->tape_ep;
151 struct ndmis_end_point *peer_ep = &is->data_ep;
153 return ndmis_audit_ep_listen (sess, addr_type, reason,
158 ndmis_audit_data_connect (struct ndm_session *sess,
159 ndmp9_addr_type addr_type, char *reason)
161 struct ndm_image_stream *is = &sess->plumb.image_stream;
162 struct ndmis_end_point *mine_ep = &is->data_ep;
163 struct ndmis_end_point *peer_ep = &is->tape_ep;
165 return ndmis_audit_ep_connect (sess, addr_type, reason,
170 ndmis_audit_tape_connect (struct ndm_session *sess,
171 ndmp9_addr_type addr_type, char *reason)
173 struct ndm_image_stream *is = &sess->plumb.image_stream;
174 struct ndmis_end_point *mine_ep = &is->tape_ep;
175 struct ndmis_end_point *peer_ep = &is->data_ep;
177 return ndmis_audit_ep_connect (sess, addr_type, reason,
182 ndmis_data_listen (struct ndm_session *sess,
183 ndmp9_addr_type addr_type, ndmp9_addr *ret_addr, char *reason)
185 struct ndm_image_stream *is = &sess->plumb.image_stream;
186 struct ndmis_end_point *mine_ep = &is->data_ep;
187 struct ndmis_end_point *peer_ep = &is->tape_ep;
189 return ndmis_ep_listen (sess, addr_type, ret_addr, reason,
194 ndmis_tape_listen (struct ndm_session *sess,
195 ndmp9_addr_type addr_type, ndmp9_addr *ret_addr, char *reason)
197 struct ndm_image_stream *is = &sess->plumb.image_stream;
198 struct ndmis_end_point *mine_ep = &is->tape_ep;
199 struct ndmis_end_point *peer_ep = &is->data_ep;
201 return ndmis_ep_listen (sess, addr_type, ret_addr, reason,
206 ndmis_data_connect (struct ndm_session *sess,
207 ndmp9_addr *addr, char *reason)
209 struct ndm_image_stream *is = &sess->plumb.image_stream;
210 struct ndmis_end_point *mine_ep = &is->data_ep;
211 struct ndmis_end_point *peer_ep = &is->tape_ep;
214 error = ndmis_ep_connect (sess, addr, reason, mine_ep, peer_ep);
215 #ifndef NDMOS_OPTION_NO_TAPE_AGENT
216 if (error == NDMP9_NO_ERR) {
217 if (peer_ep->connect_status == NDMIS_CONN_ACCEPTED
218 && peer_ep->addr_type == NDMP9_ADDR_LOCAL) {
219 ndmta_quantum (sess);
222 #endif /* !NDMOS_OPTION_NO_TAPE_AGENT */
227 ndmis_tape_connect (struct ndm_session *sess,
228 ndmp9_addr *addr, char *reason)
230 struct ndm_image_stream *is = &sess->plumb.image_stream;
231 struct ndmis_end_point *mine_ep = &is->tape_ep;
232 struct ndmis_end_point *peer_ep = &is->data_ep;
234 return ndmis_ep_connect (sess, addr, reason, mine_ep, peer_ep);
238 ndmis_ep_start (struct ndm_session *sess, int chan_mode,
239 struct ndmis_end_point *mine_ep, struct ndmis_end_point *peer_ep)
241 struct ndm_image_stream *is = &sess->plumb.image_stream;
243 if (mine_ep->connect_status != NDMIS_CONN_CONNECTED
244 && mine_ep->connect_status != NDMIS_CONN_ACCEPTED) {
248 if (mine_ep->transfer_mode != NDMCHAN_MODE_IDLE) {
252 if (mine_ep->addr_type == NDMP9_ADDR_LOCAL) {
253 ndmchan_start_resident (&is->chan);
254 if (chan_mode == NDMCHAN_MODE_WRITE) {
255 peer_ep->transfer_mode = NDMCHAN_MODE_READ;
257 peer_ep->transfer_mode = NDMCHAN_MODE_WRITE;
259 } else if (chan_mode == NDMCHAN_MODE_WRITE) {
260 ndmchan_pending_to_write (&is->chan);
261 } else if (chan_mode == NDMCHAN_MODE_READ) {
262 ndmchan_pending_to_read (&is->chan);
267 mine_ep->transfer_mode = chan_mode;
273 ndmis_data_start (struct ndm_session *sess, int chan_mode)
275 struct ndm_image_stream *is = &sess->plumb.image_stream;
276 struct ndmis_end_point *mine_ep = &is->data_ep;
277 struct ndmis_end_point *peer_ep = &is->tape_ep;
279 return ndmis_ep_start (sess, chan_mode, mine_ep, peer_ep);
283 ndmis_tape_start (struct ndm_session *sess, int chan_mode)
285 struct ndm_image_stream *is = &sess->plumb.image_stream;
286 struct ndmis_end_point *mine_ep = &is->tape_ep;
287 struct ndmis_end_point *peer_ep = &is->data_ep;
289 return ndmis_ep_start (sess, chan_mode, mine_ep, peer_ep);
293 ndmis_data_close (struct ndm_session *sess)
295 struct ndm_image_stream *is = &sess->plumb.image_stream;
296 struct ndmis_end_point *mine_ep = &is->data_ep;
297 struct ndmis_end_point *peer_ep = &is->tape_ep;
299 return ndmis_ep_close (sess, mine_ep, peer_ep);
303 ndmis_tape_close (struct ndm_session *sess)
305 struct ndm_image_stream *is = &sess->plumb.image_stream;
306 struct ndmis_end_point *mine_ep = &is->tape_ep;
307 struct ndmis_end_point *peer_ep = &is->data_ep;
309 return ndmis_ep_close (sess, mine_ep, peer_ep);
316 * Quantum -- get a bit of work done
317 ****************************************************************
321 ndmis_quantum (struct ndm_session *sess)
323 struct ndm_image_stream *is = &sess->plumb.image_stream;
324 struct ndmis_end_point *mine_ep;
327 if (is->remote.connect_status != NDMIS_CONN_LISTEN)
328 return 0; /* did nothing */
330 if (!is->remote.listen_chan.ready)
331 return 0; /* did nothing */
333 /* now this is going to get hard */
335 if (is->data_ep.connect_status == NDMIS_CONN_LISTEN) {
336 mine_ep = &is->data_ep;
337 /* assert (is->tape_ep.connect_status == NDMIS_CONN_REMOTE); */
338 } else if (is->tape_ep.connect_status == NDMIS_CONN_LISTEN) {
339 mine_ep = &is->tape_ep;
340 /* assert (is->data_ep.connect_status == NDMIS_CONN_REMOTE); */
346 rc = ndmis_tcp_accept (sess);
348 mine_ep->connect_status = NDMIS_CONN_ACCEPTED;
349 is->remote.connect_status = NDMIS_CONN_ACCEPTED;
351 mine_ep->connect_status = NDMIS_CONN_BOTCHED;
352 is->remote.connect_status = NDMIS_CONN_BOTCHED;
355 return 1; /* did something */
362 * ndmis_end_point oriented helper routines
363 ****************************************************************
367 ndmis_audit_ep_listen (
368 struct ndm_session *sess,
369 ndmp9_addr_type addr_type,
371 struct ndmis_end_point *mine_ep,
372 struct ndmis_end_point *peer_ep)
374 ndmp9_error error = NDMP9_NO_ERR;
377 sprintf (reason, "IS %s_LISTEN: ", mine_ep->name);
379 while (*reason_end) reason_end++;
381 if (mine_ep->connect_status != NDMIS_CONN_IDLE) {
382 sprintf (reason_end, "%s not idle", mine_ep->name);
383 error = NDMP9_ILLEGAL_STATE_ERR;
386 if (peer_ep->connect_status != NDMIS_CONN_IDLE) {
387 sprintf (reason_end, "%s not idle", peer_ep->name);
388 error = NDMP9_ILLEGAL_STATE_ERR;
393 case NDMP9_ADDR_LOCAL:
400 strcpy (reason_end, "unknown addr_type");
401 error = NDMP9_ILLEGAL_ARGS_ERR;
406 if (error == NDMP9_NO_ERR)
407 strcpy (reason_end, "OK");
409 ndmalogf (sess, 0, 2, "listen %s messy mcs=%d pcs=%d",
411 mine_ep->connect_status,
412 peer_ep->connect_status);
418 ndmis_audit_ep_connect (
419 struct ndm_session *sess,
420 ndmp9_addr_type addr_type,
422 struct ndmis_end_point *mine_ep,
423 struct ndmis_end_point *peer_ep)
425 ndmp9_error error = NDMP9_NO_ERR;
428 sprintf (reason, "IS %s_CONNECT: ", mine_ep->name);
430 while (*reason_end) reason_end++;
432 if (mine_ep->connect_status != NDMIS_CONN_IDLE) {
433 sprintf (reason_end, "%s not idle", mine_ep->name);
434 error = NDMP9_ILLEGAL_STATE_ERR;
439 case NDMP9_ADDR_LOCAL:
440 if (peer_ep->connect_status != NDMIS_CONN_LISTEN) {
441 sprintf (reason_end, "LOCAL %s not LISTEN",
443 error = NDMP9_ILLEGAL_STATE_ERR;
446 if (peer_ep->addr_type != NDMP9_ADDR_LOCAL) {
447 sprintf (reason_end, "LOCAL %s not LOCAL",
449 error = NDMP9_ILLEGAL_STATE_ERR;
455 if (peer_ep->connect_status != NDMIS_CONN_IDLE) {
456 sprintf (reason_end, "LOCAL %s not IDLE",
458 error = NDMP9_ILLEGAL_STATE_ERR;
464 strcpy (reason_end, "unknown addr_type");
465 error = NDMP9_ILLEGAL_ARGS_ERR;
470 if (error == NDMP9_NO_ERR)
471 strcpy (reason_end, "OK");
479 struct ndm_session *sess,
480 ndmp9_addr_type addr_type,
481 ndmp9_addr *ret_addr,
483 struct ndmis_end_point *mine_ep,
484 struct ndmis_end_point *peer_ep)
486 struct ndm_image_stream *is = &sess->plumb.image_stream;
490 error = ndmis_audit_ep_listen (sess, addr_type, reason,
492 if (error != NDMP9_NO_ERR)
496 while (*reason_end && *reason_end != ':') reason_end++;
497 *reason_end++ = ':'; *reason_end++ = ' '; *reason_end = 0;
499 NDMOS_MACRO_ZEROFILL (ret_addr);
500 ret_addr->addr_type = addr_type;
503 case NDMP9_ADDR_LOCAL:
504 mine_ep->addr_type = NDMP9_ADDR_LOCAL;
505 mine_ep->connect_status = NDMIS_CONN_LISTEN;
506 is->remote.connect_status = NDMIS_CONN_EXCLUDE;
510 if (ndmis_tcp_listen (sess, ret_addr) != 0) {
511 strcpy (reason_end, "TCP listen() failed");
512 error = NDMP9_CONNECT_ERR;
515 mine_ep->addr_type = NDMP9_ADDR_TCP;
516 mine_ep->connect_status = NDMIS_CONN_LISTEN;
517 peer_ep->connect_status = NDMIS_CONN_REMOTE;
521 reason = "unknown addr_type (bad)";
522 error = NDMP9_ILLEGAL_ARGS_ERR;
527 if (error == NDMP9_NO_ERR)
528 strcpy (reason_end, "OK");
535 struct ndm_session *sess,
538 struct ndmis_end_point *mine_ep,
539 struct ndmis_end_point *peer_ep)
541 struct ndm_image_stream *is = &sess->plumb.image_stream;
542 ndmp9_addr_type addr_type = addr->addr_type;
546 error = ndmis_audit_ep_connect (sess, addr_type, reason,
548 if (error != NDMP9_NO_ERR)
552 while (*reason_end && *reason_end != ':') reason_end++;
553 *reason_end++ = ':'; *reason_end++ = ' '; *reason_end = 0;
556 case NDMP9_ADDR_LOCAL:
557 mine_ep->addr_type = NDMP9_ADDR_LOCAL;
558 mine_ep->connect_status = NDMIS_CONN_CONNECTED;
559 peer_ep->connect_status = NDMIS_CONN_ACCEPTED;
560 is->remote.connect_status = NDMIS_CONN_EXCLUDE;
564 if (ndmis_tcp_connect (sess, addr) != 0) {
565 strcpy (reason_end, "TCP connect() failed");
566 error = NDMP9_CONNECT_ERR;
569 mine_ep->addr_type = NDMP9_ADDR_TCP;
570 mine_ep->connect_status = NDMIS_CONN_CONNECTED;
571 peer_ep->connect_status = NDMIS_CONN_REMOTE;
575 reason = "unknown addr_type (bad)";
576 error = NDMP9_ILLEGAL_ARGS_ERR;
585 ndmis_ep_close (struct ndm_session *sess,
586 struct ndmis_end_point *mine_ep, struct ndmis_end_point *peer_ep)
588 struct ndm_image_stream *is = &sess->plumb.image_stream;
589 char * save_name = mine_ep->name;
591 switch (mine_ep->connect_status) {
592 case NDMIS_CONN_IDLE:
595 case NDMIS_CONN_BOTCHED:
596 case NDMIS_CONN_REMOTE:
597 case NDMIS_CONN_EXCLUDE:
600 case NDMIS_CONN_LISTEN:
601 switch (mine_ep->addr_type) {
605 case NDMP9_ADDR_LOCAL:
606 ndmis_reinit_remote (sess);
607 if (peer_ep->connect_status != NDMIS_CONN_IDLE)
612 ndmis_tcp_close (sess);
613 if (peer_ep->connect_status != NDMIS_CONN_REMOTE)
615 peer_ep->connect_status = NDMIS_CONN_IDLE;
620 case NDMIS_CONN_ACCEPTED:
621 switch (mine_ep->addr_type) {
625 case NDMP9_ADDR_LOCAL:
626 if (peer_ep->connect_status != NDMIS_CONN_CONNECTED)
628 peer_ep->connect_status = NDMIS_CONN_DISCONNECTED;
630 if (mine_ep->transfer_mode == NDMCHAN_MODE_READ)
631 is->chan.error = 1; /* EPIPE */
635 ndmis_tcp_close (sess);
636 if (peer_ep->connect_status != NDMIS_CONN_REMOTE)
638 peer_ep->connect_status = NDMIS_CONN_IDLE;
643 case NDMIS_CONN_CONNECTED:
644 switch (mine_ep->addr_type) {
648 case NDMP9_ADDR_LOCAL:
649 if (peer_ep->connect_status != NDMIS_CONN_ACCEPTED)
651 peer_ep->connect_status = NDMIS_CONN_DISCONNECTED;
653 if (mine_ep->transfer_mode == NDMCHAN_MODE_READ)
654 is->chan.error = 1; /* EPIPE */
658 ndmis_tcp_close (sess);
659 if (peer_ep->connect_status != NDMIS_CONN_REMOTE)
661 peer_ep->connect_status = NDMIS_CONN_IDLE;
666 case NDMIS_CONN_DISCONNECTED: /* peer close()d first */
667 ndmis_reinit_remote (sess);
670 case NDMIS_CONN_CLOSED:
674 NDMOS_MACRO_ZEROFILL (mine_ep);
675 mine_ep->name = save_name;
680 ndmalogf (sess, 0, 2, "close %s messy mcs=%d pcs=%d",
682 mine_ep->connect_status,
683 peer_ep->connect_status);
684 NDMOS_MACRO_ZEROFILL (mine_ep);
685 mine_ep->name = save_name;
691 ndmis_ep_could_start (
692 struct ndm_session *sess,
693 int want_transfer_mode, /* NDMCHAN_MODE_{IDLE|READ|WRITE} */
695 struct ndmis_end_point *mine_ep,
696 struct ndmis_end_point *peer_ep)
698 ndmp9_error error = NDMP9_NO_ERR;
701 sprintf (reason, "IS %s_START: ", mine_ep->name);
703 while (*reason_end) reason_end++;
705 if (want_transfer_mode == NDMCHAN_MODE_IDLE)
706 want_transfer_mode = mine_ep->transfer_mode;
708 switch (want_transfer_mode) {
709 case NDMCHAN_MODE_IDLE:
710 /* can't check much */
713 case NDMCHAN_MODE_READ:
717 case NDMCHAN_MODE_WRITE:
722 strcpy (reason_end, "unknown chan_mode");
723 error = NDMP9_ILLEGAL_ARGS_ERR;
728 if (error == NDMP9_NO_ERR)
729 strcpy (reason_end, "OK");
739 * ADDR_TCP helper routines
740 ****************************************************************
747 * The tricky part of listen()ing is determining the IP
748 * address to offer, which ultimately will be used by
749 * the other (peer) side for connect()ing.
751 * We can't just bind() with INADDR_ANY (0's) because
752 * that results in a local socket with INADDR_ANY, and
753 * any inbound connection to the right port will be
754 * accept()ed by the networking system. That doesn't
755 * help us here, though, because we have to have a
756 * real IP address to offer. INADDR_ANY ain't sufficient.
758 * There is also the issue of systems with multiple
759 * network connections. We of course would like to
760 * use the network data link that is most advantageous
761 * on both sides. This may vary from job run to job
762 * run, and so any method of specifying just one
763 * is IP address ain't sufficient.
765 * The approach here uses the existing control connections,
766 * which normally precede the image stream connection,
767 * as cues for which IP address to use. So, for example,
768 * if a TAPE or DATA host has four network connections,
769 * the CONTROL agent can coax them to use a specific one
770 * of the four by connecting to the IP address of the
771 * network wanted for the image stream.
773 * If the clever rules don't work out, the fallback is to
774 * look up the host name. Right now we use ndmhost_lookup()
775 * of sess->local_info.host_name because both must work
776 * before things would progress to this point.
780 ndmis_tcp_listen (struct ndm_session *sess, struct ndmp9_addr *listen_addr)
782 struct ndm_image_stream *is = &sess->plumb.image_stream;
783 ndmp9_tcp_addr * tcp_addr = &listen_addr->ndmp9_addr_u.tcp_addr;
784 struct ndmconn * conn;
785 struct sockaddr c_sa;
786 struct sockaddr l_sa;
787 struct sockaddr_in * sin;
789 int listen_sock = -1;
793 * Get the IP address thru which the CONTROL agent connected
794 * to this session. The CONTROL agent may influence the
795 * network used for the image-stream on multi-homed hosts
796 * simply by connecting to the prefered IP address.
798 what = "determine-conn";
799 conn = sess->plumb.control;
800 if (!conn || conn->conn_type != NDMCONN_TYPE_REMOTE) {
802 * If CONTROL is resident, try the other
803 * control connections in hopes of finding
804 * a clue about what IP address to offer.
806 conn = sess->plumb.data;
807 if (!conn || conn->conn_type != NDMCONN_TYPE_REMOTE) {
808 conn = sess->plumb.tape;
809 if (!conn || conn->conn_type != NDMCONN_TYPE_REMOTE) {
817 * We found a connection to use for determining
818 * what IP address to offer.
820 what = "getsockname-ctrl";
822 if (getsockname (ndmconn_fileno(conn), &c_sa, &len) < 0) {
823 /* we'll try the fallback rules */
830 * For whatever reason, we can't determine a good
831 * IP address from the connections. Try the boring
834 ndmos_sync_config_info (sess);
836 sin = (struct sockaddr_in *) &c_sa;
838 what = "ndmhost_lookup";
839 if (ndmhost_lookup (sess->config_info.hostname, sin) != 0)
843 /* c_sa is a sockaddr_in for the IP address to use */
846 listen_sock = socket (AF_INET, SOCK_STREAM, 0);
847 if (listen_sock < 0) goto fail;
849 /* could bind() to more restrictive addr based on c_sa */
850 NDMOS_MACRO_SET_SOCKADDR(&l_sa, 0, 0);
852 if (bind (listen_sock, &l_sa, sizeof l_sa) < 0) goto fail;
855 if (listen (listen_sock, 1) < 0) goto fail;
857 ndmos_condition_listen_socket (sess, listen_sock);
860 what = "getsockname-listen";
862 if (getsockname (listen_sock, &l_sa, &len) < 0) goto fail;
865 * Fill in the return address
868 listen_addr->addr_type = NDMP9_ADDR_TCP;
869 tcp_addr = &listen_addr->ndmp9_addr_u.tcp_addr;
871 /* IP addr from CONTROL connection, or where ever c_sa came from */
872 sin = (struct sockaddr_in *) &c_sa;
873 tcp_addr->ip_addr = ntohl (sin->sin_addr.s_addr);
875 /* port from the bind() and getsockname() above */
876 sin = (struct sockaddr_in *) &l_sa;
877 tcp_addr->port = ntohs (sin->sin_port);
880 * Start the listen channel
883 ndmchan_start_listen (&is->remote.listen_chan, listen_sock);
885 is->remote.connect_status = NDMIS_CONN_LISTEN;
886 is->remote.listen_addr = *listen_addr;
891 ndmalogf (sess, 0, 2, "ndmis_tcp_listen(): %s failed", what);
892 if (listen_sock >= 0) close (listen_sock);
898 ndmis_tcp_accept (struct ndm_session *sess)
900 struct ndm_image_stream *is = &sess->plumb.image_stream;
902 ndmp9_tcp_addr * tcp_addr;
904 struct sockaddr_in * sin = (struct sockaddr_in *) &sa;
906 int accept_sock = -1;
908 what = "remote-conn-stat";
909 if (is->remote.connect_status != NDMIS_CONN_LISTEN)
912 what = "remote-list-ready";
913 if (!is->remote.listen_chan.ready)
918 accept_sock = accept (is->remote.listen_chan.fd, &sa, &len);
920 ndmchan_cleanup (&is->remote.listen_chan);
922 if (accept_sock < 0) {
923 is->remote.connect_status = NDMIS_CONN_BOTCHED;
927 /* write what we know, ndmis...addrs() will update if possible */
928 is->remote.peer_addr.addr_type = NDMP9_ADDR_TCP;
929 tcp_addr = &is->remote.peer_addr.ndmp9_addr_u.tcp_addr;
930 tcp_addr->ip_addr = ntohl (sin->sin_addr.s_addr);
931 tcp_addr->port = ntohs (sin->sin_port);
933 ndmis_tcp_green_light (sess, accept_sock, NDMIS_CONN_ACCEPTED);
938 ndmalogf (sess, 0, 2, "ndmis_tcp_accept(): %s failed", what);
939 if (accept_sock >= 0) close (accept_sock);
945 ndmis_tcp_connect (struct ndm_session *sess, struct ndmp9_addr *connect_addr)
947 struct ndm_image_stream *is = &sess->plumb.image_stream;
948 ndmp9_tcp_addr * tcp_addr=&connect_addr->ndmp9_addr_u.tcp_addr;
953 NDMOS_MACRO_SET_SOCKADDR (&sa, tcp_addr->ip_addr, tcp_addr->port);
956 connect_sock = socket (AF_INET, SOCK_STREAM, 0);
957 if (connect_sock < 0)
961 if (connect (connect_sock, &sa, sizeof sa) < 0)
965 /* write what we know, ndmis...addrs() will update if possible */
966 is->remote.peer_addr = *connect_addr;
968 ndmis_tcp_green_light (sess, connect_sock, NDMIS_CONN_CONNECTED);
973 ndmalogf (sess, 0, 2, "ndmis_tcp_connect(): %s failed", what);
974 if (connect_sock >= 0) close (connect_sock);
980 ndmis_tcp_green_light (struct ndm_session *sess, int sock,
981 ndmis_connect_status new_status)
983 struct ndm_image_stream *is = &sess->plumb.image_stream;
985 ndmos_condition_image_stream_socket (sess, sock);
987 ndmchan_start_pending (&is->chan, sock);
989 is->remote.connect_status = new_status;
991 ndmis_tcp_get_local_and_peer_addrs (sess);
997 ndmis_tcp_close (struct ndm_session *sess)
999 struct ndm_image_stream *is = &sess->plumb.image_stream;
1001 switch (is->remote.connect_status) {
1002 case NDMIS_CONN_LISTEN:
1003 ndmchan_cleanup (&is->remote.listen_chan);
1006 case NDMIS_CONN_CONNECTED:
1007 case NDMIS_CONN_ACCEPTED:
1008 ndmchan_cleanup (&is->chan);
1015 ndmis_reinit_remote (sess);
1021 ndmis_tcp_get_local_and_peer_addrs (struct ndm_session *sess)
1023 struct ndm_image_stream *is = &sess->plumb.image_stream;
1024 char * what = "???";
1026 struct sockaddr_in * sin = (struct sockaddr_in *) &sa;
1027 ndmp9_tcp_addr * tcp_addr;
1032 what = "getpeername";
1033 if (getpeername (is->chan.fd, &sa, &len) < 0) {
1034 /* this is best effort */
1035 ndmalogf (sess, 0, 2, "ndmis_tcp..._addrs(): %s failed", what);
1038 is->remote.peer_addr.addr_type = NDMP9_ADDR_TCP;
1039 tcp_addr = &is->remote.peer_addr.ndmp9_addr_u.tcp_addr;
1040 tcp_addr->ip_addr = ntohl (sin->sin_addr.s_addr);
1041 tcp_addr->port = ntohs (sin->sin_port);
1045 what = "getsockname";
1046 if (getsockname (is->chan.fd, &sa, &len) < 0) {
1047 /* this is best effort */
1048 ndmalogf (sess, 0, 2, "ndmis_tcp..._addrs(): %s failed", what);
1051 is->remote.local_addr.addr_type = NDMP9_ADDR_TCP;
1052 tcp_addr = &is->remote.peer_addr.ndmp9_addr_u.tcp_addr;
1053 tcp_addr->ip_addr = ntohl (sin->sin_addr.s_addr);
1054 tcp_addr->port = ntohs (sin->sin_port);