📄 macsockotpt.c
字号:
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- *//* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is the Netscape Portable Runtime (NSPR). * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998-2000 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable * instead of those above. If you wish to allow use of your * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL. If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. *//* This turns on UNIX style errors in OT 1.1 headers */#define OTUNIXERRORS 1#include <string.h>#include <Gestalt.h>#include <Files.h>#include <OpenTransport.h>#include <OSUtils.h>#define GESTALT_OPEN_TPT_PRESENT gestaltOpenTptPresentMask#define GESTALT_OPEN_TPT_TCP_PRESENT gestaltOpenTptTCPPresentMask#include <OpenTptInternet.h> // All the internet typedefs#if (UNIVERSAL_INTERFACES_VERSION >= 0x0330)// for some reason Apple removed this typedef.typedef struct OTConfiguration OTConfiguration;#endif#include "primpl.h"typedef enum SndRcvOpCode { kSTREAM_SEND, kSTREAM_RECEIVE, kDGRAM_SEND, kDGRAM_RECEIVE} SndRcvOpCode;static struct { PRLock * lock; InetSvcRef serviceRef; PRThread * thread; void * cookie;} dnsContext;static pascal void DNSNotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie);static pascal void NotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie);static pascal void RawEndpointNotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie);static PRBool GetState(PRFileDesc *fd, PRBool *readReady, PRBool *writeReady, PRBool *exceptReady);voidWakeUpNotifiedThread(PRThread *thread, OTResult result);extern void WaitOnThisThread(PRThread *thread, PRIntervalTime timeout);extern void DoneWaitingOnThisThread(PRThread *thread);#if TARGET_CARBONOTClientContextPtr clientContext = NULL;#define INIT_OPEN_TRANSPORT() InitOpenTransportInContext(kInitOTForExtensionMask, &clientContext)#define OT_OPEN_INTERNET_SERVICES(config, flags, err) OTOpenInternetServicesInContext(config, flags, err, clientContext)#define OT_OPEN_ENDPOINT(config, flags, info, err) OTOpenEndpointInContext(config, flags, info, err, clientContext)#else#define INIT_OPEN_TRANSPORT() InitOpenTransport()#define OT_OPEN_INTERNET_SERVICES(config, flags, err) OTOpenInternetServices(config, flags, err)#define OT_OPEN_ENDPOINT(config, flags, info, err) OTOpenEndpoint(config, flags, info, err)#endif /* TARGET_CARBON */static OTNotifyUPP DNSNotifierRoutineUPP;static OTNotifyUPP NotifierRoutineUPP;static OTNotifyUPP RawEndpointNotifierRoutineUPP;void _MD_InitNetAccess(){ OSErr err; OSStatus errOT; PRBool hasOTTCPIP = PR_FALSE; PRBool hasOT = PR_FALSE; long gestaltResult; err = Gestalt(gestaltOpenTpt, &gestaltResult); if (err == noErr) if (gestaltResult & GESTALT_OPEN_TPT_PRESENT) hasOT = PR_TRUE; if (hasOT) if (gestaltResult & GESTALT_OPEN_TPT_TCP_PRESENT) hasOTTCPIP = PR_TRUE; PR_ASSERT(hasOTTCPIP == PR_TRUE); DNSNotifierRoutineUPP = NewOTNotifyUPP(DNSNotifierRoutine); NotifierRoutineUPP = NewOTNotifyUPP(NotifierRoutine); RawEndpointNotifierRoutineUPP = NewOTNotifyUPP(RawEndpointNotifierRoutine); errOT = INIT_OPEN_TRANSPORT(); PR_ASSERT(err == kOTNoError); dnsContext.serviceRef = NULL; dnsContext.lock = PR_NewLock(); PR_ASSERT(dnsContext.lock != NULL); dnsContext.thread = _PR_MD_CURRENT_THREAD(); dnsContext.cookie = NULL; /* XXX Does not handle absence of open tpt and tcp yet! */}static void _MD_FinishInitNetAccess(){ OSStatus errOT; if (dnsContext.serviceRef) return; dnsContext.serviceRef = OT_OPEN_INTERNET_SERVICES(kDefaultInternetServicesPath, NULL, &errOT); if (errOT != kOTNoError) { dnsContext.serviceRef = NULL; return; /* no network -- oh well */ } PR_ASSERT((dnsContext.serviceRef != NULL) && (errOT == kOTNoError)); /* Install notify function for DNR Address To String completion */ errOT = OTInstallNotifier(dnsContext.serviceRef, DNSNotifierRoutineUPP, &dnsContext); PR_ASSERT(errOT == kOTNoError); /* Put us into async mode */ errOT = OTSetAsynchronous(dnsContext.serviceRef); PR_ASSERT(errOT == kOTNoError);}static pascal void DNSNotifierRoutine(void * contextPtr, OTEventCode otEvent, OTResult result, void * cookie){#pragma unused(contextPtr) _PRCPU * cpu = _PR_MD_CURRENT_CPU(); OSStatus errOT; dnsContext.thread->md.osErrCode = result; dnsContext.cookie = cookie; switch (otEvent) { case T_DNRSTRINGTOADDRCOMPLETE: if (_PR_MD_GET_INTSOFF()) { dnsContext.thread->md.missedIONotify = PR_TRUE; cpu->u.missed[cpu->where] |= _PR_MISSED_IO; } else { DoneWaitingOnThisThread(dnsContext.thread); } break; case kOTProviderWillClose: errOT = OTSetSynchronous(dnsContext.serviceRef); // fall through to kOTProviderIsClosed case case kOTProviderIsClosed: errOT = OTCloseProvider((ProviderRef)dnsContext.serviceRef); dnsContext.serviceRef = nil; if (_PR_MD_GET_INTSOFF()) { dnsContext.thread->md.missedIONotify = PR_TRUE; cpu->u.missed[cpu->where] |= _PR_MISSED_IO; } else { DoneWaitingOnThisThread(dnsContext.thread); } break; default: // or else we don't handle the event PR_ASSERT(otEvent==NULL); } // or else we don't handle the event SignalIdleSemaphore();}static void macsock_map_error(OSStatus err){ _PR_MD_CURRENT_THREAD()->md.osErrCode = err; if (IsEError(err) || (err >= EPERM && err <= ELASTERRNO)) { switch (IsEError(err) ? OSStatus2E(err) : err) { case EBADF: PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); break; case EADDRNOTAVAIL: PR_SetError(PR_ADDRESS_NOT_AVAILABLE_ERROR, err); break; case EINPROGRESS: PR_SetError(PR_IN_PROGRESS_ERROR, err); break; case EWOULDBLOCK: case EAGAIN: PR_SetError(PR_WOULD_BLOCK_ERROR, err); break; case ENOTSOCK: PR_SetError(PR_NOT_SOCKET_ERROR, err); break; case ETIMEDOUT: PR_SetError(PR_IO_TIMEOUT_ERROR, err); break; case ECONNREFUSED: PR_SetError(PR_CONNECT_REFUSED_ERROR, err); break; case ENETUNREACH: PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, err); break; case EADDRINUSE: PR_SetError(PR_ADDRESS_IN_USE_ERROR, err); break; case EFAULT: PR_SetError(PR_ACCESS_FAULT_ERROR, err); break; case EINTR: PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); break; case EINVAL: PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); break; case EIO: PR_SetError(PR_IO_ERROR, err); break; case ENOENT: PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, err); break; case ENXIO: PR_SetError(PR_IO_ERROR, err); break; case EPROTOTYPE: PR_SetError(PR_PROTOCOL_NOT_SUPPORTED_ERROR, err); break; case EOPNOTSUPP: PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, err); break; default: PR_SetError(PR_UNKNOWN_ERROR, err); break; } } else { PR_ASSERT(IsXTIError(err)); switch (err) { case kOTNoDataErr: case kOTFlowErr: PR_SetError(PR_WOULD_BLOCK_ERROR, err); break; default: PR_SetError(PR_UNKNOWN_ERROR, err); break; } }}static void PrepareForAsyncCompletion(PRThread * thread, PRInt32 osfd){ thread->io_pending = PR_TRUE; thread->io_fd = osfd; thread->md.osErrCode = noErr;}voidWakeUpNotifiedThread(PRThread *thread, OTResult result){ _PRCPU * cpu = _PR_MD_CURRENT_CPU(); if (thread) { thread->md.osErrCode = result; if (_PR_MD_GET_INTSOFF()) { thread->md.missedIONotify = PR_TRUE; cpu->u.missed[cpu->where] |= _PR_MISSED_IO; } else { DoneWaitingOnThisThread(thread); } } SignalIdleSemaphore();}// Notification routine// Async callback routine.// A5 is OK. Cannot allocate memory here// Ref: http://gemma.apple.com/techpubs/mac/NetworkingOT/NetworkingWOT-100.html//static pascal void NotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie){ PRFilePrivate *secret = (PRFilePrivate *) contextPtr; _MDFileDesc * md = &(secret->md); EndpointRef endpoint = (EndpointRef)secret->md.osfd; PRThread * readThread = NULL; // also used for 'misc' PRThread * writeThread = NULL; OSStatus err; OTResult resultOT; TDiscon discon; switch (code) {// OTLook Events - case T_LISTEN: // A connection request is available // If md->doListen is true, then PR_Listen has been // called on this endpoint; therefore, we're ready to // accept connections. But we'll do that with PR_Accept // (which calls OTListen, OTAccept, etc) instead of // doing it here. if (md->doListen) { readThread = secret->md.misc.thread; secret->md.misc.thread = NULL; secret->md.misc.cookie = cookie; break; } else { // Reject the connection, we're not listening OTSndDisconnect(endpoint, NULL); } break; case T_CONNECT: // Confirmation of a connect request // cookie = sndCall parameter from OTConnect() err = OTRcvConnect(endpoint, NULL); PR_ASSERT(err == kOTNoError); // wake up waiting thread, if any. writeThread = secret->md.write.thread; secret->md.write.thread = NULL; secret->md.write.cookie = cookie; break; case T_DATA: // Standard data is available // Mark this socket as readable. secret->md.readReady = PR_TRUE; // wake up waiting thread, if any readThread = secret->md.read.thread; secret->md.read.thread = NULL; secret->md.read.cookie = cookie; break; case T_EXDATA: // Expedited data is available PR_ASSERT(!"T_EXDATA Not implemented"); return; case T_DISCONNECT: // A disconnect is available discon.udata.len = 0; err = OTRcvDisconnect(endpoint, &discon); PR_ASSERT(err == kOTNoError); secret->md.exceptReady = PR_TRUE; // XXX Check this md->disconnectError = discon.reason; // save for _MD_mac_get_nonblocking_connect_error // wake up waiting threads, if any result = -3199 - discon.reason; // obtain the negative error code if ((readThread = secret->md.read.thread) != NULL) { secret->md.read.thread = NULL; secret->md.read.cookie = cookie; } if ((writeThread = secret->md.write.thread) != NULL) { secret->md.write.thread = NULL; secret->md.write.cookie = cookie; } break; case T_ERROR: // obsolete/unused in library PR_ASSERT(!"T_ERROR Not implemented"); return; case T_UDERR: // UDP Send error; clear the error (void) OTRcvUDErr((EndpointRef) cookie, NULL); break; case T_ORDREL: // An orderly release is available err = OTRcvOrderlyDisconnect(endpoint); PR_ASSERT(err == kOTNoError); secret->md.readReady = PR_TRUE; // mark readable (to emulate bsd sockets) // remember connection is closed, so we can return 0 on read or receive secret->md.orderlyDisconnect = PR_TRUE; readThread = secret->md.read.thread; secret->md.read.thread = NULL; secret->md.read.cookie = cookie; break; case T_GODATA: // Flow control lifted on standard data secret->md.writeReady = PR_TRUE; resultOT = OTLook(endpoint); // clear T_GODATA event PR_ASSERT(resultOT == T_GODATA); // wake up waiting thread, if any writeThread = secret->md.write.thread; secret->md.write.thread = NULL; secret->md.write.cookie = cookie; break; case T_GOEXDATA: // Flow control lifted on expedited data PR_ASSERT(!"T_GOEXDATA Not implemented"); return; case T_REQUEST: // An Incoming request is available PR_ASSERT(!"T_REQUEST Not implemented"); return; case T_REPLY: // An Incoming reply is available PR_ASSERT(!"T_REPLY Not implemented");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -