~ubuntu-branches/ubuntu/saucy/nspr/saucy-updates

« back to all changes in this revision

Viewing changes to mozilla/nsprpub/pr/src/md/mac/macsockotpt.c

  • Committer: Bazaar Package Importer
  • Author(s): Alexander Sack
  • Date: 2009-08-10 11:34:26 UTC
  • mfrom: (1.1.10 upstream)
  • Revision ID: james.westby@ubuntu.com-20090810113426-3uv4diflrkcbdimm
Tags: 4.8-0ubuntu1
* New upstream release: 4.8 (LP: #387812)
* adjust patches to changed upstreanm codebase
  - update debian/patches/99_configure.patch
* update shlibs symbols to include new API elements
  - update debian/libnspr4-0d.symbols

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
4
 
 *
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/
9
 
 *
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
13
 
 * License.
14
 
 *
15
 
 * The Original Code is the Netscape Portable Runtime (NSPR).
16
 
 *
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.
21
 
 *
22
 
 * Contributor(s):
23
 
 *
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.
35
 
 *
36
 
 * ***** END LICENSE BLOCK ***** */
37
 
 
38
 
/* This turns on UNIX style errors in OT 1.1 headers */
39
 
#define OTUNIXERRORS 1
40
 
 
41
 
#include <string.h>
42
 
 
43
 
#include <Gestalt.h>
44
 
#include <Files.h>
45
 
#include <OpenTransport.h>
46
 
#include <OSUtils.h>
47
 
 
48
 
#define GESTALT_OPEN_TPT_PRESENT        gestaltOpenTptPresentMask
49
 
#define GESTALT_OPEN_TPT_TCP_PRESENT    gestaltOpenTptTCPPresentMask
50
 
 
51
 
#include <OpenTptInternet.h>    // All the internet typedefs
52
 
 
53
 
#if (UNIVERSAL_INTERFACES_VERSION >= 0x0330)
54
 
// for some reason Apple removed this typedef.
55
 
typedef struct OTConfiguration  OTConfiguration;
56
 
#endif
57
 
 
58
 
#include "primpl.h"
59
 
 
60
 
typedef enum SndRcvOpCode {
61
 
    kSTREAM_SEND,
62
 
    kSTREAM_RECEIVE,
63
 
    kDGRAM_SEND,
64
 
    kDGRAM_RECEIVE
65
 
} SndRcvOpCode;
66
 
 
67
 
static struct {
68
 
        PRLock *    lock;
69
 
        InetSvcRef  serviceRef;
70
 
        PRThread *  thread;
71
 
        void *      cookie;
72
 
} dnsContext;
73
 
 
74
 
 
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);
78
 
 
79
 
static PRBool GetState(PRFileDesc *fd, PRBool *readReady, PRBool *writeReady, PRBool *exceptReady);
80
 
 
81
 
void
82
 
WakeUpNotifiedThread(PRThread *thread, OTResult result);
83
 
 
84
 
extern void WaitOnThisThread(PRThread *thread, PRIntervalTime timeout);
85
 
extern void DoneWaitingOnThisThread(PRThread *thread);
86
 
 
87
 
#if TARGET_CARBON
88
 
OTClientContextPtr  clientContext = NULL;
89
 
 
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)
93
 
 
94
 
#else
95
 
 
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 */
100
 
 
101
 
static OTNotifyUPP      DNSNotifierRoutineUPP;
102
 
static OTNotifyUPP NotifierRoutineUPP;
103
 
static OTNotifyUPP RawEndpointNotifierRoutineUPP;
104
 
 
105
 
void _MD_InitNetAccess()
106
 
{
107
 
    OSErr       err;
108
 
    OSStatus    errOT;
109
 
    PRBool      hasOTTCPIP = PR_FALSE;
110
 
    PRBool      hasOT = PR_FALSE;
111
 
    long        gestaltResult;
112
 
 
113
 
    err = Gestalt(gestaltOpenTpt, &gestaltResult);
114
 
    if (err == noErr)
115
 
        if (gestaltResult & GESTALT_OPEN_TPT_PRESENT)
116
 
            hasOT = PR_TRUE;
117
 
    
118
 
    if (hasOT)
119
 
        if (gestaltResult & GESTALT_OPEN_TPT_TCP_PRESENT)
120
 
            hasOTTCPIP = PR_TRUE;
121
 
        
122
 
    PR_ASSERT(hasOTTCPIP == PR_TRUE);
123
 
 
124
 
    DNSNotifierRoutineUPP       =  NewOTNotifyUPP(DNSNotifierRoutine);
125
 
    NotifierRoutineUPP          =  NewOTNotifyUPP(NotifierRoutine);
126
 
    RawEndpointNotifierRoutineUPP = NewOTNotifyUPP(RawEndpointNotifierRoutine);
127
 
 
128
 
    errOT = INIT_OPEN_TRANSPORT();
129
 
    PR_ASSERT(err == kOTNoError);
130
 
 
131
 
        dnsContext.serviceRef = NULL;
132
 
        dnsContext.lock = PR_NewLock();
133
 
        PR_ASSERT(dnsContext.lock != NULL);
134
 
 
135
 
        dnsContext.thread = _PR_MD_CURRENT_THREAD();
136
 
        dnsContext.cookie = NULL;
137
 
        
138
 
/* XXX Does not handle absence of open tpt and tcp yet! */
139
 
}
140
 
 
141
 
static void _MD_FinishInitNetAccess()
142
 
{
143
 
    OSStatus    errOT;
144
 
 
145
 
        if (dnsContext.serviceRef)
146
 
                return;
147
 
                
148
 
    dnsContext.serviceRef = OT_OPEN_INTERNET_SERVICES(kDefaultInternetServicesPath, NULL, &errOT);
149
 
    if (errOT != kOTNoError) {
150
 
        dnsContext.serviceRef = NULL;
151
 
        return;    /* no network -- oh well */
152
 
    }
153
 
    
154
 
    PR_ASSERT((dnsContext.serviceRef != NULL) && (errOT == kOTNoError));
155
 
 
156
 
    /* Install notify function for DNR Address To String completion */
157
 
    errOT = OTInstallNotifier(dnsContext.serviceRef, DNSNotifierRoutineUPP, &dnsContext);
158
 
    PR_ASSERT(errOT == kOTNoError);
159
 
 
160
 
    /* Put us into async mode */
161
 
    errOT = OTSetAsynchronous(dnsContext.serviceRef);
162
 
    PR_ASSERT(errOT == kOTNoError);
163
 
}
164
 
 
165
 
 
166
 
static pascal void  DNSNotifierRoutine(void * contextPtr, OTEventCode otEvent, OTResult result, void * cookie)
167
 
{
168
 
#pragma unused(contextPtr)
169
 
    _PRCPU *    cpu    = _PR_MD_CURRENT_CPU(); 
170
 
        OSStatus    errOT;
171
 
 
172
 
                dnsContext.thread->md.osErrCode = result;
173
 
                dnsContext.cookie = cookie;
174
 
        
175
 
        switch (otEvent) {
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;
180
 
                                } else {
181
 
                                        DoneWaitingOnThisThread(dnsContext.thread);
182
 
                                }
183
 
                                break;
184
 
                
185
 
        case kOTProviderWillClose:
186
 
                errOT = OTSetSynchronous(dnsContext.serviceRef);
187
 
                // fall through to kOTProviderIsClosed case
188
 
                
189
 
        case kOTProviderIsClosed:
190
 
                errOT = OTCloseProvider((ProviderRef)dnsContext.serviceRef);
191
 
                dnsContext.serviceRef = nil;
192
 
 
193
 
                                if (_PR_MD_GET_INTSOFF()) {
194
 
                                        dnsContext.thread->md.missedIONotify = PR_TRUE;
195
 
                                        cpu->u.missed[cpu->where] |= _PR_MISSED_IO;
196
 
                                } else {
197
 
                                        DoneWaitingOnThisThread(dnsContext.thread);
198
 
                                }
199
 
                break;
200
 
 
201
 
        default: // or else we don't handle the event
202
 
                    PR_ASSERT(otEvent==NULL);
203
 
                
204
 
        }
205
 
        // or else we don't handle the event
206
 
        
207
 
        SignalIdleSemaphore();
208
 
}
209
 
 
210
 
 
211
 
static void macsock_map_error(OSStatus err)
212
 
{
213
 
    _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
214
 
 
215
 
    if (IsEError(err) || (err >= EPERM && err <= ELASTERRNO)) {
216
 
    switch (IsEError(err) ? OSStatus2E(err) : err) {
217
 
        case EBADF:
218
 
            PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err);
219
 
            break;
220
 
        case EADDRNOTAVAIL:
221
 
            PR_SetError(PR_ADDRESS_NOT_AVAILABLE_ERROR, err);
222
 
            break;
223
 
        case EINPROGRESS:
224
 
            PR_SetError(PR_IN_PROGRESS_ERROR, err);
225
 
            break;
226
 
        case EWOULDBLOCK:
227
 
        case EAGAIN:
228
 
            PR_SetError(PR_WOULD_BLOCK_ERROR, err);
229
 
            break;
230
 
        case ENOTSOCK:
231
 
            PR_SetError(PR_NOT_SOCKET_ERROR, err);
232
 
            break;
233
 
        case ETIMEDOUT:
234
 
            PR_SetError(PR_IO_TIMEOUT_ERROR, err);
235
 
            break;
236
 
        case ECONNREFUSED:
237
 
            PR_SetError(PR_CONNECT_REFUSED_ERROR, err);
238
 
            break;
239
 
        case ENETUNREACH:
240
 
            PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, err);
241
 
            break;
242
 
        case EADDRINUSE:
243
 
            PR_SetError(PR_ADDRESS_IN_USE_ERROR, err);
244
 
            break;
245
 
        case EFAULT:
246
 
            PR_SetError(PR_ACCESS_FAULT_ERROR, err);
247
 
            break;
248
 
        case EINTR:
249
 
            PR_SetError(PR_PENDING_INTERRUPT_ERROR, err);
250
 
            break;
251
 
        case EINVAL:
252
 
            PR_SetError(PR_INVALID_ARGUMENT_ERROR, err);
253
 
            break;
254
 
        case EIO:
255
 
            PR_SetError(PR_IO_ERROR, err);
256
 
            break;
257
 
        case ENOENT:
258
 
            PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, err);
