/* get host name */ void NATCPgethost(na_tcpreadp *callback, void *context) { int id; tcpinfo *tcp; struct IPParamBlock *ippb; na_win *win; if ((*tcpstate)->localhost[0]) { win = NAlockWindow((na_win **) tcpstate); (*callback)(context, -1, NATCP_connect, strlen(tstate->localhost), tstate->localhost); NAunlockWindowh((na_win **) tcpstate, win); } else if ((tcp = getTCPbuf(callback, context, &id)) != NULL) { /* here we make the assumption that an IP param block is smaller than * a TCP param block. This seems like a safe assumption to me. */ ippb = (struct IPParamBlock *) &tcp->pb; /* get IP address */ ippb->ioCRefNum = (*tcpstate)->tcp_driver; ippb->csCode = ipctlGetAddr; PBControl((ParmBlkPtr)ippb, false); if (ippb->ioResult != 0) { (*callback)(context, -1, NATCP_notcpbuf, ippb->ioResult, NULL); DisposPtr((Ptr) tcp); (*tcpstate)->tcpbufs[id] = NULL; } else { /* begin IP address lookup */ tcp->dnrdone = 0; AddrToName(ippb->ourAddress, &tcp->host, addrproc, (char *) tcp); tcp->state = TCP_GETHOST; tcp->gethost = 1; } } }
/* open a TCP connection */ na_tcp NATCPopen(na_tcpreadp *callback, void *context, char *host, long port, short flags) { int i, err = NATCP_notcpbuf; OSErr resolve = noErr; tcpinfo *tcp; if ((tcp = getTCPbuf(callback, context, &i)) == NULL) return (-1); if (flags & NATCP_server) tcp->server = 1; tcp->port = port; tcp->pb.csCode = TCPCreate; tcp->pb.csParam.create.rcvBuff = (Ptr) tcp->buf; tcp->pb.csParam.create.rcvBuffLen = (*tcpstate)->streamsize; tcp->pb.csParam.create.notifyProc = myTCPNotifyProc; tcp->pb.csParam.create.userDataPtr = (Ptr) tcp; PBControl((ParmBlkPtr)&tcp->pb, false); if (tcp->pb.ioResult == 0) { tcp->state = TCP_RESOLVE; tcp->stream = tcp->pb.tcpStream; /* a server isn't required to have a hostname */ if (!host && tcp->server) return (i); tcp->dnrdone = 0; resolve = StrToAddr(host, &tcp->host, addrproc, (char *) tcp); if (resolve == noErr) tcp->dnrdone = 1; if (resolve == cacheFault || resolve == noErr) { return (i); } err = NATCP_nohost; } DisposPtr((Ptr) tcp); (*tcpstate)->tcpbufs[i] = NULL; (*callback)(context, -1, err, resolve, NULL); return (-1); }
/* clean up the TCP task */ static short tcp_closep(na_win *win) { short i, j; tcpinfo *tcp; tcpwb *wb; TCPiopb pb; tstate->waitstart = TickCount(); tstate->waitpercent = 0; tcp_wait(tstate, NULL); memset((void *) &pb, 0, sizeof (pb)); for (i = 0; i < MAX_TCPCON; ++i) { if ((tcp = tstate->tcpbufs[i]) != NULL) { /* wait for MacTCP to finish what it's doing, but permit user cancel */ if (!tcp->server || tcp->state != TCP_CONNECT) tcp_wait(tstate, tcp); if (!tcp->gethost) { pb.ioCRefNum = tstate->tcp_driver; pb.tcpStream = tcp->stream; pb.csCode = TCPRelease; PBControl((ParmBlkPtr) &pb, false); } freewb(tcp->wb); freewb(tcp->wb + 1); DisposPtr((Ptr) tcp); tstate->tcpbufs[i] = NULL; } } tcpstate = NULL; if (tstate->tcp_driver) CloseResolver(); return (NA_CLOSED); }
/* free write buffer storage */ static void freewb(tcpwb *wb) { short i; for (i = 0; wb->rds[i].length; ++i) { if (wb->fflag[i]) { DisposPtr(wb->rds[i].ptr); wb->fflag[i] = 0; } } wb->rused = 0; wb->wused = 0; }
PRIVATE OSErr end_track_buffering_for_write (our_file_info_t *ofitp) { OSErr retval; if (length) retval = flush_buffer (ofitp); else retval = noErr; DisposPtr (track_bufp); track_bufp = 0; return retval; }
/* make sure tcp_driver is open */ static short tcp_checkdriver() { short msg = NATCP_nodriver; struct tcpstate *ts = *tcpstate; IOParam *opb = ts->open_pb; if (!opb) return (1); if (opb->ioResult == 1) return (0); if (opb->ioResult == noErr && OpenResolver(nil) == noErr) { ts->tcp_driver = opb->ioRefNum; msg = NATCP_connect; } DisposPtr((Ptr) opb); ts = *tcpstate; ts->open_pb = NULL; (*ts->tcp_initp)(msg); return (1); }
/* do I/O polling */ short NATCPtask(na_win *win) { tcpinfo *tcp; rdsEntry *rds, *trds; short result, newstate; short processed = NA_PROCESSED; na_tcp i; tcpwb *wb; int j; /* finish off driver initialization: */ if (!tstate->tcp_driver) { if (!tcp_checkdriver()) return (NA_NOTPROCESSED); if (!tstate->tcp_driver) return (NA_REQCLOSE); } /* loop through connections */ for (i = 0; i < MAX_TCPCON; ++i) { if ((tcp = tstate->tcpbufs[i]) != NULL) do { /* read data if we have it */ if (!tcp->reading && !tcp->rclose && tcp->havedata && tcp->state != TCP_CONNECT) { tcp->rpb.ioCRefNum = tstate->tcp_driver; tcp->rpb.tcpStream = tcp->stream; tcp->rpb.csCode = TCPNoCopyRcv; tcp->rpb.csParam.receive.rdsPtr = (Ptr) tcp->rrds; tcp->rpb.csParam.receive.commandTimeoutValue = 5; tcp->rpb.csParam.receive.rdsLength = RDS; if (tcp->pushed) { tcp->rpb.csParam.receive.commandTimeoutValue = 1; tcp->rpb.csParam.receive.rdsLength = 1; } tcp->havedata = 0; PBControl((ParmBlkPtr) &tcp->rpb, tcp->pushed ? false : true); tcp->reading = 1; tcp->pushed = 0; } if (tcp->reading) { if ((result = tcp->rpb.ioResult) == 1) { processed = NA_NOTPROCESSED; } else { tcp->reading = 0; if (result != noErr) { if (result != commandTimeout) { (*tcp->callback)(tcp->context, i, NATCP_noread, result, NULL); } } else { result = NATCP_data | NATCP_more; if (tcp->rpb.csParam.receive.urgentFlag) tcp->urgent = 1; if (tcp->urgent) result |= NATCP_urgent; if (tcp->rpb.csParam.receive.markFlag) tcp->urgent = 0; for (rds = tcp->rrds; rds->length; ++rds) { if (!rds[1].length) result &= ~NATCP_more; (*tcp->callback)(tcp->context, i, result, rds->length, rds->ptr); } tcp->rpb.csCode = TCPRcvBfrReturn; PBControl((ParmBlkPtr) &tcp->rpb, false); } } } result = tcp->pb.ioResult; newstate = 0; switch (tcp->state) { case TCP_GETHOST: if (tcp->dnrdone) { tcp->rclose = 3; newstate = TCP_CLOSED; if (tcp->host.rtnCode != noErr) { (*tcp->callback)(tcp->context, i, NATCP_nohost, tcp->host.rtnCode, NULL); } else { (*tcp->callback)(tcp->context, i, NATCP_connect, strlen(tcp->host.cname), tcp->host.cname); strcpy(tstate->localhost, tcp->host.cname); } } break; case TCP_RESOLVE: if (tcp->dnrdone) { if (tcp->host.rtnCode != noErr) { tcp->rclose = 3; newstate = TCP_CLOSED; (*tcp->callback)(tcp->context, i, NATCP_nohost, tcp->host.rtnCode, NULL); } else if (!tcp->lclose) { memset((void *) &tcp->pb, 0, sizeof (tcp->pb)); tcp->pb.ioCRefNum = tstate->tcp_driver; tcp->pb.tcpStream = tcp->stream; tcp->pb.csParam.open.ulpTimeoutValue = 30; tcp->pb.csParam.open.ulpTimeoutAction = 1; /* Abort on timeout */ tcp->pb.csParam.open.tosFlags = tstate->TOS; tcp->pb.csParam.open.precedence = tstate->precedence; tcp->pb.csParam.open.validityFlags = timeoutValue|timeoutAction|typeOfService|precedence; tcp->pb.csParam.open.remoteHost = tcp->host.addr[0]; if (tcp->server) { tcp->pb.csCode = TCPPassiveOpen; tcp->pb.csParam.open.commandTimeoutValue = 0; tcp->pb.csParam.open.remotePort = 0; tcp->pb.csParam.open.localPort = tcp->port; } else { tcp->pb.csCode = TCPActiveOpen; tcp->pb.csParam.open.remotePort = tcp->port; tcp->pb.csParam.open.localPort = 0; } PBControl((ParmBlkPtr) &tcp->pb, true); newstate = TCP_CONNECT; } } break; case TCP_CONNECT: if (result == 1) { processed = NA_NOTPROCESSED; break; } if (result != noErr) { tcp->rclose = 3; newstate = TCP_CLOSED; (*tcp->callback)(tcp->context, i, NATCP_nocon, result, NULL); } else { newstate = TCP_READY; if (tcp->server) { tcp->port = tcp->pb.csParam.open.remotePort; if (!*tcp->host.cname) { AddrToStr(tcp->pb.csParam.open.remoteHost, tcp->host.cname); } } (*tcp->callback)(tcp->context, i, NATCP_connect, tcp->port, tcp->host.cname); } break; case TCP_READY: /* Write data if we have it */ wb = tcp->wb + tcp->wbnum; if (wb->rused && (newstate = beginwrite(tcp))) { break; } /* check if other side wants to close */ if (tcp->rclose == 1) { tcp->rclose = 2; (*tcp->callback)(tcp->context, i, NATCP_closing, 0, NULL); } /* check if connection needs closing at this end */ if (tcp->lclose == 1) { tcp->lclose = 2; tcp->pb.csCode = TCPClose; tcp->pb.csParam.close.validityFlags = 0xC0; tcp->pb.csParam.close.ulpTimeoutValue = 30; /* give 30 secs to close */ tcp->pb.csParam.close.ulpTimeoutAction = 0; PBControl((ParmBlkPtr) &tcp->pb, true); newstate = TCP_CLOSING; break; } /* check if connection closed at both ends */ if (tcp->rclose == 3) { (*tcp->callback)(tcp->context, i, NATCP_closed, tcp->reason, NULL); newstate = TCP_CLOSED; } break; case TCP_WRITING: if (result == 1) { processed = NA_NOTPROCESSED; break; } wb = tcp->wb; if (wb->rused != -1) ++wb; freewb(wb); if (result != noErr) { tcp->pushed = 0; (*tcp->callback)(tcp->context, i, NATCP_nowrite, result, NULL); } newstate = TCP_READY; break; case TCP_CLOSING: if (result == 1) { processed = NA_NOTPROCESSED; break; } newstate = TCP_READY; break; case TCP_CLOSED: if (!tcp->rclose) break; if (!tcp->gethost) { tcp->pb.csCode = TCPRelease; PBControl((ParmBlkPtr)&tcp->pb, false); } freewb(tcp->wb); freewb(tcp->wb + 1); DisposPtr((Ptr) tcp); tstate->tcpbufs[i] = NULL; break; } if (newstate) tcp->state = newstate; } while (newstate); } return (processed); }