Exemple #1
0
/* extern */ void
_CFTypeInvalidate(CFTypeRef obj) {

	CFTypeID t = CFGetTypeID(obj);

	/* Invalidate according to type of object. */
	if (t == CFRunLoopSourceGetTypeID()) {
		CFRunLoopSourceInvalidate((CFRunLoopSourceRef)obj);
	}

	else if (t == CFMachPortGetTypeID()) {
		CFMachPortInvalidate((CFMachPortRef)obj);
	}

	else if (t == CFSocketGetTypeID()) {
		CFSocketInvalidate((CFSocketRef)obj);
	}

	/* For scheduled types of objects, it is invalidated by setting the client to NULL. */
	else if (t == CFReadStreamGetTypeID()) {
		CFReadStreamSetClient((CFReadStreamRef)obj, kCFStreamEventNone, NULL, NULL);
	}

	else if (t == CFWriteStreamGetTypeID()) {
		CFWriteStreamSetClient((CFWriteStreamRef)obj, kCFStreamEventNone, NULL, NULL);
	}

	else if (t == CFHostGetTypeID()) {
		CFHostSetClient((CFHostRef)obj, NULL, NULL);
	}

	else if (t == SCNetworkReachabilityGetTypeID()) {
		SCNetworkReachabilitySetCallback((SCNetworkReachabilityRef)obj, NULL, NULL);
	}

	else if (t == CFRunLoopTimerGetTypeID()) {
		CFRunLoopTimerInvalidate((CFRunLoopTimerRef)obj);
	}

	else if (t == CFNetServiceGetTypeID()) {
		CFNetServiceSetClient((CFNetServiceRef)obj, NULL, NULL);
	}

	else if (t == CFNetServiceBrowserGetTypeID()) {
		CFNetServiceBrowserInvalidate((CFNetServiceBrowserRef)obj);
	}

	else if (t == CFNetServiceMonitorGetTypeID()) {
		CFNetServiceMonitorInvalidate((CFNetServiceMonitorRef)obj);
	}

	else if (t == SCNetworkReachabilityGetTypeID()) {
		SCNetworkConnectionStop((SCNetworkConnectionRef)obj, FALSE);
	}
}
Exemple #2
0
/* extern */ void
_CFTypeScheduleOnRunLoop(CFTypeRef obj, CFRunLoopRef runLoop, CFStringRef runLoopMode) {

	CFTypeID t = CFGetTypeID(obj);
	CFTypeRef src = NULL;
	void(*fn)(CFTypeRef, CFRunLoopRef, CFStringRef);
	void(*fn2)(CFRunLoopRef, CFTypeRef, CFStringRef);

	fn = NULL;
	fn2 = (void(*)(CFRunLoopRef, CFTypeRef, CFStringRef))CFRunLoopAddSource;

	/* Get the correct source or function used for adding the object to the run loop. */
	if (t == CFRunLoopSourceGetTypeID()) {
		src = CFRetain(obj);
	}

	else if (t == CFMachPortGetTypeID()) {
		src = CFMachPortCreateRunLoopSource(CFGetAllocator(obj), (CFMachPortRef)obj, 0);
	}

	else if (t == CFSocketGetTypeID()) {
		src = CFSocketCreateRunLoopSource(CFGetAllocator(obj), (CFSocketRef)obj, 0);
	}

	else if (t == CFReadStreamGetTypeID()) {
		fn = (void(*)(CFTypeRef, CFRunLoopRef, CFStringRef))CFReadStreamScheduleWithRunLoop;
	}

	else if (t == CFWriteStreamGetTypeID()) {
		fn = (void(*)(CFTypeRef, CFRunLoopRef, CFStringRef))CFWriteStreamScheduleWithRunLoop;
	}

	else if (t == CFHostGetTypeID()) {
		fn = (void(*)(CFTypeRef, CFRunLoopRef, CFStringRef))CFHostScheduleWithRunLoop;
	}

	else if (t == SCNetworkReachabilityGetTypeID()) {
		fn = (void(*)(CFTypeRef, CFRunLoopRef, CFStringRef))SCNetworkReachabilityScheduleWithRunLoop;
	}

	else if (t == CFRunLoopTimerGetTypeID()) {
		src = CFRetain(obj);
		fn2 = (void(*)(CFRunLoopRef, CFTypeRef, CFStringRef))CFRunLoopAddTimer;
	}

	else if (t == CFNetServiceGetTypeID()) {
		fn = (void(*)(CFTypeRef, CFRunLoopRef, CFStringRef))CFNetServiceScheduleWithRunLoop;
	}

	else if (t == CFNetServiceBrowserGetTypeID()) {
		fn = (void(*)(CFTypeRef, CFRunLoopRef, CFStringRef))CFNetServiceBrowserScheduleWithRunLoop;
	}

	else if (t == CFNetServiceMonitorGetTypeID()) {
		fn = (void(*)(CFTypeRef, CFRunLoopRef, CFStringRef))CFNetServiceMonitorScheduleWithRunLoop;
	}

	else if (t == SCNetworkConnectionGetTypeID()) {
		fn = (void(*)(CFTypeRef, CFRunLoopRef, CFStringRef))SCNetworkConnectionScheduleWithRunLoop;
	}


	/* If a source was retrieved, need to add the source */
	if (src) {
		fn2(runLoop, src, runLoopMode);
		CFRelease(src);
	}

	/* If a schedule function was retrieved, call it. */
	else if (fn) {
		fn(obj, runLoop, runLoopMode);
	}
}
Exemple #3
0
/* extern */ void
_CFTypeUnscheduleFromMultipleRunLoops(CFTypeRef obj, CFArrayRef schedules) {

	CFTypeID t = CFGetTypeID(obj);
	CFTypeRef src = NULL;
	void(*fn)(CFTypeRef, CFRunLoopRef, CFStringRef);
	void(*fn2)(CFRunLoopRef, CFTypeRef, CFStringRef);

	fn = NULL;
	fn2 = (void(*)(CFRunLoopRef, CFTypeRef, CFStringRef))CFRunLoopRemoveSource;

	/* Get the proper source or function for removing the object from the run loop. */
	if (t == CFRunLoopSourceGetTypeID()) {
		src = CFRetain(obj);
	}

	else if (t == CFMachPortGetTypeID()) {
		src = CFMachPortCreateRunLoopSource(CFGetAllocator(obj), (CFMachPortRef)obj, 0);
	}

	else if (t == CFSocketGetTypeID()) {
		src = CFSocketCreateRunLoopSource(CFGetAllocator(obj), (CFSocketRef)obj, 0);
	}

	else if (t == CFReadStreamGetTypeID()) {
		fn = (void(*)(CFTypeRef, CFRunLoopRef, CFStringRef))CFReadStreamUnscheduleFromRunLoop;
	}

	else if (t == CFWriteStreamGetTypeID()) {
		fn = (void(*)(CFTypeRef, CFRunLoopRef, CFStringRef))CFWriteStreamUnscheduleFromRunLoop;
	}

	else if (t == CFHostGetTypeID()) {
		fn = (void(*)(CFTypeRef, CFRunLoopRef, CFStringRef))CFHostUnscheduleFromRunLoop;
	}

	else if (t == SCNetworkReachabilityGetTypeID()) {
		fn = (void(*)(CFTypeRef, CFRunLoopRef, CFStringRef))SCNetworkReachabilityUnscheduleFromRunLoop;
	}

	else if (t == CFRunLoopTimerGetTypeID()) {
		src = CFRetain(obj);
		fn2 = (void(*)(CFRunLoopRef, CFTypeRef, CFStringRef))CFRunLoopRemoveTimer;
	}

	else if (t == CFNetServiceGetTypeID()) {
		fn = (void(*)(CFTypeRef, CFRunLoopRef, CFStringRef))CFNetServiceUnscheduleFromRunLoop;
	}

	else if (t == CFNetServiceBrowserGetTypeID()) {
		fn = (void(*)(CFTypeRef, CFRunLoopRef, CFStringRef))CFNetServiceBrowserUnscheduleFromRunLoop;
	}

	else if (t == CFNetServiceMonitorGetTypeID()) {
		fn = (void(*)(CFTypeRef, CFRunLoopRef, CFStringRef))CFNetServiceMonitorUnscheduleFromRunLoop;
	}

	else if (t == SCNetworkConnectionGetTypeID()) {
		fn = (void(*)(CFTypeRef, CFRunLoopRef, CFStringRef))SCNetworkConnectionUnscheduleFromRunLoop;
	}

	/* If a source was retrieved, need to remove it from the list of run loops*/
	if (src) {

		CFIndex i, length = CFArrayGetCount(schedules);

		for (i = 0; i < length; i += 2) {
			fn2((CFRunLoopRef)CFArrayGetValueAtIndex(schedules, i),
				src,
				(CFStringRef)CFArrayGetValueAtIndex(schedules, i + 1));
		}

		CFRelease(src);
	}

	/* If an unschedule function was retrieved, need to call it for each schedule in the list. */
	else if (fn) {

		CFIndex i, length = CFArrayGetCount(schedules);

		for (i = 0; i < length; i += 2) {
			fn(obj,
			   (CFRunLoopRef)CFArrayGetValueAtIndex(schedules, i),
			   (CFStringRef)CFArrayGetValueAtIndex(schedules, i + 1));
		}
	}
}
Exemple #4
0
/* extern */ void
_CFTypeUnscheduleFromRunLoop(CFTypeRef obj, CFRunLoopRef runLoop, CFStringRef runLoopMode) {

	CFTypeID t = CFGetTypeID(obj);
	CFTypeRef src = NULL;
	void(*fn)(CFTypeRef, CFRunLoopRef, CFStringRef);
	void(*fn2)(CFRunLoopRef, CFTypeRef, CFStringRef);

	fn = NULL;
	fn2 = (void(*)(CFRunLoopRef, CFTypeRef, CFStringRef))CFRunLoopRemoveSource;

	/* Get the proper source or function for removing the object from the run loop. */
	if (t == CFRunLoopSourceGetTypeID()) {
		src = CFRetain(obj);
	}

	else if (t == CFMachPortGetTypeID()) {
		src = CFMachPortCreateRunLoopSource(CFGetAllocator(obj), (CFMachPortRef)obj, 0);
	}

	else if (t == CFSocketGetTypeID()) {
		src = CFSocketCreateRunLoopSource(CFGetAllocator(obj), (CFSocketRef)obj, 0);
	}

	else if (t == CFReadStreamGetTypeID()) {
		fn = (void(*)(CFTypeRef, CFRunLoopRef, CFStringRef))CFReadStreamUnscheduleFromRunLoop;
	}

	else if (t == CFWriteStreamGetTypeID()) {
		fn = (void(*)(CFTypeRef, CFRunLoopRef, CFStringRef))CFWriteStreamUnscheduleFromRunLoop;
	}

	else if (t == CFHostGetTypeID()) {
		fn = (void(*)(CFTypeRef, CFRunLoopRef, CFStringRef))CFHostUnscheduleFromRunLoop;
	}

	else if (t == SCNetworkReachabilityGetTypeID()) {
		fn = (void(*)(CFTypeRef, CFRunLoopRef, CFStringRef))SCNetworkReachabilityUnscheduleFromRunLoop;
	}

	else if (t == CFRunLoopTimerGetTypeID()) {
		src = CFRetain(obj);
		fn2 = (void(*)(CFRunLoopRef, CFTypeRef, CFStringRef))CFRunLoopRemoveTimer;
	}

	else if (t == CFNetServiceGetTypeID()) {
		fn = (void(*)(CFTypeRef, CFRunLoopRef, CFStringRef))CFNetServiceUnscheduleFromRunLoop;
	}

	else if (t == CFNetServiceBrowserGetTypeID()) {
		fn = (void(*)(CFTypeRef, CFRunLoopRef, CFStringRef))CFNetServiceBrowserUnscheduleFromRunLoop;
	}

	else if (t == CFNetServiceMonitorGetTypeID()) {
		fn = (void(*)(CFTypeRef, CFRunLoopRef, CFStringRef))CFNetServiceMonitorUnscheduleFromRunLoop;
	}

	else if (t == SCNetworkConnectionGetTypeID()) {
		fn = (void(*)(CFTypeRef, CFRunLoopRef, CFStringRef))SCNetworkConnectionUnscheduleFromRunLoop;
	}

	/* If a source was retrieved, need to remove it */
	if (src) {
		fn2(runLoop, src, runLoopMode);
		CFRelease(src);
	}

	/* If an unschedule function was retrieved, need to call it. */
	else if (fn) {
		fn(obj, runLoop, runLoopMode);
	}
}
void
rwsched_cfsocket_callout_intercept(CFSocketRef s,
				   CFSocketCallBackType type,
				   CFDataRef address,
				   const void *data,
				   void *info)
{
  rwsched_instance_ptr_t instance;
  rwsched_tasklet_ptr_t sched_tasklet;
  rwsched_cfsocket_callback_context_ptr_t callback_context;
  rwsched_CFSocketRef cfsocket = (rwsched_CFSocketRef) info;

  // Validate input parameters
  __CFGenericValidateType_(s, CFSocketGetTypeID(), __PRETTY_FUNCTION__);
  RW_CF_TYPE_VALIDATE(cfsocket, rwsched_CFSocketRef);
  callback_context = &cfsocket->callback_context;
  instance = callback_context->instance;
  RW_CF_TYPE_VALIDATE(instance, rwsched_instance_ptr_t);
  sched_tasklet = callback_context->tasklet_info;
  RW_CF_TYPE_VALIDATE(sched_tasklet, rwsched_tasklet_ptr_t);

  // #1 - Check to see if the cfsocket matches the current blocking source for the tasklet
  // #2 - Otherwise check if the current tasklet is in blocking mode and then relocate the runloop source
  // #3 - Otherwise the current tasklet is not blocking and the event can be processed now
  if (sched_tasklet->blocking_mode.cfsource == callback_context->cfsource) {
    // Abort the runloop that is currently blocking
    CFRunLoopRef rl = CFRunLoopGetCurrent();
    CFRunLoopStop(rl);
  }
  else if (sched_tasklet->blocking_mode.cfsource) {
    // The task is blocking and this event CANNOT be processed yet, so move it to a different runloop mode
    rwsched_cfrunloop_relocate_source(sched_tasklet, callback_context->cfsource);
  }
  else {
    // The current task is not blocking so we can invoke the callback now
    RW_ASSERT(callback_context->cf_callout);
    g_rwresource_track_handle = sched_tasklet->rwresource_track_handle;
    g_tasklet_info = sched_tasklet;


    struct timeval tv_begin, tv_end, tv_delta;
    if (sched_tasklet->instance->latency.check_threshold_ms) {
      gettimeofday(&tv_begin, NULL);
    } else {
      tv_begin.tv_sec = 0;
    }

    (*callback_context->cf_callout)(cfsocket, type, address, data, callback_context->cf_context.info);

    if (tv_begin.tv_sec
	&& sched_tasklet->instance->latency.check_threshold_ms) {
      gettimeofday(&tv_end, NULL);
      timersub(&tv_end, &tv_begin, &tv_delta);
      unsigned int cbms = (tv_delta.tv_sec * 1000 + tv_delta.tv_usec / 1000);
      if (cbms >= sched_tasklet->instance->latency.check_threshold_ms) {
	char *name = rw_btrace_get_proc_name(callback_context->cf_callout);
  RWSCHED_LOG_EVENT(instance, SchedDebug, RWLOG_ATTR_SPRINTF("rwsched[%d] CF socket/file took %ums ctx %p callback %s", 
                                                             getpid(), cbms, callback_context->cf_context.info, name));
	free(name);
      }
    }

    g_tasklet_info = 0;
    g_rwresource_track_handle = 0;
  }
}
/* CF_EXPORT */ Boolean
CFNetServiceBrowserSearchForServices(CFNetServiceBrowserRef b, CFStringRef domain, CFStringRef type, CFStreamError* error) {

	__CFNetServiceBrowser* browser = (__CFNetServiceBrowser*)b;

	CFStreamError extra;
	Boolean result = FALSE;

	if (!error)
		error = &extra;

	memset(error, 0, sizeof(error[0]));

	// Retain so it doesn't go away underneath in the case of a callout.  This is really
	// no worry for async, but makes the memmove for the error more difficult to place
	// for synchronous without it being here.
	CFRetain(browser);

	// Lock down the browser to start search
	__CFSpinLock(&(browser->_lock));

	do {

		int i;
        char properties[2][1024];
        CFStringRef argProperties[] = {type, domain};
		CFSocketContext ctxt = {0, browser, CFRetain, CFRelease, NULL};

		if (!browser->_callback) {
			browser->_error.error = kCFNetServicesErrorInvalid;
			browser->_error.domain = kCFStreamErrorDomainNetServices;
			break;
		}

		// Check to see if there is an ongoing search already
		if (browser->_trigger) {

			// If it's a mdns search, don't allow another.
			if (CFGetTypeID(browser->_trigger) == CFSocketGetTypeID()) {
				browser->_error.error = kCFNetServicesErrorInProgress;
				browser->_error.domain = kCFStreamErrorDomainNetServices;
				break;
			}

			// It's just the cancel that hasn't fired yet, so cancel it.
			else {

				// Remove the trigger from run loops and modes
				_CFTypeUnscheduleFromMultipleRunLoops(browser->_trigger, browser->_schedules);

				// Invalidate the run loop source
				CFRunLoopSourceInvalidate((CFRunLoopSourceRef)(browser->_trigger));

				// Release the trigger now.
				CFRelease(browser->_trigger);
				browser->_trigger = NULL;
			}
		}

		// Convert the type and domain to c strings to pass down
        for (i = 0; i < (sizeof(properties) / sizeof(properties[0])); i++) {

            if (!argProperties[i])
                properties[i][0] = '\0';
            else {
                CFIndex bytesUsed;

                CFStringGetBytes(argProperties[i],
                                CFRangeMake(0, CFStringGetLength(argProperties[i])),
                                kCFStringEncodingUTF8,
                                0,
                                FALSE,
                                (UInt8*)properties[i],
                                sizeof(properties[i]) - 1,
                                &bytesUsed);
                properties[i][bytesUsed] = '\0';
            }
        }

		browser->_domainSearch = FALSE;

		// Create the service search at the service discovery level
		browser->_error.error = DNSServiceBrowse(&browser->_browse,
												 0,
												 0,
												 properties[0],
												 properties[1],
												 _BrowseReply,
												 browser);

		// Fail if it did.
		if (browser->_error.error) {
			browser->_error.error = _DNSServiceErrorToCFNetServiceError(browser->_error.error);
			browser->_error.domain = kCFStreamErrorDomainNetServices;
			break;
		}

		// Create the trigger for the browse
		browser->_trigger = CFSocketCreateWithNative(CFGetAllocator(browser),
													 DNSServiceRefSockFD(browser->_browse),
													 kCFSocketReadCallBack,
													 _SocketCallBack,
													 &ctxt);

		// Make sure the CFSocket wrapper succeeded
		if (!browser->_trigger) {

			// Try to use errno for the error
			browser->_error.error = errno;

			// If it has no error in it, assume no memory
			if (!browser->_error.error)
				browser->_error.error = ENOMEM;

			// Correct domain and bail.
			browser->_error.domain = kCFStreamErrorDomainPOSIX;

			DNSServiceRefDeallocate(browser->_browse);
			browser->_browse = NULL;

			break;
		}

		// Tell CFSocket not to close the native socket on invalidation.
		CFSocketSetSocketFlags((CFSocketRef)browser->_trigger,
							   CFSocketGetSocketFlags((CFSocketRef)browser->_trigger) & ~kCFSocketCloseOnInvalidate);

		// Async mode is complete at this point
		if (CFArrayGetCount(browser->_schedules)) {

			// Schedule the trigger on the run loops and modes.
			_CFTypeScheduleOnMultipleRunLoops(browser->_trigger, browser->_schedules);

			// It's now succeeded.
			result = TRUE;
		}

		// If there is no callback, go into synchronous mode.
		else {

			// Unlock the browser
			__CFSpinUnlock(&(browser->_lock));

			// Wait for synchronous return
			result = _BrowserBlockUntilComplete(browser);

			// Lock down the browser
			__CFSpinLock(&(browser->_lock));
		}

	} while (0);

	// Copy the error.
	memmove(error, &browser->_error, sizeof(error[0]));

	// Unlock the browser
	__CFSpinUnlock(&(browser->_lock));

	// Release the earlier retain.
	CFRelease(browser);

	return result;
}