259
 
            break;
260
 
        case ENXIO:
261
 
            PR_SetError(PR_IO_ERROR, err);
262
 
            break;
263
 
        case EPROTOTYPE:
264
 
            PR_SetError(PR_PROTOCOL_NOT_SUPPORTED_ERROR, err);
265
 
            break;
266
 
        case EOPNOTSUPP:
267
 
            PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, err);
268
 
            break;
269
 
        default:
270
 
            PR_SetError(PR_UNKNOWN_ERROR, err);
271
 
            break;
272
 
        }
273
 
    } else {
274
 
    PR_ASSERT(IsXTIError(err));
275
 
    switch (err) {
276
 
        case kOTNoDataErr:
277
 
        case kOTFlowErr:
278
 
            PR_SetError(PR_WOULD_BLOCK_ERROR, err);
279
 
            break;
280
 
        default:
281
 
            PR_SetError(PR_UNKNOWN_ERROR, err);
282
 
            break;
283
 
        }
284
 
    }
285
 
}
286
 
 
287
 
static void PrepareForAsyncCompletion(PRThread * thread, PRInt32 osfd)
288
 
{
289
 
    thread->io_pending       = PR_TRUE;
290
 
    thread->io_fd            = osfd;
291
 
    thread->md.osErrCode     = noErr;
292
 
}
293
 
 
294
 
 
295
 
void
296
 
WakeUpNotifiedThread(PRThread *thread, OTResult result)
297
 
{
298
 
    _PRCPU *      cpu      = _PR_MD_CURRENT_CPU(); 
299
 
 
300
 
        if (thread) {
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;
305
 
                } else {
306
 
                        DoneWaitingOnThisThread(thread);
307
 
                }
308
 
        }
309
 
        
310
 
        SignalIdleSemaphore();
311
 
}
312
 
 
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
317
 
//
318
 
static pascal void  NotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie)
319
 
{
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;
325
 
    OSStatus      err;
326
 
    OTResult      resultOT;
327
 
    TDiscon       discon;
328
 
 
329
 
    switch (code)
330
 
    {
331
 
// OTLook Events - 
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 
337
 
            // doing it here. 
338
 
            if (md->doListen) {
339
 
                readThread = secret->md.misc.thread;
340
 
                secret->md.misc.thread    = NULL;
341
 
                secret->md.misc.cookie    = cookie;
342
 
                break;
343
 
            } else {
344
 
                // Reject the connection, we're not listening
345
 
                OTSndDisconnect(endpoint, NULL);
346
 
            }
347
 
            break;
348
 
 
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);
353
 
 
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;            
358
 
            break;
359
 
 
360
 
        case T_DATA:        // Standard data is available
361
 
            // Mark this socket as readable.
362
 
            secret->md.readReady = PR_TRUE;
363
 
 
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;
368
 
            break;
369
 
 
370
 
        case T_EXDATA:      // Expedited data is available
371
 
            PR_ASSERT(!"T_EXDATA Not implemented");
372
 
            return;
373
 
 
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
379
 
 
380
 
            md->disconnectError = discon.reason;    // save for _MD_mac_get_nonblocking_connect_error
381
 
 
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;
387
 
            }
388
 
 
389
 
            if ((writeThread = secret->md.write.thread) != NULL) {
390
 
                secret->md.write.thread    = NULL;
391
 
                secret->md.write.cookie    = cookie;
392
 
            }
393
 
            break;
394
 
 
395
 
        case T_ERROR:       // obsolete/unused in library
396
 
            PR_ASSERT(!"T_ERROR Not implemented");
397
 
            return;
398
 
 
399
 
        case T_UDERR:       // UDP Send error; clear the error
400
 
            (void) OTRcvUDErr((EndpointRef) cookie, NULL);
401
 
            break;
402
 
 
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;
409
 
            
410
 
            readThread = secret->md.read.thread;
411
 
            secret->md.read.thread    = NULL;
412
 
            secret->md.read.cookie    = cookie;
413
 
            break;              
414
 
 
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);
419
 
            
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;
424
 
            break;
425
 
 
426
 
        case T_GOEXDATA: // Flow control lifted on expedited data
427
 
            PR_ASSERT(!"T_GOEXDATA Not implemented");
428
 
            return;
429
 
 
430
 
        case T_REQUEST:  // An Incoming request is available
431
 
            PR_ASSERT(!"T_REQUEST Not implemented");
432
 
            return;
433
 
 
434
 
        case T_REPLY:    // An Incoming reply is available
435
 
            PR_ASSERT(!"T_REPLY Not implemented");
436
 
            return;
437
 
 
438
 
        case T_PASSCON:  // State is now T_DATAXFER
439
 
            // OTAccept() complete, receiving endpoint in T_DATAXFER state
440
 
            // cookie = OTAccept() resRef parameter
441
 
            break;
442
 
 
443
 
        case T_RESET:    // Protocol has been reset
444
 
            PR_ASSERT(!"T_RESET Not implemented");
445
 
            return;
446
 
            
447
 
// Async Completion Events
448
 
        case T_BINDCOMPLETE:
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;
456
 
            break;
457
 
 
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:
469
 
        // OpenTptInternet.h
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:
475
 
        default:
476
 
            // we should probably have a bit more sophisticated handling of kOTSystemSleep, etc.
477
 
            // PR_ASSERT(code != 0);
478
 
            return;
479
 
    }
480
 
 
481
 
    if (readThread)
482
 
        WakeUpNotifiedThread(readThread, result);
483
 
 
484
 
    if (writeThread && (writeThread != readThread))
485
 
        WakeUpNotifiedThread(writeThread, result);
486
 
}
487
 
 
488
 
 
489
 
static OSErr CreateSocket(int type, EndpointRef *endpoint)
490
 
{
491
 
    OSStatus err;
492
 
    PRThread *me = _PR_MD_CURRENT_THREAD();
493
 
    char *  configName;
494
 
    OTConfiguration *config;
495
 
    EndpointRef ep;
496
 
 
497
 
    // for now we just create the endpoint
498
 
    // we'll make it asynchronous and give it a notifier routine in _MD_makenonblock()
499
 
 
500
 
    switch (type){
501
 
        case SOCK_STREAM:   configName = kTCPName;  break;
502
 
        case SOCK_DGRAM:    configName = kUDPName;  break;
503
 
    }
504
 
    config = OTCreateConfiguration(configName);
505
 
    ep = OT_OPEN_ENDPOINT(config, 0, NULL, &err);
506
 
    if (err != kOTNoError)
507
 
        goto ErrorExit;
508
 
 
509
 
    *endpoint = ep;
510
 
    PR_ASSERT(*endpoint != NULL);
511
 
 
512
 
    return kOTNoError;
513
 
 
514
 
ErrorExit:
515
 
    return err;
516
 
}
517
 
 
518
 
 
519
 
// Errors returned:
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)
524
 
{
525
 
    OSStatus    err;
526
 
    EndpointRef endpoint;
527
 
    
528
 
    _MD_FinishInitNetAccess();
529
 
 
530
 
    // We only deal with internet domain
531
 
    if (domain != AF_INET) {
532
 
        err = kEPROTONOSUPPORTErr;
533
 
        goto ErrorExit;
534
 
    }
535
 
    
536
 
    // We only know about tcp & udp
537
 
    if ((type != SOCK_STREAM) && (type != SOCK_DGRAM)) {
538
 
        err = kEPROTONOSUPPORTErr;
539
 
        goto ErrorExit;
540
 
    }
541
 
    
542
 
    // Convert default types to specific types.
543
 
    if (protocol == 0)  {
544
 
        if (type == SOCK_DGRAM)
545
 
            protocol = IPPROTO_UDP;
546
 
        else if (type == SOCK_STREAM)
547
 
            protocol = IPPROTO_TCP;
548
 
    }
549
 
    
550
 
    // Only support default protocol for tcp
551
 
    if ((type == SOCK_STREAM)  && (protocol != IPPROTO_TCP)) {
552
 
        err = kEPROTONOSUPPORTErr;
553
 
        goto ErrorExit;
554
 
    }
555
 
                
556
 
    // Only support default protocol for udp
557
 
    if ((type == SOCK_DGRAM)  && (protocol != IPPROTO_UDP)) {
558
 
        err = kEPROTONOSUPPORTErr;
559
 
        goto ErrorExit;
560
 
    }
561
 
        
562
 
    // Create a socket, we might run out of memory
563
 
    err = CreateSocket(type, &endpoint);
564
 
    if (err != kOTNoError)
565
 
        goto ErrorExit;
566
 
 
567
 
    PR_ASSERT((PRInt32)endpoint != -1);
568
 
 
569
 
    return ((PRInt32)endpoint);
570
 
 
571
 
ErrorExit:
572
 
    macsock_map_error(err);
573
 
    return -1;
574
 
}
575
 
 
576
 
 
577
 
// Errors:
578
 
// EBADF  -- bad socket id
579
 
// EFAULT -- bad address format
580
 
PRInt32 _MD_bind(PRFileDesc *fd, PRNetAddr *addr, PRUint32 addrlen)
581
 
