|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T t
Length: 19314 (0x4b72) Types: TextFile Names: »ts2sunlink.c«
└─⟦3d0c2be1b⟧ Bits:30001254 ISODE-5.0 Tape └─⟦eba4602b1⟧ »./isode-5.0.tar.Z« └─⟦d3ac74d73⟧ └─⟦this⟧ »isode-5.0/tsap/ts2sunlink.c«
/* ts2sunlink.c - TPM: SunLink OSI TP4 interface */ #ifndef lint static char *rcsid = "$Header: /f/osi/tsap/RCS/ts2sunlink.c,v 6.0 89/03/18 23:45:20 mrose Rel $"; #endif /* * $Header: /f/osi/tsap/RCS/ts2sunlink.c,v 6.0 89/03/18 23:45:20 mrose Rel $ * * Contributed by John A. Scott, The MITRE Corporation * * * $Log: ts2sunlink.c,v $ * Revision 6.0 89/03/18 23:45:20 mrose * Release 5.0 * */ /* * NOTICE * * Acquisition, use, and distribution of this module and related * materials are subject to the restrictions of a license agreement. * Consult the Preface in the User's Manual for the full terms of * this agreement. * */ /* LINTLIBRARY */ #include <stdio.h> #include "tpkt.h" #ifdef TP4 #include "tp4.h" #endif #ifdef SUN_TP4 #include <errno.h> #include <sys/ioctl.h> #include <sys/uio.h> #include "tailor.h" /* A driver for SunLink OSI's TP4! * * SunLink OSI TP4 user interface is very much like a ``datagram'' * interface. Some of the hair in this port involves converting * ISODE TP packets into SUN TP4 packets. My gut feeling is that the * port should be redone to make better use of existing ISODE * structures (but this works and I hesitate to change something works). * -- John * * Actually, I think is fairly close to optimal now. * -- /mtr * * TODO: * * 1. Figure out how to implement tsaplisten.c$tp4unique() * * 2. On failure of sendto, sendmsg, or recvfrom, try to figure out if a * disconnect happened and return the right DR_ reason. * * 3. SunLink OSI should support TSELs of length greater than two. In fact, * a transport address really should be: * nsap - 64 octets, tsel - 44 octets (would prefer 64, but mbufs limit) * * 4. Should do QOS mappings for error recovery (not class 0 or 2) and cost * (class 0). * */ /* \f DATA */ #define XXX /* SunLink OSI release 5.0 bug... */ #define MAXTP4 (1 << SIZE_8K) extern int errno; /* \f UPPER HALF */ static int TConnect (tb, expedited, data, cc, td) register struct tsapblk *tb; char *data; int expedited, cc; struct TSAPdisconnect *td; { int result; register struct tp4pkt *t; if ((t = newtp4pkt (TP_CONNECT_REQ)) == NULL) return tsaplose (td, DR_CONGEST, NULLCP, NULLCP); if (gen2tp4 (&tb -> tb_responding, &t -> tp4_called, tb -> tb_initiating.ta_naddr > 0 ? tb -> tb_initiating.ta_addrs : NULLNA) == NOTOK) { result = tsaplose (td, DR_ADDRESS, NULLCP, "unable to parse remote address"); goto out; } if (gen2tp4 (&tb -> tb_initiating, &t -> tp4_calling, tb -> tb_responding.ta_naddr > 0 ? tb -> tb_responding.ta_addrs : NULLNA) == NOTOK) { result = tsaplose (td, DR_ADDRESS, NULLCP, "unable to parse local address"); goto out; } if (expedited) { tb -> tb_flags |= TB_EXPD; t -> tp4_expedited = 1; } if (sendto (tb -> tb_fd, data, cc, 0, (struct sockaddr *) t, sizeof (TP_MSG_CONNECT)) == NOTOK) result = tsaplose (td, DR_CONGEST, "failed", "sendto"); else result = OK; out: ; freetp4pkt (t); return result; } /* \f */ static int TRetry (tb, async, tc, td) register struct tsapblk *tb; int async; struct TSAPconnect *tc; struct TSAPdisconnect *td; { int cc, header_len, onoff; char data[TS_SIZE]; register struct tp4pkt *t; t = NULL; if (async) switch ((*tb -> tb_retryfnx) (tb, td)) { case NOTOK: goto out; case OK: return OK; case DONE: break; } if ((t = newtp4pkt ((TP_EVENT) 0)) == NULL) { (void) tsaplose (td, DR_CONGEST, NULLCP, NULLCP); goto out; } header_len = sizeof (TP_MSG_CONNECT); if ((cc = recvfrom (tb -> tb_fd, data, sizeof data, 0, (struct sockaddr *) t, &header_len)) == NOTOK) { if (errno == EWOULDBLOCK) { freetp4pkt (t); return OK; } (void) tsaplose (td, DR_CONGEST, "failed", "recvfrom"); goto out; } if (async) (void) ioctl (tb -> tb_fd, FIONBIO, (onoff = 0, (char *) &onoff)); switch (t -> tp4_event) { case TP_CONNECT_CONF: tc -> tc_sd = tb -> tb_fd; tc -> tc_tsdusize = tb -> tb_tsdusize = MAXTP4; (void) tp42gen (&tb -> tb_responding, &t -> tp4_calling, 0); tc -> tc_responding = tb -> tb_responding; if ((tb -> tb_flags & TB_EXPD) && !t -> tp4_expedited) tb -> tb_flags &= ~TB_EXPD; tc -> tc_expedited = (tb -> tb_flags & TB_EXPD) ? 1 : 0; if ((tc -> tc_cc = cc) > 0) bcopy (data, tc -> tc_data, cc); freetp4pkt (t); tb -> tb_flags |= TB_CONN; return DONE; case TP_DISCONNECT_IND: if ((td -> td_reason = (int) t -> tp4_reason) == DR_UNKNOWN) td -> td_reason = DR_NETWORK; if ((td -> td_cc = cc) > 0) bcopy (data, td -> td_data, cc); break; default: (void) tsaplose (td, DR_NETWORK, NULLCP, "expecting 0x%x, got 0x%x", TP_CONNECT_CONF, t -> tp4_event); break; } out: ; if (t) freetp4pkt (t); freetblk (tb); return NOTOK; } /* \f */ static int TStart (tb, cp, ts, td) register struct tsapblk *tb; char *cp; struct TSAPstart *ts; struct TSAPdisconnect *td; { int cc, i, result; register struct tp4pkt *tp; if ((i = strlen (cp)) < (cc = 2 * sizeof (TP_MSG_CONNECT))) return tsaplose (td, DR_PARAMETER, NULLCP, "bad initialization vector"); if ((tp = newtp4pkt ((TP_EVENT) 0)) == NULL) { result = tsaplose (td, DR_CONGEST, NULLCP, NULLCP); goto out; } cc = 2 * implode ((u_char *) tp, cp, cc); cp += cc, i -= cc; if (tp -> tp4_expedited) tb -> tb_flags |= TB_EXPD; (void) tp42gen (&tb -> tb_initiating, &tp -> tp4_calling, 0); (void) tp42gen (&tb -> tb_responding, &tp -> tp4_called, 0); ts -> ts_sd = tb -> tb_fd; ts -> ts_calling = tb -> tb_initiating; /* struct copy */ ts -> ts_called = tb -> tb_responding; /* struct copy */ ts -> ts_expedited = (tb -> tb_flags & TB_EXPD) ? 1 : 0; ts -> ts_tsdusize = tb -> tb_tsdusize; if (i > 0) { if (i > 2 * TS_SIZE) { result = tsaplose (td, DR_CONNECT, NULLCP, "too much initial user data"); goto out; } ts -> ts_cc = implode ((u_char *) ts -> ts_data, cp, i); } else ts -> ts_cc = 0; result = OK; out: ; if (tp) freetp4pkt (tp); return result; } /* \f */ /* ARGSUSED */ static int TAccept (tb, responding, data, cc, qos, td) register struct tsapblk *tb; char *data; int responding, cc; struct QOStype *qos; struct TSAPdisconnect *td; { int result; register struct tp4pkt *tp; if ((tp = newtp4pkt (TP_CONNECT_RESP)) == NULL) return tsaplose (td, DR_CONGEST, NULLCP, NULLCP); if (responding) (void) gen2tp4 (&tb -> tb_responding, &tp -> tp4_called, tb -> tb_initiating.ta_naddr > 0 ? tb -> tb_initiating.ta_addrs : NULLNA); if (tb -> tb_flags & TB_EXPD) tp -> tp4_expedited = 1; if (sendto (tb -> tb_fd, data, cc, 0, (struct sockaddr *) tp, sizeof (TP_MSG_CONNECT)) == NOTOK) result = tsaplose (td, DR_CONGEST, "failed", "sendto"); else { result = OK; tb -> tb_flags |= TB_CONN; } freetp4pkt (tp); return result; } /* \f */ /* life would be nice if we didn't have to worry about the maximum number of bytes that can be written in a single syscall() */ #ifndef MSG_MAXIOVLEN #define MSG_MAXIOVLEN NTPUV #endif static int TWrite (tb, uv, expedited, td) register struct tsapblk *tb; register struct udvec *uv; int expedited; struct TSAPdisconnect *td; { int cc, flags, j, len, size; register char *bp, *ep; #ifdef XXX register char *dp; char data[MAXTP4]; #endif struct msghdr msgs; register struct msghdr *msg = &msgs; register struct tp4pkt *tp; struct iovec iovs[MSG_MAXIOVLEN]; register struct iovec *vv, *wv; if ((tp = newtp4pkt (expedited ? TP_X_DATA_REQ : TP_DATA_REQ)) == NULL) { (void) tsaplose (td, DR_CONGEST, NULLCP, NULLCP); goto out; } if (expedited) size = sizeof (TP_MSG_X_DATA), flags = MSG_OOB; else size = sizeof (TP_MSG_DATA), flags = 0; ep = (bp = uv -> uv_base) + (cc = uv -> uv_len); while (uv -> uv_base) { wv = (vv = iovs) + MSG_MAXIOVLEN; for (len = tb -> tb_tsdusize; len > 0 && vv < wv; len -= j) { j = min (cc, len); vv -> iov_base = bp, vv -> iov_len = j, vv++; bp += j, cc -= j; if (bp >= ep) { if ((bp = (++uv) -> uv_base) == NULL) break; ep = bp + (cc = uv -> uv_len); } } if (!expedited) tp -> tp4_eot = uv -> uv_base == NULL; #ifdef XXX dp = data, len = 0; for (wv = iovs; wv < vv; wv++) { bcopy (wv -> iov_base, dp, wv -> iov_len); dp += wv -> iov_len, len += wv -> iov_len; } vv = iovs; vv -> iov_base = data, vv -> iov_len = len, vv++; #endif msg -> msg_name = (caddr_t) tp; msg -> msg_namelen = size; msg -> msg_iov = iovs; msg -> msg_iovlen = vv - iovs; msg -> msg_accrights = (caddr_t) NULL; msg -> msg_accrightslen = 0; if (sendmsg (tb -> tb_fd, msg, flags) == NOTOK) { (void) tsaplose (td, DR_CONGEST, "failed", "sendmsg"); goto out; } } freetp4pkt (tp); return OK; out: ; if (tp) freetp4pkt (tp); freetblk (tb); return NOTOK; } /* \f */ static int TRead (tb, tx, td, async, oob) register struct tsapblk *tb; register struct TSAPdata *tx; struct TSAPdisconnect *td; int async, oob; { int cc, header_len; register struct qbuf *qb; register struct tp4pkt *tp; bzero ((char *) tx, sizeof *tx); tx -> tx_qbuf.qb_forw = tx -> tx_qbuf.qb_back = &tx -> tx_qbuf; for (;;) { if ((qb = (struct qbuf *) malloc ((unsigned) (sizeof *qb + sizeof *tp + tb -> tb_tsdusize))) == NULL) { (void) tsaplose (td, DR_CONGEST, NULLCP, NULLCP); break; } tp = (struct tp4pkt *) qb -> qb_base; qb -> qb_data = qb -> qb_base + sizeof *tp; header_len = sizeof (struct tp4pkt); if ((cc = recvfrom (tb -> tb_fd, qb -> qb_data, tb -> tb_tsdusize, oob ? MSG_OSI_OOB : 0, (struct sockaddr *) tp, &header_len)) == NOTOK) { (void) tsaplose (td, DR_CONGEST, "failed", "recvfrom"); break; } switch (tp -> tp4_event) { case TP_DATA_IND: if (cc > 0) { insque (qb, tb -> tb_qbuf.qb_back); tb -> tb_len += (qb -> qb_len = cc); } else free ((char *) qb); if (!tp -> tp4_eot) { if (async) return DONE; continue; } tx -> tx_expedited = 0; if (tb -> tb_qbuf.qb_forw != &tb -> tb_qbuf) { tx -> tx_qbuf = tb -> tb_qbuf; /* struct copy */ tx -> tx_qbuf.qb_forw -> qb_back = tx -> tx_qbuf.qb_back -> qb_forw = &tx -> tx_qbuf; tx -> tx_cc = tb -> tb_len; tb -> tb_qbuf.qb_forw = tb -> tb_qbuf.qb_back = &tb -> tb_qbuf; tb -> tb_len = 0; } return OK; case TP_X_DATA_IND: if (cc > 0) { insque (qb, tx -> tx_qbuf.qb_back); tx -> tx_cc = (qb -> qb_len = cc); } else free ((char *) qb); tx -> tx_expedited = 1; return OK; case TP_DISCONNECT_IND: td -> td_reason = (int) tp -> tp4_reason; if ((td -> td_cc = cc) > 0) bcopy (qb -> qb_data, td -> td_data, cc); break; default: (void) tsaplose (td, DR_NETWORK, NULLCP, "unexpected response 0x%x", (int) (tp -> tp4_event)); break; } break; } if (qb) free ((char *) qb); freetblk (tb); return NOTOK; } /* \f */ static int TDisconnect (tb, data, cc, td) register struct tsapblk *tb; char *data; int cc; struct TSAPdisconnect *td; { int result; register struct tp4pkt *tp; if (tp = newtp4pkt (TP_DISCONNECT_REQ)) { tp -> tp4_reason = (TP_DR_REASON) DR_NORMAL; if (sendto (tb -> tb_fd, data, cc, 0, (struct sockaddr *) tp, sizeof (TP_MSG_DISCONNECT)) == NOTOK) result = tsaplose (td, DR_CONGEST, "failed", "sendto"); else result = OK; freetp4pkt (tp); } else result = tsaplose (td, DR_CONGEST, NULLCP, NULLCP); freetblk (tb); return result; } /* \f */ /* ARGSUSED */ static int TLose (tb, reason, td) register struct tsapblk *tb; int reason; struct TSAPdisconnect *td; { register struct tp4pkt *tp; SLOG (tsap_log, LLOG_EXCEPTIONS, NULLCP, ("TPM error %d", reason)); if (tp = newtp4pkt (TP_DISCONNECT_REQ)) { tp -> tp4_reason = (TP_DR_REASON) reason; (void) sendto (tb -> tb_fd, NULLCP, 0, 0, (struct sockaddr *) tp, sizeof (TP_MSG_DISCONNECT)); freetp4pkt (tp); } } /* \f LOWER HALF */ /* ARGSUSED */ int tp4open (tb, local_ta, local_na, remote_ta, remote_na, td, async) register struct tsapblk *tb; struct TSAPaddr *local_ta, *remote_ta; struct NSAPaddr *local_na, *remote_na; struct TSAPdisconnect *td; int async; { int fd, onoff; struct TSAPaddr tzs; register struct TSAPaddr *tz = &tzs; register struct NSAPaddr *nz = tz -> ta_addrs; OSI_ADDR ifaddr; bzero ((char *) tz, sizeof *tz); if (local_ta) *tz = *local_ta; /* struct copy */ if (local_na) { *nz = *local_na; /* struct copy */ tz -> ta_naddr = 1; } (void) gen2tp4 (tz, &ifaddr, remote_na); if ((fd = socket (AF_OSI, SOCK_EVENT, OSIPROTO_TP_EVENT)) == NOTOK) return tsaplose (td, DR_CONGEST, "socket", "unable to start"); if (bind (fd, (struct sockaddr *) &ifaddr, sizeof ifaddr) == NOTOK) { (void) tsaplose (td, DR_ADDRESS, "socket", "unable to bind"); (void) close (fd); return NOTOK; } tb -> tb_fd = fd; (void) tp4init (tb); if (async) (void) ioctl (fd, FIONBIO, (onoff = 1, (char *) &onoff)); return (async ? OK : DONE); } /* \f */ /* ARGSUSED */ static int retry_tp4_socket (tb, td) register struct tsapblk *tb; struct TSAPdisconnect *td; { fd_set mask; FD_ZERO (&mask); FD_SET (tb -> tb_fd, &mask); if (xselect (tb -> tb_fd + 1, &mask, NULLFD, NULLFD, 0) < 1) return OK; return DONE; } /* \f */ /* ARGSUSED */ char *tp4save (fd, td) int fd; struct TSAPdisconnect *td; { static char buffer[BUFSIZ]; (void) sprintf (buffer, "%c%d", NT_SUN, fd); return buffer; } /* \f */ int tp4restore (tb, buffer, td) register struct tsapblk *tb; char *buffer; struct TSAPdisconnect *td; { int fd; if (sscanf (buffer, "%d", &fd) != 1 || fd < 0) return tsaplose (td, DR_PARAMETER, NULLCP, "bad initialization vector \"%s\"", buffer); tb -> tb_fd = fd; (void) tp4init (tb); return OK; } /* \f */ int tp4init (tb) register struct tsapblk *tb; { tb -> tb_connPfnx = TConnect; tb -> tb_retryPfnx = TRetry; tb -> tb_startPfnx = TStart; tb -> tb_acceptPfnx = TAccept; tb -> tb_writePfnx = TWrite; tb -> tb_readPfnx = TRead; tb -> tb_discPfnx = TDisconnect; tb -> tb_losePfnx = TLose; tb -> tb_flags |= TB_TP4; tb -> tb_tsdusize = MAXTP4 - (tb -> tb_tpduslop = 0); tb -> tb_retryfnx = retry_tp4_socket; tb -> tb_closefnx = close_tp4_socket; tb -> tb_selectfnx = select_tp4_socket; } /* \f */ /* ARGSUSED */ int start_tp4_server (sock, backlog, opt1, opt2, td) struct TSAPaddr *sock; int backlog, opt1, opt2; struct TSAPdisconnect *td; { int sd; OSI_ADDR ifaddr; (void) gen2tp4 (sock, &ifaddr, NULLNA); if ((sd = socket (AF_OSI, SOCK_EVENT, OSIPROTO_TP_EVENT)) == NOTOK) return tsaplose (td, DR_CONGEST, "socket", "unable to start"); if (bind (sd, (struct sockaddr *) &ifaddr, sizeof ifaddr) == NOTOK) { (void) tsaplose (td, DR_ADDRESS, "socket", "unable to bind"); (void) close (sd); return NOTOK; } (void) listen (sd, backlog); return sd; } /* \f */ #ifndef notdef /* ARGSUSED */ #endif int join_tp4_client (fd, sock, td) int fd; struct TSAPaddr *sock; struct TSAPdisconnect *td; { int len, sd; OSI_ADDR ifaddr; len = sizeof (OSI_ADDR); if ((sd = accept (fd, (struct sockaddr *) &ifaddr, &len)) == NOTOK) return tsaplose (td, DR_NETWORK, "socket", "unable to accept"); #ifdef notdef /* Ouch!! Trying to get the remote address off the socket * only works for local connections. Non-local connections * causes a core dump when I try to convert. */ (void) tp42gen (sock, &ifaddr, 0); #endif return sd; } /* \f */ /* SunLink OSI address encoding/decoding */ #ifdef SUNLINK_5_2 /* ARGSUSED */ #endif static int gen2tp4 (generic, specific, template) struct TSAPaddr *generic; OSI_ADDR *specific; struct NSAPaddr *template; { int len, paddr_type; #ifndef SUNLINK_5_2 char buffer[BUFSIZ]; #endif struct NSAPaddr *na; OSI_ADDR_INIT (specific); if (generic -> ta_naddr > 0) { na = generic -> ta_addrs; paddr_type = AF_OSI, len = 0; if (na -> na_addrlen > 0) switch (na -> na_address[0]) { case 0x49: paddr_type = AF_NBS; len = 1; break; case 0x47: if (na -> na_addrlen < 3 || na -> na_address[1] != 0x00 || na -> na_address[2] != 0x04) break; paddr_type = AF_OSINET; len = 3; break; } osi_set_sap (na -> na_address + len, na -> na_addrlen - len, specific, OSI_NSAP, paddr_type); } else { #ifndef SUNLINK_5_2 /* The SunLink OSI I'm using seems to require something * although the ``manual'' says I don't. Hmmmm, I wonder * if I still need the OSI_ADDR_INIT? BTW, osi_set_sap is one * of the two functions I link from the -losi library. When I * get the source for SunLink (maybe before I retire) I'll * write my own set/get sap function and punt libosi.a */ paddr_type = AF_OSI; if (template != NULLNA && template -> na_addrlen > 0) switch (template -> na_address[0]) { case 0x49: paddr_type = AF_NBS; break; case 0x47: if (template -> na_addrlen < 3 || template -> na_address[1] != 0x00 || template -> na_address[2] != 0x04) break; paddr_type = AF_OSINET; break; } buffer[0] = 0x00, len = 1; osi_set_sap (buffer, len, specific, OSI_NSAP, paddr_type); #else mds_lookup ("localhost", "CLIENT", specific);; #endif } osi_set_sap (generic -> ta_selector, generic -> ta_selectlen, specific, OSI_TSAP, AF_GENERIC); return OK; } /* ARGSUSED */ int tp42gen (generic, specific, dummy) struct TSAPaddr *generic; OSI_ADDR *specific; int dummy; { int len, paddr_type; char buffer[NASIZE]; struct NSAPaddr *na; paddr_type = 0; if ((len = osi_get_sap (specific, buffer, sizeof buffer, OSI_NSAP, &paddr_type)) <= 0) return NOTOK; na = generic -> ta_addrs; na -> na_type = NA_NSAP; switch (paddr_type) { case AF_NBS: na -> na_address[0] = 0x49; na -> na_addrlen = 1; break; case AF_OSINET: na -> na_address[0] = 0x47; na -> na_address[1] = 0x00; na -> na_address[2] = 0x04; na -> na_addrlen = 3; break; default: na -> na_addrlen = 0; break; } bcopy (buffer, na -> na_address + na -> na_addrlen, len); na -> na_addrlen += len; generic -> ta_naddr = 1; generic -> ta_selectlen = osi_get_sap (specific, generic -> ta_selector, TSSIZE, OSI_TSAP, &paddr_type); return OK; } /* \f */ struct tp4pkt *newtp4pkt (code) TP_EVENT code; { struct tp4pkt *tp; tp = (struct tp4pkt *) calloc (1, sizeof *tp); if (tp != NULL) tp -> tp4_event = code; return tp; } #endif