1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* ***** BEGIN LICENSE BLOCK *****
3
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
5
* The contents of this file are subject to the Mozilla Public License Version
6
* 1.1 (the "License"); you may not use this file except in compliance with
7
* the License. You may obtain a copy of the License at
8
* http://www.mozilla.org/MPL/
10
* Software distributed under the License is distributed on an "AS IS" basis,
11
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12
* for the specific language governing rights and limitations under the
15
* The Original Code is the Netscape Portable Runtime (NSPR).
17
* The Initial Developer of the Original Code is
18
* Netscape Communications Corporation.
19
* Portions created by the Initial Developer are Copyright (C) 1998-2000
20
* the Initial Developer. All Rights Reserved.
24
* Alternatively, the contents of this file may be used under the terms of
25
* either the GNU General Public License Version 2 or later (the "GPL"), or
26
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27
* in which case the provisions of the GPL or the LGPL are applicable instead
28
* of those above. If you wish to allow use of your version of this file only
29
* under the terms of either the GPL or the LGPL, and not to allow others to
30
* use your version of this file under the terms of the MPL, indicate your
31
* decision by deleting the provisions above and replace them with the notice
32
* and other provisions required by the GPL or the LGPL. If you do not delete
33
* the provisions above, a recipient may use your version of this file under
34
* the terms of any one of the MPL, the GPL or the LGPL.
36
* ***** END LICENSE BLOCK ***** */
38
/* This turns on UNIX style errors in OT 1.1 headers */
39
#define OTUNIXERRORS 1
45
#include <OpenTransport.h>
48
#define GESTALT_OPEN_TPT_PRESENT gestaltOpenTptPresentMask
49
#define GESTALT_OPEN_TPT_TCP_PRESENT gestaltOpenTptTCPPresentMask
51
#include <OpenTptInternet.h> // All the internet typedefs
53
#if (UNIVERSAL_INTERFACES_VERSION >= 0x0330)
54
// for some reason Apple removed this typedef.
55
typedef struct OTConfiguration OTConfiguration;
60
typedef enum SndRcvOpCode {
69
InetSvcRef serviceRef;
75
static pascal void DNSNotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie);
76
static pascal void NotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie);
77
static pascal void RawEndpointNotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie);
79
static PRBool GetState(PRFileDesc *fd, PRBool *readReady, PRBool *writeReady, PRBool *exceptReady);
82
WakeUpNotifiedThread(PRThread *thread, OTResult result);
84
extern void WaitOnThisThread(PRThread *thread, PRIntervalTime timeout);
85
extern void DoneWaitingOnThisThread(PRThread *thread);
88
OTClientContextPtr clientContext = NULL;
90
#define INIT_OPEN_TRANSPORT() InitOpenTransportInContext(kInitOTForExtensionMask, &clientContext)
91
#define OT_OPEN_INTERNET_SERVICES(config, flags, err) OTOpenInternetServicesInContext(config, flags, err, clientContext)
92
#define OT_OPEN_ENDPOINT(config, flags, info, err) OTOpenEndpointInContext(config, flags, info, err, clientContext)
96
#define INIT_OPEN_TRANSPORT() InitOpenTransport()
97
#define OT_OPEN_INTERNET_SERVICES(config, flags, err) OTOpenInternetServices(config, flags, err)
98
#define OT_OPEN_ENDPOINT(config, flags, info, err) OTOpenEndpoint(config, flags, info, err)
99
#endif /* TARGET_CARBON */
101
static OTNotifyUPP DNSNotifierRoutineUPP;
102
static OTNotifyUPP NotifierRoutineUPP;
103
static OTNotifyUPP RawEndpointNotifierRoutineUPP;
105
void _MD_InitNetAccess()
109
PRBool hasOTTCPIP = PR_FALSE;
110
PRBool hasOT = PR_FALSE;
113
err = Gestalt(gestaltOpenTpt, &gestaltResult);
115
if (gestaltResult & GESTALT_OPEN_TPT_PRESENT)
119
if (gestaltResult & GESTALT_OPEN_TPT_TCP_PRESENT)
120
hasOTTCPIP = PR_TRUE;
122
PR_ASSERT(hasOTTCPIP == PR_TRUE);
124
DNSNotifierRoutineUPP = NewOTNotifyUPP(DNSNotifierRoutine);
125
NotifierRoutineUPP = NewOTNotifyUPP(NotifierRoutine);
126
RawEndpointNotifierRoutineUPP = NewOTNotifyUPP(RawEndpointNotifierRoutine);
128
errOT = INIT_OPEN_TRANSPORT();
129
PR_ASSERT(err == kOTNoError);
131
dnsContext.serviceRef = NULL;
132
dnsContext.lock = PR_NewLock();
133
PR_ASSERT(dnsContext.lock != NULL);
135
dnsContext.thread = _PR_MD_CURRENT_THREAD();
136
dnsContext.cookie = NULL;
138
/* XXX Does not handle absence of open tpt and tcp yet! */
141
static void _MD_FinishInitNetAccess()
145
if (dnsContext.serviceRef)
148
dnsContext.serviceRef = OT_OPEN_INTERNET_SERVICES(kDefaultInternetServicesPath, NULL, &errOT);
149
if (errOT != kOTNoError) {
150
dnsContext.serviceRef = NULL;
151
return; /* no network -- oh well */
154
PR_ASSERT((dnsContext.serviceRef != NULL) && (errOT == kOTNoError));
156
/* Install notify function for DNR Address To String completion */
157
errOT = OTInstallNotifier(dnsContext.serviceRef, DNSNotifierRoutineUPP, &dnsContext);
158
PR_ASSERT(errOT == kOTNoError);
160
/* Put us into async mode */
161
errOT = OTSetAsynchronous(dnsContext.serviceRef);
162
PR_ASSERT(errOT == kOTNoError);
166
static pascal void DNSNotifierRoutine(void * contextPtr, OTEventCode otEvent, OTResult result, void * cookie)
168
#pragma unused(contextPtr)
169
_PRCPU * cpu = _PR_MD_CURRENT_CPU();
172
dnsContext.thread->md.osErrCode = result;
173
dnsContext.cookie = cookie;
176
case T_DNRSTRINGTOADDRCOMPLETE:
177
if (_PR_MD_GET_INTSOFF()) {
178
dnsContext.thread->md.missedIONotify = PR_TRUE;
179
cpu->u.missed[cpu->where] |= _PR_MISSED_IO;
181
DoneWaitingOnThisThread(dnsContext.thread);
185
case kOTProviderWillClose:
186
errOT = OTSetSynchronous(dnsContext.serviceRef);
187
// fall through to kOTProviderIsClosed case
189
case kOTProviderIsClosed:
190
errOT = OTCloseProvider((ProviderRef)dnsContext.serviceRef);
191
dnsContext.serviceRef = nil;
193
if (_PR_MD_GET_INTSOFF()) {
194
dnsContext.thread->md.missedIONotify = PR_TRUE;
195
cpu->u.missed[cpu->where] |= _PR_MISSED_IO;
197
DoneWaitingOnThisThread(dnsContext.thread);
201
default: // or else we don't handle the event
202
PR_ASSERT(otEvent==NULL);
205
// or else we don't handle the event
207
SignalIdleSemaphore();
211
static void macsock_map_error(OSStatus err)
213
_PR_MD_CURRENT_THREAD()->md.osErrCode = err;
215
if (IsEError(err) || (err >= EPERM && err <= ELASTERRNO)) {
216
switch (IsEError(err) ? OSStatus2E(err) : err) {
218
PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
221
PR_SetError(PR_ADDRESS_NOT_AVAILABLE_ERROR, err);
224
PR_SetError(PR_IN_PROGRESS_ERROR, err);
228
PR_SetError(PR_WOULD_BLOCK_ERROR, err);
231
PR_SetError(PR_NOT_SOCKET_ERROR, err);
234
PR_SetError(PR_IO_TIMEOUT_ERROR, err);
237
PR_SetError(PR_CONNECT_REFUSED_ERROR, err);
240
PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, err);
243
PR_SetError(PR_ADDRESS_IN_USE_ERROR, err);
246
PR_SetError(PR_ACCESS_FAULT_ERROR, err);
249
PR_SetError(PR_PENDING_INTERRUPT_ERROR, err);
252
PR_SetError(PR_INVALID_ARGUMENT_ERROR, err);
255
PR_SetError(PR_IO_ERROR, err);
258
PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, err);
261
PR_SetError(PR_IO_ERROR, err);
264
PR_SetError(PR_PROTOCOL_NOT_SUPPORTED_ERROR, err);
267
PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, err);
270
PR_SetError(PR_UNKNOWN_ERROR, err);
274
PR_ASSERT(IsXTIError(err));
278
PR_SetError(PR_WOULD_BLOCK_ERROR, err);
281
PR_SetError(PR_UNKNOWN_ERROR, err);
287
static void PrepareForAsyncCompletion(PRThread * thread, PRInt32 osfd)
289
thread->io_pending = PR_TRUE;
290
thread->io_fd = osfd;
291
thread->md.osErrCode = noErr;
296
WakeUpNotifiedThread(PRThread *thread, OTResult result)
298
_PRCPU * cpu = _PR_MD_CURRENT_CPU();
301
thread->md.osErrCode = result;
302
if (_PR_MD_GET_INTSOFF()) {
303
thread->md.missedIONotify = PR_TRUE;
304
cpu->u.missed[cpu->where] |= _PR_MISSED_IO;
306
DoneWaitingOnThisThread(thread);
310
SignalIdleSemaphore();
313
// Notification routine
314
// Async callback routine.
315
// A5 is OK. Cannot allocate memory here
316
// Ref: http://gemma.apple.com/techpubs/mac/NetworkingOT/NetworkingWOT-100.html
318
static pascal void NotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie)
320
PRFilePrivate *secret = (PRFilePrivate *) contextPtr;
321
_MDFileDesc * md = &(secret->md);
322
EndpointRef endpoint = (EndpointRef)secret->md.osfd;
323
PRThread * readThread = NULL; // also used for 'misc'
324
PRThread * writeThread = NULL;
332
case T_LISTEN: // A connection request is available
333
// If md->doListen is true, then PR_Listen has been
334
// called on this endpoint; therefore, we're ready to
335
// accept connections. But we'll do that with PR_Accept
336
// (which calls OTListen, OTAccept, etc) instead of
339
readThread = secret->md.misc.thread;
340
secret->md.misc.thread = NULL;
341
secret->md.misc.cookie = cookie;
344
// Reject the connection, we're not listening
345
OTSndDisconnect(endpoint, NULL);
349
case T_CONNECT: // Confirmation of a connect request
350
// cookie = sndCall parameter from OTConnect()
351
err = OTRcvConnect(endpoint, NULL);
352
PR_ASSERT(err == kOTNoError);
354
// wake up waiting thread, if any.
355
writeThread = secret->md.write.thread;
356
secret->md.write.thread = NULL;
357
secret->md.write.cookie = cookie;
360
case T_DATA: // Standard data is available
361
// Mark this socket as readable.
362
secret->md.readReady = PR_TRUE;
364
// wake up waiting thread, if any
365
readThread = secret->md.read.thread;
366
secret->md.read.thread = NULL;
367
secret->md.read.cookie = cookie;
370
case T_EXDATA: // Expedited data is available
371
PR_ASSERT(!"T_EXDATA Not implemented");
374
case T_DISCONNECT: // A disconnect is available
375
discon.udata.len = 0;
376
err = OTRcvDisconnect(endpoint, &discon);
377
PR_ASSERT(err == kOTNoError);
378
secret->md.exceptReady = PR_TRUE; // XXX Check this
380
md->disconnectError = discon.reason; // save for _MD_mac_get_nonblocking_connect_error
382
// wake up waiting threads, if any
383
result = -3199 - discon.reason; // obtain the negative error code
384
if ((readThread = secret->md.read.thread) != NULL) {
385
secret->md.read.thread = NULL;
386
secret->md.read.cookie = cookie;
389
if ((writeThread = secret->md.write.thread) != NULL) {
390
secret->md.write.thread = NULL;
391
secret->md.write.cookie = cookie;
395
case T_ERROR: // obsolete/unused in library
396
PR_ASSERT(!"T_ERROR Not implemented");
399
case T_UDERR: // UDP Send error; clear the error
400
(void) OTRcvUDErr((EndpointRef) cookie, NULL);
403
case T_ORDREL: // An orderly release is available
404
err = OTRcvOrderlyDisconnect(endpoint);
405
PR_ASSERT(err == kOTNoError);
406
secret->md.readReady = PR_TRUE; // mark readable (to emulate bsd sockets)
407
// remember connection is closed, so we can return 0 on read or receive
408
secret->md.orderlyDisconnect = PR_TRUE;
410
readThread = secret->md.read.thread;
411
secret->md.read.thread = NULL;
412
secret->md.read.cookie = cookie;
415
case T_GODATA: // Flow control lifted on standard data
416
secret->md.writeReady = PR_TRUE;
417
resultOT = OTLook(endpoint); // clear T_GODATA event
418
PR_ASSERT(resultOT == T_GODATA);
420
// wake up waiting thread, if any
421
writeThread = secret->md.write.thread;
422
secret->md.write.thread = NULL;
423
secret->md.write.cookie = cookie;
426
case T_GOEXDATA: // Flow control lifted on expedited data
427
PR_ASSERT(!"T_GOEXDATA Not implemented");
430
case T_REQUEST: // An Incoming request is available
431
PR_ASSERT(!"T_REQUEST Not implemented");
434
case T_REPLY: // An Incoming reply is available
435
PR_ASSERT(!"T_REPLY Not implemented");
438
case T_PASSCON: // State is now T_DATAXFER
439
// OTAccept() complete, receiving endpoint in T_DATAXFER state
440
// cookie = OTAccept() resRef parameter
443
case T_RESET: // Protocol has been reset
444
PR_ASSERT(!"T_RESET Not implemented");
447
// Async Completion Events
449
case T_UNBINDCOMPLETE:
450
case T_ACCEPTCOMPLETE:
451
case T_OPTMGMTCOMPLETE:
452
case T_GETPROTADDRCOMPLETE:
453
readThread = secret->md.misc.thread;
454
secret->md.misc.thread = NULL;
455
secret->md.misc.cookie = cookie;
458
// case T_OPENCOMPLETE: // we open endpoints in synchronous mode
459
// case T_REPLYCOMPLETE:
460
// case T_DISCONNECTCOMPLETE: // we don't call OTSndDisconnect()
461
// case T_RESOLVEADDRCOMPLETE:
462
// case T_GETINFOCOMPLETE:
463
// case T_SYNCCOMPLETE:
464
// case T_MEMORYRELEASED: // only if OTAckSends() called on endpoint
465
// case T_REGNAMECOMPLETE:
466
// case T_DELNAMECOMPLETE:
467
// case T_LKUPNAMECOMPLETE:
468
// case T_LKUPNAMERESULT:
470
// case T_DNRSTRINGTOADDRCOMPLETE: // DNS is handled by dnsContext in DNSNotifierRoutine()
471
// case T_DNRADDRTONAMECOMPLETE:
472
// case T_DNRSYSINFOCOMPLETE:
473
// case T_DNRMAILEXCHANGECOMPLETE:
474
// case T_DNRQUERYCOMPLETE:
476
// we should probably have a bit more sophisticated handling of kOTSystemSleep, etc.
477
// PR_ASSERT(code != 0);
482
WakeUpNotifiedThread(readThread, result);
484
if (writeThread && (writeThread != readThread))
485
WakeUpNotifiedThread(writeThread, result);
489
static OSErr CreateSocket(int type, EndpointRef *endpoint)
492
PRThread *me = _PR_MD_CURRENT_THREAD();
494
OTConfiguration *config;
497
// for now we just create the endpoint
498
// we'll make it asynchronous and give it a notifier routine in _MD_makenonblock()
501
case SOCK_STREAM: configName = kTCPName; break;
502
case SOCK_DGRAM: configName = kUDPName; break;
504
config = OTCreateConfiguration(configName);
505
ep = OT_OPEN_ENDPOINT(config, 0, NULL, &err);
506
if (err != kOTNoError)
510
PR_ASSERT(*endpoint != NULL);
520
// kOTXXXX - OT returned error
521
// EPROTONOSUPPORT - bad socket type/protocol
522
// ENOBUFS - not enough space for another socket, or failure in socket creation routine
523
PRInt32 _MD_socket(int domain, int type, int protocol)
526
EndpointRef endpoint;
528
_MD_FinishInitNetAccess();
530
// We only deal with internet domain
531
if (domain != AF_INET) {
532
err = kEPROTONOSUPPORTErr;
536
// We only know about tcp & udp
537
if ((type != SOCK_STREAM) && (type != SOCK_DGRAM)) {
538
err = kEPROTONOSUPPORTErr;
542
// Convert default types to specific types.
544
if (type == SOCK_DGRAM)
545
protocol = IPPROTO_UDP;
546
else if (type == SOCK_STREAM)
547
protocol = IPPROTO_TCP;
550
// Only support default protocol for tcp
551
if ((type == SOCK_STREAM) && (protocol != IPPROTO_TCP)) {
552
err = kEPROTONOSUPPORTErr;
556
// Only support default protocol for udp
557
if ((type == SOCK_DGRAM) && (protocol != IPPROTO_UDP)) {
558
err = kEPROTONOSUPPORTErr;
562
// Create a socket, we might run out of memory
563
err = CreateSocket(type, &endpoint);
564
if (err != kOTNoError)
567
PR_ASSERT((PRInt32)endpoint != -1);
569
return ((PRInt32)endpoint);
572
macsock_map_error(err);
578
// EBADF -- bad socket id
579
// EFAULT -- bad address format
580
PRInt32 _MD_bind(PRFileDesc *fd, PRNetAddr *addr, PRUint32 addrlen)
583
EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
585
PRThread *me = _PR_MD_CURRENT_THREAD();
586
PRUint32 retryCount = 0;
588
if (endpoint == NULL) {
599
* There seems to be a bug with OT related to OTBind failing with kOTNoAddressErr even though
600
* a proper legal address was supplied. This happens very rarely and just retrying the
601
* operation after a certain time (less than 1 sec. does not work) seems to succeed.
606
bindReq.addr.len = addrlen;
608
bindReq.addr.maxlen = addrlen;
609
bindReq.addr.buf = (UInt8*) addr;
612
PR_Lock(fd->secret->md.miscLock);
613
PrepareForAsyncCompletion(me, fd->secret->md.osfd);
614
fd->secret->md.misc.thread = me;
616
err = OTBind(endpoint, &bindReq, NULL);
617
if (err != kOTNoError) {
618
me->io_pending = PR_FALSE;
619
PR_Unlock(fd->secret->md.miscLock);
623
WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
624
PR_Unlock(fd->secret->md.miscLock);
626
err = me->md.osErrCode;
627
if (err != kOTNoError)
633
if ((err == kOTNoAddressErr) && (++retryCount <= 4)) {
634
unsigned long finalTicks;
636
Delay(100,&finalTicks);
639
macsock_map_error(err);
645
// EBADF -- bad socket id
646
PRInt32 _MD_listen(PRFileDesc *fd, PRIntn backlog)
648
PRInt32 osfd = fd->secret->md.osfd;
650
EndpointRef endpoint = (EndpointRef) osfd;
653
PRThread *me = _PR_MD_CURRENT_THREAD();
655
if ((fd == NULL) || (endpoint == NULL)) {
663
if (endpoint == NULL) {
668
addr.inet.family = AF_INET;
669
addr.inet.port = addr.inet.ip = 0;
671
bindReq.addr.maxlen = PR_NETADDR_SIZE (&addr);
672
bindReq.addr.len = 0;
673
bindReq.addr.buf = (UInt8*) &addr;
676
PrepareForAsyncCompletion(me, fd->secret->md.osfd);
677
fd->secret->md.misc.thread = me; // tell notifier routine what to wake up
679
err = OTGetProtAddress(endpoint, &bindReq, NULL);
680
if (err != kOTNoError)
683
WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
685
err = me->md.osErrCode;
686
if (err != kOTNoError)
689
PrepareForAsyncCompletion(me, fd->secret->md.osfd);
690
fd->secret->md.misc.thread = me; // tell notifier routine what to wake up
692
err = OTUnbind(endpoint);
693
if (err != kOTNoError)
696
WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
698
err = me->md.osErrCode;
699
if (err != kOTNoError)
702
/* tell the notifier func that we are interested in pending connections */
703
fd->secret->md.doListen = PR_TRUE;
704
/* accept up to (backlog) pending connections at any one time */
705
bindReq.qlen = backlog;
707
PrepareForAsyncCompletion(me, fd->secret->md.osfd);
708
fd->secret->md.misc.thread = me; // tell notifier routine what to wake up
710
err = OTBind(endpoint, &bindReq, NULL);
711
if (err != kOTNoError)
714
WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
716
err = me->md.osErrCode;
717
if (err != kOTNoError)
719
// If OTBind failed, we're really not ready to listen after all.
720
fd->secret->md.doListen = PR_FALSE;
727
me->io_pending = PR_FALSE; // clear pending wait state if any
728
macsock_map_error(err);
734
// EBADF -- bad socket id
735
PRInt32 _MD_getsockname(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen)
738
EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
740
PRThread *me = _PR_MD_CURRENT_THREAD();
742
if (endpoint == NULL) {
752
bindReq.addr.len = *addrlen;
753
bindReq.addr.maxlen = *addrlen;
754
bindReq.addr.buf = (UInt8*) addr;
757
PR_Lock(fd->secret->md.miscLock);
758
PrepareForAsyncCompletion(me, fd->secret->md.osfd);
759
fd->secret->md.misc.thread = me;
761
err = OTGetProtAddress(endpoint, &bindReq, NULL);
762
if (err != kOTNoError) {
763
me->io_pending = PR_FALSE;
764
PR_Unlock(fd->secret->md.miscLock);
768
WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
769
PR_Unlock(fd->secret->md.miscLock);
771
err = me->md.osErrCode;
772
if (err != kOTNoError)
775
*addrlen = PR_NETADDR_SIZE(addr);
779
macsock_map_error(err);
784
PRStatus _MD_getsockopt(PRFileDesc *fd, PRInt32 level, PRInt32 optname, char* optval, PRInt32* optlen)
787
EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
790
PRThread *me = _PR_MD_CURRENT_THREAD();
791
unsigned char optionBuffer[kOTOptionHeaderSize + sizeof(PRSocketOptionData)];
793
if (endpoint == NULL) {
799
OT wants IPPROTO_IP for level and not XTI_GENERIC. SO_REUSEADDR and SO_KEEPALIVE
800
are equated to IP level and TCP level options respectively and hence we need to set
803
if (level == SOL_SOCKET) {
804
if (optname == SO_REUSEADDR)
806
else if (optname == SO_KEEPALIVE)
810
opt = (TOption *)&optionBuffer[0];
811
opt->len = sizeof(TOption);
816
cmd.opt.len = sizeof(TOption);
817
cmd.opt.maxlen = sizeof(optionBuffer);
818
cmd.opt.buf = (UInt8*)optionBuffer;
819
cmd.flags = T_CURRENT;
821
PR_Lock(fd->secret->md.miscLock);
822
PrepareForAsyncCompletion(me, fd->secret->md.osfd);
823
fd->secret->md.misc.thread = me;
825
err = OTOptionManagement(endpoint, &cmd, &cmd);
826
if (err != kOTNoError) {
827
me->io_pending = PR_FALSE;
828
PR_Unlock(fd->secret->md.miscLock);
832
WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
833
PR_Unlock(fd->secret->md.miscLock);
835
err = me->md.osErrCode;
836
if (err != kOTNoError)
839
if (opt->status == T_FAILURE || opt->status == T_NOTSUPPORT){
840
err = kEOPNOTSUPPErr;
844
PR_ASSERT(opt->status == T_SUCCESS);
848
*((t_linger*)optval) = *((t_linger*)&opt->value);
849
*optlen = sizeof(t_linger);
856
*((PRIntn*)optval) = *((PRIntn*)&opt->value);
857
*optlen = sizeof(PRIntn);
859
case IP_MULTICAST_LOOP:
860
*((PRUint8*)optval) = *((PRIntn*)&opt->value);
861
*optlen = sizeof(PRUint8);
864
*((PRUintn*)optval) = *((PRUint8*)&opt->value);
865
*optlen = sizeof(PRUintn);
867
case IP_MULTICAST_TTL:
868
*((PRUint8*)optval) = *((PRUint8*)&opt->value);
869
*optlen = sizeof(PRUint8);
871
case IP_ADD_MEMBERSHIP:
872
case IP_DROP_MEMBERSHIP:
874
/* struct ip_mreq and TIPAddMulticast are the same size and optval
875
is pointing to struct ip_mreq */
876
*((struct ip_mreq *)optval) = *((struct ip_mreq *)&opt->value);
877
*optlen = sizeof(struct ip_mreq);
880
case IP_MULTICAST_IF:
882
*((PRUint32*)optval) = *((PRUint32*)&opt->value);
883
*optlen = sizeof(PRUint32);
886
/*case IP_TOS:*/ /*IP_TOS has same value as TCP_MAXSEG */
888
if (level == IPPROTO_TCP) { /* it is TCP_MAXSEG */
889
*((PRIntn*)optval) = *((PRIntn*)&opt->value);
890
*optlen = sizeof(PRIntn);
891
} else { /* it is IP_TOS */
892
*((PRUintn*)optval) = *((PRUint8*)&opt->value);
893
*optlen = sizeof(PRUintn);
904
macsock_map_error(err);
909
PRStatus _MD_setsockopt(PRFileDesc *fd, PRInt32 level, PRInt32 optname, const char* optval, PRInt32 optlen)
912
EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
915
PRThread *me = _PR_MD_CURRENT_THREAD();
916
unsigned char optionBuffer[kOTOptionHeaderSize + sizeof(PRSocketOptionData) + 1];
918
if (endpoint == NULL) {
924
OT wants IPPROTO_IP for level and not XTI_GENERIC. SO_REUSEADDR and SO_KEEPALIVE
925
are equated to IP level and TCP level options respectively and hence we need to set
928
if (level == SOL_SOCKET) {
929
if (optname == SO_REUSEADDR)
931
else if (optname == SO_KEEPALIVE)
935
opt = (TOption *)&optionBuffer[0];
936
opt->len = kOTOptionHeaderSize + optlen;
938
/* special case adjustments for length follow */
939
if (optname == SO_KEEPALIVE) /* we need to pass the timeout value for OT */
940
opt->len = kOTOptionHeaderSize + sizeof(t_kpalive);
941
if (optname == IP_MULTICAST_TTL || optname == IP_TTL) /* it is an unsigned char value */
942
opt->len = kOTOneByteOptionSize;
943
if (optname == IP_TOS && level == IPPROTO_IP)
944
opt->len = kOTOneByteOptionSize;
950
cmd.opt.len = opt->len;
951
cmd.opt.maxlen = sizeof(optionBuffer);
952
cmd.opt.buf = (UInt8*)optionBuffer;
954
optionBuffer[opt->len] = 0;
956
cmd.flags = T_NEGOTIATE;
960
*((t_linger*)&opt->value) = *((t_linger*)optval);
966
*((PRIntn*)&opt->value) = *((PRIntn*)optval);
968
case IP_MULTICAST_LOOP:
970
opt->value[0] = T_YES;
972
opt->value[0] = T_NO;
976
t_kpalive *kpalive = (t_kpalive *)&opt->value;
978
kpalive->kp_onoff = *((long*)optval);
979
kpalive->kp_timeout = 10; /* timeout in minutes */
983
*((unsigned char*)&opt->value) = *((PRUintn*)optval);
985
case IP_MULTICAST_TTL:
986
*((unsigned char*)&opt->value) = *optval;
988
case IP_ADD_MEMBERSHIP:
989
case IP_DROP_MEMBERSHIP:
991
/* struct ip_mreq and TIPAddMulticast are the same size and optval
992
is pointing to struct ip_mreq */
993
*((TIPAddMulticast *)&opt->value) = *((TIPAddMulticast *)optval);
996
case IP_MULTICAST_IF:
998
*((PRUint32*)&opt->value) = *((PRUint32*)optval);
1001
/*case IP_TOS:*/ /*IP_TOS has same value as TCP_MAXSEG */
1003
if (level == IPPROTO_TCP) { /* it is TCP_MAXSEG */
1004
*((PRIntn*)&opt->value) = *((PRIntn*)optval);
1005
} else { /* it is IP_TOS */
1006
*((unsigned char*)&opt->value) = *((PRUintn*)optval);
1014
PR_Lock(fd->secret->md.miscLock);
1015
PrepareForAsyncCompletion(me, fd->secret->md.osfd);
1016
fd->secret->md.misc.thread = me;
1018
err = OTOptionManagement(endpoint, &cmd, &cmd);
1019
if (err != kOTNoError) {
1020
me->io_pending = PR_FALSE;
1021
PR_Unlock(fd->secret->md.miscLock);
1025
WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
1026
PR_Unlock(fd->secret->md.miscLock);
1028
err = me->md.osErrCode;
1029
if (err != kOTNoError)
1032
if (opt->status == T_FAILURE || opt->status == T_NOTSUPPORT){
1033
err = kEOPNOTSUPPErr;
1037
if (level == IPPROTO_TCP && optname == TCP_MAXSEG && opt->status == T_READONLY) {
1038
err = kEOPNOTSUPPErr;
1042
PR_ASSERT(opt->status == T_SUCCESS);
1047
macsock_map_error(err);
1052
PRInt32 _MD_socketavailable(PRFileDesc *fd)
1054
PRInt32 osfd = fd->secret->md.osfd;
1056
EndpointRef endpoint = (EndpointRef) osfd;
1059
if (endpoint == NULL) {
1066
err = OTCountDataBytes(endpoint, &bytes);
1067
if ((err == kOTLookErr) || // Not really errors, we just need to do a read,
1068
(err == kOTNoDataErr)) // or there's nothing there.
1071
if (err != kOTNoError)
1077
macsock_map_error(err);
1082
typedef struct RawEndpointAndThread
1085
EndpointRef endpoint;
1086
} RawEndpointAndThread;
1088
// Notification routine for raw endpoints not yet attached to a PRFileDesc.
1089
// Async callback routine.
1090
// A5 is OK. Cannot allocate memory here
1091
static pascal void RawEndpointNotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie)
1093
RawEndpointAndThread *endthr = (RawEndpointAndThread *) contextPtr;
1094
PRThread * thread = endthr->thread;
1095
EndpointRef * endpoint = endthr->endpoint;
1096
_PRCPU * cpu = _PR_MD_CURRENT_CPU();
1103
case T_LISTEN: // A connection request is available
1104
PR_ASSERT(!"T_EXDATA not implemented for raw endpoints");
1107
case T_CONNECT: // Confirmation of a connect request
1108
// cookie = sndCall parameter from OTConnect()
1109
err = OTRcvConnect(endpoint, NULL);
1110
PR_ASSERT(err == kOTNoError);
1112
// wake up waiting thread
1115
case T_DATA: // Standard data is available
1118
case T_EXDATA: // Expedited data is available
1119
PR_ASSERT(!"T_EXDATA Not implemented for raw endpoints");
1122
case T_DISCONNECT: // A disconnect is available
1123
err = OTRcvDisconnect(endpoint, NULL);
1124
PR_ASSERT(err == kOTNoError);
1127
case T_ERROR: // obsolete/unused in library
1128
PR_ASSERT(!"T_ERROR Not implemented for raw endpoints");
1131
case T_UDERR: // UDP Send error; clear the error
1132
(void) OTRcvUDErr((EndpointRef) cookie, NULL);
1135
case T_ORDREL: // An orderly release is available
1136
err = OTRcvOrderlyDisconnect(endpoint);
1137
PR_ASSERT(err == kOTNoError);
1140
case T_GODATA: // Flow control lifted on standard data
1141
resultOT = OTLook(endpoint); // clear T_GODATA event
1142
PR_ASSERT(resultOT == T_GODATA);
1144
// wake up waiting thread, if any
1147
case T_GOEXDATA: // Flow control lifted on expedited data
1148
PR_ASSERT(!"T_GOEXDATA Not implemented");
1151
case T_REQUEST: // An Incoming request is available
1152
PR_ASSERT(!"T_REQUEST Not implemented");
1155
case T_REPLY: // An Incoming reply is available
1156
PR_ASSERT(!"T_REPLY Not implemented");
1159
case T_PASSCON: // State is now T_DATAXFER
1160
// OTAccept() complete, receiving endpoint in T_DATAXFER state
1161
// cookie = OTAccept() resRef parameter
1164
// Async Completion Events
1165
case T_BINDCOMPLETE:
1166
case T_UNBINDCOMPLETE:
1167
case T_ACCEPTCOMPLETE:
1168
case T_OPTMGMTCOMPLETE:
1169
case T_GETPROTADDRCOMPLETE:
1172
// for other OT events, see NotifierRoutine above
1178
thread->md.osErrCode = result;
1179
if (_PR_MD_GET_INTSOFF()) {
1180
thread->md.asyncNotifyPending = PR_TRUE;
1181
cpu->u.missed[cpu->where] |= _PR_MISSED_IO;
1183
DoneWaitingOnThisThread(thread);
1187
SignalIdleSemaphore();
1190
PRInt32 _MD_accept(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout)
1193
EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
1194
PRThread *me = _PR_MD_CURRENT_THREAD();
1197
PRInt32 newosfd = -1;
1200
RawEndpointAndThread *endthr = NULL;
1202
if (endpoint == NULL) {
1207
memset(&call, 0 , sizeof(call));
1210
call.addr.maxlen = *addrlen;
1211
call.addr.len = *addrlen;
1212
call.addr.buf = (UInt8*) addr;
1214
call.addr.maxlen = sizeof(callAddr);
1215
call.addr.len = sizeof(callAddr);
1216
call.addr.buf = (UInt8*) &callAddr;
1220
PrepareForAsyncCompletion(me, fd->secret->md.osfd);
1221
fd->secret->md.misc.thread = me;
1223
// Perform the listen.
1224
err = OTListen (endpoint, &call);
1225
if (err == kOTNoError)
1226
break; // got the call information
1227
else if ((!fd->secret->nonblocking) && (err == kOTNoDataErr)) {
1228
WaitOnThisThread(me, timeout);
1229
err = me->md.osErrCode;
1230
if ((err != kOTNoError) && (err != kOTNoDataErr))
1232
// we can get kOTNoError here, but still need
1233
// to loop back to call OTListen, in order
1234
// to get call info for OTAccept
1236
goto ErrorExit; // we're nonblocking, and/or we got an error
1241
newosfd = _MD_socket(AF_INET, SOCK_STREAM, 0);
1245
// Attach the raw endpoint handler to this endpoint for now.
1246
endthr = (RawEndpointAndThread *) PR_Malloc(sizeof(RawEndpointAndThread));
1247
endthr->thread = me;
1248
endthr->endpoint = (EndpointRef) newosfd;
1250
err = OTInstallNotifier((ProviderRef) newosfd, RawEndpointNotifierRoutineUPP, endthr);
1251
PR_ASSERT(err == kOTNoError);
1253
err = OTSetAsynchronous((EndpointRef) newosfd);
1254
PR_ASSERT(err == kOTNoError);
1256
// Bind to a local port; let the system assign it.
1257
bindAddr.inet.family = AF_INET;
1258
bindAddr.inet.port = bindAddr.inet.ip = 0;
1260
bindReq.addr.maxlen = PR_NETADDR_SIZE (&bindAddr);
1261
bindReq.addr.len = 0;
1262
bindReq.addr.buf = (UInt8*) &bindAddr;
1265
PrepareForAsyncCompletion(me, newosfd);
1266
err = OTBind((EndpointRef) newosfd, &bindReq, NULL);
1267
if (err != kOTNoError)
1270
WaitOnThisThread(me, timeout);
1272
err = me->md.osErrCode;
1273
if (err != kOTNoError)
1276
PrepareForAsyncCompletion(me, newosfd);
1278
err = OTAccept (endpoint, (EndpointRef) newosfd, &call);
1279
if ((err != kOTNoError) && (err != kOTNoDataErr))
1282
WaitOnThisThread(me, timeout);
1284
err = me->md.osErrCode;
1285
if (err != kOTNoError)
1288
if (addrlen != NULL)
1289
*addrlen = call.addr.len;
1291
// Remove the temporary notifier we installed to set up the new endpoint.
1292
OTRemoveNotifier((EndpointRef) newosfd);
1293
PR_Free(endthr); // free the temporary context we set up for this endpoint
1298
me->io_pending = PR_FALSE; // clear pending wait state if any
1300
_MD_closesocket(newosfd);
1301
macsock_map_error(err);
1306
PRInt32 _MD_connect(PRFileDesc *fd, PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout)
1309
EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
1310
PRThread *me = _PR_MD_CURRENT_THREAD();
1315
if (endpoint == NULL) {
1325
// Bind to a local port; let the system assign it.
1327
bindAddr.inet.family = AF_INET;
1328
bindAddr.inet.port = bindAddr.inet.ip = 0;
1330
bindReq.addr.maxlen = PR_NETADDR_SIZE (&bindAddr);
1331
bindReq.addr.len = 0;
1332
bindReq.addr.buf = (UInt8*) &bindAddr;
1335
PR_Lock(fd->secret->md.miscLock);
1336
PrepareForAsyncCompletion(me, fd->secret->md.osfd);
1337
fd->secret->md.misc.thread = me;
1339
err = OTBind(endpoint, &bindReq, NULL);
1340
if (err != kOTNoError) {
1341
me->io_pending = PR_FALSE;
1342
PR_Unlock(fd->secret->md.miscLock);
1346
WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
1347
PR_Unlock(fd->secret->md.miscLock);
1349
err = me->md.osErrCode;
1350
if (err != kOTNoError)
1353
memset(&sndCall, 0 , sizeof(sndCall));
1355
sndCall.addr.maxlen = addrlen;
1356
sndCall.addr.len = addrlen;
1357
sndCall.addr.buf = (UInt8*) addr;
1359
if (!fd->secret->nonblocking) {
1360
PrepareForAsyncCompletion(me, fd->secret->md.osfd);
1361
PR_ASSERT(fd->secret->md.write.thread == NULL);
1362
fd->secret->md.write.thread = me;
1365
err = OTConnect (endpoint, &sndCall, NULL);
1366
if (err == kOTNoError) {
1367
PR_ASSERT(!"OTConnect returned kOTNoError in async mode!?!");
1369
if (fd->secret->nonblocking) {
1370
if (err == kOTNoDataErr)
1374
if (err != kOTNoError && err != kOTNoDataErr) {
1375
me->io_pending = PR_FALSE;
1380
WaitOnThisThread(me, timeout);
1382
err = me->md.osErrCode;
1383
if (err != kOTNoError)
1389
macsock_map_error(err);
1395
// EBADF -- bad socket id
1396
// EFAULT -- bad buffer
1397
static PRInt32 SendReceiveStream(PRFileDesc *fd, void *buf, PRInt32 amount,
1398
PRIntn flags, PRIntervalTime timeout, SndRcvOpCode opCode)
1402
EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
1403
PRThread *me = _PR_MD_CURRENT_THREAD();
1404
PRInt32 bytesLeft = amount;
1406
PR_ASSERT(flags == 0 ||
1407
(opCode == kSTREAM_RECEIVE && flags == PR_MSG_PEEK));
1408
PR_ASSERT(opCode == kSTREAM_SEND || opCode == kSTREAM_RECEIVE);
1410
if (endpoint == NULL) {
1420
PR_ASSERT(opCode == kSTREAM_SEND ? fd->secret->md.write.thread == NULL :
1421
fd->secret->md.read.thread == NULL);
1423
while (bytesLeft > 0)
1425
Boolean disabledNotifications = OTEnterNotifier(endpoint);
1427
PrepareForAsyncCompletion(me, fd->secret->md.osfd);
1429
if (opCode == kSTREAM_SEND) {
1431
fd->secret->md.write.thread = me;
1432
fd->secret->md.writeReady = PR_FALSE; // expect the worst
1433
result = OTSnd(endpoint, buf, bytesLeft, NULL);
1434
fd->secret->md.writeReady = (result != kOTFlowErr);
1435
if (fd->secret->nonblocking) // hope for the best
1439
// We drop through on anything other than a blocking write.
1440
if (result != kOTFlowErr)
1443
// Blocking write, but the pipe is full. Turn notifications on and
1444
// wait for an event, hoping that it's a T_GODATA event.
1445
if (disabledNotifications) {
1446
OTLeaveNotifier(endpoint);
1447
disabledNotifications = false;
1449
WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
1450
result = me->md.osErrCode;
1451
if (result != kOTNoError) // got interrupted, or some other error
1454
// Prepare to loop back and try again
1455
disabledNotifications = OTEnterNotifier(endpoint);
1456
PrepareForAsyncCompletion(me, fd->secret->md.osfd);
1462
fd->secret->md.read.thread = me;
1463
fd->secret->md.readReady = PR_FALSE; // expect the worst
1464
result = OTRcv(endpoint, buf, bytesLeft, NULL);
1465
if (fd->secret->nonblocking) {
1466
fd->secret->md.readReady = (result != kOTNoDataErr);
1469
if (result != kOTNoDataErr) {
1470
// If we successfully read a blocking socket, check for more data.
1471
// According to IM:OT, we should be able to rely on OTCountDataBytes
1472
// to tell us whether there is a nonzero amount of data pending.
1475
tmpResult = OTCountDataBytes(endpoint, &count);
1476
fd->secret->md.readReady = ((tmpResult == kOTNoError) && (count > 0));
1480
// Blocking read, but no data available. Turn notifications on and
1481
// wait for an event on this endpoint, and hope that we get a T_DATA event.
1482
if (disabledNotifications) {
1483
OTLeaveNotifier(endpoint);
1484
disabledNotifications = false;
1486
WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
1487
result = me->md.osErrCode;
1488
if (result != kOTNoError) // interrupted thread, etc.
1491
// Prepare to loop back and try again
1492
disabledNotifications = OTEnterNotifier(endpoint);
1493
PrepareForAsyncCompletion(me, fd->secret->md.osfd);
1496
// Retry read if we had to wait for data to show up.
1500
me->io_pending = PR_FALSE;
1502
if (opCode == kSTREAM_SEND)
1503
fd->secret->md.write.thread = NULL;
1505
fd->secret->md.read.thread = NULL;
1507
// turn notifications back on
1508
if (disabledNotifications)
1509
OTLeaveNotifier(endpoint);
1512
buf = (void *) ( (UInt32) buf + (UInt32)result );
1513
bytesLeft -= result;
1514
if (opCode == kSTREAM_RECEIVE) {
1521
PR_ASSERT(!"call to OTLook() required after all.");
1527
case kEWOULDBLOCKErr:
1528
if (fd->secret->nonblocking) {
1530
if (bytesLeft == amount) { // no data was sent
1535
// some data was sent
1536
amount -= bytesLeft;
1540
WaitOnThisThread(me, timeout);
1541
err = me->md.osErrCode;
1542
if (err != kOTNoError)
1546
case kOTOutStateErr: // if provider already closed, fall through to handle error
1547
if (fd->secret->md.orderlyDisconnect) {
1551
// else fall through
1560
PR_ASSERT(opCode == kSTREAM_SEND ? fd->secret->md.write.thread == NULL :
1561
fd->secret->md.read.thread == NULL);
1565
PR_ASSERT(opCode == kSTREAM_SEND ? fd->secret->md.write.thread == NULL :
1566
fd->secret->md.read.thread == NULL);
1567
macsock_map_error(err);
1572
PRInt32 _MD_recv(PRFileDesc *fd, void *buf, PRInt32 amount,
1573
PRIntn flags, PRIntervalTime timeout)
1575
return (SendReceiveStream(fd, buf, amount, flags, timeout, kSTREAM_RECEIVE));
1579
PRInt32 _MD_send(PRFileDesc *fd,const void *buf, PRInt32 amount,
1580
PRIntn flags, PRIntervalTime timeout)
1582
return (SendReceiveStream(fd, (void *)buf, amount, flags, timeout, kSTREAM_SEND));
1587
// EBADF -- bad socket id
1588
// EFAULT -- bad buffer
1589
static PRInt32 SendReceiveDgram(PRFileDesc *fd, void *buf, PRInt32 amount,
1590
PRIntn flags, PRNetAddr *addr, PRUint32 *addrlen,
1591
PRIntervalTime timeout, SndRcvOpCode opCode)
1594
EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
1595
PRThread *me = _PR_MD_CURRENT_THREAD();
1596
PRInt32 bytesLeft = amount;
1599
PR_ASSERT(flags == 0);
1601
if (endpoint == NULL) {
1606
if (buf == NULL || addr == NULL) {
1611
if (opCode != kDGRAM_SEND && opCode != kDGRAM_RECEIVE) {
1616
memset(&dgram, 0 , sizeof(dgram));
1617
dgram.addr.maxlen = *addrlen;
1618
dgram.addr.len = *addrlen;
1619
dgram.addr.buf = (UInt8*) addr;
1620
dgram.udata.maxlen = amount;
1621
dgram.udata.len = amount;
1622
dgram.udata.buf = (UInt8*) buf;
1624
while (bytesLeft > 0) {
1626
PrepareForAsyncCompletion(me, fd->secret->md.osfd);
1628
if (opCode == kDGRAM_SEND) {
1629
fd->secret->md.write.thread = me;
1630
fd->secret->md.writeReady = PR_FALSE; // expect the worst
1631
err = OTSndUData(endpoint, &dgram);
1632
if (err != kOTFlowErr) // hope for the best
1633
fd->secret->md.writeReady = PR_TRUE;
1635
fd->secret->md.read.thread = me;
1636
fd->secret->md.readReady = PR_FALSE; // expect the worst
1637
err = OTRcvUData(endpoint, &dgram, NULL);
1638
if (err != kOTNoDataErr) // hope for the best
1639
fd->secret->md.readReady = PR_TRUE;
1642
if (err == kOTNoError) {
1643
buf = (void *) ( (UInt32) buf + (UInt32)dgram.udata.len );
1644
bytesLeft -= dgram.udata.len;
1645
dgram.udata.buf = (UInt8*) buf;
1646
me->io_pending = PR_FALSE;
1648
PR_ASSERT(err == kOTNoDataErr || err == kOTOutStateErr);
1649
WaitOnThisThread(me, timeout);
1650
err = me->md.osErrCode;
1651
if (err != kOTNoError)
1656
if (opCode == kDGRAM_RECEIVE)
1657
*addrlen = dgram.addr.len;
1662
macsock_map_error(err);
1667
PRInt32 _MD_recvfrom(PRFileDesc *fd, void *buf, PRInt32 amount,
1668
PRIntn flags, PRNetAddr *addr, PRUint32 *addrlen,
1669
PRIntervalTime timeout)
1671
return (SendReceiveDgram(fd, buf, amount, flags, addr, addrlen,
1672
timeout, kDGRAM_RECEIVE));
1676
PRInt32 _MD_sendto(PRFileDesc *fd,const void *buf, PRInt32 amount,
1677
PRIntn flags, PRNetAddr *addr, PRUint32 addrlen,
1678
PRIntervalTime timeout)
1680
return (SendReceiveDgram(fd, (void *)buf, amount, flags, addr, &addrlen,
1681
timeout, kDGRAM_SEND));
1685
PRInt32 _MD_closesocket(PRInt32 osfd)
1688
EndpointRef endpoint = (EndpointRef) osfd;
1689
PRThread *me = _PR_MD_CURRENT_THREAD();
1691
if (endpoint == NULL) {
1696
if (me->io_pending && me->io_fd == osfd)
1697
me->io_pending = PR_FALSE;
1699
(void) OTSndOrderlyDisconnect(endpoint);
1700
err = OTCloseProvider(endpoint);
1701
if (err != kOTNoError)
1707
macsock_map_error(err);
1712
PRInt32 _MD_writev(PRFileDesc *fd, const struct PRIOVec *iov, PRInt32 iov_size, PRIntervalTime timeout)
1714
#pragma unused (fd, iov, iov_size, timeout)
1717
_PR_MD_CURRENT_THREAD()->md.osErrCode = unimpErr;
1721
// OT endpoint states are documented here:
1722
// http://gemma.apple.com/techpubs/mac/NetworkingOT/NetworkingWOT-27.html#MARKER-9-65
1724
static PRBool GetState(PRFileDesc *fd, PRBool *readReady, PRBool *writeReady, PRBool *exceptReady)
1727
// hack to emulate BSD sockets; say that a socket that has disconnected
1728
// is still readable.
1729
size_t availableData = 1;
1730
if (!fd->secret->md.orderlyDisconnect)
1731
OTCountDataBytes((EndpointRef)fd->secret->md.osfd, &availableData);
1733
*readReady = fd->secret->md.readReady && (availableData > 0);
1734
*exceptReady = fd->secret->md.exceptReady;
1736
resultOT = OTGetEndpointState((EndpointRef)fd->secret->md.osfd);
1740
// the socket is not connected. Emulating BSD sockets,
1741
// we mark it readable and writable. The next PR_Read
1742
// or PR_Write will then fail. Usually, in this situation,
1743
// fd->secret->md.exceptReady is also set, and returned if
1744
// anyone is polling for it.
1745
*readReady = PR_FALSE;
1746
*writeReady = PR_FALSE;
1749
case T_DATAXFER: // data transfer
1750
*writeReady = fd->secret->md.writeReady;
1753
case T_INREL: // incoming orderly release
1754
*writeReady = fd->secret->md.writeReady;
1757
case T_OUTCON: // outgoing connection pending
1758
case T_INCON: // incoming connection pending
1759
case T_OUTREL: // outgoing orderly release
1761
*writeReady = PR_FALSE;
1764
return *readReady || *writeReady || *exceptReady;
1767
// check to see if any of the poll descriptors have data available
1768
// for reading or writing, by calling their poll methods (layered IO).
1769
static PRInt32 CheckPollDescMethods(PRPollDesc *pds, PRIntn npds, PRInt16 *outReadFlags, PRInt16 *outWriteFlags)
1772
PRPollDesc *pd, *epd;
1773
PRInt16 *readFlag, *writeFlag;
1775
for (pd = pds, epd = pd + npds, readFlag = outReadFlags, writeFlag = outWriteFlags;
1777
pd++, readFlag++, writeFlag++)
1779
PRInt16 in_flags_read = 0, in_flags_write = 0;
1780
PRInt16 out_flags_read = 0, out_flags_write = 0;
1784
if (NULL == pd->fd || pd->in_flags == 0) continue;
1786
if (pd->in_flags & PR_POLL_READ)
1788
in_flags_read = (pd->fd->methods->poll)(
1789
pd->fd, pd->in_flags & ~PR_POLL_WRITE, &out_flags_read);
1792
if (pd->in_flags & PR_POLL_WRITE)
1794
in_flags_write = (pd->fd->methods->poll)(
1795
pd->fd, pd->in_flags & ~PR_POLL_READ, &out_flags_write);
1798
if ((0 != (in_flags_read & out_flags_read)) ||
1799
(0 != (in_flags_write & out_flags_write)))
1801
ready += 1; /* some layer has buffer input */
1802
pd->out_flags = out_flags_read | out_flags_write;
1805
*readFlag = in_flags_read;
1806
*writeFlag = in_flags_write;
1812
// check to see if any of OT endpoints of the poll descriptors have data available
1813
// for reading or writing.
1814
static PRInt32 CheckPollDescEndpoints(PRPollDesc *pds, PRIntn npds, const PRInt16 *inReadFlags, const PRInt16 *inWriteFlags)
1817
PRPollDesc *pd, *epd;
1818
const PRInt16 *readFlag, *writeFlag;
1820
for (pd = pds, epd = pd + npds, readFlag = inReadFlags, writeFlag = inWriteFlags;
1822
pd++, readFlag++, writeFlag++)
1824
PRFileDesc *bottomFD;
1825
PRBool readReady, writeReady, exceptReady;
1826
PRInt16 in_flags_read = *readFlag;
1827
PRInt16 in_flags_write = *writeFlag;
1829
if (NULL == pd->fd || pd->in_flags == 0) continue;
1831
if ((pd->in_flags & ~pd->out_flags) == 0) {
1836
bottomFD = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
1837
/* bottomFD can be NULL for pollable sockets */
1840
if (_PR_FILEDESC_OPEN == bottomFD->secret->state)
1842
if (GetState(bottomFD, &readReady, &writeReady, &exceptReady))
1846
if (in_flags_read & PR_POLL_READ)
1847
pd->out_flags |= PR_POLL_READ;
1848
if (in_flags_write & PR_POLL_READ)
1849
pd->out_flags |= PR_POLL_WRITE;
1853
if (in_flags_read & PR_POLL_WRITE)
1854
pd->out_flags |= PR_POLL_READ;
1855
if (in_flags_write & PR_POLL_WRITE)
1856
pd->out_flags |= PR_POLL_WRITE;
1858
if (exceptReady && (pd->in_flags & PR_POLL_EXCEPT))
1860
pd->out_flags |= PR_POLL_EXCEPT;
1863
if (0 != pd->out_flags) ready++;
1865
else /* bad state */
1867
ready += 1; /* this will cause an abrupt return */
1868
pd->out_flags = PR_POLL_NVAL; /* bogii */
1877
// see how many of the poll descriptors are ready
1878
static PRInt32 CountReadyPollDescs(PRPollDesc *pds, PRIntn npds)
1881
PRPollDesc *pd, *epd;
1883
for (pd = pds, epd = pd + npds; pd < epd; pd++)
1892
// set or clear the poll thread on the poll descriptors
1893
static void SetDescPollThread(PRPollDesc *pds, PRIntn npds, PRThread* thread)
1896
PRPollDesc *pd, *epd;
1898
for (pd = pds, epd = pd + npds; pd < epd; pd++)
1902
PRFileDesc *bottomFD = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
1903
if (bottomFD && (_PR_FILEDESC_OPEN == bottomFD->secret->state))
1905
if (pd->in_flags & PR_POLL_READ) {
1906
PR_ASSERT(thread == NULL || bottomFD->secret->md.read.thread == NULL);
1907
bottomFD->secret->md.read.thread = thread;
1910
if (pd->in_flags & PR_POLL_WRITE) {
1911
// it's possible for the writing thread to be non-null during
1912
// a non-blocking connect, so we assert that we're on
1913
// the same thread, or the thread is null.
1914
// Note that it's strictly possible for the connect and poll
1915
// to be on different threads, so ideally we need to assert
1916
// that if md.write.thread is non-null, there is a non-blocking
1917
// connect in progress.
1918
PR_ASSERT(thread == NULL ||
1919
(bottomFD->secret->md.write.thread == NULL ||
1920
bottomFD->secret->md.write.thread == thread));
1921
bottomFD->secret->md.write.thread = thread;
1929
#define DESCRIPTOR_FLAGS_ARRAY_SIZE 32
1931
PRInt32 _MD_poll(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
1933
PRInt16 readFlagsArray[DESCRIPTOR_FLAGS_ARRAY_SIZE];
1934
PRInt16 writeFlagsArray[DESCRIPTOR_FLAGS_ARRAY_SIZE];
1936
PRInt16 *readFlags = readFlagsArray;
1937
PRInt16 *writeFlags = writeFlagsArray;
1939
PRInt16 *ioFlags = NULL;
1941
PRThread *thread = _PR_MD_CURRENT_THREAD();
1944
if (npds > DESCRIPTOR_FLAGS_ARRAY_SIZE)
1946
// we allocate a single double-size array. The first half is used
1947
// for read flags, and the second half for write flags.
1948
ioFlags = (PRInt16*)PR_Malloc(sizeof(PRInt16) * npds * 2);
1951
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
1955
readFlags = ioFlags;
1956
writeFlags = &ioFlags[npds];
1959
// we have to be outside the lock when calling this, since
1960
// it can call arbitrary user code (including other socket
1962
ready = CheckPollDescMethods(pds, npds, readFlags, writeFlags);
1964
if (!ready && timeout != PR_INTERVAL_NO_WAIT) {
1969
PR_Lock(thread->md.asyncIOLock);
1970
PrepareForAsyncCompletion(thread, 0);
1972
SetDescPollThread(pds, npds, thread);
1974
(void)CheckPollDescEndpoints(pds, npds, readFlags, writeFlags);
1976
PR_Unlock(thread->md.asyncIOLock);
1977
_PR_FAST_INTSON(is);
1979
ready = CountReadyPollDescs(pds, npds);
1982
WaitOnThisThread(thread, timeout);
1984
// since we may have been woken by a pollable event firing,
1985
// we have to check both poll methods and endpoints.
1986
(void)CheckPollDescMethods(pds, npds, readFlags, writeFlags);
1987
ready = CheckPollDescEndpoints(pds, npds, readFlags, writeFlags);
1990
thread->io_pending = PR_FALSE;
1991
SetDescPollThread(pds, npds, NULL);
1994
ready = CheckPollDescEndpoints(pds, npds, readFlags, writeFlags);
1997
if (readFlags != readFlagsArray)
2004
void _MD_initfiledesc(PRFileDesc *fd)
2006
// Allocate a PR_Lock to arbitrate miscellaneous OT calls for this endpoint between threads
2007
// We presume that only one thread will be making Read calls (Recv/Accept) and that only
2008
// one thread will be making Write calls (Send/Connect) on the endpoint at a time.
2009
if (fd->methods->file_type == PR_DESC_SOCKET_TCP ||
2010
fd->methods->file_type == PR_DESC_SOCKET_UDP )
2012
PR_ASSERT(fd->secret->md.miscLock == NULL);
2013
fd->secret->md.miscLock = PR_NewLock();
2014
PR_ASSERT(fd->secret->md.miscLock != NULL);
2015
fd->secret->md.orderlyDisconnect = PR_FALSE;
2016
fd->secret->md.readReady = PR_FALSE; // let's not presume we have data ready to read
2017
fd->secret->md.writeReady = PR_TRUE; // let's presume we can write unless we hear otherwise
2018
fd->secret->md.exceptReady = PR_FALSE;
2023
void _MD_freefiledesc(PRFileDesc *fd)
2025
if (fd->secret->md.miscLock)
2027
PR_ASSERT(fd->methods->file_type == PR_DESC_SOCKET_TCP || fd->methods->file_type == PR_DESC_SOCKET_UDP);
2028
PR_DestroyLock(fd->secret->md.miscLock);
2029
fd->secret->md.miscLock = NULL;
2031
PR_ASSERT(fd->methods->file_type != PR_DESC_SOCKET_TCP && PR_DESC_SOCKET_TCP != PR_DESC_SOCKET_UDP);
2035
// _MD_makenonblock is also used for sockets meant to be used for blocking I/O,
2036
// in order to install the notifier routine for async completion.
2037
void _MD_makenonblock(PRFileDesc *fd)
2039
// We simulate non-blocking mode using async mode rather
2040
// than put the endpoint in non-blocking mode.
2041
// We need to install the PRFileDesc as the contextPtr for the NotifierRoutine, but it
2042
// didn't exist at the time the endpoint was created. It does now though...
2043
ProviderRef endpointRef = (ProviderRef)fd->secret->md.osfd;
2046
// Install fd->secret as the contextPtr for the Notifier function associated with this
2047
// endpoint. We use this instead of the fd itself because:
2048
// (a) in cases where you import I/O layers, the containing
2049
// fd changes, but the secret structure does not;
2050
// (b) the notifier func refers only to the secret data structure
2052
err = OTInstallNotifier(endpointRef, NotifierRoutineUPP, fd->secret);
2053
PR_ASSERT(err == kOTNoError);
2055
// Now that we have a NotifierRoutine installed, we can make the endpoint asynchronous
2056
err = OTSetAsynchronous(endpointRef);
2057
PR_ASSERT(err == kOTNoError);
2061
void _MD_initfdinheritable(PRFileDesc *fd, PRBool imported)
2063
/* XXX this function needs to be implemented */
2064
fd->secret->inheritable = _PR_TRI_UNKNOWN;
2068
void _MD_queryfdinheritable(PRFileDesc *fd)
2070
/* XXX this function needs to be implemented */
2075
PR_IMPLEMENT(PRInt32) _MD_shutdown(PRFileDesc *fd, PRIntn how)
2077
#pragma unused (fd, how)
2079
/* Just succeed silently!!! */
2084
PR_IMPLEMENT(PRStatus)
2085
_MD_getpeername(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen)
2087
PRThread *me = _PR_MD_CURRENT_THREAD();
2088
EndpointRef ep = (EndpointRef) fd->secret->md.osfd;
2089
InetAddress inetAddr;
2093
if (*addrlen < sizeof(InetAddress)) {
2095
err = (OSErr) kEINVALErr;
2099
peerAddr.addr.maxlen = sizeof(InetAddress);
2100
peerAddr.addr.len = 0;
2101
peerAddr.addr.buf = (UInt8*) &inetAddr;
2104
PrepareForAsyncCompletion(me, fd->secret->md.osfd);
2105
fd->secret->md.misc.thread = me; // tell notifier routine what to wake up
2107
err = OTGetProtAddress(ep, NULL, &peerAddr);
2109
if (err != kOTNoError)
2112
WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
2114
err = me->md.osErrCode;
2115
if ((err == kOTNoError) && (peerAddr.addr.len < sizeof(InetAddress)))
2116
err = kEBADFErr; // we don't understand the address we got
2117
if (err != kOTNoError)
2120
// Translate the OT peer information into an NSPR address.
2121
addr->inet.family = AF_INET;
2122
addr->inet.port = (PRUint16) inetAddr.fPort;
2123
addr->inet.ip = (PRUint32) inetAddr.fHost;
2125
*addrlen = PR_NETADDR_SIZE(addr); // return the amount of data obtained
2129
macsock_map_error(err);
2134
PR_IMPLEMENT(unsigned long) inet_addr(const char *cp)
2139
_MD_FinishInitNetAccess();
2141
err = OTInetStringToHost((char*) cp, &host);
2142
if (err != kOTNoError)
2149
static char *sAliases[1] = {NULL};
2150
static struct hostent sHostEnt = {NULL, &sAliases[0], AF_INET, sizeof (long), NULL};
2151
static InetHostInfo sHostInfo;
2152
static InetHost *sAddresses[kMaxHostAddrs+1];
2155
PR_IMPLEMENT(struct hostent *) gethostbyname(const char * name)
2159
PRThread *me = _PR_MD_CURRENT_THREAD();
2161
_MD_FinishInitNetAccess();
2163
me->io_pending = PR_TRUE;
2165
me->md.osErrCode = noErr;
2167
PR_Lock(dnsContext.lock); // so we can safely store our thread ptr in dnsContext
2168
dnsContext.thread = me; // so we know what thread to wake up when OTInetStringToAddress completes
2170
err = OTInetStringToAddress(dnsContext.serviceRef, (char *)name, &sHostInfo);
2171
if (err != kOTNoError) {
2172
me->io_pending = PR_FALSE;
2173
me->md.osErrCode = err;
2177
WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
2178
PR_Unlock(dnsContext.lock);
2180
if (me->md.osErrCode != kOTNoError)
2183
sHostEnt.h_name = sHostInfo.name;
2184
for (index=0; index<kMaxHostAddrs && sHostInfo.addrs[index] != NULL; index++)
2185
sAddresses[index] = &sHostInfo.addrs[index];
2186
sAddresses[index] = NULL;
2187
sHostEnt.h_addr_list = (char **)sAddresses;
2196
PR_IMPLEMENT(struct hostent *) gethostbyaddr(const void *addr, int addrlen, int type)
2198
PR_ASSERT(type == AF_INET);
2199
PR_ASSERT(addrlen == sizeof(struct in_addr));
2201
_MD_FinishInitNetAccess();
2203
OTInetHostToString((InetHost)addr, sHostInfo.name);
2205
return (gethostbyname(sHostInfo.name));
2209
PR_IMPLEMENT(char *) inet_ntoa(struct in_addr addr)
2211
_MD_FinishInitNetAccess();
2213
OTInetHostToString((InetHost)addr.s_addr, sHostInfo.name);
2215
return sHostInfo.name;
2219
PRStatus _MD_gethostname(char *name, int namelen)
2222
InetInterfaceInfo info;
2224
_MD_FinishInitNetAccess();
2227
* On a Macintosh, we don't have the concept of a local host name.
2228
* We do though have an IP address & everyone should be happy with
2229
* a string version of that for a name.
2230
* The alternative here is to ping a local DNS for our name, they
2231
* will often know it. This is the cheap, easiest, and safest way out.
2234
/* Make sure the string is as long as the longest possible address */
2235
if (namelen < strlen("123.123.123.123")) {
2240
err = OTInetGetInterfaceInfo(&info, kDefaultInetInterface);
2241
if (err != kOTNoError)
2244
OTInetHostToString(info.fAddress, name);
2249
macsock_map_error(err);
2254
#define kIPName "ip"
2255
static struct protoent sIPProto = {kIPName, NULL, INET_IP};
2256
static struct protoent sTCPProto = {kTCPName, NULL, INET_TCP};
2257
static struct protoent sUDPProto = {kUDPName, NULL, INET_UDP};
2259
PR_IMPLEMENT(struct protoent *) getprotobyname(const char * name)
2261
if (strcmp(name, kIPName) == 0)
2264
if (strcmp(name, kTCPName) == 0)
2265
return (&sTCPProto);
2267
if (strcmp(name, kUDPName) == 0)
2268
return (&sUDPProto);
2271
macsock_map_error(kEINVALErr);
2276
PR_IMPLEMENT(struct protoent *) getprotobynumber(int number)
2278
if (number == INET_IP)
2281
if (number == INET_TCP)
2282
return (&sTCPProto);
2284
if (number == INET_UDP)
2285
return (&sUDPProto);
2288
macsock_map_error(kEINVALErr);
2293
int _MD_mac_get_nonblocking_connect_error(PRFileDesc* fd)
2295
EndpointRef endpoint = (EndpointRef)fd->secret->md.osfd;
2296
OTResult resultOT = OTGetEndpointState(endpoint);
2300
macsock_map_error(EINPROGRESS);
2307
macsock_map_error(fd->secret->md.disconnectError);
2308
fd->secret->md.disconnectError = 0;
2312
macsock_map_error(ENOTCONN);
2320
return -1; // not reached