{
582
 
    OSStatus err;
583
 
    EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
584
 
    TBind bindReq;
585
 
    PRThread *me = _PR_MD_CURRENT_THREAD();
586
 
    PRUint32 retryCount = 0;
587
 
 
588
 
    if (endpoint == NULL) {
589
 
        err = kEBADFErr;
590
 
        goto ErrorExit;
591
 
    }
592
 
        
593
 
    if (addr == NULL) {
594
 
        err = kEFAULTErr;
595
 
        goto ErrorExit;
596
 
    }
597
 
        
598
 
/*
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.
602
 
 */
603
 
 
604
 
TryAgain:
605
 
    // setup our request
606
 
    bindReq.addr.len = addrlen;
607
 
        
608
 
    bindReq.addr.maxlen = addrlen;
609
 
    bindReq.addr.buf = (UInt8*) addr;
610
 
    bindReq.qlen = 1;
611
 
 
612
 
        PR_Lock(fd->secret->md.miscLock);
613
 
    PrepareForAsyncCompletion(me, fd->secret->md.osfd);
614
 
        fd->secret->md.misc.thread = me;
615
 
 
616
 
    err = OTBind(endpoint, &bindReq, NULL);
617
 
    if (err != kOTNoError) {
618
 
            me->io_pending = PR_FALSE;
619
 
            PR_Unlock(fd->secret->md.miscLock);
620
 
        goto ErrorExit;
621
 
        }
622
 
 
623
 
    WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
624
 
        PR_Unlock(fd->secret->md.miscLock);
625
 
 
626
 
    err = me->md.osErrCode;
627
 
    if (err != kOTNoError)
628
 
        goto ErrorExit;
629
 
 
630
 
    return kOTNoError;
631
 
 
632
 
ErrorExit:
633
 
    if ((err == kOTNoAddressErr) && (++retryCount <= 4)) {
634
 
        unsigned long finalTicks;
635
 
    
636
 
        Delay(100,&finalTicks);
637
 
        goto TryAgain;
638
 
    }
639
 
    macsock_map_error(err);
640
 
    return -1;
641
 
}
642
 
 
643
 
 
644
 
// Errors:
645
 
// EBADF -- bad socket id
646
 
PRInt32 _MD_listen(PRFileDesc *fd, PRIntn backlog)
647
 
{
648
 
    PRInt32 osfd = fd->secret->md.osfd;
649
 
    OSStatus err = 0;
650
 
    EndpointRef endpoint = (EndpointRef) osfd;
651
 
    TBind bindReq;
652
 
    PRNetAddr addr;
653
 
    PRThread *me = _PR_MD_CURRENT_THREAD();
654
 
 
655
 
        if ((fd == NULL) || (endpoint == NULL)) {
656
 
                err = EBADF;
657
 
                goto ErrorExit;
658
 
        }
659
 
 
660
 
    if (backlog == 0)
661
 
        backlog = 1;
662
 
 
663
 
    if (endpoint == NULL) {
664
 
        err = EBADF;
665
 
        goto ErrorExit;
666
 
    }
667
 
        
668
 
    addr.inet.family = AF_INET;
669
 
    addr.inet.port = addr.inet.ip = 0;
670
 
 
671
 
    bindReq.addr.maxlen = PR_NETADDR_SIZE (&addr);
672
 
    bindReq.addr.len = 0;
673
 
    bindReq.addr.buf = (UInt8*) &addr;
674
 
    bindReq.qlen = 0;
675
 
    
676
 
    PrepareForAsyncCompletion(me, fd->secret->md.osfd);    
677
 
        fd->secret->md.misc.thread = me; // tell notifier routine what to wake up
678
 
 
679
 
    err = OTGetProtAddress(endpoint, &bindReq, NULL);
680
 
    if (err != kOTNoError)
681
 
        goto ErrorExit;
682
 
 
683
 
    WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
684
 
 
685
 
    err = me->md.osErrCode;
686
 
    if (err != kOTNoError)
687
 
        goto ErrorExit;
688
 
 
689
 
    PrepareForAsyncCompletion(me, fd->secret->md.osfd);    
690
 
        fd->secret->md.misc.thread = me; // tell notifier routine what to wake up
691
 
 
692
 
    err = OTUnbind(endpoint);
693
 
    if (err != kOTNoError)
694
 
        goto ErrorExit;
695
 
 
696
 
    WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
697
 
 
698
 
    err = me->md.osErrCode;
699
 
    if (err != kOTNoError)
700
 
        goto ErrorExit;
701
 
 
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;
706
 
    
707
 
    PrepareForAsyncCompletion(me, fd->secret->md.osfd);    
708
 
        fd->secret->md.misc.thread = me; // tell notifier routine what to wake up
709
 
 
710
 
    err = OTBind(endpoint, &bindReq, NULL);
711
 
    if (err != kOTNoError)
712
 
        goto ErrorExit;
713
 
 
714
 
    WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
715
 
 
716
 
    err = me->md.osErrCode;
717
 
    if (err != kOTNoError)
718
 
    {
719
 
        // If OTBind failed, we're really not ready to listen after all.
720
 
                fd->secret->md.doListen = PR_FALSE;
721
 
        goto ErrorExit;
722
 
    }
723
 
 
724
 
    return kOTNoError;
725
 
 
726
 
ErrorExit:
727
 
        me->io_pending = PR_FALSE; // clear pending wait state if any
728
 
    macsock_map_error(err);
729
 
    return -1;
730
 
}
731
 
 
732
 
 
733
 
// Errors:
734
 
// EBADF -- bad socket id
735
 
PRInt32 _MD_getsockname(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen)
736
 
{
737
 
    OSStatus err;
738
 
    EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
739
 
    TBind bindReq;
740
 
    PRThread *me = _PR_MD_CURRENT_THREAD();
741
 
 
742
 
    if (endpoint == NULL) {
743
 
        err = kEBADFErr;
744
 
        goto ErrorExit;
745
 
    }
746
 
        
747
 
    if (addr == NULL) {
748
 
        err = kEFAULTErr;
749
 
        goto ErrorExit;
750
 
    }
751
 
 
752
 
    bindReq.addr.len = *addrlen;
753
 
    bindReq.addr.maxlen = *addrlen;
754
 
    bindReq.addr.buf = (UInt8*) addr;
755
 
    bindReq.qlen = 0;
756
 
    
757
 
        PR_Lock(fd->secret->md.miscLock);
758
 
    PrepareForAsyncCompletion(me, fd->secret->md.osfd);    
759
 
        fd->secret->md.misc.thread = me;
760
 
 
761
 
    err = OTGetProtAddress(endpoint, &bindReq, NULL);
762
 
    if (err != kOTNoError) {
763
 
            me->io_pending = PR_FALSE;
764
 
            PR_Unlock(fd->secret->md.miscLock);
765
 
        goto ErrorExit;
766
 
        }
767
 
 
768
 
    WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
769
 
        PR_Unlock(fd->secret->md.miscLock);
770
 
 
771
 
    err = me->md.osErrCode;
772
 
    if (err != kOTNoError)
773
 
        goto ErrorExit;
774
 
 
775
 
    *addrlen = PR_NETADDR_SIZE(addr);
776
 
    return kOTNoError;
777
 
 
778
 
ErrorExit:
779
 
    macsock_map_error(err);
780
 
    return -1;
781
 
}
782
 
 
783
 
 
784
 
PRStatus _MD_getsockopt(PRFileDesc *fd, PRInt32 level, PRInt32 optname, char* optval, PRInt32* optlen)
785
 
{
786
 
    OSStatus err;
787
 
    EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
788
 
    TOptMgmt cmd;
789
 
    TOption *opt;
790
 
    PRThread *me = _PR_MD_CURRENT_THREAD();
791
 
    unsigned char optionBuffer[kOTOptionHeaderSize + sizeof(PRSocketOptionData)];
792
 
    
793
 
    if (endpoint == NULL) {
794
 
        err = kEBADFErr;
795
 
        goto ErrorExit;
796
 
    }
797
 
    
798
 
    /* 
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 
801
 
    the level correctly.
802
 
    */
803
 
    if (level == SOL_SOCKET) {
804
 
        if (optname == SO_REUSEADDR)
805
 
            level = IPPROTO_IP;
806
 
        else if (optname == SO_KEEPALIVE)
807
 
            level = INET_TCP;
808
 
    }
809
 
 
810
 
    opt = (TOption *)&optionBuffer[0];
811
 
    opt->len = sizeof(TOption);
812
 
    opt->level = level;
813
 
    opt->name = optname;
814
 
    opt->status = 0;
815
 
    
816
 
    cmd.opt.len = sizeof(TOption);
817
 
    cmd.opt.maxlen = sizeof(optionBuffer);
818
 
    cmd.opt.buf = (UInt8*)optionBuffer;
819
 
    cmd.flags = T_CURRENT;
820
 
 
821
 
        PR_Lock(fd->secret->md.miscLock);
822
 
    PrepareForAsyncCompletion(me, fd->secret->md.osfd);    
823
 
        fd->secret->md.misc.thread = me;
824
 
 
825
 
    err = OTOptionManagement(endpoint, &cmd, &cmd);
826
 
    if (err != kOTNoError) {
827
 
            me->io_pending = PR_FALSE;
828
 
            PR_Unlock(fd->secret->md.miscLock);
829
 
        goto ErrorExit;
830
 
        }
831
 
 
832
 
    WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
833
 
        PR_Unlock(fd->secret->md.miscLock);
834
 
 
835
 
    err = me->md.osErrCode;
836
 
    if (err != kOTNoError)
837
 
        goto ErrorExit;
838
 
 
839
 
    if (opt->status == T_FAILURE || opt->status == T_NOTSUPPORT){
840
 
        err = kEOPNOTSUPPErr;
841
 
        goto ErrorExit;
842
 
    }
843
 
 
844
 
    PR_ASSERT(opt->status == T_SUCCESS);
845
 
 
846
 
    switch (optname) {
847
 
        case SO_LINGER:
848
 
            *((t_linger*)optval) = *((t_linger*)&opt->value);
849
 
            *optlen = sizeof(t_linger);
850
 
            break;
851
 
        case SO_REUSEADDR:
852
 
        case TCP_NODELAY:
853
 
        case SO_KEEPALIVE:
854
 
        case SO_RCVBUF:
855
 
        case SO_SNDBUF:
856
 
            *((PRIntn*)optval) = *((PRIntn*)&opt->value);
857
 
            *optlen = sizeof(PRIntn);
858
 
            break;
859
 
        case IP_MULTICAST_LOOP:
860
 
            *((PRUint8*)optval) = *((PRIntn*)&opt->value);
861
 
            *optlen = sizeof(PRUint8);
862
 
            break;
863
 
        case IP_TTL:
864
 
            *((PRUintn*)optval) = *((PRUint8*)&opt->value);
865
 
            *optlen = sizeof(PRUintn);
866
 
            break;
867
 
        case IP_MULTICAST_TTL:
868
 
            *((PRUint8*)optval) = *((PRUint8*)&opt->value);
869
 
            *optlen = sizeof(PRUint8);
870
 
            break;
871
 
        case IP_ADD_MEMBERSHIP:
872
 
        case IP_DROP_MEMBERSHIP:
873
 
            {
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);
878
 
            break;
879
 
            }
880
 
        case IP_MULTICAST_IF:
881
 
            {
882
 
            *((PRUint32*)optval) = *((PRUint32*)&opt->value);
883
 
            *optlen = sizeof(PRUint32);
884
 
            break;
885
 
            }
886
 
        /*case IP_TOS:*/ /*IP_TOS has same value as TCP_MAXSEG */
887
 
        case 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);
