int main (int argc, const char *argv[]) { WebSocketRef webSocket = WebSocketCreateWithHostAndPort(NULL, kWebSocketHostAny, 60001, NULL); if (webSocket) { webSocket->callbacks.didClientReadCallback = Callback; CFRunLoopRun(); WebSocketRelease(webSocket); } return 0; }
WebSocketRef WebSocketCreateWithHostAndPort (CFAllocatorRef allocator, CFStringRef host, UInt16 port, void *userInfo) { WebSocketRef self = CFAllocatorAllocate(allocator, sizeof(WebSocket), 0); if (self) { self->allocator = allocator ? CFRetain(allocator) : NULL; self->retainCount = 1; self->userInfo = userInfo; self->clientsLength = 1024; self->clientsUsedLength = 0; if (NULL == (self->clients = CFAllocatorAllocate(allocator, self->clientsLength, 0))) { WebSocketRelease(self), self = NULL; goto fin; } // Callbacks self->callbacks.didAddClientCallback = NULL; self->callbacks.willRemoveClientCallback = NULL; self->callbacks.didClientReadCallback = NULL; // Setup the context; CFSocketContext context = { .copyDescription = NULL, .retain = NULL, .release = NULL, .version = 0, .info = self }; if (NULL == (self->socket = CFSocketCreate(self->allocator, PF_INET, SOCK_STREAM, IPPROTO_TCP, kCFSocketAcceptCallBack, __WebSocketAcceptCallBack, &context))) { WebSocketRelease(self), self = NULL; goto fin; } // Re-use local addresses, if they're still in TIME_WAIT int yes = 1; setsockopt(CFSocketGetNative(self->socket), SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes)); // Set the port and address we want to listen on memset(&self->addr, 0, sizeof(self->addr)); self->addr.sin_len = sizeof(self->addr); self->addr.sin_family = AF_INET; if (CFEqual(kWebSocketHostAny, host)) { // Host is set to "0.0.0.0", set it to INADDR_ANY self->addr.sin_addr.s_addr = htonl(INADDR_ANY); } else { // Set the host based on provided string. TODO: hostname resolution? CFIndex hostCStringLength = CFStringGetMaximumSizeForEncoding(CFStringGetLength(host), kCFStringEncodingASCII) + 1; char *hostCString = CFAllocatorAllocate(self->allocator, hostCStringLength, 0); if (hostCString) { if (CFStringGetCString(host, hostCString, hostCStringLength, kCFStringEncodingASCII)) { inet_aton(hostCString, &self->addr.sin_addr); } else { // TODO: Couldn't get CString } CFAllocatorDeallocate(self->allocator, hostCString); } else { // TODO: Couldn't allocate buffer } } self->addr.sin_port = htons(port); CFDataRef address = CFDataCreate(self->allocator, (const void *) &self->addr, sizeof(self->addr)); if (address) { if (CFSocketSetAddress(self->socket, (CFDataRef) address) != kCFSocketSuccess) { WebSocketRelease(self), self = NULL; CFRelease(address); goto fin; } CFRelease(address); } // Create run loop source and add it to the current run loop CFRunLoopSourceRef source = CFSocketCreateRunLoopSource(self->allocator, self->socket, 0); CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopCommonModes); CFRelease(source); } fin: return self; } WebSocketRef WebSocketCreate (CFAllocatorRef allocator, void *userInfo) { return WebSocketCreateWithHostAndPort(allocator, kWebSocketHostLoopBack, kWebSocketPortAny, userInfo); } void WebSocketRetain (WebSocketRef self) { if_self { ++self->retainCount; } }