tcp_mac.c
上传用户:ycwykj01
上传日期:2007-01-04
资源大小:1819k
文件大小:16k
源码类别:

网络编程

开发平台:

Unix_Linux

  1. /*
  2.  * Program: Macintosh TCP/IP routines
  3.  *
  4.  * Author: Mark Crispin
  5.  * 6158 Lariat Loop NE
  6.  * Bainbridge Island, WA  98110-2098
  7.  * Internet: MRC@Panda.COM
  8.  *
  9.  * Date: 26 January 1992
  10.  * Last Edited: 16 December 1998
  11.  *
  12.  * Copyright 1998 by Mark Crispin
  13.  *
  14.  *  Permission to use, copy, modify, and distribute this software and its
  15.  * documentation for any purpose and without fee is hereby granted, provided
  16.  * that the above copyright notice appears in all copies and that both the
  17.  * above copyright notices and this permission notice appear in supporting
  18.  * documentation, and that the name of Mark Crispin not be used in advertising
  19.  * or publicity pertaining to distribution of the software without specific,
  20.  * written prior permission.  This software is made available "as is", and
  21.  * MARK CRISPIN DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD TO
  22.  * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED WARRANTIES OF
  23.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN NO EVENT SHALL
  24.  * MARK CRISPIN BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES
  25.  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  26.  * WHETHER IN AN ACTION OF CONTRACT, TORT (INCLUDING NEGLIGENCE) OR STRICT
  27.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
  28.  * THIS SOFTWARE.
  29.  *
  30.  */
  31. /*  This is a totally new operating-system dependent module for the Macintosh,
  32.  * written using THINK C on my Mac PowerBook-100 in my free time.
  33.  * Unlike earlier efforts, this version requires no external TCP library.  It
  34.  * also takes advantage of the Map panel in System 7 for the timezone.
  35.  */
  36. static tcptimeout_t tmoh = NIL; /* TCP timeout handler routine */
  37. static long ttmo_open = 75; /* TCP timeouts, in seconds */
  38. static long ttmo_read = 0;
  39. static long ttmo_write = 0;
  40. static long ttmo_close = 0;
  41. /* TCP/IP manipulate parameters
  42.  * Accepts: function code
  43.  *     function-dependent value
  44.  * Returns: function-dependent return value
  45.  */
  46. void *tcp_parameters (long function,void *value)
  47. {
  48.   switch ((int) function) {
  49.   case SET_TIMEOUT:
  50.     tmoh = (tcptimeout_t) value;
  51.     break;
  52.   case GET_TIMEOUT:
  53.     value = (void *) tmoh;
  54.     break;
  55.   case SET_OPENTIMEOUT:
  56.     ttmo_open = (long) value;
  57.     break;
  58.   case GET_OPENTIMEOUT:
  59.     value = (void *) ttmo_open;
  60.     break;
  61.   case SET_READTIMEOUT:
  62.     ttmo_read = (long) value;
  63.     break;
  64.   case GET_READTIMEOUT:
  65.     value = (void *) ttmo_read;
  66.     break;
  67.   case SET_WRITETIMEOUT:
  68.     ttmo_write = (long) value;
  69.     break;
  70.   case GET_WRITETIMEOUT:
  71.     value = (void *) ttmo_write;
  72.     break;
  73.   case SET_CLOSETIMEOUT:
  74.     ttmo_close = (long) value;
  75.     break;
  76.   case GET_CLOSETIMEOUT:
  77.     value = (void *) ttmo_close;
  78.     break;
  79.   default:
  80.     value = NIL; /* error case */
  81.     break;
  82.   }
  83.   return value;
  84. }
  85. /* TCP/IP open
  86.  * Accepts: host name
  87.  *     contact service name
  88.  *     contact port number
  89.  * Returns: TCP stream if success else NIL
  90.  */
  91. TCPSTREAM *tcp_open (char *host,char *service,unsigned long port)
  92. {
  93.   TCPSTREAM *stream;
  94.   struct hostInfo hst;
  95.   struct TCPCreatePB *createpb;
  96.   struct TCPOpenPB *openpb;
  97.   char *s;
  98.   unsigned long i,j,k,l;
  99.   char tmp[MAILTMPLEN];
  100. /* init MacTCP */
  101.   if (!TCPdriver && OpenDriver (TCPDRIVER,&TCPdriver)) {
  102.     mm_log ("Can't init MacTCP",ERROR);
  103.     return NIL;
  104.   }
  105.   if (!resolveropen && OpenResolver (NIL)) {
  106.     mm_log ("Can't init domain resolver",ERROR);
  107.     return NIL;
  108.   }
  109.   resolveropen = T; /* note resolver open now */
  110. /* domain literal? */
  111.   if (host[0] == '[' && host[strlen (host)-1] == ']') {
  112.     if (((i = strtoul (s = host+1,&s,10)) <= 255) && *s++ == '.' &&
  113. ((j = strtoul (s,&s,10)) <= 255) && *s++ == '.' &&
  114. ((k = strtoul (s,&s,10)) <= 255) && *s++ == '.' &&
  115. ((l = strtoul (s,&s,10)) <= 255) && *s++ == ']' && !*s) {
  116.       hst.addr[0] = (i << 24) + (j << 16) + (k << 8) + l;
  117.       hst.addr[1] = 0; /* only one address to try! */
  118.       sprintf (hst.cname,"[%ld.%ld.%ld.%ld]",i,j,k,l);
  119.     }
  120.     else {
  121.       sprintf (tmp,"Bad format domain-literal: %.80s",host);
  122.       mm_log (tmp,ERROR);
  123.       return NIL;
  124.     }
  125.   }
  126.   else { /* look up host name */
  127.     if (!tcp_dns_upp) tcp_dns_upp = NewResultProc (tcp_dns_result);
  128.     if (StrToAddr (host,&hst,tcp_dns_upp,NIL)) {
  129.       while (hst.rtnCode == cacheFault && wait ());
  130. /* kludge around MacTCP bug */
  131.       if (hst.rtnCode == outOfMemory) {
  132. mm_log ("Re-initializing domain resolver",WARN);
  133. CloseResolver (); /* bop it on the head and try again */
  134. OpenResolver (NIL); /* note this will leak 12K */
  135. StrToAddr (host,&hst,tcp_dns_upp,NIL);
  136. while (hst.rtnCode == cacheFault && wait ());
  137.       }
  138.       if (hst.rtnCode) { /* still have error status? */
  139. switch (hst.rtnCode) { /* analyze return */
  140. case nameSyntaxErr:
  141.   s = "Syntax error in name";
  142.   break;
  143. case noResultProc:
  144.   s = "No result procedure";
  145.   break;
  146. case noNameServer:
  147.   s = "No name server found";
  148.   break;
  149. case authNameErr:
  150.   s = "Host does not exist";
  151.   break;
  152. case noAnsErr:
  153.   s = "No name servers responding";
  154.   break;
  155. case dnrErr:
  156.   s = "Name server returned an error";
  157.   break;
  158. case outOfMemory:
  159.   s = "Not enough memory to resolve name";
  160.   break;
  161. case notOpenErr:
  162.   s = "Driver not open";
  163.   break;
  164. default:
  165.   s = NIL;
  166.   break;
  167. }
  168. if (s) sprintf (tmp,"%s: %.80s",s,host);
  169. else sprintf (tmp,"Unknown resolver error (%ld): %.80s",
  170.       hst.rtnCode,host);
  171. mm_log (tmp,ERROR);
  172. return NIL;
  173.       }
  174.     }
  175.   }
  176. /* create local TCP/IP stream */
  177.   stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM));
  178.   stream->ictr = 0; /* initialize input */
  179.   stream->pb.ioCRefNum = TCPdriver;
  180.   createpb = &stream->pb.csParam.create;
  181.   openpb = &stream->pb.csParam.open;
  182.   stream->pb.csCode = TCPCreate;/* create a TCP stream */
  183. /* set up buffer for TCP */
  184.   createpb->rcvBuffLen = 4*BUFLEN;
  185.   createpb->rcvBuff = fs_get (createpb->rcvBuffLen);
  186.   createpb->notifyProc = NIL; /* no special notify procedure */
  187.   createpb->userDataPtr = NIL;
  188.   if (PBControlSync ((ParmBlkPtr) &stream->pb))
  189.     fatal ("Can't create TCP stream");
  190.    /* open TCP connection */
  191.   stream->pb.csCode = TCPActiveOpen;
  192.   openpb->ulpTimeoutValue = (int) ttmo_open;
  193.   openpb->ulpTimeoutAction = T;
  194.   openpb->validityFlags = timeoutValue|timeoutAction;
  195. /* remote host (should try all) */
  196.   openpb->remoteHost = hst.addr[0];
  197.   openpb->remotePort = port; /* caller specified remote port */
  198.   openpb->localPort = 0; /* generate a local port */
  199.   openpb->tosFlags = 0; /* no special TOS */
  200.   openpb->precedence = 0; /* no special precedence */
  201.   openpb->dontFrag = 0; /* allow fragmentation */
  202.   openpb->timeToLive = 255; /* standards say 60, UNIX uses 255 */
  203.   openpb->security = 0; /* no special security */
  204.   openpb->optionCnt = 0; /* no IP options */
  205.   openpb->options[0] = 0;
  206.   openpb->userDataPtr = NIL; /* no special data pointer */
  207.   PBControlAsync ((ParmBlkPtr) &stream->pb);
  208.   while (stream->pb.ioResult == inProgress && wait ());
  209.   if (stream->pb.ioResult) { /* got back error status? */
  210.     sprintf (tmp,"Can't connect to %.80s,%ld",hst.cname,port);
  211.     mm_log (tmp,ERROR);
  212. /* nuke the buffer */
  213.     stream->pb.csCode = TCPRelease;
  214.     createpb->userDataPtr = NIL;
  215.     if (PBControlSync ((ParmBlkPtr) &stream->pb)) fatal ("TCPRelease lossage");
  216. /* free its buffer */
  217.     fs_give ((void **) &createpb->rcvBuff);
  218.     fs_give ((void **) &stream);/* and the local stream */
  219.     return NIL;
  220.   }
  221. /* copy host names for later use */
  222.   stream->host = cpystr (hst.cname);
  223. /* tie off trailing dot */
  224.   stream->host[strlen (stream->host) - 1] = '';
  225. /* the open gave us our address */
  226.   i = (openpb->localHost >> 24) & 0xff;
  227.   j = (openpb->localHost >> 16) & 0xff;
  228.   k = (openpb->localHost >> 8) & 0xff;
  229.   l = openpb->localHost & 0xff;
  230.   sprintf (tmp,"[%ld.%ld.%ld.%ld]",i,j,k,l);
  231.   stream->localhost = cpystr (tmp);
  232.   if (!myLocalHost) myLocalHost = cpystr (tmp);
  233.   stream->port = port; /* copy port number */
  234.   return stream;
  235. }
  236. /* Called when have return from DNS
  237.  * Accepts: host info pointer
  238.  *     user data pointer
  239.  */
  240. ResultUPP tcp_dns_upp = NIL;
  241. pascal void tcp_dns_result (struct hostInfo *hostInfoPtr,char *userDataPtr)
  242. {
  243.   /* dummy routine */
  244. }
  245. /* TCP/IP authenticated open
  246.  * Accepts: NETMBX specifier
  247.  *     service name
  248.  *     returned user name buffer
  249.  * Returns: TCP/IP stream if success else NIL
  250.  */
  251. TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
  252. {
  253.   return NIL; /* no authenticated opens on Mac */
  254. }
  255. /* TCP/IP receive line
  256.  * Accepts: TCP/IP stream
  257.  * Returns: text line string or NIL if failure
  258.  */
  259. char *tcp_getline (TCPSTREAM *stream)
  260. {
  261.   int n,m;
  262.   char *st,*ret,*stp;
  263.   char c = '';
  264.   char d;
  265. /* make sure have data */
  266.   if (!tcp_getdata (stream)) return NIL;
  267.   st = stream->iptr; /* save start of string */
  268.   n = 0; /* init string count */
  269.   while (stream->ictr--) { /* look for end of line */
  270.     d = *stream->iptr++; /* slurp another character */
  271.     if ((c == '15') && (d == '12')) {
  272.       ret = (char *) fs_get (n--);
  273.       memcpy (ret,st,n); /* copy into a free storage string */
  274.       ret[n] = ''; /* tie off string with null */
  275.       return ret;
  276.     }
  277.     n++; /* count another character searched */
  278.     c = d; /* remember previous character */
  279.   }
  280. /* copy partial string from buffer */
  281.   memcpy ((ret = stp = (char *) fs_get (n)),st,n);
  282. /* get more data from the net */
  283.   if (!tcp_getdata (stream)) return NIL;
  284. /* special case of newline broken by buffer */
  285.   if ((c == '15') && (*stream->iptr == '12')) {
  286.     stream->iptr++; /* eat the line feed */
  287.     stream->ictr--;
  288.     ret[n - 1] = ''; /* tie off string with null */
  289.   }
  290. /* else recurse to get remainder */
  291.   else if (st = tcp_getline (stream)) {
  292.     ret = (char *) fs_get (n + 1 + (m = strlen (st)));
  293.     memcpy (ret,stp,n); /* copy first part */
  294.     memcpy (ret + n,st,m); /* and second part */
  295.     fs_give ((void **) &stp); /* flush first part */
  296.     fs_give ((void **) &st); /* flush second part */
  297.     ret[n + m] = ''; /* tie off string with null */
  298.   }
  299.   return ret;
  300. }
  301. /* TCP/IP receive buffer
  302.  * Accepts: TCP/IP stream
  303.  *     size in bytes
  304.  *     buffer to read into
  305.  * Returns: T if success, NIL otherwise
  306.  */
  307. long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer)
  308. {
  309.   unsigned long n;
  310.   char *bufptr = buffer;
  311.   while (size > 0) { /* until request satisfied */
  312.     if (!tcp_getdata (stream)) return NIL;
  313.     n = min (size,stream->ictr);/* number of bytes to transfer */
  314. /* do the copy */
  315.     memcpy (bufptr,stream->iptr,n);
  316.     bufptr += n; /* update pointer */
  317.     stream->iptr +=n;
  318.     size -= n; /* update # of bytes to do */
  319.     stream->ictr -=n;
  320.   }
  321.   bufptr[0] = ''; /* tie off string */
  322.   return T;
  323. }
  324. /* TCP/IP receive data
  325.  * Accepts: TCP/IP stream
  326.  * Returns: T if success, NIL otherwise
  327.  */
  328. long tcp_getdata (TCPSTREAM *stream)
  329. {
  330.   time_t t = time (0);
  331.   struct TCPReceivePB *receivepb = &stream->pb.csParam.receive;
  332.   struct TCPAbortPB *abortpb = &stream->pb.csParam.abort;
  333.   while (stream->ictr < 1) { /* if nothing in the buffer */
  334.     time_t tl = time (0);
  335.     stream->pb.csCode = TCPRcv; /* receive TCP data */
  336.     receivepb->commandTimeoutValue = (int) ttmo_read;
  337.     receivepb->rcvBuff = stream->ibuf;
  338.     receivepb->rcvBuffLen = BUFLEN;
  339.     receivepb->secondTimeStamp = 0;
  340.     receivepb->userDataPtr = NIL;
  341.     PBControlAsync ((ParmBlkPtr) &stream->pb);
  342.     while (stream->pb.ioResult == inProgress && wait ());
  343.     if (stream->pb.ioResult) { /* punt if got an error */
  344.       time_t tc = time (0);
  345.       if ((stream->pb.ioResult == commandTimeout) && tmoh &&
  346.   ((*tmoh) (tc - t,tc - tl))) continue;
  347.      /* nuke connection */
  348.       stream->pb.csCode = TCPAbort;
  349.       abortpb->userDataPtr = NIL;
  350.       PBControlSync ((ParmBlkPtr) &stream->pb);
  351.       return NIL;
  352.     }
  353.     stream->iptr = stream->ibuf;/* point at TCP buffer */
  354.     stream->ictr = receivepb->rcvBuffLen;
  355.   }
  356.   return T;
  357. }
  358. /* TCP/IP send string as record
  359.  * Accepts: TCP/IP stream
  360.  *     string pointer
  361.  * Returns: T if success else NIL
  362.  */
  363. long tcp_soutr (TCPSTREAM *stream,char *string)
  364. {
  365.   return tcp_sout (stream,string,(unsigned long) strlen (string));
  366. }
  367. /* TCP/IP send string
  368.  * Accepts: TCP/IP stream
  369.  *     string pointer
  370.  *     byte count
  371.  * Returns: T if success else NIL
  372.  */
  373. long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
  374. {
  375.   struct TCPSendPB *sendpb = &stream->pb.csParam.send;
  376.   struct TCPAbortPB *abortpb = &stream->pb.csParam.abort;
  377.   struct {
  378.     unsigned short length;
  379.     Ptr buffer;
  380.     unsigned short trailer;
  381.   } wds;
  382.   while (wds.length = (size > (unsigned long) 32768) ? 32768 : size) {
  383.     wds.buffer = string; /* buffer */
  384.     wds.trailer = 0; /* tie off buffer */
  385.     size -= wds.length; /* this many words will be output */
  386.     string += wds.length;
  387.     stream->pb.csCode = TCPSend;/* send TCP data */
  388.     sendpb->ulpTimeoutValue = (int) ttmo_write;
  389.     sendpb->ulpTimeoutAction = 0;
  390.     sendpb->validityFlags = timeoutValue|timeoutAction;
  391.     sendpb->pushFlag = T; /* send the data now */
  392.     sendpb->urgentFlag = NIL; /* non-urgent data */
  393.     sendpb->wdsPtr = (Ptr) &wds;
  394.     sendpb->userDataPtr = NIL;
  395.     PBControlAsync ((ParmBlkPtr) &stream->pb);
  396.     while (stream->pb.ioResult == inProgress && wait ());
  397.     if (stream->pb.ioResult) { /* punt if got an error */
  398. /* nuke connection */
  399.       stream->pb.csCode =TCPAbort;
  400.       abortpb->userDataPtr = NIL;
  401.       PBControlSync ((ParmBlkPtr) &stream->pb);
  402.       return NIL;
  403.     }
  404.   }
  405.   return T; /* success */
  406. }
  407. /* TCP/IP close
  408.  * Accepts: TCP/IP stream
  409.  */
  410. void tcp_close (TCPSTREAM *stream)
  411. {
  412.   struct TCPClosePB *closepb = &stream->pb.csParam.close;
  413.   struct TCPCreatePB *createpb = &stream->pb.csParam.create;
  414.   stream->pb.csCode = TCPClose; /* close TCP stream */
  415.   closepb->ulpTimeoutValue = (int) ttmo_close;
  416.   closepb->ulpTimeoutAction = 0;
  417.   closepb->validityFlags = timeoutValue|timeoutAction;
  418.   closepb->userDataPtr = NIL;
  419.   PBControlAsync ((ParmBlkPtr) &stream->pb);
  420.   while (stream->pb.ioResult == inProgress && wait ());
  421.   stream->pb.csCode =TCPRelease;/* flush the buffers */
  422.   createpb->userDataPtr = NIL;
  423.   if (PBControlSync ((ParmBlkPtr) &stream->pb)) fatal ("TCPRelease lossage");
  424. /* free its buffer */
  425.   fs_give ((void **) &createpb->rcvBuff);
  426. /* flush host names */
  427.   fs_give ((void **) &stream->host);
  428.   fs_give ((void **) &stream->localhost);
  429.   fs_give ((void **) &stream); /* flush the stream */
  430. }
  431. /* TCP/IP return host for this stream
  432.  * Accepts: TCP/IP stream
  433.  * Returns: host name for this stream
  434.  */
  435. char *tcp_host (TCPSTREAM *stream)
  436. {
  437.   return stream->host; /* return host name */
  438. }
  439. /* TCP/IP return remote host for this stream
  440.  * Accepts: TCP/IP stream
  441.  * Returns: host name for this stream
  442.  */
  443. char *tcp_remotehost (TCPSTREAM *stream)
  444. {
  445.   return stream->host; /* return host name */
  446. }
  447. /* TCP/IP return port for this stream
  448.  * Accepts: TCP/IP stream
  449.  * Returns: port number for this stream
  450.  */
  451. unsigned long tcp_port (TCPSTREAM *stream)
  452. {
  453.   return stream->port; /* return port number */
  454. }
  455. /* TCP/IP return local host for this stream
  456.  * Accepts: TCP/IP stream
  457.  * Returns: local host name for this stream
  458.  */
  459. char *tcp_localhost (TCPSTREAM *stream)
  460. {
  461.   return stream->localhost; /* return local host name */
  462. }
  463. /* TCP/IP return canonical form of host name
  464.  * Accepts: host name
  465.  * Returns: canonical form of host name
  466.  */
  467. char *tcp_canonical (char *name)
  468. {
  469.   int i;
  470.   struct hostInfo hst;
  471. /* look like domain literal? */
  472.   if (name[0] == '[' && name[i = (strlen (name))-1] == ']') return name;
  473.   if (StrToAddr (name,&hst,tcp_dns_upp,NIL)) {
  474.     while (hst.rtnCode == cacheFault && wait ());
  475. /* kludge around MacTCP bug */
  476.     if (hst.rtnCode == outOfMemory) {
  477.       mm_log ("Re-initializing domain resolver",WARN);
  478.       CloseResolver (); /* bop it on the head and try again */
  479.       OpenResolver (NIL); /* note this will leak 12K */
  480.       StrToAddr (name,&hst,tcp_dns_upp,NIL);
  481.       while (hst.rtnCode == cacheFault && wait ());
  482.     }
  483. /* still have error status? */
  484.     if (hst.rtnCode) return name;
  485.   }
  486.   return hst.cname; /* success */
  487. }
  488. /* TCP/IP get client host name (server calls only)
  489.  * Returns: client host name
  490.  */
  491. char *tcp_clienthost ()
  492. {
  493.   return "UNKNOWN";
  494. }