894
 
            }
895
 
            break;
896
 
        default:
897
 
            PR_ASSERT(0);
898
 
            break;    
899
 
    }
900
 
    
901
 
    return PR_SUCCESS;
902
 
 
903
 
ErrorExit:
904
 
    macsock_map_error(err);
905
 
    return PR_FAILURE;
906
 
}
907
 
 
908
 
 
909
 
PRStatus _MD_setsockopt(PRFileDesc *fd, PRInt32 level, PRInt32 optname, const char* optval, PRInt32 optlen)
910
 
{
911
 
    OSStatus err;
912
 
    EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
913
 
    TOptMgmt cmd;
914
 
    TOption *opt;
915
 
    PRThread *me = _PR_MD_CURRENT_THREAD();
916
 
    unsigned char optionBuffer[kOTOptionHeaderSize + sizeof(PRSocketOptionData) + 1];
917
 
    
918
 
    if (endpoint == NULL) {
919
 
        err = kEBADFErr;
920
 
        goto ErrorExit;
921
 
    }
922
 
    
923
 
    /* 
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 
926
 
    the level correctly.
927
 
    */
928
 
    if (level == SOL_SOCKET) {
929
 
        if (optname == SO_REUSEADDR)
930
 
            level = IPPROTO_IP;
931
 
        else if (optname == SO_KEEPALIVE)
932
 
            level = INET_TCP;
933
 
    }
934
 
 
935
 
    opt = (TOption *)&optionBuffer[0];
936
 
    opt->len = kOTOptionHeaderSize + optlen;
937
 
 
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;
945
 
 
946
 
    opt->level = level;
947
 
    opt->name = optname;
948
 
    opt->status = 0;
949
 
    
950
 
    cmd.opt.len = opt->len;
951
 
    cmd.opt.maxlen = sizeof(optionBuffer);
952
 
    cmd.opt.buf = (UInt8*)optionBuffer;
953
 
    
954
 
    optionBuffer[opt->len] = 0;
955
 
    
956
 
    cmd.flags = T_NEGOTIATE;
957
 
 
958
 
    switch (optname) {
959
 
        case SO_LINGER:
960
 
            *((t_linger*)&opt->value) = *((t_linger*)optval);
961
 
            break;
962
 
        case SO_REUSEADDR:
963
 
        case TCP_NODELAY:
964
 
        case SO_RCVBUF:
965
 
        case SO_SNDBUF:
966
 
            *((PRIntn*)&opt->value) = *((PRIntn*)optval);
967
 
            break;
968
 
        case IP_MULTICAST_LOOP:
969
 
            if (*optval != 0)
970
 
                opt->value[0] = T_YES;
971
 
            else
972
 
                opt->value[0] = T_NO;
973
 
            break;
974
 
        case SO_KEEPALIVE:
975
 
            {
976
 
            t_kpalive *kpalive = (t_kpalive *)&opt->value;
977
 
            
978
 
            kpalive->kp_onoff = *((long*)optval);
979
 
            kpalive->kp_timeout = 10; /* timeout in minutes */
980
 
            break;
981
 
            }
982
 
        case IP_TTL:
983
 
            *((unsigned char*)&opt->value) = *((PRUintn*)optval);
984
 
            break;
985
 
        case IP_MULTICAST_TTL:
986
 
            *((unsigned char*)&opt->value) = *optval;
987
 
            break;
988
 
        case IP_ADD_MEMBERSHIP:
989
 
        case IP_DROP_MEMBERSHIP:
990
 
            {
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);
994
 
            break;
995
 
            }
996
 
        case IP_MULTICAST_IF:
997
 
            {
998
 
            *((PRUint32*)&opt->value) = *((PRUint32*)optval);
999
 
            break;
1000
 
            }
1001
 
        /*case IP_TOS:*/ /*IP_TOS has same value as TCP_MAXSEG */
1002
 
        case 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);
1007
 
            }
1008
 
            break;
1009
 
        default:
1010
 
            PR_ASSERT(0);
1011
 
            break;    
1012
 
    }
1013
 
    
1014
 
        PR_Lock(fd->secret->md.miscLock);
1015
 
    PrepareForAsyncCompletion(me, fd->secret->md.osfd);    
1016
 
        fd->secret->md.misc.thread = me;
1017
 
 
1018
 
    err = OTOptionManagement(endpoint, &cmd, &cmd);
1019
 
    if (err != kOTNoError) {
1020
 
            me->io_pending = PR_FALSE;
1021
 
            PR_Unlock(fd->secret->md.miscLock);
1022
 
        goto ErrorExit;
1023
 
        }
1024
 
 
1025
 
    WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
1026
 
        PR_Unlock(fd->secret->md.miscLock);
1027
 
 
1028
 
    err = me->md.osErrCode;
1029
 
    if (err != kOTNoError)
1030
 
        goto ErrorExit;
1031
 
 
1032
 
    if (opt->status == T_FAILURE || opt->status == T_NOTSUPPORT){
1033
 
        err = kEOPNOTSUPPErr;
1034
 
        goto ErrorExit;
1035
 
    }
1036
 
    
1037
 
    if (level == IPPROTO_TCP && optname == TCP_MAXSEG && opt->status == T_READONLY) {
1038
 
        err = kEOPNOTSUPPErr;
1039
 
        goto ErrorExit;
1040
 
    }
1041
 
 
1042
 
    PR_ASSERT(opt->status == T_SUCCESS);
1043
 
 
1044
 
    return PR_SUCCESS;
1045
 
 
1046
 
ErrorExit:
1047
 
    macsock_map_error(err);
1048
 
    return PR_FAILURE;
1049
 
}
1050
 
 
1051
 
 
1052
 
PRInt32 _MD_socketavailable(PRFileDesc *fd)
1053
 
{
1054
 
    PRInt32 osfd = fd->secret->md.osfd;
1055
 
    OSStatus err;
1056
 
    EndpointRef endpoint = (EndpointRef) osfd;
1057
 
    size_t bytes;
1058
 
 
1059
 
    if (endpoint == NULL) {
1060
 
        err = kEBADFErr;
1061
 
        goto ErrorExit;
1062
 
    }
1063
 
    
1064
 
    bytes = 0;
1065
 
    
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.
1069
 
        err = kOTNoError;
1070
 
        
1071
 
    if (err != kOTNoError)
1072
 
        goto ErrorExit;
1073
 
        
1074
 
    return bytes;
1075
 
 
1076
 
ErrorExit:
1077
 
    macsock_map_error(err);
1078
 
    return -1;
1079
 
}
1080
 
 
1081
 
 
1082
 
typedef struct RawEndpointAndThread
1083
 
{
1084
 
        PRThread *  thread;
1085
 
        EndpointRef endpoint;
1086
 
} RawEndpointAndThread;
1087
 
 
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)
1092
 
{
1093
 
    RawEndpointAndThread *endthr = (RawEndpointAndThread *) contextPtr;
1094
 
    PRThread *    thread   = endthr->thread;
1095
 
    EndpointRef * endpoint = endthr->endpoint;
1096
 
    _PRCPU *      cpu      = _PR_MD_CURRENT_CPU(); 
1097
 
    OSStatus      err;
1098
 
    OTResult      resultOT;
1099
 
 
1100
 
    switch (code)
1101
 
    {
1102
 
// OTLook Events - 
1103
 
        case T_LISTEN:        // A connection request is available
1104
 
            PR_ASSERT(!"T_EXDATA not implemented for raw endpoints");
1105
 
            break;
1106
 
                        
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);
1111
 
 
1112
 
                        // wake up waiting thread
1113
 
            break;
1114
 
 
1115
 
        case T_DATA:        // Standard data is available
1116
 
                        break;
1117
 
 
1118
 
        case T_EXDATA:      // Expedited data is available
1119
 
            PR_ASSERT(!"T_EXDATA Not implemented for raw endpoints");
1120
 
                        return;
1121
 
 
1122
 
        case T_DISCONNECT:  // A disconnect is available
1123
 
            err = OTRcvDisconnect(endpoint, NULL);
1124
 
            PR_ASSERT(err == kOTNoError);
1125
 
            break;
1126
 
                
1127
 
        case T_ERROR:       // obsolete/unused in library
1128
 
            PR_ASSERT(!"T_ERROR Not implemented for raw endpoints");
1129
 
                        return;         
1130
 
                
1131
 
        case T_UDERR:       // UDP Send error; clear the error
1132
 
                        (void) OTRcvUDErr((EndpointRef) cookie, NULL);
1133
 
            break;
1134
 
 
1135
 
        case T_ORDREL:      // An orderly release is available
1136
 
            err = OTRcvOrderlyDisconnect(endpoint);
1137
 
            PR_ASSERT(err == kOTNoError);
1138
 
            break;              
1139
 
 
1140
 
        case T_GODATA:   // Flow control lifted on standard data
1141
 
                        resultOT = OTLook(endpoint);            // clear T_GODATA event
1142
 
                        PR_ASSERT(resultOT == T_GODATA);
1143
 
                        
1144
 
                        // wake up waiting thread, if any
1145
 
            break;
1146
 
 
1147
 
        case T_GOEXDATA: // Flow control lifted on expedited data
1148
 
            PR_ASSERT(!"T_GOEXDATA Not implemented");
1149
 
                        return;
1150
 
 
1151
 
        case T_REQUEST:  // An Incoming request is available
1152
 
            PR_ASSERT(!"T_REQUEST Not implemented");
1153
 
            return;
1154
 
 
1155
 
        case T_REPLY:    // An Incoming reply is available
1156
 
            PR_ASSERT(!"T_REPLY Not implemented");
1157
 
            return;
1158
 
 
1159
 
        case T_PASSCON:  // State is now T_DATAXFER
1160
 
                        // OTAccept() complete, receiving endpoint in T_DATAXFER state
1161
 
                        // cookie = OTAccept() resRef parameter
1162
 
                        break;
1163
 
            
1164
 
// Async Completion Events
1165
 
        case T_BINDCOMPLETE:
1166
 
        case T_UNBINDCOMPLETE:
1167
 
        case T_ACCEPTCOMPLETE:
1168
 
        case T_OPTMGMTCOMPLETE:
1169
 
        case T_GETPROTADDRCOMPLETE:
1170
 
            break;
1171
 
 
1172
 
                // for other OT events, see NotifierRoutine above
1173
 
        default:
1174
 
            return;
1175
 
    }
