Exemplo n.º 1
0
static OSErr CreateSocket(int type, EndpointRef *endpoint)
{
	OSStatus err;
	PRThread *me = _PR_MD_CURRENT_THREAD();

	switch (type){
		case SOCK_STREAM:
			err = OTAsyncOpenEndpoint(OTCreateConfiguration(kTCPName), 0, NULL, 
					NotifierRoutine, me);
			break;
		case SOCK_DGRAM:
			err = OTAsyncOpenEndpoint(OTCreateConfiguration(kUDPName), 0, NULL,
					NotifierRoutine, me);
			break;
	}
	if (err != kOTNoError)
		goto ErrorExit;

	WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);

	err = me->md.osErrCode;
	if (err != kOTNoError)
		goto ErrorExit;

	*endpoint = me->md.cookie;
	PR_ASSERT(*endpoint != NULL);

	return kOTNoError;

ErrorExit:
	return err;
}
Exemplo n.º 2
0
NMErr
EndpointHander::GetStreamEP(void)
{
	DEBUG_ENTRY_EXIT("EndpointHander::GetStreamEP");

	CachedEP		*streamEP = NULL;
	OTLink			*acceptorLink = NULL;
	NMErr			status = kNMNoError;

	//Try_
	{
		//	Get a cached stream ep
		acceptorLink = OTLIFODequeue(&OTEndpoint::sStreamEPCache.Q);
	
		//if there was an available one in the cache
		if (acceptorLink)
		{
			OTAtomicAdd32(-1, &OTEndpoint::sStreamEPCache.readyCount);
			OTAtomicAdd32(-1, &OTEndpoint::sStreamEPCache.totalCount);
			//jacked up and good to go
			mState |= kGotStreamEP;
			
			//get the cache reloading itself
			OTEndpoint::ServiceEPCaches();
		}
		//otherwise, make one now
		else
		{
			return OTAsyncOpenEndpoint(OTCreateConfiguration(mListenerEP->GetStreamProtocolName()), 0, NULL, mNotifier.fUPP, this);
		}

		//	Get the pointer to the cached ep object
		streamEP = OTGetLinkObject(acceptorLink, CachedEP, link);
		op_assert(streamEP != NULL);
		
		//	Remove the notifier that was being used for cacheing and install the "normal" one
		OTRemoveNotifier(streamEP->ep);
		OTInstallNotifier(streamEP->ep, mNotifier.fUPP, this);
		
		mNewEP->mStreamEndpoint->mEP = streamEP->ep;

		delete streamEP;

	}
	//Catch_(code)
	error:
	if (status)
	{
		NMErr code = status;
		return code;
	}
	
	mState |= kStreamDone;
	
	return kNMNoError;
}
Exemplo n.º 3
0
/* Open a UDP network socket
   If 'port' is non-zero, the UDP socket is bound to a fixed local port.
*/
extern UDPsocket SDLNet_UDP_Open(Uint16 port)
{
	UDPsocket sock;
#ifdef MACOS_OPENTRANSPORT
	EndpointRef dummy = NULL;
#endif

	/* Allocate a UDP socket structure */
	sock = (UDPsocket)malloc(sizeof(*sock));
	if ( sock == NULL ) {
		SDLNet_SetError("Out of memory");
		goto error_return;
	}
	memset(sock, 0, sizeof(*sock));
	
	/* Open the socket */
#ifdef MACOS_OPENTRANSPORT
	{
		sock->error = OTAsyncOpenEndpoint(
			OTCreateConfiguration(kUDPName),0, &(sock->info),
			(OTNotifyProcPtr)AsyncUDPNotifier, sock );
		AsyncUDPPopEvent( sock );
		while( !sock->error && !( sock->completion & CompleteMask(T_OPENCOMPLETE)))
		{
			AsyncUDPPopEvent( sock );
		}
		if( sock->error )
		{
			SDLNet_SetError("Could not open UDP socket");
			goto error_return;
		}
		// Should we ??
		// (01/05/03 minami<*****@*****.**>
		OTSetBlocking( sock->channel );
	}
#else
	sock->channel = socket(AF_INET, SOCK_DGRAM, 0);
#endif /* MACOS_OPENTRANSPORT */

	if ( sock->channel == INVALID_SOCKET ) 
	{
		SDLNet_SetError("Couldn't create socket");
		goto error_return;
	}

#ifdef MACOS_OPENTRANSPORT
	{
	InetAddress required, assigned;
	TBind req_addr, assigned_addr;
	OSStatus status;
	InetInterfaceInfo info;
		
		memset(&assigned_addr, 0, sizeof(assigned_addr));
		assigned_addr.addr.maxlen = sizeof(assigned);
		assigned_addr.addr.len = sizeof(assigned);
		assigned_addr.addr.buf = (UInt8 *) &assigned;
		
		if ( port ) {
			status = OTInetGetInterfaceInfo( &info, kDefaultInetInterface );
			if( status != kOTNoError )
				goto error_return;
			OTInitInetAddress(&required, port, info.fAddress );
			req_addr.addr.maxlen = sizeof( required );
			req_addr.addr.len = sizeof( required );
			req_addr.addr.buf = (UInt8 *) &required;
		
			sock->error = OTBind(sock->channel, &req_addr, &assigned_addr);
		} else {
			sock->error = OTBind(sock->channel, nil, &assigned_addr );
		}
		AsyncUDPPopEvent(sock);

		while( !sock->error && !(sock->completion & CompleteMask(T_BINDCOMPLETE)))
		{
			AsyncUDPPopEvent(sock);
		}	
		if (sock->error != noErr)
		{
			SDLNet_SetError("Couldn't bind to local port, OTBind() = %d",(int) status);
			goto error_return;
		}

		sock->address.host = assigned.fHost;
		sock->address.port = assigned.fPort;
		
#ifdef DEBUG_NET
		printf("UDP open host = %d, port = %d\n", assigned.fHost, assigned.fPort );
#endif
	}
#else
	/* Bind locally, if appropriate */
	if ( port )
	{
		struct sockaddr_in sock_addr;
		memset(&sock_addr, 0, sizeof(sock_addr));
		sock_addr.sin_family = AF_INET;
		sock_addr.sin_addr.s_addr = INADDR_ANY;
		sock_addr.sin_port = SDL_SwapBE16(port);

		/* Bind the socket for listening */
		if ( bind(sock->channel, (struct sockaddr *)&sock_addr,
				sizeof(sock_addr)) == SOCKET_ERROR ) {
			SDLNet_SetError("Couldn't bind to local port");
			goto error_return;
		}
		/* Fill in the channel host address */
		sock->address.host = sock_addr.sin_addr.s_addr;
		sock->address.port = sock_addr.sin_port;
	}

	/* Allow LAN broadcasts with the socket */
	{ int yes = 1;
		setsockopt(sock->channel, SOL_SOCKET, SO_BROADCAST, (char*)&yes, sizeof(yes));
	}
#endif /* MACOS_OPENTRANSPORT */

	/* The socket is ready */
	
	return(sock);

error_return:
#ifdef MACOS_OPENTRANSPORT
	if( dummy )
		OTCloseProvider( dummy );
#endif
	SDLNet_UDP_Close(sock);
	
	return(NULL);
}
Exemplo n.º 4
0
void *ottcp_new(Symbol *s, short argc, Atom *argv) {
	OTTCP *x;
	OSStatus err;
	
	// These variables will be filled with the args we parse
	char *inetHostName = 0;
	InetPort port = 0;
	long readbufsize = DEFAULT_BUFFER_SIZE;
	long writebufsize = DEFAULT_BUFFER_SIZE;
	
	EnterCallback();
		
	if (ParseArgs(argc, argv, &inetHostName, &port, &readbufsize, &readbufsize) == 0) {
		ouchstring("ottcp usage: \"ottcp [<hostname> <port>] [readbufsize <nbytes>] [writebufsize <nbytes>]\"");
		ExitCallback();
		return 0;
	}
	
	post("Parsed args: inetHostName %s, port %ld, readbufsize %ld, writebufsize %ld",
		 inetHostName, port, readbufsize, writebufsize);
	
	x = newobject(ottcp_class);
	x->o_a5 = (long) LMGetCurrentA5();
	x->o_inetHostName = inetHostName;
	x->o_inetPort = port;
	x->o_inetHost = 0;

	if (x->o_inetHostName != 0) {
		// They gave the server's IP address and port # as arguments
		if (LookUpInetHost(x->o_inetHostName, &(x->o_inetHost)) == 0) {
			post("е OTTCP: can't understand host \"%s\"; not connecting",  x->o_inetHostName);
		}
	}

	x->o_state = SETTING_UP;
	x->o_datawaiting = 0;
	x->o_errorreporting = 1;
	x->o_outlet = outlet_new(x,0L);
	x->o_clock = clock_new(x, (method) do_output);
	x->o_connectedclock = clock_new(x, (method) do_output_connected);
	x->o_connectionSymbol = 0;
	
	OTClearLock(&(x->o_readlock));
	
	/* Allocate buffers */
	x->o_ReadBufSize = readbufsize;
	x->o_WriteBufSize = writebufsize;
	
	x->o_ReadBufA = NewPtr(readbufsize);
	x->o_ReadBufB = NewPtr(readbufsize);
	x->o_WriteBuf = NewPtr(writebufsize);
	if (x->o_ReadBufA == 0 || x->o_ReadBufB == 0 || x->o_WriteBuf == 0) {
		ouchstring("ottcp: not enough memory for two %ld byte read buffers and a %ld byte write buffer.",
				   readbufsize, writebufsize);
	}
	
	x->o_currentReadBuf = x->o_ReadBufA;
	x->o_nextReadBuf = x->o_ReadBufB;
	x->o_bytesRead = 0;
	x->o_bytesReadForNextTime = 0;
	x->o_WBReadPos = 0;
	x->o_WBWritePos = 0;
	

	/* Make the endpoint */	
	x->o_tcp_ep = 0;		// Indicates endpoint hasn't been created yet.
	err = OTAsyncOpenEndpoint(OTCreateConfiguration(kTCPName), 0, &(x->epinfo), OTTCPNotifier, x);
	if (err != noErr) {
		ouchstring("otudp: Error %d from OTAsyncOpenEndpoint. This is bad.", err);
		return 0;
	}
	// This didn't actually make the endpoint; my notifier should get the T_OPENCOMPLETE
	// event after the endpoint is opened.


	ExitCallback();
	return (x);
}
Exemplo n.º 5
0
/* Accept an incoming connection on the given server socket.
   The newly created socket is returned, or NULL if there was an error.
*/
TCPsocket SDLNet_TCP_Accept(TCPsocket server)
{
	
	/* Only server sockets can accept */
	if ( ! server->sflag ) {
		SDLNet_SetError("Only server sockets can accept()");
		return(NULL);
	}
	server->ready = 0;

	/* Accept a new TCP connection on a server socket */
	{
		InetAddress peer;
		TCall peerinfo;
		TCPsocket sock = NULL;
		Boolean mustListen = false;
		OTResult err;
		
		memset(&peerinfo, 0, (sizeof peerinfo ));
		peerinfo.addr.buf = (Uint8 *) &peer;
		peerinfo.addr.maxlen = sizeof(peer);
		
		while( mustListen || !sock )
		{
			// OTListen
			// We do NOT block ---- right thing ? (TODO)
			err = OTListen( server->channel, &peerinfo );

			if( err )
				goto error_return;
			else
			{
				mustListen = false;
				sock = AsyncTCPNewSocket();
				if( ! sock )
					goto error_return;
			}
		}
		if( sock )
		{
			// OTAsyncOpenEndpoint
			server->error = OTAsyncOpenEndpoint( OTCloneConfiguration( server->config ),
				NULL, &(sock->info), (OTNotifyProcPtr)AsyncTCPNotifier, sock );
			AsyncTCPPopEvent( sock );
			while( !sock->error && !( sock->completion & CompleteMask( T_OPENCOMPLETE)))
			{
				AsyncTCPPopEvent( sock );
			}
			if( ! sock->channel )
			{
				mustListen = false;
				goto error_return;
			}
			
			// OTAccept
			server->completion &= ~(CompleteMask(T_ACCEPTCOMPLETE));
			server->error = OTAccept( server->channel, sock->channel, &peerinfo );
			AsyncTCPPopEvent( server );
			while( !(server->completion & CompleteMask(T_ACCEPTCOMPLETE)))
			{
				AsyncTCPPopEvent( server );
			}
			
			switch( server->error )
			{
				case kOTLookErr:
					switch( OTLook(server->channel ))
					{
						case T_LISTEN:
							mustListen = true;
							break;
						case T_DISCONNECT:
							goto error_return;
					}
					break;
				case 0:
					sock->nextListener = server->nextListener;
					server->nextListener = sock;
					sock->remoteAddress.host = peer.fHost;
					sock->remoteAddress.port = peer.fPort;
					return sock;
					// accept successful
					break;
				default:
					free( sock );
			}
		}
		sock->remoteAddress.host = peer.fHost;
		sock->remoteAddress.port = peer.fPort;
		sock->sflag = 0;
		sock->ready = 0;

		/* The socket is ready */
		return(sock);
	
	// Error; close the socket and return	
	error_return:
		SDLNet_TCP_Close(sock);
		return(NULL);
	}
}
Exemplo n.º 6
0
/* Open a TCP network socket
   If 'remote' is NULL, this creates a local server socket on the given port,
   otherwise a TCP connection to the remote host and port is attempted.
   The newly created socket is returned, or NULL if there was an error.

   ( re-written by masahiro minami<*****@*****.**>
     Now endpoint is created in Async mode.
     01/02/20 )
*/
TCPsocket SDLNet_TCP_Open(IPaddress *ip)
{
	EndpointRef dummy = NULL;

	TCPsocket sock = AsyncTCPNewSocket();
	if( ! sock)
		return NULL;

	// Determin whether bind locally, or connect to remote
	if ( (ip->host != INADDR_NONE) && (ip->host != INADDR_ANY) )
	{
		// ######## Connect to remote
		OTResult stat;
		InetAddress inAddr;
		TBind bindReq;

		// Open endpoint
		sock->error = OTAsyncOpenEndpoint(
			OTCreateConfiguration(kTCPName), NULL, &(sock->info),
			(OTNotifyProcPtr)(AsyncTCPNotifier),
			sock );

		AsyncTCPPopEvent( sock );
		while( !sock->error && !( sock->completion & CompleteMask(T_OPENCOMPLETE)))
		{
			//SetThreadState( kCurrentThreadID, kReadyThreadState, kNoThreadID );
			//YieldToAnyThread();
			//WaitNextEvent(everyEvent, &macEvent, 1, NULL);
			AsyncTCPPopEvent( sock );
		}

		if( !sock->channel )
		{
			SDLNet_SetError("OTAsyncOpenEndpoint failed --- client socket could not be opened");
			goto error_return;
		}

		// Set blocking mode
		// I'm not sure if this is a good solution....
		// Check out Apple's sample code, OT Virtual Server
		// ( 010314 masahiro minami<*****@*****.**>)

		sock->error = OTSetBlocking( sock->channel );
		if( sock->error != kOTNoError )
		{
			SDLNet_SetError("OTSetBlocking() returned an error");
			goto error_return;
		}

		// Bind the socket
		OTInitInetAddress(&inAddr, 0, 0 );
		bindReq.addr.len = sizeof( InetAddress );
		bindReq.addr.buf = (unsigned char*)&inAddr;
		bindReq.qlen = 0;

		sock->error = OTBind( sock->channel, &bindReq, NULL );
		AsyncTCPPopEvent(sock);
		while( !sock->error && !( sock->completion & CompleteMask(T_BINDCOMPLETE)))
		{
			//YieldToAnyThread();
			//WaitNextEvent(everyEvent, &macEvent, 1, NULL);
			AsyncTCPPopEvent(sock);
		}


		switch( stat = OTGetEndpointState( sock->channel ))
		{
			InetAddress inAddr;
			TCall sndCall;
			OTResult res;

			case T_OUTCON:
				SDLNet_SetError("SDLNet_Open() failed -- T_OUTCON");
				goto error_return;
				break;
			case T_IDLE:
				sock->readShutdown = false;
				sock->writeShutdown = false;
				sock->event &=~T_CONNECT;

				OTMemzero(&sndCall, sizeof(TCall));
				OTInitInetAddress(&inAddr, ip->port, ip->host );
				sndCall.addr.len = sizeof(InetAddress);
				sndCall.addr.buf = (unsigned char*)&inAddr;
				sock->connected = 0;
				res = OTConnect( sock->channel, &sndCall, NULL );
				AsyncTCPPopEvent(sock);
				while( sock->error == kOTNoDataErr || !sock->connected )
					AsyncTCPPopEvent(sock);
				break;
			default:
				// What's to be done ? (TODO)
				SDLNet_SetError("SDLNet_TCP_Open() failed -- EndpointState not good");
				goto error_return;

		}
		if( !(sock->event & (T_CONNECT|T_DISCONNECT)))
			goto error_return;

		AsyncTCPPopEvent( sock );
		while( !(sock->event & (T_CONNECT|T_DISCONNECT)))
		{
			AsyncTCPPopEvent( sock );
		}
		// OTConnect successfull
		if( sock->event & T_CONNECT)
		{
			sock->remoteAddress.host = inAddr.fHost;
			sock->remoteAddress.port = inAddr.fPort;
			sock->sflag = false;
		}
		else
		{
			// OTConnect failed
			sock->event &= ~T_DISCONNECT;
			goto error_return;
		}
	}
	else
	{
		// ######## Bind locally
		TBind bindReq;
		InetAddress	inAddr;

	// First, get InetInterfaceInfo.
	// I don't search for all of them.
	// Does that matter ?

		sock->error = OTAsyncOpenEndpoint(
			OTCreateConfiguration("tilisten, tcp"), NULL, &(sock->info),
			(OTNotifyProcPtr)(AsyncTCPNotifier),
			sock);
		AsyncTCPPopEvent( sock );
		while( !sock->error && !( sock->completion & CompleteMask( T_OPENCOMPLETE)))
		{
			AsyncTCPPopEvent( sock );
		}

		if( ! sock->channel )
		{
			SDLNet_SetError("OTAsyncOpenEndpoint failed --- server socket could not be opened");
			goto error_return;
		}

		// Create a master OTConfiguration
		sock->config = OTCreateConfiguration(kTCPName);
		if( ! sock->config )
		{
			SDLNet_SetError("Could not create master OTConfiguration");
			goto error_return;
		}

		// Bind the socket
		OTInitInetAddress(&inAddr, ip->port, 0 );
		inAddr.fAddressType = AF_INET;
		bindReq.addr.len = sizeof( InetAddress );
		bindReq.addr.buf = (unsigned char*)&inAddr;
		bindReq.qlen = 35;	// This number is NOT well considered. (TODO)
		sock->localAddress.host = inAddr.fHost;
		sock->localAddress.port = inAddr.fPort;
		sock->sflag = true;
		
		sock->error = OTBind( sock->channel, &bindReq, NULL );
		AsyncTCPPopEvent(sock);
		while( !sock->error && !( sock->completion & CompleteMask(T_BINDCOMPLETE)))
		{
			AsyncTCPPopEvent(sock);
		}
		if( sock->error != kOTNoError )
		{
			SDLNet_SetError("Could not bind server socket");
			goto error_return;
		}
		
		if( dummy )
			OTCloseProvider( dummy );

	}
	
	sock->ready = 0;
	return sock;
	
	error_return:
	if( dummy )
		OTCloseProvider( dummy );
	SDLNet_TCP_Close( sock );
	return NULL;	
}
Exemplo n.º 7
0
pascal void
EndpointHander::Notifier(
	void		*contextPtr,
	OTEventCode code,
	OTResult	result,
	void		*cookie)
{
	NMErr status;
	DEBUG_ENTRY_EXIT("EndpointHander::Notifier");
	EndpointHander *epHander = (EndpointHander *) contextPtr;

	UNUSED_PARAMETER(result);

	switch (code)
	{
		case T_OPENCOMPLETE:		// one of our endpoints finished opening
		
			//if we were waiting on the stream ep, move on to the datagram ep if necessary
			if (!(epHander->mState & kGotStreamEP))
			{
				epHander->mNewEP->mStreamEndpoint->mEP = (EndpointRef)cookie;	
				epHander->mState |= kGotStreamEP;
				if (!(epHander->mState & kGotDatagramEP))
				{
					OTAsyncOpenEndpoint(OTCreateConfiguration(epHander->mListenerEP->GetDatagramProtocolName()), 0, NULL, epHander->mNotifier.fUPP, contextPtr);
				}
			}
			//it must be our datagram ep that's done
			else
			{
				epHander->mNewEP->mDatagramEndpoint->mEP = (EndpointRef)cookie;		
				epHander->mState |= kGotDatagramEP;				
			}
			
			//once both eps are done, we go ahead and bind
			if ((epHander->mState & kGotStreamEP) && (epHander->mState & kGotDatagramEP))
			{
				//	Bind the endpoint.  Execution continues in the notifier for T_BINDCOMPLETE
				epHander->mBindReq.addr.len = 0;
				epHander->mBindReq.addr.buf = NULL;
				epHander->mBindRet.addr = epHander->mNewEP->mDatagramEndpoint->mLocalAddress;

				//ECF011114 caused problems under MacOSX...
				status = OTBind(epHander->mNewEP->mDatagramEndpoint->mEP, NULL, &epHander->mBindRet);			
				//status = OTBind(epHander->mNewEP->mDatagramEndpoint->mEP, &epHander->mBindReq, &epHander->mBindRet);
				DEBUG_NETWORK_API(epHander->mNewEP->mDatagramEndpoint->mEP, "OTBind", status);								
			}
			break;
			
		case T_BINDCOMPLETE:		// The datagram endpoint has finished
			epHander->mState |= kDatagramDone;
			
			//	by this time, we should have both endpoints ready to go
			op_assert(epHander->mState & (kStreamDone | kDatagramDone) == (kStreamDone | kDatagramDone));
			
			//	we got the local address from the bind
			epHander->mState |= kDatagramLocalAddr;
			
			//	Now that everything is ready, accept the connection
			epHander->Finish();
			break;

		default:
			break;
	}
}
Exemplo n.º 8
0
NMErr
EndpointHander::GetDatagramEP(void)
{
	DEBUG_ENTRY_EXIT("EndpointHander::GetDatagramEP");

	CachedEP		*datagramEP = NULL;
	OTLink			*acceptorLink = NULL;
	NMErr		status = kNMNoError;

	//	if we're not in uber mode, there should be no datagram ep
	//	just jump to the notifier
	if (mNewEP->mMode != kNMNormalMode)
	{
		Notifier(this, T_BINDCOMPLETE, kNMNoError, NULL);
		return kNMNoError;
	}
		
	//Try_
	{
		//	Get a datagram endpoint from the cache
		acceptorLink = OTLIFODequeue(&OTEndpoint::sDatagramEPCache.Q);
		if (acceptorLink)
		{
			OTAtomicAdd32(-1, &OTEndpoint::sDatagramEPCache.readyCount);
			OTAtomicAdd32(-1, &OTEndpoint::sDatagramEPCache.totalCount);
			
			//jacked up and good to go
			mState |= kGotDatagramEP;
			
			//get the cache reloading itself
			OTEndpoint::ServiceEPCaches();
		}
		//if we couldn't get one off the cache, we'll make one after we have a stream endpoint
		// (one at a time for simplicity)
		else
		{
			if (mState & kGotStreamEP)
			{
				return OTAsyncOpenEndpoint(OTCreateConfiguration(mListenerEP->GetDatagramProtocolName()), 0, NULL, mNotifier.fUPP, this);
			}
			return kNMNoError; //we just wait for the stream endpoint to get done
		}

		//	Get the pointer to the cached ep object
		datagramEP = OTGetLinkObject(acceptorLink, CachedEP, link);
		op_assert(datagramEP != NULL);
		
		//	Remove the notifier that was being used for cacheing and install the "normal" one
		OTRemoveNotifier(datagramEP->ep);
		OTInstallNotifier(datagramEP->ep, mNotifier.fUPP, this);

		mNewEP->mDatagramEndpoint->mEP = datagramEP->ep;
		
		delete datagramEP;
		
		//if we got both endpoints, go ahead and bind here
		if (mState & kGotStreamEP)
		{
			//	Bind the endpoint.  Execution continues in the notifier for T_BINDCOMPLETE
			mBindReq.addr.len = 0;
			mBindReq.addr.buf = NULL;
			mBindRet.addr = mNewEP->mDatagramEndpoint->mLocalAddress;

			status = OTBind(mNewEP->mDatagramEndpoint->mEP,NULL, &mBindRet);
			//status = OTBind(mNewEP->mDatagramEndpoint->mEP,&mBindReq, &mBindRet);

			DEBUG_NETWORK_API(mNewEP->mDatagramEndpoint->mEP, "OTBind", status);					
			//ThrowIfOSErr_(status);
			if (status)
				goto error;
		}
	}
	//Catch_(code)
	error:
	if (status)
	{
		NMErr code = status;
		return code;
	}
	
	return kNMNoError;
}