苹果CFSocketStream

转自:http://www.opensource.apple.com/source/CFNetwork/CFNetwork-129.9/Stream/CFSocketStream.c


/* static */ Boolean
_SocketStreamAttemptNextConnection_NoLock(_CFSocketStreamContext* ctxt) {
	
	do {
		/* Attempt to get the primary host for connecting */
		CFTypeRef lookup = (CFTypeRef)CFDictionaryGetValue(ctxt->_properties, _kCFStreamPropertyHostForOpen);
		SInt32* attempt = NULL;

		/* If there was a host, there is more work to do */
		if (lookup) {

			CFIndex count;
			CFArrayRef list = NULL;
			CFDataRef address = NULL;
			CFNumberRef port = _CFNumberCopyPortForOpen(ctxt->_properties);
			CFMutableDataRef a = (CFMutableDataRef)CFDictionaryGetValue(ctxt->_properties, _kCFStreamPropertySocketAddressAttempt);
			
			/* If there is an address attempt, point to the counter. */
			if (a)
				attempt = (SInt32*)CFDataGetMutableBytePtr(a);
			
			/* This is the first attempt so create and add the counter. */
			else {
				
				SInt32 i = 0;
				
				/* Create the counter. */
				a = CFDataCreateMutable(CFGetAllocator(ctxt->_properties), sizeof(i));
				
				/* If it fails, set out of memory and bail. */
				if (!a) {
					ctxt->_error.error = ENOMEM;
					ctxt->_error.domain = kCFStreamErrorDomainPOSIX;
					
					/* Not needed anymore. */
					if (port) CFRelease(port);

					break;
				}
				
				/* Add the attempt counter to the properties for later */
				CFDictionaryAddValue(ctxt->_properties, _kCFStreamPropertySocketAddressAttempt, a);
				CFRelease(a);
				
				/* Point the attempt at the counter */
				attempt = (SInt32*)CFDataGetMutableBytePtr(a);
				
				/* Start counting at zero. */
				*attempt = 0;
			}
			
			/* Get the address list from the lookup. */
			if (CFGetTypeID(lookup) == CFHostGetTypeID())
				list = CFHostGetAddressing((CFHostRef)lookup, NULL);
			else
				list = CFNetServiceGetAddressing((CFNetServiceRef)lookup);
			
			/* If there were no addresses, return an error. */
			if (!list || (*attempt >= (count = CFArrayGetCount(list)))) {
			
				if (!ctxt->_error.error) {
					ctxt->_error.error = EAI_NODATA;
					ctxt->_error.domain = kCFStreamErrorDomainNetDB;
				}
				
				/* Not needed anymore. */
				if (port) CFRelease(port);
				
				break;
			}
			
			/* Go through the list until a usable address is found */
			do {
				/* Create the address for connecting. */
				address = _CFDataCopyAddressByInjectingPort((CFDataRef)CFArrayGetValueAtIndex(list, *attempt), port);
				
				/* The next attempt will be the next address in the list. */
				*attempt = *attempt + 1;
				
				/* Only try to connect if there is an address */
				if (address) {
					
					/* If there was a socket, only need to connect it. */
					if (ctxt->_socket) {
						
						/*
						 ** If a socket was created previously, there is only one attempt
						 ** since the required socket type and protocol aren't known.
						 */
						*attempt = count;
						
						/* Start the connection. */
						_SocketStreamConnect_NoLock(ctxt, address);			
					}
					
					/* Try to create and start connecting to the address */
					else if (_SocketStreamCreateSocket_NoLock(ctxt, address))
						_SocketStreamConnect_NoLock(ctxt, address);
					
					/* No longer need the address */
					CFRelease(address);
					
					/* If succeeded in starting connect, don't continue anymore. */
					if (!ctxt->_error.error) {
						
						/* Not needed anymore. */
						if (port) CFRelease(port);

						return TRUE;				/* NOTE the early return here. */
					}
				}
			
			/* Continue through the list until all are exhausted. */
			} while (*attempt < count);
			
			/* Not needed anymore. */
			if (port) CFRelease(port);
			
			/*
			 ** It's an error to get to this point.  It means that none
			 ** of the addresses were suitable or worked.
			 */

			if (!ctxt->_error.error) {
				ctxt->_error.error = EINVAL;
				ctxt->_error.domain = kCFStreamErrorDomainPOSIX;
			}
				
			break;
		}
		
		/* If there is no lookup and no socket, something is bad. */
		else {
			
			int i;
			int yes = 1;
			CFOptionFlags flags;
			CFBooleanRef boolean;
			CFSocketNativeHandle s;		
			CFSocketContext c = {0, ctxt, NULL, NULL, NULL};
			CFArrayRef loops[3] = {ctxt->_readloops, ctxt->_writeloops, ctxt->_sharedloops};
			
			if (!ctxt->_socket) {
				
				/* Try to get the native socket for creation. */
				CFDataRef wrapper = (CFDataRef)CFDictionaryGetValue(ctxt->_properties, kCFStreamPropertySocketNativeHandle);
				
				if (!wrapper) {
					ctxt->_error.error = EINVAL;
					ctxt->_error.domain = kCFStreamErrorDomainPOSIX;
					break;
				}
				
				/* Create the CFSocket for riding. */
				ctxt->_socket = CFSocketCreateWithNative(CFGetAllocator(ctxt->_properties),
														 *((CFSocketNativeHandle*)CFDataGetBytePtr(wrapper)),
														 kSocketEvents,
														 (CFSocketCallBack)_SocketCallBack,
														 &c);
				
				if (!ctxt->_socket) {
					
					/*
					 ** Try to pull any error that may have just occurred.  If none,
					 ** assume an out of memory occurred.
					 */
					if (!_LastError(&ctxt->_error)) {
						ctxt->_error.error = ENOMEM;
						ctxt->_error.domain = kCFStreamErrorDomainPOSIX;
					}
					
					break;
				}
				
				/* Remove the cached value so it's only created when the client asks for it. */
				CFDictionaryRemoveValue(ctxt->_properties, kCFStreamPropertySocketNativeHandle);
			}
			
			/*
			** No host lookup and a socket means that the streams were
			** created with a connected socket already.
			*/

			__CFBitSet(ctxt->_flags, kFlagBitOpenComplete);
			__CFBitClear(ctxt->_flags, kFlagBitPollOpen);

			/* Get the native socket for setting options. */
			s = CFSocketGetNative(ctxt->_socket);
			
#if !defined(__WIN32)
			/* Turn off SIGPIPE on the socket (SIGPIPE doesn't exist on WIN32) */
			setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(yes));
#endif
			
			/* Place the socket in nonblocking mode. */
			ioctl(s, FIONBIO, (void*)&yes);
			
			/* Get the current socket flags and turn off the auto re-enable for reads and writes. */
			flags = CFSocketGetSocketFlags(ctxt->_socket) &
				~kCFSocketAutomaticallyReenableReadCallBack &
				~kCFSocketAutomaticallyReenableWriteCallBack;
			
			/* Find out if CFSocket should close the socket on invalidation. */
			boolean = (CFBooleanRef)CFDictionaryGetValue(ctxt->_properties, kCFStreamPropertyShouldCloseNativeSocket);
			
			/* Adjust the flags on the setting.  No value is the default which means to close. */
			if (!boolean || (boolean != kCFBooleanFalse))
				flags |= kCFSocketCloseOnInvalidate;
			else
				flags &= ~kCFSocketCloseOnInvalidate;
			
			/* Set up the correct flags and enable the callbacks. */
			CFSocketSetSocketFlags(ctxt->_socket, flags);
			CFSocketEnableCallBacks(ctxt->_socket, kCFSocketReadCallBack | kCFSocketWriteCallBack);
			
			/* Now schedule the socket on all loops and modes */
			for (i = 0; i < (sizeof(loops) / sizeof(loops[0])); i++)
				_CFTypeScheduleOnMultipleRunLoops(ctxt->_socket, loops[i]);
			
			/* Succeeded so make sure the socket is in the list of schedulables for future. */
			_SchedulablesAdd(ctxt->_schedulables, ctxt->_socket);
		}
		
		return TRUE;
		
	} while (0);
	
	return FALSE;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值