1176
 
 
1177
 
        if (thread) {
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;
1182
 
                } else {
1183
 
                        DoneWaitingOnThisThread(thread);
1184
 
                }
1185
 
        }
1186
 
 
1187
 
        SignalIdleSemaphore();
1188
 
}
1189
 
 
1190
 
PRInt32 _MD_accept(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout)
1191
 
{
1192
 
    OSStatus err;
1193
 
    EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
1194
 
    PRThread *me = _PR_MD_CURRENT_THREAD();
1195
 
    TBind bindReq;
1196
 
    PRNetAddr bindAddr;
1197
 
    PRInt32 newosfd = -1;
1198
 
    TCall call;
1199
 
    PRNetAddr callAddr;
1200
 
    RawEndpointAndThread *endthr = NULL;
1201
 
 
1202
 
    if (endpoint == NULL) {
1203
 
        err = kEBADFErr;
1204
 
        goto ErrorExit;
1205
 
    }
1206
 
        
1207
 
    memset(&call, 0 , sizeof(call));
1208
 
 
1209
 
    if (addr != NULL) {
1210
 
        call.addr.maxlen = *addrlen;
1211
 
        call.addr.len = *addrlen;
1212
 
        call.addr.buf = (UInt8*) addr;
1213
 
    } else {
1214
 
        call.addr.maxlen = sizeof(callAddr);
1215
 
        call.addr.len = sizeof(callAddr);
1216
 
        call.addr.buf = (UInt8*) &callAddr;
1217
 
    }
1218
 
 
1219
 
        do {
1220
 
            PrepareForAsyncCompletion(me, fd->secret->md.osfd);
1221
 
            fd->secret->md.misc.thread = me;
1222
 
            
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))
1231
 
                        goto ErrorExit;
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
1235
 
            } else {
1236
 
                goto ErrorExit; // we're nonblocking, and/or we got an error
1237
 
            }   
1238
 
        }
1239
 
        while(1);
1240
 
 
1241
 
    newosfd = _MD_socket(AF_INET, SOCK_STREAM, 0);
1242
 
    if (newosfd == -1)
1243
 
        return -1;
1244
 
            
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;
1249
 
        
1250
 
        err = OTInstallNotifier((ProviderRef) newosfd, RawEndpointNotifierRoutineUPP, endthr);
1251
 
    PR_ASSERT(err == kOTNoError);
1252
 
    
1253
 
        err = OTSetAsynchronous((EndpointRef) newosfd);
1254
 
        PR_ASSERT(err == kOTNoError);
1255
 
 
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;
1259
 
 
1260
 
    bindReq.addr.maxlen = PR_NETADDR_SIZE (&bindAddr);
1261
 
    bindReq.addr.len = 0;
1262
 
    bindReq.addr.buf = (UInt8*) &bindAddr;
1263
 
    bindReq.qlen = 0;
1264
 
 
1265
 
    PrepareForAsyncCompletion(me, newosfd);    
1266
 
    err = OTBind((EndpointRef) newosfd, &bindReq, NULL);
1267
 
    if (err != kOTNoError)
1268
 
        goto ErrorExit;
1269
 
 
1270
 
    WaitOnThisThread(me, timeout);
1271
 
 
1272
 
    err = me->md.osErrCode;
1273
 
    if (err != kOTNoError)
1274
 
        goto ErrorExit;
1275
 
 
1276
 
    PrepareForAsyncCompletion(me, newosfd);    
1277
 
 
1278
 
    err = OTAccept (endpoint, (EndpointRef) newosfd, &call);
1279
 
        if ((err != kOTNoError) && (err != kOTNoDataErr))
1280
 
        goto ErrorExit;
1281
 
 
1282
 
    WaitOnThisThread(me, timeout);
1283
 
 
1284
 
    err = me->md.osErrCode;
1285
 
    if (err != kOTNoError)
1286
 
        goto ErrorExit;
1287
 
 
1288
 
    if (addrlen != NULL)
1289
 
        *addrlen = call.addr.len;
1290
 
 
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
1294
 
 
1295
 
    return newosfd;
1296
 
 
1297
 
ErrorExit:
1298
 
        me->io_pending = PR_FALSE; // clear pending wait state if any
1299
 
    if (newosfd != -1)
1300
 
        _MD_closesocket(newosfd);
1301
 
    macsock_map_error(err);
1302
 
    return -1;
1303
 
}
1304
 
 
1305
 
 
1306
 
PRInt32 _MD_connect(PRFileDesc *fd, PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout)
1307
 
{
1308
 
    OSStatus err;
1309
 
    EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
1310
 
    PRThread *me = _PR_MD_CURRENT_THREAD();
1311
 
    TCall sndCall;
1312
 
    TBind bindReq;
1313
 
    PRNetAddr bindAddr;
1314
 
 
1315
 
    if (endpoint == NULL) {
1316
 
        err = kEBADFErr;
1317
 
        goto ErrorExit;
1318
 
    }
1319
 
        
1320
 
    if (addr == NULL) {
1321
 
        err = kEFAULTErr;
1322
 
        goto ErrorExit;
1323
 
    }
1324
 
    
1325
 
    // Bind to a local port; let the system assign it.
1326
 
 
1327
 
    bindAddr.inet.family = AF_INET;
1328
 
    bindAddr.inet.port = bindAddr.inet.ip = 0;
1329
 
 
1330
 
    bindReq.addr.maxlen = PR_NETADDR_SIZE (&bindAddr);
1331
 
    bindReq.addr.len = 0;
1332
 
    bindReq.addr.buf = (UInt8*) &bindAddr;
1333
 
    bindReq.qlen = 0;
1334
 
    
1335
 
    PR_Lock(fd->secret->md.miscLock);
1336
 
    PrepareForAsyncCompletion(me, fd->secret->md.osfd);    
1337
 
    fd->secret->md.misc.thread = me;
1338
 
 
1339
 
    err = OTBind(endpoint, &bindReq, NULL);
1340
 
    if (err != kOTNoError) {
1341
 
      me->io_pending = PR_FALSE;
1342
 
      PR_Unlock(fd->secret->md.miscLock);
1343
 
      goto ErrorExit;
1344
 
    }
1345
 
 
1346
 
    WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
1347
 
    PR_Unlock(fd->secret->md.miscLock);
1348
 
 
1349
 
    err = me->md.osErrCode;
1350
 
    if (err != kOTNoError)
1351
 
        goto ErrorExit;
1352
 
 
1353
 
    memset(&sndCall, 0 , sizeof(sndCall));
1354
 
 
1355
 
    sndCall.addr.maxlen = addrlen;
1356
 
    sndCall.addr.len = addrlen;
1357
 
    sndCall.addr.buf = (UInt8*) addr;
1358
 
 
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;
1363
 
    }
1364
 
 
1365
 
    err = OTConnect (endpoint, &sndCall, NULL);
1366
 
    if (err == kOTNoError) {
1367
 
      PR_ASSERT(!"OTConnect returned kOTNoError in async mode!?!");     
1368
 
    }
1369
 
    if (fd->secret->nonblocking) {
1370
 
      if (err == kOTNoDataErr)
1371
 
      err = EINPROGRESS;
1372
 
      goto ErrorExit;
1373
 
    } else {
1374
 
      if (err != kOTNoError && err != kOTNoDataErr) {
1375
 
        me->io_pending = PR_FALSE;
1376
 
        goto ErrorExit;
1377
 
      }
1378
 
    }
1379
 
        
1380
 
    WaitOnThisThread(me, timeout);
1381
 
 
1382
 
    err = me->md.osErrCode;
1383
 
    if (err != kOTNoError)
1384
 
        goto ErrorExit;
1385
 
 
1386
 
    return kOTNoError;
1387
 
 
1388
 
ErrorExit:
1389
 
    macsock_map_error(err);
1390
 
    return -1;
1391
 
}
1392
 
 
1393
 
 
1394
 
// Errors:
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)
1399
 
