/[MITgcm]/MITgcm/tools/mpack-1.6/macntcp.c
ViewVC logotype

Annotation of /MITgcm/tools/mpack-1.6/macntcp.c

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.1 - (hide annotations) (download)
Tue Aug 26 20:45:25 2003 UTC (20 years, 8 months ago) by edhill
Branch: MAIN
CVS Tags: checkpoint64y, checkpoint64x, checkpoint58l_post, checkpoint64z, checkpoint51k_post, checkpoint57t_post, checkpoint64q, checkpoint64p, checkpoint64s, checkpoint64r, checkpoint64u, checkpoint64t, checkpoint64w, checkpoint64v, checkpoint64i, checkpoint64h, checkpoint64k, checkpoint64j, checkpoint64m, checkpoint64l, checkpoint64o, checkpoint64n, checkpoint64a, checkpoint57o_post, checkpoint64c, checkpoint64b, checkpoint64e, checkpoint64d, checkpoint64g, checkpoint64f, checkpoint52l_pre, checkpoint52e_pre, hrcube4, checkpoint58e_post, mitgcm_mapl_00, checkpoint52n_post, checkpoint52j_post, checkpoint53d_post, checkpoint58u_post, checkpoint58w_post, checkpoint54a_pre, checkpoint51o_pre, checkpoint57m_post, checkpoint55c_post, checkpoint54e_post, checkpoint52e_post, checkpoint57s_post, checkpoint51n_pre, checkpoint54a_post, checkpoint63p, checkpoint63q, checkpoint63r, checkpoint63s, checkpoint63l, checkpoint63m, checkpoint63n, checkpoint63o, checkpoint63h, checkpoint63i, checkpoint63j, checkpoint63k, checkpoint63d, checkpoint63e, checkpoint63f, checkpoint63g, checkpoint53c_post, checkpoint63a, checkpoint63b, checkpoint63c, checkpoint57k_post, checkpoint55d_pre, checkpoint57d_post, checkpoint51l_post, checkpoint57g_post, checkpoint51q_post, checkpoint64, checkpoint65, checkpoint60, checkpoint61, checkpoint62, checkpoint63, checkpoint57b_post, checkpoint57c_pre, checkpoint51j_post, checkpoint58r_post, checkpoint55j_post, checkpoint56b_post, checkpoint57i_post, checkpoint57y_post, hrcube_1, checkpoint57e_post, checkpoint66g, checkpoint66f, checkpoint66e, checkpoint66d, checkpoint66c, checkpoint66b, checkpoint66a, checkpoint66o, checkpoint66n, checkpoint66m, checkpoint66l, checkpoint66k, checkpoint66j, checkpoint66i, checkpoint66h, branch-netcdf, checkpoint52d_pre, checkpoint52l_post, checkpoint55h_post, checkpoint58n_post, checkpoint53b_post, checkpoint58x_post, checkpoint52k_post, checkpoint52b_pre, checkpoint57g_pre, checkpoint54b_post, checkpoint53b_pre, checkpoint55b_post, checkpoint58t_post, checkpoint58h_post, checkpoint65z, checkpoint65x, checkpoint65y, checkpoint54d_post, checkpoint65r, checkpoint65s, checkpoint65p, checkpoint65q, checkpoint65v, checkpoint65w, checkpoint65t, checkpoint65u, checkpoint65j, checkpoint65k, checkpoint65h, checkpoint65i, checkpoint65n, checkpoint65o, checkpoint65l, checkpoint65m, checkpoint65b, checkpoint65c, checkpoint65a, checkpoint65f, checkpoint65g, checkpoint65d, checkpoint65e, checkpoint56c_post, checkpoint52m_post, checkpoint57y_pre, checkpoint55, checkpoint53a_post, checkpoint57f_pre, checkpoint57a_post, checkpoint54, checkpoint58q_post, checkpoint54f_post, checkpoint57v_post, checkpoint59q, checkpoint59p, checkpoint55g_post, checkpoint59r, checkpoint51o_post, checkpoint51p_post, checkpoint58j_post, checkpoint52a_pre, checkpoint59e, checkpoint59d, checkpoint59g, checkpoint59f, checkpoint59a, checkpoint55f_post, checkpoint59c, checkpoint59b, checkpoint59m, checkpoint59l, checkpoint59o, checkpoint59n, checkpoint59i, checkpoint59h, checkpoint59k, checkpoint59j, checkpoint57r_post, checkpoint59, checkpoint58, checkpoint57a_pre, checkpoint55i_post, checkpoint57, checkpoint56, checkpoint51i_post, checkpoint53, checkpoint52, checkpoint51f_post, checkpoint52d_post, eckpoint57e_pre, checkpoint51r_post, checkpoint52a_post, checkpoint57h_done, checkpoint58f_post, checkpoint52b_post, checkpoint53g_post, checkpoint52f_post, branchpoint-genmake2, checkpoint57x_post, checkpoint57n_post, checkpoint52c_post, checkpoint58d_post, checkpoint58c_post, checkpoint57w_post, checkpoint57p_post, checkpint57u_post, checkpoint57f_post, checkpoint58a_post, checkpoint51h_pre, checkpoint51l_pre, checkpoint58i_post, checkpoint57q_post, checkpoint51g_post, checkpoint58g_post, ecco_c52_e35, hrcube5, checkpoint58o_post, checkpoint57z_post, checkpoint62c, checkpoint62b, checkpoint62a, checkpoint62g, checkpoint62f, checkpoint62e, checkpoint62d, checkpoint62k, checkpoint62j, checkpoint62i, checkpoint62h, checkpoint62o, checkpoint62n, checkpoint62m, checkpoint62l, checkpoint62s, checkpoint62r, checkpoint62q, checkpoint62p, checkpoint62w, checkpoint62v, checkpoint62u, checkpoint62t, checkpoint57c_post, checkpoint62z, checkpoint62y, checkpoint62x, checkpoint58y_post, checkpoint55e_post, checkpoint58k_post, checkpoint52i_post, checkpoint52j_pre, checkpoint58v_post, checkpoint53f_post, checkpoint55a_post, checkpoint51t_post, checkpoint53d_pre, checkpoint54c_post, checkpoint58s_post, checkpoint61f, checkpoint61g, checkpoint61d, checkpoint61e, checkpoint61b, checkpoint61c, checkpoint58p_post, checkpoint61a, checkpoint61n, checkpoint61o, checkpoint61l, checkpoint61m, checkpoint61j, checkpoint61k, checkpoint61h, checkpoint61i, checkpoint61v, checkpoint61w, checkpoint61t, checkpoint61u, checkpoint61r, checkpoint61s, checkpoint61p, checkpoint61q, checkpoint51n_post, checkpoint57j_post, checkpoint61z, checkpoint61x, checkpoint61y, checkpoint58b_post, checkpoint57h_pre, checkpoint51i_pre, checkpoint58m_post, checkpoint57l_post, checkpoint52i_pre, checkpoint51u_post, checkpoint52h_pre, checkpoint52f_pre, checkpoint57h_post, hrcube_2, hrcube_3, checkpoint56a_post, checkpoint51m_post, checkpoint51s_post, checkpoint55d_post, HEAD
Branch point for: branch-nonh, branch-genmake2, tg2-branch, checkpoint51n_branch, netcdf-sm0
File MIME type: text/plain
Initial check-in of the CMU "mpack" utility.  This allows us to (portably)
send MITgcm output as MIME-encoded email messages and will be used by the
"testreport" script.  The CMU license is basically an "AS-IS" statement.

