void socket_callback(CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef address, const void *data, void *info) { CFSocketNativeHandle socket = (CFSocketNativeHandle)(*((CFSocketNativeHandle *)data)); struct msghdr message; struct iovec iov[1]; struct cmsghdr *control_message = NULL; char ctrl_buf[CMSG_SPACE(sizeof(int))]; char dummy_data[1]; memset(&message, 0, sizeof(struct msghdr)); memset(ctrl_buf, 0, CMSG_SPACE(sizeof(int))); dummy_data[0] = ' '; iov[0].iov_base = dummy_data; iov[0].iov_len = sizeof(dummy_data); message.msg_name = NULL; message.msg_namelen = 0; message.msg_iov = iov; message.msg_iovlen = 1; message.msg_controllen = CMSG_SPACE(sizeof(int)); message.msg_control = ctrl_buf; control_message = CMSG_FIRSTHDR(&message); control_message->cmsg_level = SOL_SOCKET; control_message->cmsg_type = SCM_RIGHTS; control_message->cmsg_len = CMSG_LEN(sizeof(int)); *((uintptr_t *) CMSG_DATA(control_message)) = (uintptr_t)info; sendmsg(socket, &message, 0); CFSocketInvalidate(s); CFRelease(s); }
/* * CFRunloop callback that calls DNSServiceProcessResult() when * there's new data on the socket. */ static void socket_callback(CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef address, const void *data, void *context) { struct cbinfo *info = context; DNSServiceErrorType err; if (callbackType == kCFSocketNoCallBack) { printf("socket_callback: kCFSocketNoCallBack?\n"); return; } if ((err = DNSServiceProcessResult(info->sdref)) != kDNSServiceErr_NoError) { printf("DNSServiceProcessResult() returned an error! %d\n", err); if (err == kDNSServiceErr_BadReference) { printf("bad reference?: %p, %d, %p, %p %p\n", s, (int)callbackType, address, data, context); return; } if ((context == &nfsinfo) || (context == &mountdinfo)) { /* bail if there's a problem with the main browse connection */ exit(1); } /* dump the troublesome service connection */ CFRunLoopRemoveSource(CFRunLoopGetCurrent(), info->rls, kCFRunLoopDefaultMode); CFRelease(info->rls); CFSocketInvalidate(info->sockref); CFRelease(info->sockref); DNSServiceRefDeallocate(info->sdref); free(info); } }
static void eventCallback(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void *data, void *info) { int so = CFSocketGetNative(s); int status; char buf[1024]; struct kern_event_msg *ev_msg = (struct kern_event_msg *)&buf[0]; int offset = 0; status = recv(so, &buf, sizeof(buf), 0); if (status == -1) { SCLog(TRUE, LOG_ERR, CFSTR("recv() failed: %s"), strerror(errno)); goto error; } cache_open(); while (offset < status) { if ((offset + ev_msg->total_size) > status) { SCLog(TRUE, LOG_NOTICE, CFSTR("missed SYSPROTO_EVENT event, buffer not big enough")); break; } switch (ev_msg->vendor_code) { case KEV_VENDOR_APPLE : switch (ev_msg->kev_class) { case KEV_NETWORK_CLASS : processEvent_Apple_Network(ev_msg); break; case KEV_IOKIT_CLASS : processEvent_Apple_IOKit(ev_msg); break; default : /* unrecognized (Apple) event class */ logEvent(CFSTR("New (Apple) class"), ev_msg); break; } break; default : /* unrecognized vendor code */ logEvent(CFSTR("New vendor"), ev_msg); break; } offset += ev_msg->total_size; ev_msg = (struct kern_event_msg *)&buf[offset]; } cache_write(store); cache_close(); return; error : SCLog(TRUE, LOG_ERR, CFSTR("kernel event monitor disabled.")); CFSocketInvalidate(s); return; }
wxCFEventLoopSource::~wxCFEventLoopSource() { if ( m_cfSocket ) { CFSocketInvalidate(m_cfSocket); CFRelease(m_cfSocket); } }
/*== Remove socket ==*/ int removeSocketAtIndex(int index, transport_context_t *context) { int i; tsk_safeobj_lock(context); if (index < (int)context->count) { transport_socket_t *sock = context->sockets[index]; // Free tls context //TSK_OBJECT_SAFE_FREE(sock->tlshandle); // Invalidate CFSocket if (sock->cf_socket) { if (CFSocketIsValid(sock->cf_socket)) { CFSocketInvalidate(sock->cf_socket); } CFRelease(sock->cf_socket); } // Close and free read stream if (sock->cf_read_stream) { // TODO: Investigate if we really need to do that //if (CFReadStreamGetStatus(sock->cf_read_stream) == kCFStreamStatusOpen) { // CFReadStreamClose(sock->cf_read_stream); //} CFRelease(sock->cf_read_stream); } // Close and free write stream if (sock->cf_write_stream) { // TODO: Investigate if we really need to do that //if (CFWriteStreamGetStatus(sock->cf_write_stream) == kCFStreamStatusOpen) { // CFWriteStreamClose(sock->cf_write_stream); //} CFRelease(sock->cf_write_stream); } // Close the socket if we are the owner. if (sock->owner) { tnet_sockfd_close(&(sock->fd)); } TSK_FREE(sock); for(i=index ; i<context->count-1; i++) { context->sockets[i] = context->sockets[i+1]; } context->sockets[context->count-1] = 0; context->count--; TSK_DEBUG_INFO("Socket removed"); } tsk_safeobj_unlock(context); return 0; }
void GSocketGUIFunctionsTableConcrete::Disable_Events(GSocket *socket) { struct MacGSocketData* data = _GSocket_Get_Mac_Socket(socket); if (!data) return; /* CFSocketInvalidate does CFRunLoopRemoveSource anyway */ CFRunLoopRemoveSource(s_mainRunLoop, data->source, kCFRunLoopCommonModes); CFSocketInvalidate(data->socket); }
/* 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); } }
/*! Called due to source signal detected by the CFRunLoop. This is nearly identical to the wxGTK equivalent. */ extern "C" void WXCF_EndProcessDetector(CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef address, void const *data, void *info) { wxEndProcessData * const proc_data = static_cast<wxEndProcessData*>(info); /// This code could reasonably be shared between wxMac/wxCocoa and wxGTK /// // PID is always positive on UNIX but wx uses the sign bit as a flag. int pid = (proc_data->pid > 0) ? proc_data->pid : -proc_data->pid; int status = 0; int rc = waitpid(pid, &status, WNOHANG); if(rc == 0) { // Keep waiting in case we got a spurious notification // NOTE: In my limited testing, this doesn't happen. return; } if(rc == -1) { // Error.. really shouldn't happen but try to gracefully handle it wxLogLastError(_T("waitpid")); proc_data->exitcode = -1; } else { // Process ended for some reason wxASSERT_MSG(rc == pid, _T("unexpected waitpid() return value")); if(WIFEXITED(status)) proc_data->exitcode = WEXITSTATUS(status); else if(WIFSIGNALED(status)) // wxGTK doesn't do this but why not? proc_data->exitcode = -WTERMSIG(status); else { // Should NEVER happen according to waitpid docs wxLogError(wxT("waitpid indicates process exited but not due to exiting or signalling")); proc_data->exitcode = -1; } } /// The above code could reasonably be shared between wxMac/wxCocoa and wxGTK /// /* Either waitpid failed or the process ended successfully. Either way, we're done. It's not if waitpid is going to magically succeed when we get fired again. CFSocketInvalidate closes the fd for us and also invalidates the run loop source for us which should cause it to release the CFSocket (thus causing it to be deallocated) and remove itself from the runloop which should release it and cause it to also be deallocated. Of course, it's possible the RunLoop hangs onto one or both of them by retaining/releasing them within its stack frame. However, that shouldn't be depended on. Assume that s is deallocated due to the following call. */ CFSocketInvalidate(s); // Now tell wx that the process has ended. wxHandleProcessTermination(proc_data); }
int browse(void) { DNSServiceErrorType err; CFSocketContext ctx = { 0, NULL, NULL, NULL, NULL }; err = DNSServiceBrowse(&nfsinfo.sdref, 0, 0, "_nfs._tcp", NULL, browser_callback, NULL); if (err != kDNSServiceErr_NoError) return (1); ctx.info = (void*)&nfsinfo; nfsinfo.sockref = CFSocketCreateWithNative(kCFAllocatorDefault, DNSServiceRefSockFD(nfsinfo.sdref), kCFSocketReadCallBack, socket_callback, &ctx); if (!nfsinfo.sockref) return (1); nfsinfo.rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, nfsinfo.sockref, 1); CFRunLoopAddSource(CFRunLoopGetCurrent(), nfsinfo.rls, kCFRunLoopDefaultMode); /* For backwards compatibility, browse for "mountd" services too */ err = DNSServiceBrowse(&mountdinfo.sdref, 0, 0, "_mountd._tcp", NULL, browser_callback, NULL); if (err != kDNSServiceErr_NoError) return (1); ctx.info = (void*)&mountdinfo; mountdinfo.sockref = CFSocketCreateWithNative(kCFAllocatorDefault, DNSServiceRefSockFD(mountdinfo.sdref), kCFSocketReadCallBack, socket_callback, &ctx); if (!mountdinfo.sockref) return (1); mountdinfo.rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, mountdinfo.sockref, 1); CFRunLoopAddSource(CFRunLoopGetCurrent(), mountdinfo.rls, kCFRunLoopDefaultMode); CFRunLoopRun(); CFRelease(nfsinfo.rls); CFSocketInvalidate(nfsinfo.sockref); CFRelease(nfsinfo.sockref); DNSServiceRefDeallocate(nfsinfo.sdref); CFRelease(mountdinfo.rls); CFSocketInvalidate(mountdinfo.sockref); CFRelease(mountdinfo.sockref); DNSServiceRefDeallocate(mountdinfo.sdref); return (0); }
void QCFSocketNotifier::removeSocketNotifiers() { // Remove CFSockets from the runloop. for (MacSocketHash::ConstIterator it = macSockets.constBegin(); it != macSockets.constEnd(); ++it) { MacSocketInfo *socketInfo = (*it); if (CFSocketIsValid(socketInfo->socket)) { qt_mac_remove_socket_from_runloop(socketInfo->socket, socketInfo->runloop); CFRunLoopSourceInvalidate(socketInfo->runloop); CFRelease(socketInfo->runloop); CFSocketInvalidate(socketInfo->socket); CFRelease(socketInfo->socket); } } }
/* Unregister QSocketNotifer. The CFSocket correspoding to this notifier is removed from the runloop of this is the last notifier that users that CFSocket. */ void QEventDispatcherMac::unregisterSocketNotifier(QSocketNotifier *notifier) { Q_ASSERT(notifier); int nativeSocket = notifier->socket(); int type = notifier->type(); #ifndef QT_NO_DEBUG if (nativeSocket < 0 || nativeSocket > FD_SETSIZE) { qWarning("QSocketNotifier: Internal error"); return; } else if (notifier->thread() != thread() || thread() != QThread::currentThread()) { qWarning("QSocketNotifier: socket notifiers cannot be disabled from another thread"); return; } #endif Q_D(QEventDispatcherMac); QEventDispatcherUNIX::unregisterSocketNotifier(notifier); if (type == QSocketNotifier::Exception) { qWarning("QSocketNotifier::Exception is not supported on Mac OS X"); return; } MacSocketInfo *socketInfo = d->macSockets.value(nativeSocket); if (!socketInfo) { qWarning("QEventDispatcherMac::unregisterSocketNotifier: Tried to unregister a not registered notifier"); return; } // Decrement read/write counters and disable callbacks if necessary. if (type == QSocketNotifier::Read) { if (--socketInfo->read == 0) CFSocketDisableCallBacks(socketInfo->socket, kCFSocketReadCallBack); } else if (type == QSocketNotifier::Write) { if (--socketInfo->write == 0) CFSocketDisableCallBacks(socketInfo->socket, kCFSocketWriteCallBack); } // Remove CFSocket from runloop if this was the last QSocketNotifier. if (socketInfo->read <= 0 && socketInfo->write <= 0) { if (CFSocketIsValid(socketInfo->socket)) qt_mac_remove_socket_from_runloop(socketInfo->socket, socketInfo->runloop); CFRunLoopSourceInvalidate(socketInfo->runloop); CFRelease(socketInfo->runloop); CFSocketInvalidate(socketInfo->socket); CFRelease(socketInfo->socket); delete socketInfo; d->macSockets.remove(nativeSocket); } }
/*------------------------------------ udpPortFree ---*/ static void udpPortFree(UdpObjectData * xx) { if (xx) { xx->fClosing = true; if (xx->fSocket) { CFSocketInvalidate(xx->fSocket); CFRelease(xx->fSocket); xx->fSocket = NULL; } releaseObjectMemory(xx); } } // udpPortFree
/* static */ void _ServerReleaseSocket(Server* server) { unsigned i; for (i = 0; i < (sizeof(server->_sockets) / sizeof(server->_sockets[0])); i++) { // Invalidate and release the socket if there is one. if (server->_sockets[i] != NULL) { CFSocketInvalidate(server->_sockets[i]); CFRelease(server->_sockets[i]); server->_sockets[i] = NULL; } } }
static void resolve_callback( __unused DNSServiceRef sdRef, __unused DNSServiceFlags flags, __unused uint32_t interfaceIndex, __unused DNSServiceErrorType errorCode, Dused const char *fullName, const char *hostTarget, Dused uint16_t port, Dused uint16_t txtLen, Dused const unsigned char *txtRecord, void *context) { struct cbinfo *info = context; #ifdef DEBUG const char *p; char *q, *s; int len; printf("resolve: %s %s:%d TXT %d\n", fullName, hostTarget, port, txtLen); if ((txtLen > 1) && ((s = malloc(txtLen+2)))) { p = txtRecord; q = s; len = txtLen; while (len > 0) { strncpy(q, p+1, *p); len -= *p + 1; q += *p; p += *p + 1; } *q = '\0'; printf(" %s\n", s); free(s); } #endif do_print(hostTarget); CFRunLoopRemoveSource(CFRunLoopGetCurrent(), info->rls, kCFRunLoopDefaultMode); CFRelease(info->rls); CFSocketInvalidate(info->sockref); CFRelease(info->sockref); DNSServiceRefDeallocate(info->sdref); free(info); }
void KprZeroconfPlatformServiceDispose(KprZeroconfPlatformService self) { if (self) { #if KPR_ZEROCONF_EMBEDDED gEmbeddedServiceCount--; if (!gEmbeddedServiceCount) { FskTimeCallbackDispose(gEmbeddedServiceTimer); gEmbeddedServiceTimer = NULL; } #elif TARGET_OS_MAC if (self->source) { CFRunLoopRemoveSource(CFRunLoopGetCurrent(), self->source, kCFRunLoopCommonModes); CFRelease(self->source); self->source = NULL; } if (self->socket) { CFSocketInvalidate(self->socket); CFRelease(self->socket); self->socket = NULL; } #else FskSocketActivate(self->source, false); if (self->handler) { FskThreadRemoveDataHandler(&self->handler); self->handler = NULL; } if (self->source) { FskMemPtrDispose(self->source); self->source = NULL; } #endif if (self->serviceRef) { DNSServiceRefDeallocate(self->serviceRef); self->serviceRef = NULL; } FskMemPtrDispose(self->txt); FskMemPtrDispose(self->name); FskInstrumentedItemDispose(self); FskMemPtrDispose(self); } }
/*! Implements the GUI-specific AddProcessCallback() for both wxMac and wxCocoa using the CFSocket/CFRunLoop API which is available to both. Takes advantage of the fact that sockets on UNIX are just regular file descriptors and thus even a non-socket file descriptor can apparently be used with CFSocket so long as you only tell CFSocket to do things with it that would be valid for a non-socket fd. */ int wxGUIAppTraits::AddProcessCallback(wxEndProcessData *proc_data, int fd) { static int s_last_tag = 0; CFSocketContext context = { 0 , static_cast<void*>(proc_data) , NULL , NULL , NULL }; CFSocketRef cfSocket = CFSocketCreateWithNative(kCFAllocatorDefault,fd,kCFSocketReadCallBack,&WXCF_EndProcessDetector,&context); if(cfSocket == NULL) { wxLogError(wxT("Failed to create socket for end process detection")); return 0; } CFRunLoopSourceRef runLoopSource = CFSocketCreateRunLoopSource(kCFAllocatorDefault, cfSocket, /*highest priority:*/0); if(runLoopSource == NULL) { wxLogError(wxT("Failed to create CFRunLoopSource from CFSocket for end process detection")); // closes the fd.. we can't really stop it, nor do we necessarily want to. CFSocketInvalidate(cfSocket); CFRelease(cfSocket); return 0; } // Now that the run loop source has the socket retained and we no longer // need to refer to it within this method, we can release it. CFRelease(cfSocket); CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes); // Now that the run loop has the source retained we can release it. CFRelease(runLoopSource); /* Feed wx some bullshit.. we don't use it since CFSocket helpfully passes itself into our callback and that's enough to be able to CFSocketInvalidate it which is all we need to do to get everything we just created to be deallocated. */ return ++s_last_tag; }
QEventDispatcherMac::~QEventDispatcherMac() { Q_D(QEventDispatcherMac); //timer cleanup d->zero_timer_count = 0; if(d->macTimerList) { for (int i = 0; i < d->macTimerList->size(); ++i) { const MacTimerInfo &t = d->macTimerList->at(i); if (t.mac_timer) { RemoveEventLoopTimer(t.mac_timer); if (t.pending) { EventComparatorUPP fnc = NewEventComparatorUPP(find_timer_event); FlushSpecificEventsFromQueue(GetMainEventQueue(), fnc, (void *)&t); DisposeEventComparatorUPP(fnc); } } } delete d->macTimerList; d->macTimerList = 0; } if(timerUPP) { DisposeEventLoopTimerUPP(timerUPP); timerUPP = 0; } // Remove CFSockets from the runloop. for (MacSocketHash::ConstIterator it = d->macSockets.constBegin(); it != d->macSockets.constEnd(); ++it) { MacSocketInfo *socketInfo = (*it); if (CFSocketIsValid(socketInfo->socket)) { qt_mac_remove_socket_from_runloop(socketInfo->socket, socketInfo->runloop); CFRunLoopSourceInvalidate(socketInfo->runloop); CFRelease(socketInfo->runloop); CFSocketInvalidate(socketInfo->socket); CFRelease(socketInfo->socket); } } CFRunLoopRemoveSource(runLoopForCarbonLoop(GetMainEventLoop()), d->postedEventsSource, kCFRunLoopCommonModes); CFRelease(d->postedEventsSource); d->postedEventsSource = 0; }
static void MyDNSServiceFree(MyDNSServiceState *ref) { assert(ref); if (ref->socket) { //Invalidate the CFSocket. CFSocketInvalidate(ref->socket); CFRelease(ref->socket); // Workaround that gives time to CFSocket's select thread so it can remove the socket from its // FD set before we close the socket by calling DNSServiceRefDeallocate. <rdar://problem/3585273> usleep(1000); } if (ref->service) { // Terminate the connection with the mDNSResponder daemon, which cancels the operation. DNSServiceRefDeallocate(ref->service); } free(ref); }
/*! Called due to source signal detected by the CFRunLoop. This is nearly identical to the wxGTK equivalent. */ extern "C" void WXCF_EndProcessDetector(CFSocketRef s, CFSocketCallBackType WXUNUSED(callbackType), CFDataRef WXUNUSED(address), void const *WXUNUSED(data), void *info) { /* Either our pipe was closed or the process ended successfully. Either way, we're done. It's not if waitpid is going to magically succeed when we get fired again. CFSocketInvalidate closes the fd for us and also invalidates the run loop source for us which should cause it to release the CFSocket (thus causing it to be deallocated) and remove itself from the runloop which should release it and cause it to also be deallocated. Of course, it's possible the RunLoop hangs onto one or both of them by retaining/releasing them within its stack frame. However, that shouldn't be depended on. Assume that s is deallocated due to the following call. */ CFSocketInvalidate(s); // Now tell wx that the process has ended. wxHandleProcessTermination(static_cast<wxEndProcessData *>(info)); }
static int _cf_source_schedule( struct MIDIRunloopSource * source, int event ) { int i, created; struct CFMIDIRunLoopSource * cf = source->scheduler; CFSocketContext socket_context; CFOptionFlags socket_cb_types = kCFSocketNoCallBack; CFSocketRef socket; if( event & MIDI_RUNLOOP_READ ) socket_cb_types |= kCFSocketReadCallBack; if( event & MIDI_RUNLOOP_WRITE ) socket_cb_types |= kCFSocketWriteCallBack; socket_context.version = 0; socket_context.info = source; socket_context.release = NULL; socket_context.retain = NULL; socket_context.copyDescription = NULL; for( i=0; i<source->nfds; i++ ) { created = 0; if( FD_ISSET(i, &(source->readfds)) ) { created = 1; } if( FD_ISSET(i, &(source->writefds)) ) { created = 1; } if( created ) { socket = CFSocketCreateWithNative( NULL, i, socket_cb_types, &_cf_socket_callback, &socket_context ); if( event & MIDI_RUNLOOP_INVALIDATE ) { CFSocketInvalidate( socket ); } else if( socket_cb_types != kCFSocketNoCallBack ) { CFSocketEnableCallBacks( socket, socket_cb_types ); } CFRelease( socket ); } } return 0; }
bool wxServiceDiscoveryTaskBase::Stop( void ) { bool output = false; if ( ! m_bUseThreads ) { #ifdef __DARWIN__ if ( ( CFRunLoopGetCurrent() != NULL ) && ( source != NULL ) && ( cfsocket != NULL ) ) { // Remove the CFRunLoopSource from the current run loop. CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source, kCFRunLoopCommonModes); CFRelease(source); // Invalidate the CFSocket. CFSocketInvalidate(cfsocket); CFRelease(cfsocket); cfsocket = NULL; source = NULL; // Workaround to give time to CFSocket's select() thread // so it can remove the socket from its FD set before we // close the socket by calling DNSServiceRefDeallocate. usleep(1000); } #elif defined( _WIN32 ) if ( wind != NULL ) { // Clean up. This is not strictly necessary since the normal // process cleanup will close DNS-SD socket(s) and release memory, // but it's here to demonstrate how to do it. // WSAAsyncSelect( dns_sd_fd, // wind, // DNSSD_EVENT, // 0 ); DestroyWindow( wind ); wind = NULL; } #endif } if ( m_rServiceRef != NULL ) { // Order is important. We deallocate the DNSServiceRef *prior* to deleting // the thread. The thread is blocking permanently for a response on this // service reference. If we delete the thread first, we wind up in a // deadlock situation. If we delete the service first, we get an error, // but at least the thread stops. As long as we prepare for that error, // everything will be fine. DNSServiceRefDeallocate( m_rServiceRef ); m_rServiceRef = NULL; output = true; } if ( m_bUseThreads ) { if ( m_pThread != NULL ) { m_pThread->Delete(); delete m_pThread; m_pThread = NULL; } } return output; }
/* static */ void _DomainEnumReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char* replyDomain, void* context) { __CFNetServiceBrowser* browser = context; CFNetServiceBrowserClientCallBack cb = NULL; CFStreamError error; void* info = NULL; CFStringRef domain = NULL; // Retain here to guarantee safety really after the trigger release, // but definitely before the callback. CFRetain(browser); // Lock the browser __CFSpinLock(&browser->_lock); // If the browse canceled, don't need to do any of this. if (browser->_browse) { // If there is an error, fold the browse. if (errorCode) { // Save the error browser->_error.error = _DNSServiceErrorToCFNetServiceError(errorCode); browser->_error.domain = kCFStreamErrorDomainNetServices; // Remove the browse from run loops and modes _CFTypeUnscheduleFromMultipleRunLoops(browser->_trigger, browser->_schedules); // Go ahead and invalidate the socket CFSocketInvalidate((CFSocketRef)(browser->_trigger)); // Release the browse now. CFRelease(browser->_trigger); browser->_trigger = NULL; // Clean up the underlying service discovery stuff DNSServiceRefDeallocate(browser->_browse); browser->_browse = NULL; } // If got a domain from service discovery, create the CFString for the domain. else if (replyDomain) { domain = CFStringCreateWithCString(CFGetAllocator(browser), replyDomain, kCFStringEncodingUTF8); } cb = browser->_callback; // Save the error and client information for the callback memmove(&error, &(browser->_error), sizeof(error)); info = browser->_client.info; } // Unlock the browser so the callback can be made safely. __CFSpinUnlock(&browser->_lock); // If there is a callback, inform the client of the finish. if (cb && domain) { // Time to translate the service discovery flags into CFNetServices // flags. This is known to be a domain, so start there. UInt32 f = kCFNetServiceFlagIsDomain; // If more is coming, set that bit. if (flags & kDNSServiceFlagsMoreComing) f |= kCFNetServiceFlagMoreComing; // SD notifies that it's adding. CFNetServices needs to translate to // ones that are going away. if (!(flags & kDNSServiceFlagsAdd)) f |= kCFNetServiceFlagRemove; // Set the bit if this is a registration domain if (flags & kDNSServiceFlagsDefault) f |= kCFNetServiceFlagIsDefault; // Inform the client. cb((CFNetServiceBrowserRef)browser, f, domain, &error, info); } // No longer need this after the callback if (domain) CFRelease(domain); // Go ahead and release now that the callback is done. CFRelease(browser); }
/* Register a QSocketNotifier with the mac event system by creating a CFSocket with with a read/write callback. Qt has separate socket notifiers for reading and writing, but on the mac there is a limitation of one CFSocket object for each native socket. */ void QEventDispatcherMac::registerSocketNotifier(QSocketNotifier *notifier) { Q_ASSERT(notifier); int nativeSocket = notifier->socket(); int type = notifier->type(); #ifndef QT_NO_DEBUG if (nativeSocket < 0 || nativeSocket > FD_SETSIZE) { qWarning("QSocketNotifier: Internal error"); return; } else if (notifier->thread() != thread() || thread() != QThread::currentThread()) { qWarning("QSocketNotifier: socket notifiers cannot be enabled from another thread"); return; } #endif Q_D(QEventDispatcherMac); QEventDispatcherUNIX::registerSocketNotifier(notifier); if (type == QSocketNotifier::Exception) { qWarning("QSocketNotifier::Exception is not supported on Mac OS X"); return; } // Check if we have a CFSocket for the native socket, create one if not. MacSocketInfo *socketInfo = d->macSockets.value(nativeSocket); if (!socketInfo) { socketInfo = new MacSocketInfo(); // Create CFSocket, specify that we want both read and write callbacks (the callbacks // are enabled/disabled later on). const int callbackTypes = kCFSocketReadCallBack | kCFSocketWriteCallBack; CFSocketContext context = {0, this, NULL, NULL, NULL}; socketInfo->socket = CFSocketCreateWithNative(kCFAllocatorDefault, nativeSocket, callbackTypes, qt_mac_socket_callback, &context); if (CFSocketIsValid(socketInfo->socket) == false) { qWarning("QEventDispatcherMac::registerSocketNotifier: Failed to create CFSocket"); return; } CFOptionFlags flags = CFSocketGetSocketFlags(socketInfo->socket); flags |= kCFSocketAutomaticallyReenableWriteCallBack; //QSocketNotifier stays enabled after a write flags &= ~kCFSocketCloseOnInvalidate; //QSocketNotifier doesn't close the socket upon destruction/invalidation CFSocketSetSocketFlags(socketInfo->socket, flags); // Add CFSocket to runloop. if(!(socketInfo->runloop = qt_mac_add_socket_to_runloop(socketInfo->socket))) { qWarning("QEventDispatcherMac::registerSocketNotifier: Failed to add CFSocket to runloop"); CFSocketInvalidate(socketInfo->socket); CFRelease(socketInfo->socket); return; } // Disable both callback types by default. This must be done after // we add the CFSocket to the runloop, or else these calls will have // no effect. CFSocketDisableCallBacks(socketInfo->socket, kCFSocketReadCallBack); CFSocketDisableCallBacks(socketInfo->socket, kCFSocketWriteCallBack); d->macSockets.insert(nativeSocket, socketInfo); } // Increment read/write counters and select enable callbacks if necessary. if (type == QSocketNotifier::Read) { if (++socketInfo->read == 1) CFSocketEnableCallBacks(socketInfo->socket, kCFSocketReadCallBack); } else if (type == QSocketNotifier::Write) { if (++socketInfo->write == 1) CFSocketEnableCallBacks(socketInfo->socket, kCFSocketWriteCallBack); } }
/* static */ void _BrowseReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char* serviceName, const char* regtype, const char* replyDomain, void* context) { __CFNetServiceBrowser* browser = context; CFNetServiceBrowserClientCallBack cb = NULL; CFStreamError error = {0, 0}; void* info = NULL; CFNetServiceRef service = NULL; // Retain here to guarantee safety really after the trigger release, // but definitely before the callback. CFRetain(browser); // Lock the browser __CFSpinLock(&browser->_lock); // If the browse canceled, don't need to do any of this. if (browser->_browse) { // If there is an error, fold the browse. if (errorCode) { // Save the error browser->_error.error = _DNSServiceErrorToCFNetServiceError(errorCode); browser->_error.domain = kCFStreamErrorDomainNetServices; // Remove the browse from run loops and modes _CFTypeUnscheduleFromMultipleRunLoops(browser->_trigger, browser->_schedules); // Go ahead and invalidate the socket CFSocketInvalidate((CFSocketRef)(browser->_trigger)); // Release the browse now. CFRelease(browser->_trigger); browser->_trigger = NULL; // Clean up the underlying service discovery stuff DNSServiceRefDeallocate(browser->_browse); browser->_browse = NULL; // Dump all the lists of items. CFDictionaryRemoveAllValues(browser->_found); CFArrayRemoveAllValues(browser->_adds); CFArrayRemoveAllValues(browser->_removes); } // If got service info from service discovery, create the CFNetServiceRef. else if (serviceName && regtype && replyDomain) { // Create CFString's for each of the service components CFAllocatorRef alloc = CFGetAllocator(browser); CFStringRef domain = CFStringCreateWithCString(alloc, replyDomain, kCFStringEncodingUTF8); CFStringRef type = CFStringCreateWithCString(alloc, regtype, kCFStringEncodingUTF8); CFStringRef name = CFStringCreateWithCString(alloc, serviceName, kCFStringEncodingUTF8); // Can only make the service if all the strings were created. This // will skip over items that are not properly UTF8 encoded on the wire. if (domain && type && name) service = _CFNetServiceCreateCommon(alloc, domain, type, name, 0); if (domain) CFRelease(domain); if (type) CFRelease(type); if (name) CFRelease(name); if (service) { intptr_t count = (intptr_t)CFDictionaryGetValue(browser->_found, service); if (flags & kDNSServiceFlagsAdd) { count++; if (count != 1) CFDictionaryReplaceValue(browser->_found, service, (const void*)count); else { CFIndex i = CFArrayGetFirstIndexOfValue(browser->_removes, CFRangeMake(0, CFArrayGetCount(browser->_removes)), service); CFDictionaryAddValue(browser->_found, service, (const void*)count); CFArrayAppendValue(browser->_adds, service); if (i != kCFNotFound) CFArrayRemoveValueAtIndex(browser->_removes, i); } } else { count--; if (count > 0) CFDictionaryReplaceValue(browser->_found, service, (const void*)count); else { CFIndex i = CFArrayGetFirstIndexOfValue(browser->_adds, CFRangeMake(0, CFArrayGetCount(browser->_adds)), service); CFDictionaryRemoveValue(browser->_found, service); CFArrayAppendValue(browser->_removes, service); if (i != kCFNotFound) CFArrayRemoveValueAtIndex(browser->_adds, i); } } CFRelease(service); } } cb = browser->_callback; // Save the error and client information for the callback memmove(&error, &(browser->_error), sizeof(error)); info = browser->_client.info; } // If there is a callback, inform the client of the error. if (cb && error.error) { // Unlock the browser so the callback can be made safely. __CFSpinUnlock(&browser->_lock); cb((CFNetServiceBrowserRef)browser, 0, NULL, &error, info); } else if (cb && ((flags & kDNSServiceFlagsMoreComing) == 0)) { CFIndex i, adds = CFArrayGetCount(browser->_adds); CFIndex removes = CFArrayGetCount(browser->_removes); CFIndex total = adds + removes; for (i = 0; i < adds; i++) { const void* saved = browser->_trigger; service = (CFNetServiceRef)CFArrayGetValueAtIndex(browser->_adds, i); // Unlock the browser so the callback can be made safely. __CFSpinUnlock(&browser->_lock); cb((CFNetServiceBrowserRef)browser, (i == (total - 1)) ? 0 : kCFNetServiceFlagMoreComing, service, &error, info); // Lock the browser __CFSpinLock(&browser->_lock); if (saved != browser->_trigger) { cb = NULL; break; } } if (cb) { for (i = 0; i < removes; i++) { const void* saved = browser->_trigger; service = (CFNetServiceRef)CFArrayGetValueAtIndex(browser->_removes, i); // Unlock the browser so the callback can be made safely. __CFSpinUnlock(&browser->_lock); cb((CFNetServiceBrowserRef)browser, kCFNetServiceFlagRemove | ((i == (removes - 1)) ? 0 : kCFNetServiceFlagMoreComing), service, &error, info); // Lock the browser __CFSpinLock(&browser->_lock); if (saved != browser->_trigger) break; } } // Dump the lists of items, so can start new again. CFArrayRemoveAllValues(browser->_adds); CFArrayRemoveAllValues(browser->_removes); // Unlock the browser so the callback can be made safely. __CFSpinUnlock(&browser->_lock); } else __CFSpinUnlock(&browser->_lock); // Go ahead and release now that the callback is done. CFRelease(browser); }
static void ConnectionShutdown(ConnectionRef conn) // This routine shuts down down the connection to the server // without saying goodbye; it leaves conn valid. This routine // is primarily used internally to the connection abstraction // where we notice that the connection has failed for some reason. // It's also called by the client after a successful quit RPC // because we know that the server has closed its end of the // connection. // // It's important to nil out the fields as we close them because // this routine is called if any messaging routine fails. If it // doesn't nil out the fields, two bad things might happen: // // o When the connection is eventually closed, ConnectionCloseInternal // will try to send a Goodbye, which fails triggering an assert. // // o If ConnectionShutdown is called twice on a particular connection // (which happens a lot; this is a belts and braces implementation // [that's "belts and suspenders" for the Americans reading this; // ever wonder why Monty Python's lumberjacks sing about "suspenders // and a bra"?; well look up "suspenders" in a non-American dictionary // for a quiet chuckle :-] ) { int junk; Boolean hadSockCF; assert(conn != NULL); conn->fCallback = NULL; conn->fCallbackRefCon = NULL; if (conn->fRunLoopSource != NULL) { CFRunLoopSourceInvalidate(conn->fRunLoopSource); CFRelease(conn->fRunLoopSource); conn->fRunLoopSource = NULL; } // CFSocket will close conn->fSockFD when we invalidate conn->fSockCF, // so we remember whether we did this so that, later on, we know // whether to close the file descriptor ourselves. We need an extra // variable because we NULL out fSockCF as we release it, for the reason // described above. hadSockCF = (conn->fSockCF != NULL); if (conn->fSockCF != NULL) { CFSocketInvalidate(conn->fSockCF); CFRelease(conn->fSockCF); conn->fSockCF = NULL; } if (conn->fBufferedPackets != NULL) { CFRelease(conn->fBufferedPackets); conn->fBufferedPackets = NULL; } if ( (conn->fSockFD != -1) && ! hadSockCF ) { junk = close(conn->fSockFD); assert(junk == 0); } // We always set fSockFD to -1 because either we've closed it or // CFSocket has. conn->fSockFD = -1; }
/*------------------------------------ udpPortSetPort ---*/ bool udpPortSetPort(UdpObjectData * xx, const bool bangOnError) { bool okSoFar = true; if (xx) { if (xx->fSocket) { CFSocketInvalidate(xx->fSocket); CFRelease(xx->fSocket); xx->fSocket = NULL; } int err; int sock = socket(AF_INET, SOCK_DGRAM, 0); if (0 > sock) { err = errno; okSoFar = false; } else { err = 0; } if (okSoFar) { sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_len = sizeof(addr); addr.sin_family = AF_INET; addr.sin_port = htons(xx->fSelfPort); addr.sin_addr.s_addr = INADDR_ANY; err = bind(sock, reinterpret_cast<sockaddr *>(&addr), sizeof(addr)); if (0 > err) { err = errno; okSoFar = false; } } if (okSoFar) { int flags = fcntl(sock, F_GETFL); err = fcntl(sock, F_SETFL, flags | O_NONBLOCK); if (0 > err) { err = errno; okSoFar = false; } } if (okSoFar) { const CFSocketContext context = { 0, xx, NULL, NULL, NULL }; xx->fSocket = CFSocketCreateWithNative(kCFAllocatorDefault, sock, kCFSocketReadCallBack, socketReadCallback, &context); sock = -1; CFRunLoopSourceRef rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, xx->fSocket, 0); CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); CFRelease(rls); setObjectState(xx, kUdpStateBound); } if (! okSoFar) { close(sock); LOG_ERROR_2(xx, OUTPUT_PREFIX "set port failed (%ld)", static_cast<long>(err)) if (bangOnError) { signalError(xx); } } }