{
1400
 
    OSStatus err;
1401
 
    OTResult result;
1402
 
    EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
1403
 
    PRThread *me = _PR_MD_CURRENT_THREAD();
1404
 
    PRInt32 bytesLeft = amount;
1405
 
 
1406
 
    PR_ASSERT(flags == 0 ||
1407
 
        (opCode == kSTREAM_RECEIVE && flags == PR_MSG_PEEK));
1408
 
    PR_ASSERT(opCode == kSTREAM_SEND || opCode == kSTREAM_RECEIVE);
1409
 
    
1410
 
    if (endpoint == NULL) {
1411
 
        err = kEBADFErr;
1412
 
        goto ErrorExit;
1413
 
    }
1414
 
        
1415
 
    if (buf == NULL) {
1416
 
        err = kEFAULTErr;
1417
 
        goto ErrorExit;
1418
 
    }
1419
 
 
1420
 
    PR_ASSERT(opCode == kSTREAM_SEND ? fd->secret->md.write.thread == NULL :
1421
 
                                       fd->secret->md.read.thread  == NULL);
1422
 
 
1423
 
    while (bytesLeft > 0)
1424
 
    {
1425
 
        Boolean disabledNotifications = OTEnterNotifier(endpoint);
1426
 
    
1427
 
        PrepareForAsyncCompletion(me, fd->secret->md.osfd);    
1428
 
 
1429
 
        if (opCode == kSTREAM_SEND) {
1430
 
                do {
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
1436
 
                                        break;
1437
 
                                else {
1438
 
 
1439
 
                                        // We drop through on anything other than a blocking write.
1440
 
                                        if (result != kOTFlowErr)
1441
 
                                                break;
1442
 
 
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;
1448
 
                    }
1449
 
                                        WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
1450
 
                                        result = me->md.osErrCode;
1451
 
                                        if (result != kOTNoError) // got interrupted, or some other error
1452
 
                                                break;
1453
 
 
1454
 
                                        // Prepare to loop back and try again
1455
 
                                        disabledNotifications = OTEnterNotifier(endpoint);
1456
 
                                        PrepareForAsyncCompletion(me, fd->secret->md.osfd);  
1457
 
                                }
1458
 
                        }
1459
 
                        while(1);
1460
 
        } else {
1461
 
                do {
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);
1467
 
                                        break;
1468
 
                                } else {
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.
1473
 
                                        size_t count;
1474
 
                                        OSErr tmpResult;
1475
 
                                        tmpResult = OTCountDataBytes(endpoint, &count);
1476
 
                                        fd->secret->md.readReady = ((tmpResult == kOTNoError) && (count > 0));
1477
 
                                                break;
1478
 
                                    }
1479
 
 
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;
1485
 
                    }
1486
 
                                        WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
1487
 
                                        result = me->md.osErrCode;
1488
 
                                        if (result != kOTNoError) // interrupted thread, etc.
1489
 
                                                break;
1490
 
 
1491
 
                                        // Prepare to loop back and try again
1492
 
                                        disabledNotifications = OTEnterNotifier(endpoint);
1493
 
                                        PrepareForAsyncCompletion(me, fd->secret->md.osfd);  
1494
 
                                }
1495
 
                        }
1496
 
                        // Retry read if we had to wait for data to show up.
1497
 
                        while(1);
1498
 
        }
1499
 
 
1500
 
                me->io_pending = PR_FALSE;
1501
 
                
1502
 
        if (opCode == kSTREAM_SEND)
1503
 
            fd->secret->md.write.thread = NULL;
1504
 
        else
1505
 
            fd->secret->md.read.thread  = NULL;
1506
 
 
1507
 
        // turn notifications back on
1508
 
        if (disabledNotifications)
1509
 
            OTLeaveNotifier(endpoint);
1510
 
 
1511
 
        if (result > 0) {
1512
 
            buf = (void *) ( (UInt32) buf + (UInt32)result );
1513
 
            bytesLeft -= result;
1514
 
            if (opCode == kSTREAM_RECEIVE) {
1515
 
                amount = result;
1516
 
                goto NormalExit;
1517
 
            }
1518
 
        } else {
1519
 
                        switch (result) {
1520
 
                                case kOTLookErr:
1521
 
                                    PR_ASSERT(!"call to OTLook() required after all.");
1522
 
                                        break;
1523
 
                                
1524
 
                                case kOTFlowErr:
1525
 
                                case kOTNoDataErr:
1526
 
                                case kEAGAINErr:
1527
 
                                case kEWOULDBLOCKErr:
1528
 
                                        if (fd->secret->nonblocking) {
1529
 
                                        
1530
 
                                            if (bytesLeft == amount) {  // no data was sent
1531
 
                                                    err = result;
1532
 
                                                    goto ErrorExit;
1533
 
                                                }
1534
 
                                                
1535
 
                                                // some data was sent
1536
 
                                                amount -= bytesLeft;
1537
 
                                                goto NormalExit;
1538
 
                                        }
1539
 
 
1540
 
                                        WaitOnThisThread(me, timeout);
1541
 
                                        err = me->md.osErrCode;
1542
 
                                        if (err != kOTNoError)
1543
 
                                                goto ErrorExit;                         
1544
 
                                        break;
1545
 
                                        
1546
 
                                case kOTOutStateErr:    // if provider already closed, fall through to handle error
1547
 
                                        if (fd->secret->md.orderlyDisconnect) {
1548
 
                                                amount = 0;
1549
 
                                                goto NormalExit;
1550
 
                                        }
1551
 
                                        // else fall through
1552
 
                                default:
1553
 
                                        err = result;
1554
 
                                        goto ErrorExit;
1555
 
                        }
1556
 
                }
1557
 
    }
1558
 
 
1559
 
NormalExit:
1560
 
    PR_ASSERT(opCode == kSTREAM_SEND ? fd->secret->md.write.thread == NULL :
1561
 
                                       fd->secret->md.read.thread  == NULL);
1562
 
    return amount;
1563
 
 
1564
 
ErrorExit:
1565
 
    PR_ASSERT(opCode == kSTREAM_SEND ? fd->secret->md.write.thread == NULL :
1566
 
                                       fd->secret->md.read.thread  == NULL);
1567
 
    macsock_map_error(err);
1568
 
    return -1;
1569
 
}
1570
 
 
1571
 
 
1572
 
PRInt32 _MD_recv(PRFileDesc *fd, void *buf, PRInt32 amount, 
1573
 
                               PRIntn flags, PRIntervalTime timeout)
1574
 
{
1575
 
    return (SendReceiveStream(fd, buf, amount, flags, timeout, kSTREAM_RECEIVE));
1576
 
}
1577
 
 
1578
 
 
1579
 
PRInt32 _MD_send(PRFileDesc *fd,const void *buf, PRInt32 amount, 
1580
 
                               PRIntn flags, PRIntervalTime timeout)
1581
 
{
1582
 
    return (SendReceiveStream(fd, (void *)buf, amount, flags, timeout, kSTREAM_SEND));
1583
 
}
1584
 
 
1585
 
 
1586
 
// Errors:
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)
1592
 
{
1593
 
    OSStatus err;
1594
 
    EndpointRef endpoint = (EndpointRef) fd->secret->md.osfd;
1595
 
    PRThread *me = _PR_MD_CURRENT_THREAD();
1596
 
    PRInt32 bytesLeft = amount;
1597
 
    TUnitData dgram;
1598
 
 
1599
 
    PR_ASSERT(flags == 0);
1600
 
    
1601
 
    if (endpoint == NULL) {
1602
 
        err = kEBADFErr;
1603
 
        goto ErrorExit;
1604
 
    }
1605
 
        
1606
 
    if (buf == NULL || addr == NULL) {
1607
 
        err = kEFAULTErr;
1608
 
        goto ErrorExit;
1609
 
    }
1610
 
    
1611
 
    if (opCode != kDGRAM_SEND && opCode != kDGRAM_RECEIVE) {
1612
 
        err = kEINVALErr;
1613
 
        goto ErrorExit;
1614
 
    }
1615
 
        
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;    
1623
 
 
1624
 
    while (bytesLeft > 0) {
1625
 
    
1626
 
        PrepareForAsyncCompletion(me, fd->secret->md.osfd);    
1627
 
 
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;
1634
 
                } else {
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;
1640
 
                }
1641
 
 
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;
1647
 
        } else {
1648
 
            PR_ASSERT(err == kOTNoDataErr || err == kOTOutStateErr);
1649
 
            WaitOnThisThread(me, timeout);
1650
 
            err = me->md.osErrCode;
1651
 
            if (err != kOTNoError)
1652
 
                goto ErrorExit;
1653
 
        }
1654
 
    }
1655
 
 
1656
 
    if (opCode == kDGRAM_RECEIVE)
1657
 
        *addrlen = dgram.addr.len;
1658
 
 
1659
 
    return amount;
1660
 
 
1661
 
ErrorExit:
1662
 
    macsock_map_error(err);
1663
 
    return -1;
1664
 
}
1665
 
 
1666
 
 
1667
 
PRInt32 _MD_recvfrom(PRFileDesc *fd, void *buf, PRInt32 amount, 
1668
 
                               PRIntn flags, PRNetAddr *addr, PRUint32 *addrlen,
1669
 
                               PRIntervalTime timeout)
1670
 
{
1671
 
    return (SendReceiveDgram(fd, buf, amount, flags, addr, addrlen,
1672
 
                            timeout, kDGRAM_RECEIVE));
1673
 
}
1674
 
 
1675
 
 
1676
 
PRInt32 _MD_sendto(PRFileDesc *fd,const void *buf, PRInt32 amount, 
1677
 
                               PRIntn flags, PRNetAddr *addr, PRUint32 addrlen,
1678
 
                               PRIntervalTime timeout)
1679
 
{
1680
 
    return (SendReceiveDgram(fd, (void *)buf, amount, flags, addr, &addrlen,
1681
 
                            timeout, kDGRAM_SEND));
1682
 
}
1683
 
 
1684
 
 
1685
 
PRInt32 _MD_closesocket(PRInt32 osfd)
1686
 
{
1687
 
    OSStatus err;
1688
 
    EndpointRef endpoint = (EndpointRef) osfd;
1689
 
    PRThread *me = _PR_MD_CURRENT_THREAD();
1690
 
 
1691
 
    if (endpoint == NULL) {
1692
 
        err = kEBADFErr;
1693
 
        goto ErrorExit;
1694
 
    }
1695
 
        
1696
 
    if (me->io_pending && me->io_fd == osfd)
1697
 
        me->io_pending = PR_FALSE;
1698
 
 
1699
 
    (void) OTSndOrderlyDisconnect(endpoint);
1700
 
    err = OTCloseProvider(endpoint);
1701
 
    if (err != kOTNoError)
1702
 
        goto ErrorExit;
1703
 
 
1704
 
    return kOTNoError;
1705
 
 
1706
 
ErrorExit:
1707
 
    macsock_map_error(err);
1708
 
    return -1;
1709
 
}
1710
 
 
1711
 
 
1712
 
PRInt32 _MD_writev(PRFileDesc *fd, const struct PRIOVec *iov, PRInt32 iov_size, PRIntervalTime timeout)
1713
 
{
1714
 
#pragma unused (fd, iov, iov_size, timeout)
1715
 
 
1716
 
    PR_ASSERT(0);
1717
 
    _PR_MD_CURRENT_THREAD()->md.osErrCode = unimpErr;
1718
 
    return -1;
1719
 
}
1720
 
 
1721
 