1 edhill 1.1 /* macntcp.c -- macintosh nifty application library async TCP routines
2     */
3     /* (C) Copyright 1995 by Carnegie Mellon University
4     * All Rights Reserved.
5     *
6     * Permission to use, copy, modify, distribute, and sell this software
7     * and its documentation for any purpose is hereby granted without
8     * fee, provided that the above copyright notice appear in all copies
9     * and that both that copyright notice and this permission notice
10     * appear in supporting documentation, and that the name of Carnegie
11     * Mellon University not be used in advertising or publicity
12     * pertaining to distribution of the software without specific,
13     * written prior permission. Carnegie Mellon University makes no
14     * representations about the suitability of this software for any
15     * purpose. It is provided "as is" without express or implied
16     * warranty.
17     *
18     * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
19     * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
20     * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
21     * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
22     * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
23     * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
24     * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
25     * SOFTWARE.
26     */
27     /* (C) Copyright 1994-1995 by Christopher J. Newman
28     * All Rights Reserved.
29     *
30     * Permission to use, copy, modify, distribute, and sell this software and its
31     * documentation for any purpose is hereby granted without fee, provided that
32     * the above copyright notice appear in all copies and that both that
33     * copyright notice and this permission notice appear in supporting
34     * documentation, and that the name of Christopher J. Newman not be used in
35     * advertising or publicity pertaining to distribution of the software without
36     * specific, written prior permission. Christopher J. Newman makes no
37     * representations about the suitability of this software for any purpose. It
38     * is provided "as is" without express or implied warranty.
39     *
40     * CHRISTOPHER J. NEWMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
41     * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT
42     * SHALL CHRISTOPHER J. NEWMAN BE LIABLE FOR ANY SPECIAL, INDIRECT OR
43     * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
44     * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
45     * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
46     * OF THIS SOFTWARE.
47     *
48     * Author: Christopher J. Newman
49     * Message: This is a nifty program.
50     */
51    
52     #include <string.h>
53     #include <MacTCPCommonTypes.h>
54     #include <TCPPB.h>
55     #include <AddressXlation.h>
56     #include <GetMyIPAddr.h>
57     #include "macnapp.h"
58    
59     #define DEF_STREAM_SIZE 8192
60     #define MAX_TCPCON 16
61     #define RDS 8
62    
63     /* write buffer for TCP writes
64     */
65     typedef struct tcpwb {
66     short rused; /* number of RDS used (-1 == in TCPsend) */
67     short wused; /* amount of small buffer used */
68     rdsEntry rds[RDS+1]; /* array of RDS pointers */
69     char fflag[RDS+1]; /* free flags for RDS pointers (1 = call DisposPtr) */
70     char *buf; /* write buffer */
71     } tcpwb;
72    
73     /* structure describing a TCP connection
74     */
75     typedef struct tcpinfo {
76     short state; /* current state */
77     short rclose; /* remote host wants to close */
78     short lclose; /* local host wants to close */
79     int havedata:1; /* data is available to read */
80     int urgent:1; /* TCP in urgent mode */
81     int push:1; /* next write should be pushed */
82     int pushed:1; /* last write was pushed */
83     int reading:1; /* reading data */
84     int server:1; /* is a server, rather than client */
85     int gethost:1; /* getting hostname -- not a real connection */
86     int dnrdone:1; /* DNR query is done */
87     short wbnum; /* write buffer for next write */
88     unsigned short wbsize; /* size of write buffer */
89     unsigned short reason; /* reason for TCP termination */
90     StreamPtr stream; /* TCP stream */
91     ip_port port; /* TCP port number to connect to */
92     void *context; /* user context */
93     na_tcpreadp *callback; /* callback function */
94     rdsEntry rrds[RDS+1]; /* read RDS structure */
95     tcpwb wb[2]; /* write buffers */
96     struct hostInfo host; /* hostname & ip_addr of host */
97     TCPiopb pb; /* parameter block for TCP connect/write/close */
98     TCPiopb rpb; /* parameter block for TCP read */
99     char buf[1]; /* stream buffer follows */
100     } tcpinfo;
101    
102     /* TCP task state information
103     */
104     struct tcpstate {
105     na_win win;
106     short tcp_driver;
107     na_tcpinitp *tcp_initp;
108     tcpinfo *tcpbufs[MAX_TCPCON];
109     IOParam *open_pb;
110     long waiticks, waitstart;
111     short waitpercent;
112     long streamsize;
113     byte TOS, precedence;
114     unsigned short wbsize;
115     char localhost[256];
116     } **tcpstate = NULL;
117     #define tstate ((struct tcpstate *) win)
118    
119     /* tcp state bitmasks */
120     #define TCP_PBINUSE 0x04 /* tcp->pb in use */
121     #define TCP_DNSINUSE 0x08 /* DNS in use */
122     #define TCP_NOTREADY 0x10 /* not ready for reading */
123     /* tcp states */
124     #define TCP_READY 1 /* inactive */
125     #define TCP_RESOLVE (TCP_NOTREADY + TCP_DNSINUSE + 0) /* resolving hostname */
126     #define TCP_GETHOST (TCP_NOTREADY + TCP_DNSINUSE + 1) /* looking up hostname */
127     #define TCP_WRITING (TCP_PBINUSE + 0) /* writing data */
128     #define TCP_CONNECT (TCP_NOTREADY + TCP_PBINUSE + 0) /* waiting for a connection */
129     #define TCP_CLOSING (TCP_NOTREADY + TCP_PBINUSE + 1) /* waiting for TCPclose */
130     #define TCP_CLOSED 2 /* closed */
131    
132     /* free write buffer storage
133     */
134     static void freewb(tcpwb *wb)
135     {
136     short i;
137    
138     for (i = 0; wb->rds[i].length; ++i) {
139     if (wb->fflag[i]) {
140     DisposPtr(wb->rds[i].ptr);
141     wb->fflag[i] = 0;
142     }
143     }
144     wb->rused = 0;
145     wb->wused = 0;
146     }
147    
148     /* make sure tcp_driver is open
149     */
150     static short tcp_checkdriver()
151     {
152     short msg = NATCP_nodriver;
153     struct tcpstate *ts = *tcpstate;
154     IOParam *opb = ts->open_pb;
155    
156     if (!opb) return (1);
157     if (opb->ioResult == 1) return (0);
158     if (opb->ioResult == noErr && OpenResolver(nil) == noErr) {
159     ts->tcp_driver = opb->ioRefNum;
160     msg = NATCP_connect;
161     }
162     DisposPtr((Ptr) opb);
163     ts = *tcpstate;
164     ts->open_pb = NULL;
165     (*ts->tcp_initp)(msg);
166    
167     return (1);
168     }
169    
170     /* wait for MacTCP to finish whatever it's doing, with user cancel
171     */
172     static short tcp_wait(struct tcpstate *ts, tcpinfo *tcp)
173     {
174     KeyMap mapkeys;
175     #define keys ((unsigned char *)mapkeys)
176     short percent;
177    
178     while (!tcp_checkdriver()
179     || (tcp && (tcp->state & TCP_DNSINUSE) && ! (volatile) tcp->dnrdone)
180     || (tcp && (tcp->state & TCP_PBINUSE) && (volatile short) tcp->pb.ioResult == 1)) {
181     if (ts) {
182     if (!ts->waiticks) return (0);
183     percent = ((TickCount() - ts->waitstart) * 100) / ts->waiticks;
184     if (percent > 100) percent = 100;
185     if (percent != ts->waitpercent) {
186     (*ts->tcp_initp)(ts->waitpercent = percent);
187     }
188     if (percent == 100) return (0);
189     }
190     SystemTask();
191     GetKeys(mapkeys);
192     if ((keys[0x37 >> 3] >> (0x37 & 7))
193     & (keys[0x2f >> 3] >> (0x2f & 7)) & 1) {
194     return (0);
195     }
196     }
197    
198     return (1);
199     }
200    
201     /* clean up the TCP task
202     */
203     static short tcp_closep(na_win *win)
204     {
205     short i, j;
206     tcpinfo *tcp;
207     tcpwb *wb;
208     TCPiopb pb;
209    
210     tstate->waitstart = TickCount();
211     tstate->waitpercent = 0;
212     tcp_wait(tstate, NULL);
213     memset((void *) &pb, 0, sizeof (pb));
214     for (i = 0; i < MAX_TCPCON; ++i) {
215     if ((tcp = tstate->tcpbufs[i]) != NULL) {
216     /* wait for MacTCP to finish what it's doing, but permit user cancel */
217     if (!tcp->server || tcp->state != TCP_CONNECT) tcp_wait(tstate, tcp);
218     if (!tcp->gethost) {
219     pb.ioCRefNum = tstate->tcp_driver;
220     pb.tcpStream = tcp->stream;
221     pb.csCode = TCPRelease;
222     PBControl((ParmBlkPtr) &pb, false);
223     }
224     freewb(tcp->wb);
225     freewb(tcp->wb + 1);
226     DisposPtr((Ptr) tcp);
227     tstate->tcpbufs[i] = NULL;
228     }
229     }
230     tcpstate = NULL;
231     if (tstate->tcp_driver) CloseResolver();
232    
233     return (NA_CLOSED);
234     }
235    
236     /* begin writing data
237     */
238     static short beginwrite(tcpinfo *tcp)
239     {
240     tcpwb *wb = tcp->wb + tcp->wbnum;
241    
242     /* if connection terminated, or we've sent a TCPclose, we can't write */
243     if (tcp->rclose == 3 || tcp->lclose > 1) return (0);
244     memset((void *) &tcp->pb.csParam, 0, sizeof (tcp->pb.csParam));
245     tcp->pb.csCode = TCPSend;
246     tcp->pb.csParam.send.ulpTimeoutValue = 60; /* 1 minute to send data */
247     tcp->pb.csParam.send.ulpTimeoutAction = 0;
248     tcp->pb.csParam.send.validityFlags = 0xC0;
249     tcp->pb.csParam.send.wdsPtr = (Ptr) wb->rds;
250     tcp->pb.csParam.send.pushFlag = tcp->pushed = tcp->push;
251     PBControl((ParmBlkPtr) &tcp->pb, true);
252     tcp->push = 0;
253     tcp->wbnum = 1 - tcp->wbnum;
254     wb->rused = -1;
255    
256     return (tcp->state = TCP_WRITING);
257     }
258    
259     /* do I/O polling
260     */
261     short NATCPtask(na_win *win)
262     {
263     tcpinfo *tcp;
264     rdsEntry *rds, *trds;
265     short result, newstate;
266     short processed = NA_PROCESSED;
267     na_tcp i;
268     tcpwb *wb;
269     int j;
270    
271     /* finish off driver initialization: */
272     if (!tstate->tcp_driver) {
273     if (!tcp_checkdriver()) return (NA_NOTPROCESSED);
274     if (!tstate->tcp_driver) return (NA_REQCLOSE);
275     }
276     /* loop through connections */
277     for (i = 0; i < MAX_TCPCON; ++i) {
278     if ((tcp = tstate->tcpbufs[i]) != NULL) do {
279     /* read data if we have it */
280     if (!tcp->reading && !tcp->rclose && tcp->havedata && tcp->state != TCP_CONNECT) {
281     tcp->rpb.ioCRefNum = tstate->tcp_driver;
282     tcp->rpb.tcpStream = tcp->stream;
283     tcp->rpb.csCode = TCPNoCopyRcv;
284     tcp->rpb.csParam.receive.rdsPtr = (Ptr) tcp->rrds;
285     tcp->rpb.csParam.receive.commandTimeoutValue = 5;
286     tcp->rpb.csParam.receive.rdsLength = RDS;
287     if (tcp->pushed) {
288     tcp->rpb.csParam.receive.commandTimeoutValue = 1;
289     tcp->rpb.csParam.receive.rdsLength = 1;
290     }
291     tcp->havedata = 0;
292     PBControl((ParmBlkPtr) &tcp->rpb, tcp->pushed ? false : true);
293     tcp->reading = 1;
294     tcp->pushed = 0;
295     }
296     if (tcp->reading) {
297     if ((result = tcp->rpb.ioResult) == 1) {
298     processed = NA_NOTPROCESSED;
299     } else {
300     tcp->reading = 0;
301     if (result != noErr) {
302     if (result != commandTimeout) {
303     (*tcp->callback)(tcp->context, i, NATCP_noread, result, NULL);
304     }
305     } else {
306     result = NATCP_data | NATCP_more;
307     if (tcp->rpb.csParam.receive.urgentFlag) tcp->urgent = 1;
308     if (tcp->urgent) result |= NATCP_urgent;
309     if (tcp->rpb.csParam.receive.markFlag) tcp->urgent = 0;
310     for (rds = tcp->rrds; rds->length; ++rds) {
311     if (!rds[1].length) result &= ~NATCP_more;
312     (*tcp->callback)(tcp->context, i, result,
313     rds->length, rds->ptr);
314     }
315     tcp->rpb.csCode = TCPRcvBfrReturn;
316     PBControl((ParmBlkPtr) &tcp->rpb, false);
317     }
318     }
319     }
320     result = tcp->pb.ioResult;
321     newstate = 0;
322     switch (tcp->state) {
323     case TCP_GETHOST:
324     if (tcp->dnrdone) {
325     tcp->rclose = 3;
326     newstate = TCP_CLOSED;
327     if (tcp->host.rtnCode != noErr) {
328     (*tcp->callback)(tcp->context, i, NATCP_nohost,
329     tcp->host.rtnCode, NULL);
330     } else {
331     (*tcp->callback)(tcp->context, i, NATCP_connect,
332     strlen(tcp->host.cname), tcp->host.cname);
333     strcpy(tstate->localhost, tcp->host.cname);
334     }
335     }
336     break;
337     case TCP_RESOLVE:
338     if (tcp->dnrdone) {
339     if (tcp->host.rtnCode != noErr) {
340     tcp->rclose = 3;
341     newstate = TCP_CLOSED;
342     (*tcp->callback)(tcp->context, i, NATCP_nohost,
343     tcp->host.rtnCode, NULL);
344     } else if (!tcp->lclose) {
345     memset((void *) &tcp->pb, 0, sizeof (tcp->pb));
346     tcp->pb.ioCRefNum = tstate->tcp_driver;
347     tcp->pb.tcpStream = tcp->stream;
348     tcp->pb.csParam.open.ulpTimeoutValue = 30;
349     tcp->pb.csParam.open.ulpTimeoutAction = 1; /* Abort on timeout */
350     tcp->pb.csParam.open.tosFlags = tstate->TOS;
351     tcp->pb.csParam.open.precedence = tstate->precedence;
352     tcp->pb.csParam.open.validityFlags =
353     timeoutValue|timeoutAction|typeOfService|precedence;
354     tcp->pb.csParam.open.remoteHost = tcp->host.addr[0];
355     if (tcp->server) {
356     tcp->pb.csCode = TCPPassiveOpen;
357     tcp->pb.csParam.open.commandTimeoutValue = 0;
358     tcp->pb.csParam.open.remotePort = 0;
359     tcp->pb.csParam.open.localPort = tcp->port;
360     } else {
361     tcp->pb.csCode = TCPActiveOpen;
362     tcp->pb.csParam.open.remotePort = tcp->port;
363     tcp->pb.csParam.open.localPort = 0;
364     }
365     PBControl((ParmBlkPtr) &tcp->pb, true);
366     newstate = TCP_CONNECT;
367     }
368     }
369     break;
370     case TCP_CONNECT:
371     if (result == 1) {
372     processed = NA_NOTPROCESSED;
373     break;
374     }
375     if (result != noErr) {
376     tcp->rclose = 3;
377     newstate = TCP_CLOSED;
378     (*tcp->callback)(tcp->context, i, NATCP_nocon, result, NULL);
379     } else {
380     newstate = TCP_READY;
381     if (tcp->server) {
382     tcp->port = tcp->pb.csParam.open.remotePort;
383     if (!*tcp->host.cname) {
384     AddrToStr(tcp->pb.csParam.open.remoteHost, tcp->host.cname);
385     }
386     }
387     (*tcp->callback)(tcp->context, i, NATCP_connect,
388     tcp->port, tcp->host.cname);
389     }
390     break;
391     case TCP_READY:
392     /* Write data if we have it */
393     wb = tcp->wb + tcp->wbnum;
394     if (wb->rused && (newstate = beginwrite(tcp))) {
395     break;
396     }
397     /* check if other side wants to close */
398     if (tcp->rclose == 1) {
399     tcp->rclose = 2;
400     (*tcp->callback)(tcp->context, i, NATCP_closing, 0, NULL);
401     }
402     /* check if connection needs closing at this end */
403     if (tcp->lclose == 1) {
404     tcp->lclose = 2;
405     tcp->pb.csCode = TCPClose;
406     tcp->pb.csParam.close.validityFlags = 0xC0;
407     tcp->pb.csParam.close.ulpTimeoutValue = 30; /* give 30 secs to close */
408     tcp->pb.csParam.close.ulpTimeoutAction = 0;
409     PBControl((ParmBlkPtr) &tcp->pb, true);
410     newstate = TCP_CLOSING;
411     break;
412     }
413     /* check if connection closed at both ends */
414     if (tcp->rclose == 3) {
415     (*tcp->callback)(tcp->context, i, NATCP_closed, tcp->reason, NULL);
416     newstate = TCP_CLOSED;
417     }
418     break;
419     case TCP_WRITING:
420     if (result == 1) {
421     processed = NA_NOTPROCESSED;
422     break;
423     }
424     wb = tcp->wb;
425     if (wb->rused != -1) ++wb;
426     freewb(wb);
427     if (result != noErr) {
428     tcp->pushed = 0;
429     (*tcp->callback)(tcp->context, i, NATCP_nowrite, result, NULL);
430     }
431     newstate = TCP_READY;
432     break;
433     case TCP_CLOSING:
434     if (result == 1) {
435     processed = NA_NOTPROCESSED;
436     break;
437     }
438     newstate = TCP_READY;
439     break;
440     case TCP_CLOSED:
441     if (!tcp->rclose) break;
442     if (!tcp->gethost) {
443     tcp->pb.csCode = TCPRelease;
444     PBControl((ParmBlkPtr)&tcp->pb, false);
445     }
446     freewb(tcp->wb);
447     freewb(tcp->wb + 1);
448     DisposPtr((Ptr) tcp);
449     tstate->tcpbufs[i] = NULL;
450     break;
451     }
452     if (newstate) tcp->state = newstate;
453     } while (newstate);
454     }
455    
456     return (processed);
457     }
458    
459     /* Async notification routine
460     */
461     static pascal void myTCPNotifyProc(StreamPtr stream, unsigned short eventCode,
462     Ptr userDataPtr, unsigned short terminReason, struct ICMPReport *icmpMsg)
463     {
464     tcpinfo *tcp = (tcpinfo *) userDataPtr;
465    
466     switch (eventCode) {
467     case TCPTerminate:
468     tcp->rclose = 3;
469     tcp->reason = terminReason;
470     break;
471     case TCPClosing:
472     tcp->rclose = 1;
473     break;
474     case TCPDataArrival:
475     tcp->havedata = 1;
476     break;
477     case TCPUrgent:
478     tcp->urgent = 1;
479     break;
480     }
481     }
482    
483     /* DNR resultproc */
484     static pascal void addrproc(struct hostInfo *hinfop, char *udata)
485     {
486     ((tcpinfo *) udata)->dnrdone = 1;
487     }
488    
489     /* callback to pass TCP info to window
490     */
491     static void winreadp(void *context, na_tcp i, short status, long len, char *buf)
492     {
493     natcp_win *w;
494    
495     w = (natcp_win *) NAlockWindow((na_win **) context);
496     w->s = i;
497     (*w->readp)(&w->winp, status, len, buf);
498     NAunlockWindowh((na_win **) context, &w->winp);
499     }
500    
501     /* adjust TCP settings
502     */
503     void NATCPsettings(long streamsize, short type_of_service, short precedence, unsigned short wbsize)
504     {
505     if (!streamsize) streamsize = DEF_STREAM_SIZE;
506     (*tcpstate)->streamsize = streamsize ? streamsize : DEF_STREAM_SIZE;
507     (*tcpstate)->TOS = type_of_service;
508     (*tcpstate)->precedence = precedence;
509     if (!wbsize) wbsize = 1024;
510     (*tcpstate)->wbsize = wbsize;
511     }
512    
513     /* initialize TCP system
514     */
515     void NATCPinit(na_tcpinitp *initp)
516     {
517     IOParam *pb;
518     int i;
519     struct tcpstate *ts;
520    
521     pb = (IOParam *) NewPtrClear(sizeof (IOParam));
522     tcpstate = (struct tcpstate **) NAaddtask(NATCPtask, sizeof (struct tcpstate));
523     if (!tcpstate || !pb) {
524     (*initp)(NATCP_nomem);
525     } else {
526     pb->ioNamePtr = "\p.IPP";
527     PBOpen((ParmBlkPtr) pb, true);
528     ts = *tcpstate;
529     for (i = 0; i < MAX_TCPCON; ++i) ts->tcpbufs[i] = NULL;
530     ts->waiticks = 60; /* wait 1 sec for TCP close by default */
531     ts->win.type = NA_TCPTYPE;
532     ts->win.closep = tcp_closep;
533     ts->win.priority = -1;
534     ts->tcp_initp = initp;
535     ts->open_pb = pb;
536     NATCPsettings(0, 0, 0, 0);
537     }
538     }
539    
540     /* get a TCP buffer block
541     */
542     static tcpinfo *getTCPbuf(na_tcpreadp *callback, void *context, int *id)
543     {
544     int i;
545     tcpinfo *tcp;
546    
547     /* make sure driver is open */
548     if (!(*tcpstate)->tcp_driver
549     && (!tcp_wait(NULL, NULL) || !(*tcpstate)->tcp_driver)) {
550     (*callback)(context, -1, NATCP_nodriver, 0, NULL);
551     return (NULL);
552     }
553    
554     /* find pointer slot and create buffer */
555     for (i = 0; i < MAX_TCPCON && (*tcpstate)->tcpbufs[i]; ++i);
556     if (i == MAX_TCPCON) {
557     (*callback)(context, -1, NATCP_notcpbuf, 0, NULL);
558     return (NULL);
559     }
560     tcp = (tcpinfo *) NewPtr(sizeof (tcpinfo) - 1
561     + (*tcpstate)->streamsize + (unsigned long) (*tcpstate)->wbsize * 2);
562     if (!tcp) {
563     (*callback)(context, -1, NATCP_nomem, 0, NULL);
564     return (NULL);
565     };
566     *id = i;
567     (*tcpstate)->tcpbufs[i] = tcp;
568     memset((char *) tcp, 0, sizeof (tcpinfo));
569    
570     /* initialize fields from global state */
571     tcp->wbsize = (*tcpstate)->wbsize;
572     tcp->wb[0].buf = tcp->buf + (*tcpstate)->streamsize;
573     tcp->wb[1].buf = tcp->wb[0].buf + tcp->wbsize;
574     tcp->pb.ioCRefNum = (*tcpstate)->tcp_driver;
575     tcp->context = context;
576     tcp->callback = callback;
577    
578     return (tcp);
579     }
580    
581     /* get host name
582     */
583     void NATCPgethost(na_tcpreadp *callback, void *context)
584     {
585     int id;
586     tcpinfo *tcp;
587     struct IPParamBlock *ippb;
588     na_win *win;
589    
590     if ((*tcpstate)->localhost[0]) {
591     win = NAlockWindow((na_win **) tcpstate);
592     (*callback)(context, -1, NATCP_connect, strlen(tstate->localhost),
593     tstate->localhost);
594     NAunlockWindowh((na_win **) tcpstate, win);
595     } else if ((tcp = getTCPbuf(callback, context, &id)) != NULL) {
596     /* here we make the assumption that an IP param block is smaller than
597     * a TCP param block. This seems like a safe assumption to me.
598     */
599     ippb = (struct IPParamBlock *) &tcp->pb;
600     /* get IP address */
601     ippb->ioCRefNum = (*tcpstate)->tcp_driver;
602     ippb->csCode = ipctlGetAddr;
603     PBControl((ParmBlkPtr)ippb, false);
604     if (ippb->ioResult != 0) {
605     (*callback)(context, -1, NATCP_notcpbuf, ippb->ioResult, NULL);
606     DisposPtr((Ptr) tcp);
607     (*tcpstate)->tcpbufs[id] = NULL;
608     } else {
609     /* begin IP address lookup */
610     tcp->dnrdone = 0;
611     AddrToName(ippb->ourAddress, &tcp->host, addrproc, (char *) tcp);
612     tcp->state = TCP_GETHOST;
613     tcp->gethost = 1;
614     }
615     }
616     }
617    
618     /* open a TCP connection
619     */
620     na_tcp NATCPopen(na_tcpreadp *callback, void *context, char *host, long port, short flags)
621     {
622     int i, err = NATCP_notcpbuf;
623     OSErr resolve = noErr;
624     tcpinfo *tcp;
625    
626     if ((tcp = getTCPbuf(callback, context, &i)) == NULL) return (-1);
627     if (flags & NATCP_server) tcp->server = 1;
628     tcp->port = port;
629     tcp->pb.csCode = TCPCreate;
630     tcp->pb.csParam.create.rcvBuff = (Ptr) tcp->buf;
631     tcp->pb.csParam.create.rcvBuffLen = (*tcpstate)->streamsize;
632     tcp->pb.csParam.create.notifyProc = myTCPNotifyProc;
633     tcp->pb.csParam.create.userDataPtr = (Ptr) tcp;
634     PBControl((ParmBlkPtr)&tcp->pb, false);
635     if (tcp->pb.ioResult == 0) {
636     tcp->state = TCP_RESOLVE;
637     tcp->stream = tcp->pb.tcpStream;
638     /* a server isn't required to have a hostname */
639     if (!host && tcp->server) return (i);
640     tcp->dnrdone = 0;
641     resolve = StrToAddr(host, &tcp->host, addrproc, (char *) tcp);
642     if (resolve == noErr) tcp->dnrdone = 1;
643     if (resolve == cacheFault || resolve == noErr) {
644     return (i);
645     }
646     err = NATCP_nohost;
647     }
648     DisposPtr((Ptr) tcp);
649     (*tcpstate)->tcpbufs[i] = NULL;
650     (*callback)(context, -1, err, resolve, NULL);
651    
652     return (-1);
653     }
654    
655     /* open a connection to a tcp window
656     */
657     na_tcp NATCPwinopen(natcp_win *w, char *host, long port, short flags)
658     {
659     return (NATCPopen(winreadp, (void *) RecoverHandle((Ptr) w), host, port, flags));
660     }
661    
662     /* pass a buffer to tcp connection for writing
663     * dispose of -1 = copy data
664     */
665     short NATCPwrite(na_tcp i, Ptr data, long len, short dispose)
666     {
667     tcpinfo *tcp = (*tcpstate)->tcpbufs[i];
668     rdsEntry *rds = NULL;
669     tcpwb *wb;
670     long totallen = 0;
671     int j;
672    
673     if (tcp == NULL || tcp->lclose > 0 || tcp->rclose == 3) {
674     return (NATCP_nocon);
675     }
676     wb = tcp->wb + tcp->wbnum;
677     if (wb->rused == RDS) wb = tcp->wb + (1 - tcp->wbnum);
678     if (wb->rused == -1 || wb->rused == RDS) return (NATCP_notcpbuf);
679     for (j = 0; j < wb->rused; ++j) {
680     totallen += wb->rds[j].length;
681     }
682     if (totallen + len >= 65535) return (NATCP_notcpbuf);
683     rds = wb->rds + wb->rused;
684     rds->length = len;
685     rds->ptr = data;
686     rds[1].length = 0;
687     if (dispose < 0) {
688     if (len < tcp->wbsize - wb->wused) {
689     /* if data short enough, use small internal buffer */
690     rds->ptr = wb->buf + wb->wused;
691     wb->wused += len;
692     dispose = 0;
693     /* If adjacent to last rds, attach to it */
694     if (wb->rused && rds[-1].ptr + rds[-1].length == rds->ptr) {
695     --wb->rused;
696     rds[-1].length += len;
697     rds->length = 0;
698     }
699     } else {
700     rds->ptr = NewPtr(len);
701     if (!rds->ptr) return (NATCP_nomem);
702     dispose = 1;
703     }
704     memcpy(rds->ptr, data, len);
705     }
706     wb->fflag[wb->rused++] = dispose;
707     if (tcp->push && tcp->state == TCP_READY) {
708     (void) beginwrite(tcp);
709     }
710    
711     return (NATCP_data);
712     }
713    
714     /* put a character on the TCP connection -- optimized for fast turnaround
715     */
716     short NATCPputchar(na_tcp i, char c)
717     {
718     (*tcpstate)->tcpbufs[i]->push = 1;
719    
720     return (NATCPwrite(i, (Ptr) &c, 1, -1));
721     }
722    
723     /* close a TCP connection
724     */
725     void NATCPclose(na_tcp i)
726     {
727     tcpinfo *tcp = (*tcpstate)->tcpbufs[i];
728    
729     if (tcp && tcp->lclose < 1) tcp->lclose = 1;
730     }
731    
732     /* dispose of all TCP system resources
733     */
734     void NATCPdone(long waiticks)
735     {
736     struct tcpstate *ts;
737    
738     if (tcpstate) {
739     ts = (struct tcpstate *) NAlockWindow((na_win **) tcpstate);
740     ts->waiticks = waiticks;
741     NAcloseWindow((na_win *) ts, NA_REQCLOSE);
742     }
743     }

  ViewVC Help
Powered by ViewVC 1.1.22