Download
jcs
/wallops
/tcp.c
(View History)
jcs tcp: Sync with libjcs | Latest amendment: 30 on 2022-02-10 |
1 | #include <stdio.h> |
2 | #include <string.h> |
3 | #include "tcp.h" |
4 | |
5 | #define RCV_BUFFER_SIZE 1024 |
6 | #define TCP_BUFFER_SIZE 8192 |
7 | #define OPEN_TIMEOUT 60 |
8 | |
9 | short gIPPDriverRefNum; |
10 | |
11 | pascal void StrToAddrMarkDone(struct hostInfo *hi, char *data); |
12 | |
13 | unsigned long resolved_ip; |
14 | |
15 | OSErr |
16 | _TCPInit(void) |
17 | { |
18 | ParamBlockRec pb; |
19 | OSErr osErr; |
20 | |
21 | memset(&pb, 0, sizeof(pb)); |
22 | |
23 | gIPPDriverRefNum = -1; |
24 | |
25 | pb.ioParam.ioCompletion = 0; |
26 | pb.ioParam.ioNamePtr = "\p.IPP"; |
27 | pb.ioParam.ioPermssn = fsCurPerm; |
28 | |
29 | osErr = PBOpen(&pb, false); |
30 | if (noErr == osErr) |
31 | gIPPDriverRefNum = pb.ioParam.ioRefNum; |
32 | |
33 | return osErr; |
34 | } |
35 | |
36 | OSErr |
37 | _TCPGetOurIP(ip_addr *ip, long *netMask) |
38 | { |
39 | OSErr osErr; |
40 | GetAddrParamBlock pb; |
41 | |
42 | memset(&pb, 0, sizeof(pb)); |
43 | |
44 | pb.csCode = ipctlGetAddr; |
45 | pb.ioCRefNum = gIPPDriverRefNum; |
46 | pb.ioResult = 1; |
47 | |
48 | osErr = PBControl((ParmBlkPtr)&pb, true); |
49 | while (pb.ioResult > 0) |
50 | ; |
51 | |
52 | if (pb.ioResult != noErr) |
53 | return pb.ioResult; |
54 | |
55 | if (ip != NULL) |
56 | *ip = pb.ourAddress; |
57 | if (netMask != NULL) |
58 | *netMask = pb.ourNetMask; |
59 | |
60 | return osErr; |
61 | } |
62 | |
63 | OSErr |
64 | _TCPCreate(TCPiopb *pb, StreamPtr *stream, Ptr rcvBufPtr, long rcvBufLen, |
65 | TCPNotifyProc aNotifyProc, Ptr userDataPtr, |
66 | TCPIOCompletionProc ioCompletion, Boolean async) |
67 | { |
68 | OSErr osErr; |
69 | |
70 | memset(pb, 0, sizeof(*pb)); |
71 | |
72 | pb->csCode = TCPCreate; |
73 | pb->ioCompletion = ioCompletion; |
74 | pb->ioCRefNum = gIPPDriverRefNum; |
75 | pb->ioResult = 1; |
76 | |
77 | pb->csParam.create.rcvBuff = rcvBufPtr; |
78 | pb->csParam.create.rcvBuffLen = rcvBufLen; |
79 | pb->csParam.create.notifyProc = aNotifyProc; |
80 | pb->csParam.create.userDataPtr = userDataPtr; |
81 | |
82 | osErr = PBControl((ParmBlkPtr)pb, async); |
83 | if (!async && (noErr == osErr)) { |
84 | *stream = pb->tcpStream; |
85 | } |
86 | |
87 | return osErr; |
88 | } |
89 | |
90 | /* listen for an incoming connection */ |
91 | OSErr |
92 | _TCPPassiveOpen(TCPiopb *pb, StreamPtr stream, ip_addr *remoteIP, |
93 | tcp_port *remotePort, ip_addr *localIP, tcp_port *localPort, |
94 | Ptr userData, TCPIOCompletionProc ioCompletion, Boolean async) |
95 | { |
96 | OSErr osErr; |
97 | short index; |
98 | |
99 | memset(pb, 0, sizeof(*pb)); |
100 | |
101 | pb->csCode = TCPPassiveOpen; |
102 | pb->ioCompletion = ioCompletion; |
103 | pb->ioCRefNum = gIPPDriverRefNum; |
104 | pb->tcpStream = stream; |
105 | pb->ioResult = 1; |
106 | |
107 | pb->csParam.open.ulpTimeoutAction = 1; /* abort half-open connection */ |
108 | pb->csParam.open.ulpTimeoutValue = 5; /* after 5 seconds */ |
109 | pb->csParam.open.validityFlags = 0xC0; |
110 | pb->csParam.open.commandTimeoutValue = 0; |
111 | pb->csParam.open.remoteHost = 0; |
112 | pb->csParam.open.remotePort = 0; |
113 | pb->csParam.open.localHost = 0; |
114 | pb->csParam.open.localPort = *localPort; |
115 | pb->csParam.open.tosFlags = 0; |
116 | pb->csParam.open.precedence = 0; |
117 | pb->csParam.open.dontFrag = 0; |
118 | pb->csParam.open.timeToLive = 0; |
119 | pb->csParam.open.security = 0; |
120 | pb->csParam.open.optionCnt = 0; |
121 | for (index = 0; index < sizeof(pb->csParam.open.options); ++index) |
122 | pb->csParam.open.options[index] = 0; |
123 | pb->csParam.open.userDataPtr = userData; |
124 | |
125 | osErr = PBControl((ParmBlkPtr) pb, async); |
126 | if (!async && (osErr == noErr)) { |
127 | if (remoteIP) |
128 | *remoteIP = pb->csParam.open.remoteHost; |
129 | if (remotePort) |
130 | *remotePort = pb->csParam.open.remotePort; |
131 | if (localIP) |
132 | *localIP = pb->csParam.open.localHost; |
133 | *localPort = pb->csParam.open.localPort; |
134 | } |
135 | |
136 | return osErr; |
137 | } |
138 | |
139 | /* make an outgoing connection */ |
140 | OSErr |
141 | _TCPActiveOpen(TCPiopb *pb, StreamPtr stream, ip_addr remoteIP, |
142 | tcp_port remotePort, ip_addr *localIP, tcp_port *localPort, |
143 | Ptr userData, TCPIOCompletionProc ioCompletion, Boolean async) |
144 | { |
145 | OSErr osErr; |
146 | short index; |
147 | |
148 | memset(pb, 0, sizeof(*pb)); |
149 | |
150 | pb->csCode = TCPActiveOpen; |
151 | pb->ioCompletion = ioCompletion; |
152 | pb->ioCRefNum = gIPPDriverRefNum; |
153 | pb->tcpStream = stream; |
154 | pb->ioResult = 1; |
155 | |
156 | pb->csParam.open.ulpTimeoutValue = 30; |
157 | pb->csParam.open.ulpTimeoutAction = 1; |
158 | pb->csParam.open.validityFlags = 0xC0; |
159 | #if 0 |
160 | /* not available with this csCode */ |
161 | pb->csParam.open.commandTimeoutValue = 30; |
162 | #endif |
163 | pb->csParam.open.remoteHost = remoteIP; |
164 | pb->csParam.open.remotePort = remotePort; |
165 | pb->csParam.open.localHost = 0; |
166 | pb->csParam.open.localPort = *localPort; |
167 | pb->csParam.open.tosFlags = 0; |
168 | pb->csParam.open.precedence = 0; |
169 | pb->csParam.open.dontFrag = 0; |
170 | pb->csParam.open.timeToLive = 0; |
171 | pb->csParam.open.security = 0; |
172 | pb->csParam.open.optionCnt = 0; |
173 | for (index = 0; index < sizeof(pb->csParam.open.options); ++index) |
174 | pb->csParam.open.options[index] = 0; |
175 | pb->csParam.open.userDataPtr = userData; |
176 | |
177 | osErr = PBControl((ParmBlkPtr) pb, async); |
178 | if (!async && (noErr == osErr)) { |
179 | *localIP = pb->csParam.open.localHost; |
180 | *localPort = pb->csParam.open.localPort; |
181 | } |
182 | |
183 | return osErr; |
184 | } |
185 | |
186 | OSErr |
187 | _TCPSend(TCPiopb *pb, StreamPtr stream, wdsEntry *wdsPtr, Ptr userData, |
188 | TCPIOCompletionProc ioCompletion, Boolean async) |
189 | { |
190 | memset(pb, 0, sizeof(*pb)); |
191 | |
192 | pb->csCode = TCPSend; |
193 | pb->ioCompletion = ioCompletion; |
194 | pb->ioCRefNum = gIPPDriverRefNum; |
195 | pb->tcpStream = stream; |
196 | pb->ioResult = 1; |
197 | |
198 | pb->csParam.send.ulpTimeoutValue = 30; |
199 | pb->csParam.send.ulpTimeoutAction = 1; |
200 | pb->csParam.send.validityFlags = 0xC0; |
201 | pb->csParam.send.pushFlag = 1; /* XXX */ |
202 | pb->csParam.send.urgentFlag = 0; |
203 | pb->csParam.send.wdsPtr = (Ptr)wdsPtr; |
204 | pb->csParam.send.sendFree = 0; |
205 | pb->csParam.send.sendLength = 0; |
206 | pb->csParam.send.userDataPtr = userData; |
207 | |
208 | return PBControl((ParmBlkPtr)pb, async); |
209 | } |
210 | |
211 | OSErr |
212 | _TCPNoCopyRcv(TCPiopb *pb, StreamPtr stream, Ptr rdsPtr, |
213 | unsigned short rdsLength, Ptr userData, TCPIOCompletionProc ioCompletion, |
214 | Boolean async) |
215 | { |
216 | OSErr osErr; |
217 | |
218 | memset(pb, 0, sizeof(*pb)); |
219 | |
220 | pb->csCode = TCPNoCopyRcv; |
221 | pb->ioCompletion = ioCompletion; |
222 | pb->ioCRefNum = gIPPDriverRefNum; |
223 | pb->tcpStream = stream; |
224 | pb->ioResult = 1; |
225 | |
226 | pb->csParam.receive.commandTimeoutValue = 30; |
227 | pb->csParam.receive.urgentFlag = 0; |
228 | pb->csParam.receive.markFlag = 0; |
229 | pb->csParam.receive.rdsPtr = rdsPtr; |
230 | pb->csParam.receive.rdsLength = rdsLength; |
231 | pb->csParam.receive.userDataPtr = userData; |
232 | |
233 | return PBControl((ParmBlkPtr)pb, async); |
234 | } |
235 | |
236 | OSErr |
237 | _TCPRcv(TCPiopb *pb, StreamPtr stream, Ptr rcvBufPtr, |
238 | unsigned short *rcvBufLen, Ptr userData, TCPIOCompletionProc ioCompletion, |
239 | Boolean async) |
240 | { |
241 | OSErr osErr; |
242 | |
243 | memset(pb, 0, sizeof(*pb)); |
244 | |
245 | pb->csCode = TCPRcv; |
246 | pb->ioCompletion = ioCompletion; |
247 | pb->ioCRefNum = gIPPDriverRefNum; |
248 | pb->tcpStream = stream; |
249 | pb->ioResult = 1; |
250 | |
251 | pb->csParam.receive.commandTimeoutValue = 30; |
252 | pb->csParam.receive.urgentFlag = 0; |
253 | pb->csParam.receive.markFlag = 0; |
254 | pb->csParam.receive.rcvBuff = rcvBufPtr; |
255 | pb->csParam.receive.rcvBuffLen = *rcvBufLen; |
256 | pb->csParam.receive.userDataPtr = userData; |
257 | |
258 | osErr = PBControl((ParmBlkPtr)pb, async); |
259 | if (!async) |
260 | *rcvBufLen = pb->csParam.receive.rcvBuffLen; |
261 | |
262 | return osErr; |
263 | } |
264 | |
265 | OSErr |
266 | _TCPBfrReturn(TCPiopb *pb, StreamPtr stream, Ptr rdsPtr, Ptr userData, |
267 | TCPIOCompletionProc ioCompletion, Boolean async) |
268 | { |
269 | memset(pb, 0, sizeof(*pb)); |
270 | |
271 | pb->csCode = TCPRcvBfrReturn; |
272 | pb->ioCompletion = ioCompletion; |
273 | pb->ioCRefNum = gIPPDriverRefNum; |
274 | pb->tcpStream = stream; |
275 | pb->ioResult = 1; |
276 | |
277 | pb->csParam.receive.rdsPtr = rdsPtr; |
278 | pb->csParam.receive.userDataPtr = userData; |
279 | |
280 | return PBControl((ParmBlkPtr)pb, async); |
281 | } |
282 | |
283 | OSErr |
284 | _TCPClose(TCPiopb *pb, StreamPtr stream, Ptr userData, |
285 | TCPIOCompletionProc ioCompletion, Boolean async) |
286 | { |
287 | memset(pb, 0, sizeof(*pb)); |
288 | |
289 | pb->csCode = TCPClose; |
290 | pb->ioCompletion = ioCompletion; |
291 | pb->ioCRefNum = gIPPDriverRefNum; |
292 | pb->tcpStream = stream; |
293 | pb->ioResult = 1; |
294 | |
295 | pb->csParam.close.ulpTimeoutValue = 30; |
296 | pb->csParam.close.ulpTimeoutAction = 1; |
297 | pb->csParam.close.validityFlags = 0xC0; |
298 | pb->csParam.close.userDataPtr = userData; |
299 | |
300 | return PBControl((ParmBlkPtr)pb, async); |
301 | } |
302 | |
303 | OSErr |
304 | _TCPAbort(TCPiopb *pb, StreamPtr stream, Ptr userData, |
305 | TCPIOCompletionProc ioCompletion, Boolean async) |
306 | { |
307 | memset(pb, 0, sizeof(*pb)); |
308 | |
309 | pb->csCode = TCPAbort; |
310 | pb->ioCompletion = ioCompletion; |
311 | pb->ioCRefNum = gIPPDriverRefNum; |
312 | pb->tcpStream = stream; |
313 | pb->ioResult = 1; |
314 | |
315 | pb->csParam.abort.userDataPtr = userData; |
316 | |
317 | return PBControl((ParmBlkPtr)pb, async); |
318 | } |
319 | |
320 | OSErr |
321 | _TCPStatus(TCPiopb *pb, StreamPtr stream, struct TCPStatusPB *status, |
322 | Ptr userData, TCPIOCompletionProc ioCompletion, Boolean async) |
323 | { |
324 | OSErr osErr; |
325 | |
326 | memset(pb, 0, sizeof(*pb)); |
327 | |
328 | pb->csCode = TCPStatus; |
329 | pb->ioCompletion = ioCompletion; |
330 | pb->ioCRefNum = gIPPDriverRefNum; |
331 | pb->tcpStream = stream; |
332 | pb->csParam.status.userDataPtr = userData; |
333 | pb->ioResult = 1; |
334 | |
335 | osErr = PBControl((ParmBlkPtr)pb, async); |
336 | if (!async && (noErr == osErr)) { |
337 | *status = pb->csParam.status; |
338 | } |
339 | |
340 | return osErr; |
341 | } |
342 | |
343 | OSErr |
344 | _TCPRelease(TCPiopb *pb, StreamPtr stream, Ptr userData, |
345 | TCPIOCompletionProc ioCompletion, Boolean async) |
346 | { |
347 | OSErr osErr; |
348 | |
349 | memset(pb, 0, sizeof(*pb)); |
350 | |
351 | pb->csCode = TCPRelease; |
352 | pb->ioCompletion = ioCompletion; |
353 | pb->ioCRefNum = gIPPDriverRefNum; |
354 | pb->tcpStream = stream; |
355 | pb->ioResult = 1; |
356 | |
357 | pb->csParam.status.userDataPtr = userData; |
358 | |
359 | osErr = PBControl((ParmBlkPtr)pb, async); |
360 | |
361 | return osErr; |
362 | } |
363 | |
364 | OSErr |
365 | _UDPMaxMTUSize(UDPiopb *pb, short *mtu) |
366 | { |
367 | OSErr osErr; |
368 | |
369 | memset(pb, 0, sizeof(*pb)); |
370 | |
371 | pb->csCode = UDPMaxMTUSize; |
372 | pb->ioCRefNum = gIPPDriverRefNum; |
373 | pb->ioResult = 1; |
374 | |
375 | pb->csParam.mtu.remoteHost = (ip_addr)0; |
376 | |
377 | osErr = PBControl((ParmBlkPtr)pb, false); |
378 | |
379 | if (osErr == noErr) |
380 | *mtu = pb->csParam.mtu.mtuSize; |
381 | |
382 | return osErr; |
383 | } |
384 | |
385 | /* convenience functions */ |
386 | |
387 | static pascal void |
388 | StrToAddrMarkDone(struct hostInfo *hi, char *data) |
389 | { |
390 | volatile int *done = (int *)data; |
391 | *done = 1; |
392 | } |
393 | |
394 | OSErr |
395 | TCPResolveName(char **name, unsigned long *ipAddress) |
396 | { |
397 | OSErr osErr; |
398 | struct hostInfo aHostInfo; |
399 | volatile int done = 0; |
400 | |
401 | osErr = OpenResolver(nil); |
402 | if (osErr) |
403 | return osErr; |
404 | |
405 | osErr = StrToAddr(*name, &aHostInfo, (ResultProcPtr)StrToAddrMarkDone, |
406 | (char *)&done); |
407 | |
408 | if (osErr == cacheFault) { |
409 | /* StrToAddrMarkDone will set done when DNS resolution finishes */ |
410 | while (!done) |
411 | ; |
412 | } |
413 | |
414 | if ((aHostInfo.rtnCode == noErr) || (aHostInfo.rtnCode == cacheFault)) { |
415 | /* use the first IP address for this host */ |
416 | *ipAddress = aHostInfo.addr[0]; |
417 | osErr = noErr; |
418 | } else |
419 | osErr = aHostInfo.rtnCode; |
420 | |
421 | CloseResolver(); |
422 | return osErr; |
423 | } |
424 | |
425 | long |
426 | ip2long(char *ip) |
427 | { |
428 | long address = 0; |
429 | int dotcount = 0, i; |
430 | unsigned int b = 0; |
431 | |
432 | for (i = 0; ip[i] != 0; i++) { |
433 | if (ip[i] == '.') { |
434 | if (++dotcount > 3) |
435 | return (0); |
436 | address <<= 8; |
437 | address |= b; |
438 | b = 0; |
439 | } else if (ip[i] >= '0' && ip[i] <= '9') { |
440 | b *= 10; |
441 | b += (ip[i] - '0'); |
442 | if (b > 255) |
443 | return (0); |
444 | } else |
445 | return (0); |
446 | } |
447 | |
448 | if (dotcount != 3) |
449 | return (0); |
450 | address <<= 8; |
451 | address |= b; |
452 | return address; |
453 | } |
454 | |
455 | void |
456 | long2ip(unsigned long num, char *ip) |
457 | { |
458 | unsigned char *tmp = (unsigned char *)# |
459 | (void)sprintf(ip, (const char *)"%d.%d.%d.%d", tmp[0], tmp[1], tmp[2], tmp[3]); |
460 | } |
461 | |
462 | #define SOCKS_VERSION_SOCKS5 0x5 |
463 | #define SOCKS_METHOD_AUTH_NONE 0x0 |
464 | #define SOCKS_REQUEST_CONNECT 0x1 |
465 | #define SOCKS_REQUEST_ATYP_DOMAINNAME 0x3 |
466 | #define SOCKS_REPLY_SUCCESS 0x0 |
467 | |
468 | OSErr |
469 | SOCKS5TCPActiveOpen(TCPiopb *pb, StreamPtr stream, ip_addr socks_ip, |
470 | tcp_port socks_port, char *remote_host, tcp_port remote_port, |
471 | ip_addr *local_ip, tcp_port *local_port, Ptr user_data, |
472 | TCPIOCompletionProc io_completion, Boolean async) |
473 | { |
474 | OSErr err; |
475 | TCPStatusPB status_pb; |
476 | wdsEntry wds[2]; |
477 | char data[255] = { 0 }; |
478 | unsigned short len, remote_host_len; |
479 | |
480 | remote_host_len = strlen(remote_host); |
481 | if (remote_host_len + 7 > sizeof(data)) |
482 | return -1; |
483 | |
484 | err = _TCPActiveOpen(pb, stream, socks_ip, socks_port, local_ip, |
485 | local_port, user_data, io_completion, async); |
486 | if (err != noErr) |
487 | return err; |
488 | |
489 | data[0] = SOCKS_VERSION_SOCKS5; |
490 | data[1] = 1; /* nmethods */ |
491 | data[2] = SOCKS_METHOD_AUTH_NONE; |
492 | |
493 | memset(&wds, 0, sizeof(wds)); |
494 | wds[0].ptr = (Ptr)&data; |
495 | wds[0].length = 3; |
496 | |
497 | err = _TCPSend(pb, stream, wds, nil, nil, false); |
498 | if (err) |
499 | goto fail; |
500 | |
501 | for (;;) { |
502 | err = _TCPStatus(pb, stream, &status_pb, nil, nil, false); |
503 | if (err != noErr) |
504 | goto fail; |
505 | |
506 | if (status_pb.amtUnreadData >= 2) |
507 | break; |
508 | } |
509 | |
510 | len = 2; |
511 | err = _TCPRcv(pb, stream, (Ptr)&data, &len, nil, nil, false); |
512 | if (err != noErr) |
513 | goto fail; |
514 | |
515 | if (data[0] != SOCKS_VERSION_SOCKS5 || data[1] != SOCKS_METHOD_AUTH_NONE) |
516 | goto fail; |
517 | |
518 | len = 0; |
519 | data[len++] = SOCKS_VERSION_SOCKS5; |
520 | data[len++] = SOCKS_REQUEST_CONNECT; |
521 | data[len++] = 0; /* reserved */ |
522 | data[len++] = SOCKS_REQUEST_ATYP_DOMAINNAME; |
523 | data[len++] = remote_host_len; |
524 | memcpy(data + len, remote_host, remote_host_len); |
525 | len += remote_host_len; |
526 | data[len++] = (remote_port >> 8); |
527 | data[len++] = (remote_port & 0xff); |
528 | |
529 | memset(&wds, 0, sizeof(wds)); |
530 | wds[0].ptr = (Ptr)&data; |
531 | wds[0].length = len; |
532 | |
533 | err = _TCPSend(pb, stream, wds, nil, nil, false); |
534 | if (err) |
535 | goto fail; |
536 | |
537 | for (;;) { |
538 | err = _TCPStatus(pb, stream, &status_pb, nil, nil, false); |
539 | if (err != noErr) |
540 | goto fail; |
541 | |
542 | if (status_pb.amtUnreadData >= 7) |
543 | break; |
544 | } |
545 | |
546 | len = status_pb.amtUnreadData; |
547 | if (len > sizeof(data)) |
548 | len = sizeof(data); |
549 | err = _TCPRcv(pb, stream, (Ptr)&data, &len, nil, nil, false); |
550 | if (err != noErr) |
551 | goto fail; |
552 | |
553 | if (data[0] != SOCKS_VERSION_SOCKS5 || data[1] != SOCKS_REPLY_SUCCESS) |
554 | goto fail; |
555 | |
556 | return noErr; |
557 | |
558 | fail: |
559 | _TCPClose(pb, stream, nil, nil, false); |
560 | return err; |
561 | } |