// OT endpoint states are documented here:
1722
 
// http://gemma.apple.com/techpubs/mac/NetworkingOT/NetworkingWOT-27.html#MARKER-9-65
1723
 
//
1724
 
static PRBool GetState(PRFileDesc *fd, PRBool *readReady, PRBool *writeReady, PRBool *exceptReady)
1725
 
{
1726
 
    OTResult resultOT;
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);
1732
 
 
1733
 
    *readReady = fd->secret->md.readReady && (availableData > 0);
1734
 
    *exceptReady = fd->secret->md.exceptReady;
1735
 
 
1736
 
    resultOT = OTGetEndpointState((EndpointRef)fd->secret->md.osfd);
1737
 
    switch (resultOT) {
1738
 
        case T_IDLE:
1739
 
        case T_UNBND:
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;
1747
 
            break;
1748
 
 
1749
 
        case T_DATAXFER:        // data transfer
1750
 
            *writeReady = fd->secret->md.writeReady;
1751
 
            break;
1752
 
 
1753
 
        case T_INREL:           // incoming orderly release
1754
 
            *writeReady = fd->secret->md.writeReady;
1755
 
            break;
1756
 
 
1757
 
        case T_OUTCON:          // outgoing connection pending  
1758
 
        case T_INCON:           // incoming connection pending
1759
 
        case T_OUTREL:          // outgoing orderly release
1760
 
        default:
1761
 
            *writeReady = PR_FALSE;
1762
 
    }
1763
 
    
1764
 
    return  *readReady || *writeReady || *exceptReady;
1765
 
}
1766
 
 
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)
1770
 
{
1771
 
    PRInt32     ready = 0;
1772
 
    PRPollDesc  *pd, *epd;
1773
 
    PRInt16     *readFlag, *writeFlag;
1774
 
    
1775
 
    for (pd = pds, epd = pd + npds, readFlag = outReadFlags, writeFlag = outWriteFlags;
1776
 
        pd < epd;
1777
 
        pd++, readFlag++, writeFlag++)
1778
 
    {
1779
 
        PRInt16  in_flags_read = 0,  in_flags_write = 0;
1780
 
        PRInt16 out_flags_read = 0, out_flags_write = 0;
1781
 
 
1782
 
        pd->out_flags = 0;
1783
 
 
1784
 
        if (NULL == pd->fd || pd->in_flags == 0) continue;
1785
 
 
1786
 
        if (pd->in_flags & PR_POLL_READ)
1787
 
        {
1788
 
            in_flags_read = (pd->fd->methods->poll)(
1789
 
                pd->fd, pd->in_flags & ~PR_POLL_WRITE, &out_flags_read);
1790
 
        }
1791
 
 
1792
 
        if (pd->in_flags & PR_POLL_WRITE)
1793
 
        {
1794
 
            in_flags_write = (pd->fd->methods->poll)(
1795
 
                pd->fd, pd->in_flags & ~PR_POLL_READ, &out_flags_write);
1796
 
        }
1797
 
 
1798
 
        if ((0 != (in_flags_read & out_flags_read)) ||
1799
 
            (0 != (in_flags_write & out_flags_write)))
1800
 
        {
1801
 
            ready += 1;  /* some layer has buffer input */
1802
 
            pd->out_flags = out_flags_read | out_flags_write;
1803
 
        }
1804
 
        
1805
 
        *readFlag = in_flags_read;
1806
 
        *writeFlag = in_flags_write;
1807
 
    }
1808
 
 
1809
 
    return ready;
1810
 
}
1811
 
 
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)
1815
 
{
1816
 
    PRInt32 ready = 0;
1817
 
    PRPollDesc *pd, *epd;
1818
 
    const PRInt16   *readFlag, *writeFlag;
1819
 
    
1820
 
    for (pd = pds, epd = pd + npds, readFlag = inReadFlags, writeFlag = inWriteFlags;
1821
 
         pd < epd;
1822
 
        pd++, readFlag++, writeFlag++)
1823
 
    {
1824
 
        PRFileDesc *bottomFD;
1825
 
        PRBool      readReady, writeReady, exceptReady;
1826
 
        PRInt16     in_flags_read = *readFlag;
1827
 
        PRInt16     in_flags_write = *writeFlag;
1828
 
 
1829
 
        if (NULL == pd->fd || pd->in_flags == 0) continue;
1830
 
 
1831
 
        if ((pd->in_flags & ~pd->out_flags) == 0) {
1832
 
            ready++;
1833
 
            continue;
1834
 
        }
1835
 
 
1836
 
        bottomFD = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
1837
 
        /* bottomFD can be NULL for pollable sockets */
1838
 
        if (bottomFD)
1839
 
        {
1840
 
            if (_PR_FILEDESC_OPEN == bottomFD->secret->state)
1841
 
            {
1842
 
                if (GetState(bottomFD, &readReady, &writeReady, &exceptReady))
1843
 
                {
1844
 
                    if (readReady)
1845
 
                    {
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;
1850
 
                    }
1851
 
                    if (writeReady)
1852
 
                    {
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;
1857
 
                    }
1858
 
                    if (exceptReady && (pd->in_flags & PR_POLL_EXCEPT))
1859
 
                    {
1860
 
                        pd->out_flags |= PR_POLL_EXCEPT;
1861
 
                    }
1862
 
                }
1863
 
                if (0 != pd->out_flags) ready++;
1864
 
            }
1865
 
            else    /* bad state */
1866
 
            {
1867
 
                ready += 1;  /* this will cause an abrupt return */
1868
 
                pd->out_flags = PR_POLL_NVAL;  /* bogii */
1869
 
            }
1870
 
        }
1871
 
    }
1872
 
 
1873
 
    return ready;
1874
 
}
1875
 
 
1876
 
 
1877
 
// see how many of the poll descriptors are ready
1878
 
static PRInt32 CountReadyPollDescs(PRPollDesc *pds, PRIntn npds)
1879
 
{
1880
 
    PRInt32 ready = 0;
1881
 
    PRPollDesc *pd, *epd;
1882
 
    
1883
 
    for (pd = pds, epd = pd + npds; pd < epd; pd++)
1884
 
    {
1885
 
        if (pd->out_flags)
1886
 
            ready ++;
1887
 
    }
1888
 
 
1889
 
    return ready;
1890
 
}
1891
 
 
1892
 
// set or clear the poll thread on the poll descriptors
1893
 
static void SetDescPollThread(PRPollDesc *pds, PRIntn npds, PRThread* thread)
1894
 
{
1895
 
    PRInt32     ready = 0;
1896
 
    PRPollDesc *pd, *epd;
1897
 
 
1898
 
    for (pd = pds, epd = pd + npds; pd < epd; pd++)
1899
 
    {   
1900
 
        if (pd->fd)
1901
 
        { 
1902
 
            PRFileDesc *bottomFD = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
1903
 
            if (bottomFD && (_PR_FILEDESC_OPEN == bottomFD->secret->state))
1904
 
            {
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;
1908
 
                }
1909
 
 
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;
1922
 
                }
1923
 
            }
1924
 
        }
1925
 
    }
1926
 
}
1927
 
 
1928
 
 
1929
 
#define DESCRIPTOR_FLAGS_ARRAY_SIZE     32
1930
 
 
1931
 
PRInt32 _MD_poll(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
1932
 
{
1933
 
    PRInt16     readFlagsArray[DESCRIPTOR_FLAGS_ARRAY_SIZE];
1934
 
    PRInt16     writeFlagsArray[DESCRIPTOR_FLAGS_ARRAY_SIZE];
1935
 
    
1936
 
    PRInt16     *readFlags  = readFlagsArray;
1937
 
    PRInt16     *writeFlags = writeFlagsArray;
1938
 
 
1939
 
    PRInt16     *ioFlags = NULL;
1940
 
    
1941
 
    PRThread    *thread = _PR_MD_CURRENT_THREAD();
1942
 
    PRInt32     ready;
1943
 
    
1944
 
    if (npds > DESCRIPTOR_FLAGS_ARRAY_SIZE)
1945
 
    {
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);
1949
 
        if (!ioFlags)
1950
 
        {
1951
 
            PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
1952
 
            return -1;
1953
 
        }
1954
 
        
1955
 
        readFlags = ioFlags;
1956
 
        writeFlags = &ioFlags[npds];
1957
 
    }
1958
 
 
1959
 
    // we have to be outside the lock when calling this, since
1960
 
    // it can call arbitrary user code (including other socket
1961
 
    // entry points)
1962
 
    ready = CheckPollDescMethods(pds, npds, readFlags, writeFlags);
1963
 
 
1964
 
    if (!ready && timeout != PR_INTERVAL_NO_WAIT) {
1965
 
        intn        is;
1966
 
        
1967
 
 
1968
 
        _PR_INTSOFF(is);
1969
 
        PR_Lock(thread->md.asyncIOLock);
1970
 
        PrepareForAsyncCompletion(thread, 0);
1971
 
 
1972
 
        SetDescPollThread(pds, npds, thread);
1973
 
 
1974
 
        (void)CheckPollDescEndpoints(pds, npds, readFlags, writeFlags);
1975
 
 
1976
 
        PR_Unlock(thread->md.asyncIOLock);
1977
 
        _PR_FAST_INTSON(is);
1978
 
 
1979
 
        ready = CountReadyPollDescs(pds, npds);
1980
 
 
1981
 
        if (ready == 0) {
1982
 
            WaitOnThisThread(thread, timeout);
1983
 
 
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);
1988
 
        }
1989
 
        
1990
 
        thread->io_pending = PR_FALSE;
1991
 
        SetDescPollThread(pds, npds, NULL);
1992
 
    }
1993
 
    else {
1994
 
        ready = CheckPollDescEndpoints(pds, npds, readFlags, writeFlags);
1995
 
    }
1996
 
 
1997
 
    if (readFlags != readFlagsArray)
1998
 
        PR_Free(ioFlags);
1999
 
    
2000
 
    return ready;
2001
 
}
2002
 
 
2003
 
 
2004
 
