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

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

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


Revision 1.1 - (show annotations) (download)
Tue Aug 26 20:45:25 2003 UTC (20 years, 7 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 /* 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