📄 mtcpnet.c
字号:
mactcp_set_frozen, mactcp_socket_error }; TCPiopb pb; UDPiopb upb; Actual_Socket ret; ip_addr dstaddr; size_t buflen; /* * Create Socket structure. */ ret = snew(struct Socket_tag); ret->s = 0; ret->fn = &fn_table; ret->err = noErr; ret->plug = plug; bufchain_init(&ret->output_data); ret->connected = 0; /* to start with */ ret->writable = 0; /* to start with */ ret->sending_oob = 0; ret->frozen = 0; ret->frozen_readable = 0; ret->localhost_only = 0; /* unused, but best init anyway */ ret->pending_error = 0; ret->oobinline = oobinline; ret->oobpending = FALSE; ret->listener = 0; dstaddr = addr->hostinfo.addr[0]; /* XXX should try all of them */ /* * Create a TCP stream. * * MacTCP requires us to provide it with some buffer memory. Page * 31 of the Programmer's Guide says it should be a minimum of * 4*MTU+1024. Page 36 says a minimum of 4096 bytes. Assume * they're both correct. */ assert(addr->resolved); upb.ioCRefNum = mactcp.refnum; upb.csCode = UDPMaxMTUSize; upb.csParam.mtu.remoteHost = dstaddr; upb.csParam.mtu.userDataPtr = NULL; ret->err = PBControlSync((ParmBlkPtr)&upb); if (ret->err != noErr) return (Socket)ret; buflen = upb.csParam.mtu.mtuSize * 4 + 1024; if (buflen < 4096) buflen = 4096; if (mactcp_asr_upp == NULL) mactcp_asr_upp = NewTCPNotifyUPP(&mactcp_asr); GetCurrentProcess(&mactcp.self); pb.ioCRefNum = mactcp.refnum; pb.csCode = TCPCreate; pb.csParam.create.rcvBuff = snewn(buflen, char); pb.csParam.create.rcvBuffLen = buflen; pb.csParam.create.notifyProc = mactcp_asr_upp; pb.csParam.create.userDataPtr = (Ptr)ret; ret->err = PBControlSync((ParmBlkPtr)&pb); if (ret->err != noErr) return (Socket)ret; ret->s = pb.tcpStream; /* * Open the connection. */ pb.ioCRefNum = mactcp.refnum; pb.csCode = TCPActiveOpen; pb.tcpStream = ret->s; pb.csParam.open.validityFlags = 0; pb.csParam.open.remoteHost = dstaddr; pb.csParam.open.remotePort = port; pb.csParam.open.localPort = privport ? 1023 : 0; pb.csParam.open.dontFrag = FALSE; pb.csParam.open.timeToLive = 0; pb.csParam.open.security = 0; pb.csParam.open.optionCnt = 0; pb.csParam.open.userDataPtr = (Ptr)ret; while (1) { ret->err = PBControlSync((ParmBlkPtr)&pb); if (!privport || ret->err != duplicateSocket) break; pb.csParam.open.localPort--; if (pb.csParam.open.localPort == 0) break; } if (ret->err != noErr) return (Socket)ret; ret->connected = TRUE; ret->writable = TRUE; /* Add this to the list of all sockets */ ret->next = mactcp.socklist; ret->prev = &mactcp.socklist; if (ret->next != NULL) ret->next->prev = &ret->next; mactcp.socklist = ret; sk_addr_free(addr); /* don't need this anymore */ return (Socket)ret;}Socket mactcp_newlistener(char *srcaddr, int port, Plug plug, int local_host_only){ fatalbox("mactcp_newlistener");}static void mactcp_close(Socket sock){ Actual_Socket s = (Actual_Socket)sock; TCPiopb pb; /* * TCPClose is equivalent to shutdown(fd, SHUT_WR), and hence * leaves the Rx side open, while TCPAbort seems rather vicious, * throwing away Tx data that haven't been ACKed yet. We do both * in succession. */ pb.ioCRefNum = mactcp.refnum; pb.csCode = TCPClose; pb.tcpStream = s->s; pb.csParam.close.validityFlags = 0; pb.csParam.close.userDataPtr = (Ptr)s; s->err = PBControlSync((ParmBlkPtr)&pb); /* Not much we can do about an error anyway. */ pb.ioCRefNum = mactcp.refnum; pb.csCode = TCPAbort; pb.tcpStream = s->s; pb.csParam.abort.userDataPtr = (Ptr)s; s->err = PBControlSync((ParmBlkPtr)&pb); /* Even less we can do about an error here. */ pb.ioCRefNum = mactcp.refnum; pb.csCode = TCPRelease; pb.tcpStream = s->s; pb.csParam.create.userDataPtr = (Ptr)s; s->err = PBControlSync((ParmBlkPtr)&pb); if (s->err == noErr) sfree(pb.csParam.create.rcvBuff); /* Unhitch from list of sockets */ *s->prev = s->next; if (s->next != NULL) s->next->prev = s->prev; sfree(s);}static int mactcp_write(Socket sock, char const *buf, int len){ Actual_Socket s = (Actual_Socket) sock; wdsEntry wds[2]; TCPiopb pb; /* * Casting away const from buf should be safe -- MacTCP won't * write to it. */ wds[0].length = len; wds[0].ptr = (char *)buf; wds[1].length = 0; pb.ioCRefNum = mactcp.refnum; pb.csCode = TCPSend; pb.tcpStream = s->s; pb.csParam.send.validityFlags = 0; pb.csParam.send.pushFlag = TRUE; /* XXX we want it to return. */ pb.csParam.send.urgentFlag = 0; pb.csParam.send.wdsPtr = (Ptr)wds; pb.csParam.send.userDataPtr = (Ptr)s; s->err = PBControlSync((ParmBlkPtr)&pb); return 0;}static int mactcp_write_oob(Socket sock, char const *buf, int len){ fatalbox("mactcp_write_oob");}static pascal void mactcp_asr(StreamPtr str, unsigned short event, Ptr cookie, unsigned short termin_reason, struct ICMPReport *icmp){ WakeUpProcess(&mactcp.self);} /* * Called from our event loop if there's work to do. */void mactcp_poll(void){ Actual_Socket s, next; TCPiopb pb; for (s = mactcp.socklist; s != NULL; s = next) { next = s->next; do { pb.ioCRefNum = mactcp.refnum; pb.csCode = TCPStatus; pb.tcpStream = s->s; pb.csParam.status.userDataPtr = (Ptr)s; s->err = PBControlSync((ParmBlkPtr)&pb); if (s->err != noErr) goto next_socket; if (pb.csParam.status.amtUnreadData == 0) break; mactcp_recv(s, pb.csParam.status.amtUnreadData); } while (TRUE); switch (pb.csParam.status.connectionState) { case TCPS_CLOSE_WAIT: /* Remote end has sent us a FIN */ plug_closing(s->plug, NULL, 0, 0); } next_socket: ; }}static void mactcp_recv(Actual_Socket s, size_t len){ rdsEntry rds[2]; TCPiopb pb; if (s->frozen) return; while (len > 0) { pb.ioCRefNum = mactcp.refnum; pb.csCode = TCPNoCopyRcv; pb.tcpStream = s->s; pb.csParam.receive.commandTimeoutValue = 0; pb.csParam.receive.rdsPtr = (Ptr)rds; pb.csParam.receive.rdsLength = lenof(rds) - 1; pb.csParam.receive.userDataPtr = (Ptr)s; s->err = PBControlSync((ParmBlkPtr)&pb); if (s->err != noErr) return; plug_receive(s->plug, 0, rds[0].ptr, rds[0].length); len -= rds[0].length; pb.csCode = TCPRcvBfrReturn; s->err = PBControlSync((ParmBlkPtr)&pb); if (s->err != noErr) return; } }/* * Each socket abstraction contains a `void *' private field in * which the client can keep state. */static void mactcp_set_private_ptr(Socket sock, void *ptr){ Actual_Socket s = (Actual_Socket) sock; s->private_ptr = ptr;}static void *mactcp_get_private_ptr(Socket sock){ Actual_Socket s = (Actual_Socket) sock; return s->private_ptr;}/* * Special error values are returned from mactcp_namelookup and * mactcp_new if there's a problem. These functions extract an error * message, or return NULL if there's no problem. */char *mactcp_addr_error(SockAddr addr){ static char buf[64]; switch (addr->hostinfo.rtnCode) { case noErr: return NULL; case nameSyntaxErr: return "Name syntax error"; case noNameServer: return "No name server found"; case authNameErr: return "Domain name does not exist"; case noAnsErr: return "No answer from domain name server"; case dnrErr: return "Domain name server returned an error"; case outOfMemory: return "Out of memory"; default: sprintf(buf, "Unknown DNR error %d", addr->hostinfo.rtnCode); return buf; }}static const char *mactcp_socket_error(Socket sock){ static char buf[64]; Actual_Socket s = (Actual_Socket) sock; switch (s->err) { case noErr: return NULL; case insufficientResources: return "Insufficient resources to open TCP stream"; case duplicateSocket: return "Duplicate socket"; case openFailed: return "Connection failed while opening"; default: sprintf(buf, "Unknown MacTCP error %d", s->err); return buf; }}static void mactcp_set_frozen(Socket sock, int is_frozen){ Actual_Socket s = (Actual_Socket) sock; if (s->frozen == is_frozen) return; s->frozen = is_frozen;}/* * Bits below here would usually be in dnr.c, shipped with the MacTCP * SDK, but its convenient not to require that, and since we assume * System 7 we can actually simplify things a lot. */static OSErr OpenResolver(char *hosts_file){ short vrefnum; long dirid; HParamBlockRec pb; Str255 filename; OSErr err; int fd; Handle dnr_handle; if (mactcp.dnr_handle != NULL) return noErr; err = FindFolder(kOnSystemDisk, kControlPanelFolderType, FALSE, &vrefnum, &dirid); if (err != noErr) return err; /* * Might be better to use PBCatSearch here, but it's not always * available. */ pb.fileParam.ioCompletion = NULL; pb.fileParam.ioNamePtr = filename; pb.fileParam.ioVRefNum = vrefnum; pb.fileParam.ioFDirIndex = 1; pb.fileParam.ioDirID = dirid; fd = -1; while (PBHGetFInfoSync(&pb) == noErr) { if (pb.fileParam.ioFlFndrInfo.fdType == 'cdev' && pb.fileParam.ioFlFndrInfo.fdCreator == 'ztcp') { fd = HOpenResFile(vrefnum, dirid, filename, fsRdPerm); if (fd == -1) continue; dnr_handle = Get1IndResource('dnrp', 1); if (dnr_handle != NULL) break; CloseResFile(fd); fd = -1; } pb.fileParam.ioDirID = dirid; pb.fileParam.ioFDirIndex++; } if (fd == -1) return fnfErr; DetachResource(dnr_handle); CloseResFile(fd); MoveHHi(dnr_handle); HLock(dnr_handle); err = InvokeOpenResolverUPP(OPENRESOLVER, hosts_file, (OpenResolverUPP)*dnr_handle); if (err != noErr) { HUnlock(dnr_handle); DisposeHandle(dnr_handle); return err; } mactcp.dnr_handle = dnr_handle; return noErr;}OSErr CloseResolver(void){ Handle dnr_handle = mactcp.dnr_handle; OSErr err; if (mactcp.dnr_handle == NULL) return notOpenErr; err = InvokeCloseResolverUPP(CLOSERESOLVER, (CloseResolverUPP)*mactcp.dnr_handle); if (err != noErr) return err; mactcp.dnr_handle = NULL; HUnlock(dnr_handle); DisposeHandle(dnr_handle); return noErr;}#endif/* * Local Variables: * c-file-style: "simon" * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -