static void __CFMessagePortDeallocate(CFTypeRef cf) { CFMessagePortRef ms = (CFMessagePortRef)cf; __CFMessagePortSetIsDeallocing(ms); CFMessagePortInvalidate(ms); // Delay cleanup of _replies until here so that invalidation during // SendRequest does not cause _replies to disappear out from under that function. if (NULL != ms->_replies) { CFRelease(ms->_replies); } if (NULL != ms->_name) { CFRelease(ms->_name); } if (NULL != ms->_port) { if (__CFMessagePortExtraMachRef(ms)) { mach_port_mod_refs(mach_task_self(), CFMachPortGetPort(ms->_port), MACH_PORT_RIGHT_SEND, -1); mach_port_mod_refs(mach_task_self(), CFMachPortGetPort(ms->_port), MACH_PORT_RIGHT_RECEIVE, -1); } CFMachPortInvalidate(ms->_port); CFRelease(ms->_port); } // A remote message port for a local message port in the same process will get the // same mach port, and the remote port will keep the mach port from being torn down, // thus keeping the remote port from getting any sort of death notification and // auto-invalidating; so we manually implement the 'auto-invalidation' here by // tickling each remote port to check its state after any message port is destroyed, // but most importantly after local message ports are destroyed. __CFLock(&__CFAllMessagePortsLock); CFMessagePortRef *remotePorts = NULL; CFIndex cnt = 0; if (NULL != __CFAllRemoteMessagePorts) { cnt = CFDictionaryGetCount(__CFAllRemoteMessagePorts); remotePorts = CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(CFMessagePortRef), __kCFAllocatorGCScannedMemory); CFDictionaryGetKeysAndValues(__CFAllRemoteMessagePorts, NULL, (const void **)remotePorts); for (CFIndex idx = 0; idx < cnt; idx++) { CFRetain(remotePorts[idx]); } } __CFUnlock(&__CFAllMessagePortsLock); if (remotePorts) { for (CFIndex idx = 0; idx < cnt; idx++) { // as a side-effect, this will auto-invalidate the CFMessagePort if the CFMachPort is invalid CFMessagePortIsValid(remotePorts[idx]); CFRelease(remotePorts[idx]); } CFAllocatorDeallocate(kCFAllocatorSystemDefault, remotePorts); } }
static Boolean __CFMessagePortNativeSetNameLocal(CFMachPortRef port, uint8_t *portname) { mach_port_t bp; kern_return_t ret; task_get_bootstrap_port(mach_task_self(), &bp); ret = bootstrap_register(bp, portname, CFMachPortGetPort(port)); return (ret == KERN_SUCCESS) ? true : false; }
void CFMessagePortInvalidate(CFMessagePortRef ms) { __CFGenericValidateType(ms, __kCFMessagePortTypeID); if (!__CFMessagePortIsDeallocing(ms)) { CFRetain(ms); } __CFMessagePortLock(ms); if (__CFMessagePortIsValid(ms)) { CFMessagePortInvalidationCallBack callout = ms->_icallout; CFRunLoopSourceRef source = ms->_source; CFMachPortRef replyPort = ms->_replyPort; CFMachPortRef port = ms->_port; CFStringRef name = ms->_name; void *info = NULL; __CFMessagePortUnsetValid(ms); if (!__CFMessagePortIsRemote(ms)) { info = ms->_context.info; ms->_context.info = NULL; } ms->_source = NULL; ms->_replyPort = NULL; __CFMessagePortUnlock(ms); __CFSpinLock(&__CFAllMessagePortsLock); if (NULL != (__CFMessagePortIsRemote(ms) ? __CFAllRemoteMessagePorts : __CFAllLocalMessagePorts)) { CFDictionaryRemoveValue(__CFMessagePortIsRemote(ms) ? __CFAllRemoteMessagePorts : __CFAllLocalMessagePorts, name); } __CFSpinUnlock(&__CFAllMessagePortsLock); if (NULL != callout) { callout(ms, info); } // We already know we're going invalid, don't need this callback // anymore; plus, this solves a reentrancy deadlock; also, this // must be done before the deallocate of the Mach port, to // avoid a race between the notification message which could be // handled in another thread, and this NULL'ing out. CFMachPortSetInvalidationCallBack(port, NULL); // For hashing and equality purposes, cannot get rid of _port here if (!__CFMessagePortIsRemote(ms) && NULL != ms->_context.release) { ms->_context.release(info); } if (NULL != source) { CFRunLoopSourceInvalidate(source); CFRelease(source); } if (NULL != replyPort) { CFMachPortInvalidate(replyPort); CFRelease(replyPort); } if (__CFMessagePortIsRemote(ms)) { // Get rid of our extra ref on the Mach port gotten from bs server mach_port_deallocate(mach_task_self(), CFMachPortGetPort(port)); } } else { __CFMessagePortUnlock(ms); } if (!__CFMessagePortIsDeallocing(ms)) { CFRelease(ms); } }
CFRunLoopSourceRef CreateIPCRunLoopSource(CFStringRef aPortName, StartupContext aStartupContext) { CFRunLoopSourceRef aSource = NULL; CFMachPortRef aMachPort = NULL; CFMachPortContext aContext; kern_return_t aKernReturn = KERN_FAILURE; aContext.version = 0; aContext.info = (void*) aStartupContext; aContext.retain = 0; aContext.release = 0; aContext.copyDescription = 0; aMachPort = CFMachPortCreate(NULL, NULL, &aContext, NULL); if (aMachPort && aPortName) { CFIndex aPortNameLength = CFStringGetLength(aPortName); CFIndex aPortNameSize = CFStringGetMaximumSizeForEncoding(aPortNameLength, kCFStringEncodingUTF8) + 1; uint8_t *aBuffer = CFAllocatorAllocate(NULL, aPortNameSize, 0); if (aBuffer && CFStringGetCString(aPortName, aBuffer, aPortNameSize, kCFStringEncodingUTF8)) { mach_port_t aBootstrapPort; task_get_bootstrap_port(mach_task_self(), &aBootstrapPort); aKernReturn = bootstrap_register(aBootstrapPort, aBuffer, CFMachPortGetPort(aMachPort)); } if (aBuffer) CFAllocatorDeallocate(NULL, aBuffer); } if (aMachPort && aKernReturn == KERN_SUCCESS) { CFRunLoopSourceContext1 aSourceContext; aSourceContext.version = 1; aSourceContext.info = aMachPort; aSourceContext.retain = CFRetain; aSourceContext.release = CFRelease; aSourceContext.copyDescription = CFCopyDescription; aSourceContext.equal = CFEqual; aSourceContext.hash = CFHash; aSourceContext.getPort = getIPCPort; aSourceContext.perform = (void*)handleIPCMessage; aSource = CFRunLoopSourceCreate(NULL, 0, (CFRunLoopSourceContext*)&aSourceContext); } if (aMachPort && (!aSource || aKernReturn != KERN_SUCCESS)) { CFMachPortInvalidate(aMachPort); CFRelease(aMachPort); aMachPort = NULL; } return aSource; }
void _SCDPluginExecInit() { struct sigaction act; CFMachPortContext context = { 0 , (void *)1 , NULL , NULL , childReapedMPCopyDescription }; CFRunLoopSourceRef rls; // create the "a child has been reaped" notification port childReaped = CFMachPortCreate(NULL, childrenReaped, &context, NULL); // set queue limit { mach_port_limits_t limits; kern_return_t status; limits.mpl_qlimit = 1; status = mach_port_set_attributes(mach_task_self(), CFMachPortGetPort(childReaped), MACH_PORT_LIMITS_INFO, (mach_port_info_t)&limits, MACH_PORT_LIMITS_INFO_COUNT); if (status != KERN_SUCCESS) { perror("mach_port_set_attributes"); } } // add to our runloop rls = CFMachPortCreateRunLoopSource(NULL, childReaped, 0); CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); CFRelease(rls); // enable signal handler act.sa_handler = reaper; sigemptyset(&act.sa_mask); act.sa_flags = SA_RESTART|SA_NOCLDSTOP; if (sigaction(SIGCHLD, &act, NULL) == -1) { perror("sigaction"); } return; }
static void reaper(int sigraised) { /* * block additional SIGCHLD's until current children have * been reaped. */ blockSignal(); /* * send message to indicate that at least one child is ready * to be reaped. */ _SC_sendMachMessage(CFMachPortGetPort(childReaped), 0); return; }
/* Radar 6386278 New launchd api is npot on embedded yet */ int ppp_mach_start_server() { boolean_t active; kern_return_t status; CFRunLoopSourceRef rls; active = FALSE; status = bootstrap_status(bootstrap_port, PPPCONTROLLER_SERVER, &active); switch (status) { case BOOTSTRAP_SUCCESS: if (active) { fprintf(stderr, "\"%s\" is currently active.\n", PPPCONTROLLER_SERVER); return -1; } break; case BOOTSTRAP_UNKNOWN_SERVICE: break; default: fprintf(stderr, "bootstrap_status(): %s\n", mach_error_string(status)); return -1; } gServer_cfport = CFMachPortCreate(NULL, server_handle_request, NULL, NULL); rls = CFMachPortCreateRunLoopSource(NULL, gServer_cfport, 0); gControllerRunloop = CFRunLoopGetCurrent(); CFRunLoopAddSource(gControllerRunloop, rls, kCFRunLoopDefaultMode); CFRunLoopAddSource(gControllerRunloop, gTerminalrls, kCFRunLoopDefaultMode); CFRelease(rls); status = bootstrap_register(bootstrap_port, PPPCONTROLLER_SERVER, CFMachPortGetPort(gServer_cfport)); if (status != BOOTSTRAP_SUCCESS) { mach_error("bootstrap_register", status); return -1; } return 0; }
static void init_self_audittoken(void) { /* create a mach port and an event source */ CFMachPortRef server_port = CFMachPortCreate (NULL, server_callback, NULL, false); CFRunLoopSourceRef server_source = CFMachPortCreateRunLoopSource(NULL, server_port, 0/*order*/); /* add the source to the current run loop */ CFRunLoopAddSource(CFRunLoopGetCurrent(), server_source, kCFRunLoopDefaultMode); CFRelease(server_source); /* Send the request */ sectask_client_request(CFMachPortGetPort(server_port)); /* Run the loop to process the message */ CFRunLoopRun(); /* done */ CFRelease(server_port); }
__private_extern__ int server_shutdown() { if (configd_port != NULL) { mach_port_t service_port = CFMachPortGetPort(configd_port); CFMachPortInvalidate(configd_port); CFRelease(configd_port); configd_port = NULL; if (service_port != MACH_PORT_NULL) { (void) mach_port_mod_refs(mach_task_self(), service_port, MACH_PORT_RIGHT_RECEIVE, -1); } } return EX_OK; }
static void __DACommandSignal( int sig ) { /* * Process a SIGCHLD signal. mach_msg() is safe from a signal handler. */ mach_msg_header_t message; kern_return_t status; message.msgh_bits = MACH_MSGH_BITS( MACH_MSG_TYPE_COPY_SEND, 0 ); message.msgh_id = 0; message.msgh_local_port = MACH_PORT_NULL; message.msgh_remote_port = CFMachPortGetPort( __gDACommandRunLoopSourcePort ); message.msgh_reserved = 0; message.msgh_size = sizeof( message ); status = mach_msg( &message, MACH_SEND_MSG | MACH_SEND_TIMEOUT, message.msgh_size, 0, MACH_PORT_NULL, 0, MACH_PORT_NULL ); if ( status == MACH_SEND_TIMED_OUT ) { mach_msg_destroy( &message ); } }
kern_return_t CACFMachPort::ReceiveMessage(UInt32 inMaxMessageSize, mach_msg_header_t* outMessage, mach_msg_timeout_t inTimeOut) { // snag the port mach_port_t thePort = CFMachPortGetPort(mMachPort); // fill out the message header outMessage->msgh_bits = 0; outMessage->msgh_size = 0; outMessage->msgh_remote_port = MACH_PORT_NULL; outMessage->msgh_local_port = thePort; outMessage->msgh_reserved = 0; outMessage->msgh_id = 0; // figure the options mach_msg_options_t theOptions = MACH_RCV_MSG; if(inTimeOut > 0) { theOptions |= MACH_RCV_TIMEOUT; } // receive the messsage return mach_msg(outMessage, theOptions, 0, inMaxMessageSize, thePort, inTimeOut, MACH_PORT_NULL); }
/*! Opens a connection to the iSCSI initiator. A connection must be * successfully opened before any of the supporting functions below can be * called. */ errno_t iSCSIKernelInitialize(iSCSIKernelNotificationCallback callback) { kern_return_t result; // Create a dictionary to match iSCSIkext CFMutableDictionaryRef matchingDict = NULL; matchingDict = IOServiceMatching(kiSCSIVirtualHBA_IOClassName); service = IOServiceGetMatchingService(kIOMasterPortDefault,matchingDict); // Check to see if the driver was found in the I/O registry if(service == IO_OBJECT_NULL) return kIOReturnNotFound; // Using the service handle, open a connection result = IOServiceOpen(service,mach_task_self(),0,&connection); if(result != kIOReturnSuccess) { IOObjectRelease(service); return kIOReturnNotFound; } notificationContext.info = (void *)¬ificationContext; notificationContext.version = 0; notificationContext.release = NULL; notificationContext.retain = NULL; notificationContext.copyDescription = NULL; // Create a mach port to receive notifications from the kernel notificationPort = CFMachPortCreate(kCFAllocatorDefault, iSCSIKernelNotificationHandler, ¬ificationContext,NULL); IOConnectSetNotificationPort(connection,0,CFMachPortGetPort(notificationPort),0); return IOReturnToErrno(IOConnectCallScalarMethod(connection,kiSCSIOpenInitiator,0,0,0,0)); }
/** * A CFMachPort invalidation callback that records the termination of * a startup item task. Stops the current run loop to give system_starter * another go at running items. **/ static void startupItemTerminated (CFMachPortRef aMachPort, void *anInfo) { TerminationContext aTerminationContext = (TerminationContext) anInfo; if (aMachPort) { mach_port_deallocate(mach_task_self(), CFMachPortGetPort(aMachPort)); } if (aTerminationContext && aTerminationContext->anItem) { pid_t aPID = 0; pid_t rPID = 0; int aStatus = 0; CFMutableDictionaryRef anItem = aTerminationContext->anItem; StartupContext aStartupContext = aTerminationContext->aStartupContext; /* Get the exit status */ if (anItem) { aPID = StartupItemGetPID(anItem); if (aPID > 0) rPID = waitpid(aPID, &aStatus, WNOHANG); } if (aStartupContext) { --aStartupContext->aRunningCount; /* Record the item's status */ if (aStartupContext->aStatusDict) { StartupItemExit(aStartupContext->aStatusDict, anItem, (WIFEXITED(aStatus) && WEXITSTATUS(aStatus) == 0)); if (aStatus) { warning(CFSTR("%@ (%d) did not complete successfully.\n"), CFDictionaryGetValue(anItem, CFSTR("Description")), aPID); } else { if (gDebugFlag) debug(CFSTR("Finished %@ (%d)\n"), CFDictionaryGetValue(anItem, CFSTR("Description")), aPID); } displayProgress(aStartupContext->aDisplayContext, ((float)CFDictionaryGetCount(aStartupContext->aStatusDict)/((float)aStartupContext->aServicesCount + 1.0))); } /* If the item failed to start, then add it to the failed list */ if (WEXITSTATUS(aStatus) || WTERMSIG(aStatus) || WCOREDUMP(aStatus)) { CFDictionarySetValue(anItem, kErrorKey, kErrorReturnNonZero); AddItemToFailedList(aStartupContext, anItem); } /* Remove the item from the waiting list regardless if it was successful or it failed. */ RemoveItemFromWaitingList(aStartupContext, anItem); } } if (aTerminationContext) free(aTerminationContext); /* Stop the current run loop so the system_starter engine will cycle and try to start any newly eligible items */ CFRunLoopStop(CFRunLoopGetCurrent()); }
//------------------------------------------------------------------------------ // IOMIGMachPortGetPort //------------------------------------------------------------------------------ mach_port_t IOMIGMachPortGetPort(IOMIGMachPortRef migPort) { return CFMachPortGetPort(migPort->port); }
IOReturn IOPSCreatePowerSource( IOPSPowerSourceID *outPS, CFStringRef powerSourceType) { IOPSPowerSourceID newPS = NULL; mach_port_t pm_server = MACH_PORT_NULL; char psType[kMaxPSTypeLength]; char scdsKey[kMaxSCDSKeyLength]; mach_port_t local_port = MACH_PORT_NULL; int return_code = kIOReturnSuccess; kern_return_t kr = KERN_SUCCESS; IOReturn ret = kIOReturnError; if (!powerSourceType || !outPS) return kIOReturnBadArgument; // newPS - This tracking structure must be freed by IOPSReleasePowerSource() newPS = calloc(1, sizeof(struct OpaqueIOPSPowerSourceID)); if (!newPS) return kIOReturnVMError; // We allocate a port in our namespace, and pass it to configd. // If this process dies, configd will cleanup our unattached power sources. newPS->configdConnection = CFMachPortCreate(kCFAllocatorDefault, NULL, NULL, NULL); if (newPS->configdConnection) local_port = CFMachPortGetPort(newPS->configdConnection); if (MACH_PORT_NULL == local_port) { ret = kIOReturnInternalError; goto fail; } if (!CFStringGetCString(powerSourceType, psType, sizeof(psType), kCFStringEncodingMacRoman)) { ret = kIOReturnBadMedia; goto fail; } ret = _pm_connect(&pm_server); if(kIOReturnSuccess != ret) { ret = kIOReturnNotOpen; goto fail; } kr = io_pm_new_pspowersource( pm_server, local_port, // in: mach port psType, // in: type name scdsKey, // out: SCDS key &return_code); // out: Return code if(KERN_SUCCESS != kr) { ret = kIOReturnNotResponding; goto fail; } _pm_disconnect(pm_server); newPS->scdsKey = CFStringCreateWithCString(0, scdsKey, kCFStringEncodingUTF8); // success: *outPS = newPS; return (IOReturn)return_code; fail: if (newPS) free(newPS); if (IO_OBJECT_NULL != pm_server) _pm_disconnect(pm_server); *outPS = NULL; return ret; }
CFRunLoopSourceRef DACommandCreateRunLoopSource( CFAllocatorRef allocator, CFIndex order ) { /* * Create a CFRunLoopSource for DACommand callbacks. */ CFRunLoopSourceRef source = NULL; pthread_mutex_lock( &__gDACommandRunLoopSourceLock ); /* * Initialize our minimal state. */ if ( __gDACommandRunLoopSourcePort == NULL ) { /* * Create the global CFMachPort. It will be used to post jobs to the run loop. */ __gDACommandRunLoopSourcePort = CFMachPortCreate( kCFAllocatorDefault, __DACommandRunLoopSourceCallback, NULL, NULL ); if ( __gDACommandRunLoopSourcePort ) { /* * Set up the global CFMachPort. It requires no more than one queue element. */ mach_port_limits_t limits = { 0 }; limits.mpl_qlimit = 1; mach_port_set_attributes( mach_task_self( ), CFMachPortGetPort( __gDACommandRunLoopSourcePort ), MACH_PORT_LIMITS_INFO, ( mach_port_info_t ) &limits, MACH_PORT_LIMITS_INFO_COUNT ); } if ( __gDACommandRunLoopSourcePort ) { /* * Set up the global signal handler to catch child status changes from BSD. */ sig_t sig; sig = signal( SIGCHLD, __DACommandSignal ); if ( sig == SIG_ERR ) { CFRelease( __gDACommandRunLoopSourcePort ); __gDACommandRunLoopSourcePort = NULL; } } } /* * Obtain the CFRunLoopSource for our CFMachPort. */ if ( __gDACommandRunLoopSourcePort ) { source = CFMachPortCreateRunLoopSource( allocator, __gDACommandRunLoopSourcePort, order ); } pthread_mutex_unlock( &__gDACommandRunLoopSourceLock ); return source; }
static void rlsSchedule(void *info, CFRunLoopRef rl, CFStringRef mode) { SCDynamicStoreRef store = (SCDynamicStoreRef)info; SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; #ifdef DEBUG SCLog(_sc_verbose, LOG_DEBUG, CFSTR("schedule notifications for mode %@"), (rl != NULL) ? mode : CFSTR("libdispatch")); #endif /* DEBUG */ if (storePrivate->rlList == NULL) { CFMachPortContext context = { 0 , (void *)store , CFRetain , CFRelease , notifyMPCopyDescription }; mach_port_t oldNotify; mach_port_t port; int sc_status; kern_return_t status; #ifdef DEBUG SCLog(_sc_verbose, LOG_DEBUG, CFSTR(" activate callback runloop source")); #endif /* DEBUG */ /* Allocating port (for server response) */ status = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port); if (status != KERN_SUCCESS) { SCLog(TRUE, LOG_ERR, CFSTR("rlsSchedule mach_port_allocate(): %s"), mach_error_string(status)); return; } status = mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND); if (status != KERN_SUCCESS) { /* * We can't insert a send right into our own port! This should * only happen if someone stomped on OUR port (so let's leave * the port alone). */ SCLog(TRUE, LOG_ERR, CFSTR("rlsSchedule mach_port_insert_right(): %s"), mach_error_string(status)); return; } /* Request a notification when/if the server dies */ status = mach_port_request_notification(mach_task_self(), port, MACH_NOTIFY_NO_SENDERS, 1, port, MACH_MSG_TYPE_MAKE_SEND_ONCE, &oldNotify); if (status != KERN_SUCCESS) { /* * We can't request a notification for our own port! This should * only happen if someone stomped on OUR port (so let's leave * the port alone). */ SCLog(TRUE, LOG_ERR, CFSTR("rlsSchedule mach_port_request_notification(): %s"), mach_error_string(status)); return; } if (oldNotify != MACH_PORT_NULL) { SCLog(TRUE, LOG_ERR, CFSTR("rlsSchedule(): oldNotify != MACH_PORT_NULL")); } retry : __MACH_PORT_DEBUG(TRUE, "*** rlsSchedule", port); status = notifyviaport(storePrivate->server, port, 0, (int *)&sc_status); if (__SCDynamicStoreCheckRetryAndHandleError(store, status, &sc_status, "rlsSchedule notifyviaport()")) { goto retry; } if (status != KERN_SUCCESS) { if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { /* remove the send right that we tried (but failed) to pass to the server */ (void) mach_port_deallocate(mach_task_self(), port); } /* remove our receive right */ (void) mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_RECEIVE, -1); return; } if (sc_status != kSCStatusOK) { /* something [else] didn't work, remove our receive right */ (void) mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_RECEIVE, -1); return; } __MACH_PORT_DEBUG(TRUE, "*** rlsSchedule (after notifyviaport)", port); storePrivate->rlsNotifyPort = _SC_CFMachPortCreateWithPort("SCDynamicStore", port, rlsCallback, &context); storePrivate->rlsNotifyRLS = CFMachPortCreateRunLoopSource(NULL, storePrivate->rlsNotifyPort, 0); storePrivate->rlList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); } if ((rl != NULL) && (storePrivate->rlsNotifyRLS != NULL)) { if (!_SC_isScheduled(store, rl, mode, storePrivate->rlList)) { /* * if we are not already scheduled with this runLoop / runLoopMode */ CFRunLoopAddSource(rl, storePrivate->rlsNotifyRLS, mode); __MACH_PORT_DEBUG(TRUE, "*** rlsSchedule (after CFRunLoopAddSource)", CFMachPortGetPort(storePrivate->rlsNotifyPort)); } _SC_schedule(store, rl, mode, storePrivate->rlList); } return; }
Boolean SCDynamicStoreSetDispatchQueue(SCDynamicStoreRef store, dispatch_queue_t queue) { dispatch_group_t drainGroup = NULL; dispatch_queue_t drainQueue = NULL; dispatch_group_t group = NULL; mach_port_t mp; Boolean ok = FALSE; dispatch_source_t source; SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; if (store == NULL) { // sorry, you must provide a session _SCErrorSet(kSCStatusNoStoreSession); return FALSE; } if (queue == NULL) { if (storePrivate->dispatchQueue == NULL) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } ok = TRUE; goto cleanup; } if (storePrivate->server == MACH_PORT_NULL) { // sorry, you must have an open session to play _SCErrorSet(kSCStatusNoStoreServer); return FALSE; } if ((storePrivate->dispatchQueue != NULL) || (storePrivate->rls != NULL)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } if (storePrivate->notifyStatus != NotifierNotRegistered) { // sorry, you can only have one notification registered at once... _SCErrorSet(kSCStatusNotifierActive); return FALSE; } /* * mark our using of the SCDynamicStore notifications, create and schedule * the notification port (storePrivate->rlsNotifyPort), and a bunch of other * "setup" */ storePrivate->notifyStatus = Using_NotifierInformViaDispatch; rlsSchedule((void*)store, NULL, NULL); if (storePrivate->rlsNotifyPort == NULL) { /* if we could not schedule the notification */ _SCErrorSet(kSCStatusFailed); goto cleanup; } // retain the dispatch queue storePrivate->dispatchQueue = queue; dispatch_retain(storePrivate->dispatchQueue); // // We've taken a reference to the callers dispatch_queue and we // want to hold on to that reference until we've processed any/all // notifications. To facilitate this we create a group, dispatch // any notification blocks to via that group, and when the caller // has told us to stop the notifications (unschedule) we wait for // the group to empty and use the group's finalizer to release // our reference to the SCDynamicStore. // group = dispatch_group_create(); storePrivate->dispatchGroup = group; CFRetain(store); dispatch_set_context(storePrivate->dispatchGroup, (void *)store); dispatch_set_finalizer_f(storePrivate->dispatchGroup, (dispatch_function_t)CFRelease); // create a dispatch source for the mach notifications mp = CFMachPortGetPort(storePrivate->rlsNotifyPort); source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, mp, 0, queue); if (source == NULL) { SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStore dispatch_source_create() failed")); _SCErrorSet(kSCStatusFailed); goto cleanup; } dispatch_source_set_event_handler(source, ^{ kern_return_t kr; mach_msg_id_t msgid; union { u_int8_t buf[sizeof(mach_msg_empty_t) + MAX_TRAILER_SIZE]; mach_msg_empty_rcv_t msg; mach_no_senders_notification_t no_senders; } notify_msg; kr = mach_msg(¬ify_msg.msg.header, // msg MACH_RCV_MSG, // options 0, // send_size sizeof(notify_msg), // rcv_size mp, // rcv_name MACH_MSG_TIMEOUT_NONE, // timeout MACH_PORT_NULL); // notify if (kr != KERN_SUCCESS) { SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStore notification handler, kr=0x%x"), kr); return; } msgid = notify_msg.msg.header.msgh_id; CFRetain(store); dispatch_group_async(group, queue, ^{ if (msgid == MACH_NOTIFY_NO_SENDERS) { // re-establish notification and inform the client (void)__SCDynamicStoreReconnectNotifications(store); } rlsPerform(storePrivate); CFRelease(store); }); });
static void rlsCancel(void *info, CFRunLoopRef rl, CFStringRef mode) { CFIndex n = 0; SCDynamicStoreRef store = (SCDynamicStoreRef)info; SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; #ifdef DEBUG SCLog(_sc_verbose, LOG_DEBUG, CFSTR("cancel notifications for mode %@"), (rl != NULL) ? mode : CFSTR("libdispatch")); #endif /* DEBUG */ if ((rl != NULL) && (storePrivate->rlsNotifyRLS != NULL)) { if (_SC_unschedule(store, rl, mode, storePrivate->rlList, FALSE)) { /* * if currently scheduled on this runLoop / runLoopMode */ n = CFArrayGetCount(storePrivate->rlList); if (n == 0 || !_SC_isScheduled(store, rl, mode, storePrivate->rlList)) { /* * if we are no longer scheduled to receive notifications for * this runLoop / runLoopMode */ CFRunLoopRemoveSource(rl, storePrivate->rlsNotifyRLS, mode); } } } if (n == 0) { int sc_status; kern_return_t status; #ifdef DEBUG SCLog(_sc_verbose, LOG_DEBUG, CFSTR(" cancel callback runloop source")); #endif /* DEBUG */ __MACH_PORT_DEBUG((storePrivate->rlsNotifyPort != NULL), "*** rlsCancel", CFMachPortGetPort(storePrivate->rlsNotifyPort)); if (storePrivate->rlList != NULL) { CFRelease(storePrivate->rlList); storePrivate->rlList = NULL; } if (storePrivate->rlsNotifyRLS != NULL) { /* invalidate & remove the run loop source */ CFRunLoopSourceInvalidate(storePrivate->rlsNotifyRLS); CFRelease(storePrivate->rlsNotifyRLS); storePrivate->rlsNotifyRLS = NULL; } if (storePrivate->rlsNotifyPort != NULL) { mach_port_t mp; mp = CFMachPortGetPort(storePrivate->rlsNotifyPort); __MACH_PORT_DEBUG((storePrivate->rlsNotifyPort != NULL), "*** rlsCancel (before invalidating/releasing CFMachPort)", mp); /* invalidate and release port */ CFMachPortInvalidate(storePrivate->rlsNotifyPort); CFRelease(storePrivate->rlsNotifyPort); storePrivate->rlsNotifyPort = NULL; /* and, finally, remove our receive right */ (void)mach_port_mod_refs(mach_task_self(), mp, MACH_PORT_RIGHT_RECEIVE, -1); } if (storePrivate->server != MACH_PORT_NULL) { status = notifycancel(storePrivate->server, (int *)&sc_status); (void) __SCDynamicStoreCheckRetryAndHandleError(store, status, &sc_status, "rlsCancel notifycancel()"); if (status != KERN_SUCCESS) { return; } } } return; }
SInt32 CFMessagePortSendRequest(CFMessagePortRef remote, SInt32 msgid, CFDataRef data, CFTimeInterval sendTimeout, CFTimeInterval rcvTimeout, CFStringRef replyMode, CFDataRef *returnDatap) { struct __CFMessagePortMachMessage *sendmsg; CFRunLoopRef currentRL = CFRunLoopGetCurrent(); CFRunLoopSourceRef source = NULL; CFDataRef reply = NULL; int64_t termTSR; uint32_t sendOpts = 0, sendTimeOut = 0; int32_t desiredReply; Boolean didRegister = false; kern_return_t ret; //#warning CF: This should be an assert // if (!__CFMessagePortIsRemote(remote)) return -999; if (!__CFMessagePortIsValid(remote)) return kCFMessagePortIsInvalid; __CFMessagePortLock(remote); if (NULL == remote->_replyPort) { CFMachPortContext context; context.version = 0; context.info = remote; context.retain = (const void *(*)(const void *))CFRetain; context.release = (void (*)(const void *))CFRelease; context.copyDescription = (CFStringRef (*)(const void *))__CFMessagePortCopyDescription; remote->_replyPort = CFMachPortCreate(CFGetAllocator(remote), __CFMessagePortReplyCallBack, &context, NULL); } remote->_convCounter++; desiredReply = -remote->_convCounter; CFDictionarySetValue(remote->_replies, (void *)desiredReply, NULL); sendmsg = __CFMessagePortCreateMessage(CFGetAllocator(remote), false, CFMachPortGetPort(remote->_port), (replyMode != NULL ? CFMachPortGetPort(remote->_replyPort) : MACH_PORT_NULL), -desiredReply, msgid, (data ? CFDataGetBytePtr(data) : NULL), (data ? CFDataGetLength(data) : 0)); __CFMessagePortUnlock(remote); if (replyMode != NULL) { source = CFMachPortCreateRunLoopSource(CFGetAllocator(remote), remote->_replyPort, -100); didRegister = !CFRunLoopContainsSource(currentRL, source, replyMode); if (didRegister) { CFRunLoopAddSource(currentRL, source, replyMode); } } if (sendTimeout < 10.0*86400) { // anything more than 10 days is no timeout! sendOpts = MACH_SEND_TIMEOUT; sendTimeout *= 1000.0; if (sendTimeout < 1.0) sendTimeout = 0.0; sendTimeOut = floor(sendTimeout); } ret = mach_msg((mach_msg_header_t *)sendmsg, MACH_SEND_MSG|sendOpts, sendmsg->head.msgh_size, 0, MACH_PORT_NULL, sendTimeOut, MACH_PORT_NULL); CFAllocatorDeallocate(CFGetAllocator(remote), sendmsg); if (KERN_SUCCESS != ret) { if (didRegister) { CFRunLoopRemoveSource(currentRL, source, replyMode); CFRelease(source); } if (MACH_SEND_TIMED_OUT == ret) return kCFMessagePortSendTimeout; return kCFMessagePortTransportError; } if (replyMode == NULL) { return kCFMessagePortSuccess; } CFRetain(remote); // retain during run loop to avoid invalidation causing freeing _CFMachPortInstallNotifyPort(currentRL, replyMode); termTSR = mach_absolute_time() + __CFTimeIntervalToTSR(rcvTimeout); for (;;) { CFRunLoopRunInMode(replyMode, __CFTSRToTimeInterval(termTSR - mach_absolute_time()), true); // warning: what, if anything, should be done if remote is now invalid? reply = CFDictionaryGetValue(remote->_replies, (void *)desiredReply); if (NULL != reply || termTSR < (int64_t)mach_absolute_time()) { break; } if (!CFMessagePortIsValid(remote)) { // no reason that reply port alone should go invalid so we don't check for that break; } } // Should we uninstall the notify port? A complex question... if (didRegister) { CFRunLoopRemoveSource(currentRL, source, replyMode); CFRelease(source); } if (NULL == reply) { CFDictionaryRemoveValue(remote->_replies, (void *)desiredReply); CFRelease(remote); return CFMessagePortIsValid(remote) ? kCFMessagePortReceiveTimeout : -5; } if (NULL != returnDatap) { *returnDatap = ((void *)0xffffffff == reply) ? NULL : reply; } else if ((void *)0xffffffff != reply) { CFRelease(reply); } CFDictionaryRemoveValue(remote->_replies, (void *)desiredReply); CFRelease(remote); return kCFMessagePortSuccess; }
void MachRunLoopServer::cfInvalidate(CFMachPortRef cfPort, void *context) { reinterpret_cast<MachRunLoopServer *>(context)->notifyDeadName(CFMachPortGetPort(cfPort)); //@@@ should we CFRelease cfPort here? }
/* * For now, this requires a single argument, which is the service file. * The service file is formatted as described in the SLP API specification. */ int main(int argc, char *pcArgv[]) { SAState sa; struct sockaddr_in sin; /* for active da discovery */ int err = 0; const char * pcScopes; struct rlimit rlim; rlim_t i; // first just see if they are only checking the version... if ( argc > 1 && strcmp(pcArgv[1], "-v") == 0 ) { // they just want the version number fprintf( stdout, "%s\n", SLPD_VERSION ); exit(0); } #ifdef ENABLE_SLP_LOGGING SLP_LOG( SLP_LOG_STATE, "*** slpd started ***" ); #endif // we need to close all the open file descriptors of who ever launched us! if ( getrlimit(RLIMIT_NOFILE, &rlim) < 0 ) { SLPLOG(SLP_LOG_ERR, "Failed to getrlimit!"); rlim.rlim_cur = FD_SETSIZE; } for ( i=rlim.rlim_cur; i>=0; i-- ) close(i); // Ignore SIGPIPE's mysteriously generated by AFP/ServerControl. struct sigaction sSigAction, sSigOldAction ; sigemptyset (&sSigAction.sa_mask) ; sSigAction.sa_handler = (void (*) (int)) SIG_IGN ; ::sigaction (SIGPIPE, &sSigAction, &sSigOldAction) ; mach_port_limits_t limits = { 1 }; CFMachPortRef port; port = CFMachPortCreate(NULL,(CFMachPortCallBack)SignalMessageHandler,NULL,NULL); CFRunLoopAddSource(CFRunLoopGetCurrent(),CFMachPortCreateRunLoopSource(NULL,port,0),kCFRunLoopCommonModes); gSignalPort = CFMachPortGetPort(port); mach_port_set_attributes(mach_task_self(),gSignalPort,MACH_PORT_LIMITS_INFO, (mach_port_info_t)&limits,sizeof(limits) / sizeof(natural_t)); signal(SIGINT,SignalHandler); if ( IsNetworkSetToTriggerDialup() ) { SLPLOG(SLP_LOG_ERR, "slpd: Network is set to auto dial ppp, - abort"); return 0; } OPEN_NETWORKING(); // have to call this to intialize our lock mutex InitSLPRegistrar(); memset( &sa, 0, sizeof(SAState) ); err = reset_slpd( argc, pcArgv, &sin, &sa ); // do initialization and process config file if ( err ) { SLPLOG(SLP_LOG_ERR, "slpd: could not do initial setup - abort"); return err; } SDatexit(exit_handler); /* * time to daemonize */ /* * initialize network stuff */ if (mslpd_init_network(&sa) != SLP_OK) { SLPLOG(SLP_LOG_FAIL, "slpd: could not init networking - abort"); return -3; } /* * save socket handles so we can free them on exit. */ global_resources.sdUDP = sa.sdUDP; global_resources.sdTCP = sa.sdTCP; if ((pcScopes = SLPGetProperty("net.slp.useScopes"))==NULL) { pcScopes = SLP_DEFAULT_SCOPE; } InitializeListeners( &sa ); StartSLPUDPListener( &sa ); StartSLPTCPListener( &sa ); if ( AreWeADirectoryAgent() ) { StartSLPDAAdvertiser( &sa ); SLPRegistrar::TheSLPR()->EnableRAdminNotification(); } /* * discover DAs actively * each time one is found, local registration is immediately forward * * NOTE: This is very simple-minded. If there are many DAs or any of * them are slow - the forwarding will take too long and the active * discovery will time out before all DAs are found. A better way to * do this would be to simply go through all DAs after this round and * forward to them sequentially. */ InitializeSLPDARegisterer( &sa ); StartSLPDALocator( (void *)mslpd_daadvert_callback, CFRunLoopGetCurrent(), &sa ); sa.pdat = GetGlobalDATable(); /* * The main loop is such that it simply launches handlers. These could * be done in a separate thread. Note that the SAState is read only * except for the fd_set, which should only be set in this thread. * If the mslpd accepts register/deregister ipc commands in the future, * the SAStore.store field will require locks. */ #ifdef ENABLE_SLP_LOGGING SLP_LOG( SLP_LOG_MSG, "slpd: initialization finished"); #endif err = RunSLPInternalProcessListener( &sa ); // this is just going to listen for IPC communications CFRunLoopRun(); // this will run forever until interrupted from the command line or CFRunLoopStop #ifdef ENABLE_SLP_LOGGING SLP_LOG( SLP_LOG_MSG, "slpd: exiting"); #endif return _Signal; }
static mach_port_t __CFMessagePortGetPort(void *info) { CFMessagePortRef ms = info; return CFMachPortGetPort(ms->_port); }
static mach_port_t getIPCPort(void* anInfo) { return anInfo ? CFMachPortGetPort((CFMachPortRef)anInfo) : MACH_PORT_NULL; }