void _MD_initfiledesc(PRFileDesc *fd)
2005
 
{
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 )
2011
 
        {
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;
2019
 
        }
2020
 
}
2021
 
 
2022
 
 
2023
 
void _MD_freefiledesc(PRFileDesc *fd)
2024
 
{
2025
 
        if (fd->secret->md.miscLock)
2026
 
        {
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;
2030
 
        } else {
2031
 
                PR_ASSERT(fd->methods->file_type != PR_DESC_SOCKET_TCP && PR_DESC_SOCKET_TCP != PR_DESC_SOCKET_UDP);
2032
 
        }
2033
 
}
2034
 
 
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)
2038
 
{
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;
2044
 
        OSStatus        err;
2045
 
        
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
2051
 
        //                anyway.
2052
 
        err = OTInstallNotifier(endpointRef, NotifierRoutineUPP, fd->secret);
2053
 
        PR_ASSERT(err == kOTNoError);
2054
 
        
2055
 
        // Now that we have a NotifierRoutine installed, we can make the endpoint asynchronous
2056
 
        err = OTSetAsynchronous(endpointRef);
2057
 
        PR_ASSERT(err == kOTNoError);
2058
 
}
2059
 
 
2060
 
 
2061
 
void _MD_initfdinheritable(PRFileDesc *fd, PRBool imported)
2062
 
{
2063
 
        /* XXX this function needs to be implemented */
2064
 
        fd->secret->inheritable = _PR_TRI_UNKNOWN;
2065
 
}
2066
 
 
2067
 
 
2068
 
void _MD_queryfdinheritable(PRFileDesc *fd)
2069
 
{
2070
 
        /* XXX this function needs to be implemented */
2071
 
        PR_ASSERT(0);
2072
 
}
2073
 
 
2074
 
 
2075
 
PR_IMPLEMENT(PRInt32) _MD_shutdown(PRFileDesc *fd, PRIntn how)
2076
 
{
2077
 
#pragma unused (fd, how)
2078
 
 
2079
 
/* Just succeed silently!!! */
2080
 
return (0);
2081
 
}
2082
 
 
2083
 
 
2084
 
PR_IMPLEMENT(PRStatus) 
2085
 
_MD_getpeername(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen)
2086
 
{
2087
 
    PRThread *me = _PR_MD_CURRENT_THREAD();
2088
 
        EndpointRef ep = (EndpointRef) fd->secret->md.osfd;
2089
 
        InetAddress inetAddr;
2090
 
        TBind peerAddr;
2091
 
        OSErr err;
2092
 
        
2093
 
        if (*addrlen < sizeof(InetAddress)) {
2094
 
 
2095
 
                err = (OSErr) kEINVALErr;
2096
 
                goto ErrorExit;
2097
 
        }
2098
 
 
2099
 
    peerAddr.addr.maxlen = sizeof(InetAddress);
2100
 
    peerAddr.addr.len = 0;
2101
 
    peerAddr.addr.buf = (UInt8*) &inetAddr;
2102
 
    peerAddr.qlen = 0;
2103
 
 
2104
 
    PrepareForAsyncCompletion(me, fd->secret->md.osfd);    
2105
 
        fd->secret->md.misc.thread = me; // tell notifier routine what to wake up
2106
 
 
2107
 
        err = OTGetProtAddress(ep, NULL, &peerAddr);
2108
 
        
2109
 
    if (err != kOTNoError)
2110
 
        goto ErrorExit;
2111
 
 
2112
 
    WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
2113
 
 
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)
2118
 
        goto ErrorExit;
2119
 
        
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;
2124
 
    
2125
 
    *addrlen = PR_NETADDR_SIZE(addr); // return the amount of data obtained
2126
 
        return PR_SUCCESS;
2127
 
 
2128
 
ErrorExit:
2129
 
    macsock_map_error(err);
2130
 
    return PR_FAILURE;
2131
 
}
2132
 
 
2133
 
 
2134
 
PR_IMPLEMENT(unsigned long) inet_addr(const char *cp)
2135
 
{
2136
 
    OSStatus err;
2137
 
    InetHost host;    
2138
 
 
2139
 
    _MD_FinishInitNetAccess();
2140
 
 
2141
 
    err = OTInetStringToHost((char*) cp, &host);
2142
 
    if (err != kOTNoError)
2143
 
        return -1;
2144
 
    
2145
 
    return host;
2146
 
}
2147
 
 
2148
 
 
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];
2153
 
 
2154
 
 
2155
 
PR_IMPLEMENT(struct hostent *) gethostbyname(const char * name)
2156
 
{
2157
 
    OSStatus err;
2158
 
    PRUint32 index;
2159
 
    PRThread *me = _PR_MD_CURRENT_THREAD();
2160
 
 
2161
 
        _MD_FinishInitNetAccess();
2162
 
 
2163
 
    me->io_pending       = PR_TRUE;
2164
 
    me->io_fd            = NULL;
2165
 
    me->md.osErrCode     = noErr;
2166
 
        
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
2169
 
 
2170
 
    err = OTInetStringToAddress(dnsContext.serviceRef, (char *)name, &sHostInfo);
2171
 
    if (err != kOTNoError) {
2172
 
        me->io_pending = PR_FALSE;
2173
 
        me->md.osErrCode = err;
2174
 
        goto ErrorExit;
2175
 
    }
2176
 
 
2177
 
    WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
2178
 
        PR_Unlock(dnsContext.lock);
2179
 
 
2180
 
    if (me->md.osErrCode != kOTNoError)
2181
 
        goto ErrorExit;
2182
 
 
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;
2188
 
 
2189
 
    return (&sHostEnt);
2190
 
 
2191
 
ErrorExit:
2192
 
    return NULL;
2193
 
}
2194
 
 
2195
 
 
2196
 
PR_IMPLEMENT(struct hostent *) gethostbyaddr(const void *addr, int addrlen, int type)
2197
 
{
2198
 
    PR_ASSERT(type == AF_INET);
2199
 
    PR_ASSERT(addrlen == sizeof(struct in_addr));
2200
 
 
2201
 
        _MD_FinishInitNetAccess();
2202
 
 
2203
 
    OTInetHostToString((InetHost)addr, sHostInfo.name);
2204
 
    
2205
 
    return (gethostbyname(sHostInfo.name));
2206
 
}
2207
 
 
2208
 
 
2209
 
PR_IMPLEMENT(char *) inet_ntoa(struct in_addr addr)
2210
 
{
2211
 
    _MD_FinishInitNetAccess();
2212
 
 
2213
 
    OTInetHostToString((InetHost)addr.s_addr, sHostInfo.name);
2214
 
    
2215
 
    return sHostInfo.name;
2216
 
}
2217
 
 
2218
 
 
2219
 
PRStatus _MD_gethostname(char *name, int namelen)
2220
 
{
2221
 
    OSStatus err;
2222
 
    InetInterfaceInfo info;
2223
 
 
2224
 
    _MD_FinishInitNetAccess();
2225
 
 
2226
 
    /*
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.
2232
 
     */
2233
 
 
2234
 
    /* Make sure the string is as long as the longest possible address */
2235
 
    if (namelen < strlen("123.123.123.123")) {
2236
 
        err = kEINVALErr;
2237
 
        goto ErrorExit;
2238
 
    }
2239
 
 
2240
 
    err = OTInetGetInterfaceInfo(&info, kDefaultInetInterface);
2241
 
    if (err != kOTNoError)
2242
 
        goto ErrorExit;
2243
 
    
2244
 
    OTInetHostToString(info.fAddress, name);
2245
 
    
2246
 
    return PR_SUCCESS;
2247
 
 
2248
 
ErrorExit:
2249
 
    macsock_map_error(err);
2250
 
    return PR_FAILURE;
2251
 
}
2252
 
 
2253
 
 
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};
2258
 
 
2259
 
PR_IMPLEMENT(struct protoent *) getprotobyname(const char * name)
2260
 
{
2261
 
    if (strcmp(name, kIPName) == 0)
2262
 
        return (&sIPProto);
2263
 
        
2264
 
    if (strcmp(name, kTCPName) == 0)
2265
 
        return (&sTCPProto);
2266
 
        
2267
 
    if (strcmp(name, kUDPName) == 0)
2268
 
        return (&sUDPProto);
2269
 
        
2270
 
ErrorExit:
2271
 
    macsock_map_error(kEINVALErr);
2272
 
    return NULL;
2273
 
}
2274
 
 
2275
 
 
2276
 
PR_IMPLEMENT(struct protoent *) getprotobynumber(int number)
2277
 
{
2278
 
    if (number == INET_IP)
2279
 
        return (&sIPProto);
2280
 
        
2281
 
    if (number == INET_TCP)
2282
 
        return (&sTCPProto);
2283
 
        
2284
 
    if (number == INET_UDP)
2285
 
        return (&sUDPProto);
2286
 
        
2287
 
ErrorExit:
2288
 
    macsock_map_error(kEINVALErr);
2289
 
    return NULL;
2290
 
}
2291
 
 
2292
 
 
2293
 
int _MD_mac_get_nonblocking_connect_error(PRFileDesc* fd)
2294
 
{
2295
 
    EndpointRef endpoint = (EndpointRef)fd->secret->md.osfd;
2296
 
    OTResult    resultOT = OTGetEndpointState(endpoint);
2297
 
 
2298
 
    switch (resultOT)    {
2299
 
        case T_OUTCON:
2300
 
            macsock_map_error(EINPROGRESS);
2301
 
            return -1;
2302
 
            
2303
 
        case T_DATAXFER:
2304
 
            return 0;
2305
 
            
2306
 
        case T_IDLE:
2307
 
            macsock_map_error(fd->secret->md.disconnectError);
2308
 
            fd->secret->md.disconnectError = 0;
2309
 
            return -1;
2310
 
 
2311
 
        case T_INREL:
2312
 
            macsock_map_error(ENOTCONN);
2313
 
            return -1;
2314
 
 
2315
 
        default:
2316
 
            PR_ASSERT(0);
2317
 
            return -1;
2318
 
    }
2319
 
 
2320
 
    return -1;      // not reached
2321
 
}