static ssize_t mailstream_low_cfstream_write(mailstream_low * s, const void * buf, size_t count) { #if HAVE_CFNETWORK struct mailstream_cfstream_data * cfstream_data; int r; cfstream_data = (struct mailstream_cfstream_data *) s->data; cfstream_data->writeBuffer = buf; cfstream_data->writeBufferSize = count; if (cfstream_data->cancelled) return -1; if (CFWriteStreamCanAcceptBytes(cfstream_data->writeStream)) { writeDataToStream(s); return cfstream_data->writeResult; } r = wait_runloop(s, STATE_WAIT_WRITE); if (r != WAIT_RUNLOOP_EXIT_NO_ERROR) { return -1; } return cfstream_data->writeResult; #else return -1; #endif }
int SocketStreamHandle::platformSend(const char* data, int length) { if (!CFWriteStreamCanAcceptBytes(m_writeStream.get())) return 0; return CFWriteStreamWrite(m_writeStream.get(), reinterpret_cast<const UInt8*>(data), length); }
/* static */ void _HttpContextHandleHasBytesAvailable(HttpContextRef context) { UInt8 buffer[2048]; // Try reading the bytes into the buffer. CFIndex bytesRead = CFReadStreamRead(context->_inStream, buffer, sizeof(buffer)); // Reset the timeout. CFRunLoopTimerSetNextFireDate(context->_timer, CFAbsoluteTimeGetCurrent() + kTimeOutInSeconds); // If there wasn't an error (-1) and not end (0), process the data. if (bytesRead > 0) { // Add the bytes of data to the receive buffer. CFDataAppendBytes(context->_rcvdBytes, buffer, bytesRead); // Parse recieved data int result = HTTPParseRequest(context); if ( result == 1 ) { // HTTP message is fully loaded, process it HTTPProcessMessage(context); // Reset the timeout. CFRunLoopTimerSetNextFireDate(context->_timer, CFAbsoluteTimeGetCurrent() + kTimeOutInSeconds); } // If the ouput stream can write, try sending the bytes. if (result != 0 && CFWriteStreamCanAcceptBytes(context->_outStream)) _HttpContextHandleCanAcceptBytes(context); } }
void SocketStreamHandle::writeStreamCallback(CFStreamEventType type) { switch(type) { case kCFStreamEventNone: break; case kCFStreamEventOpenCompleted: break; case kCFStreamEventHasBytesAvailable: ASSERT_NOT_REACHED(); break; case kCFStreamEventCanAcceptBytes: { // Possibly, a spurious event from CONNECT handshake. if (!CFWriteStreamCanAcceptBytes(m_writeStream.get())) return; if (m_connectingSubstate == WaitingForCredentials) break; if (m_connectingSubstate == WaitingForConnect) { m_connectingSubstate = Connected; m_state = Open; RefPtr<SocketStreamHandle> protect(this); // The client can close the handle, potentially removing the last reference. m_client->didOpen(this); break; } ASSERT(m_state == Open); ASSERT(m_connectingSubstate == Connected); sendPendingData(); break; } case kCFStreamEventErrorOccurred: { #ifndef BUILDING_ON_TIGER RetainPtr<CFErrorRef> error(AdoptCF, CFWriteStreamCopyError(m_writeStream.get())); reportErrorToClient(error.get()); #else CFStreamError error = CFWriteStreamGetError(m_writeStream.get()); m_client->didFail(this, SocketStreamError(error.error)); // FIXME: Provide a sensible error. #endif break; } case kCFStreamEventEndEncountered: // FIXME: Currently, we handle closing in read callback, but these can come independently (e.g. a server can stop listening, but keep sending data). break; } }
ssize_t SSLImpl::send(const void *mem, size_t len, void *storage) { ssl_data_t *data = (ssl_data_t*)storage; if (!CFWriteStreamCanAcceptBytes(data->writeStream)) return 0; int rc = CFWriteStreamWrite(data->writeStream, (const UInt8 *)mem, len); if (rc < 0) { CFStreamError err = CFWriteStreamGetError(data->writeStream); report_error("SSL send failed", &err); return -1; } return rc; }
OSStatus TCPStream_CFNetwork::secureTransportWriteCallback (SSLConnectionRef connection, const void *data, size_t *dataLength) { auto actualStream = reinterpret_cast<TCPStream_CFNetwork const *>(connection); if (!CFWriteStreamCanAcceptBytes(actualStream->outputStream)) { *dataLength = 0; return errSSLWouldBlock; } auto bytesWritten = CFWriteStreamWrite(actualStream->outputStream, reinterpret_cast<UInt8 const *>(data), *dataLength); if (bytesWritten < *dataLength) { *dataLength = bytesWritten; return errSSLWouldBlock; } return noErr; }
void SocketStreamHandle::writeStreamCallback(CFStreamEventType type) { switch(type) { case kCFStreamEventNone: break; case kCFStreamEventOpenCompleted: break; case kCFStreamEventHasBytesAvailable: ASSERT_NOT_REACHED(); break; case kCFStreamEventCanAcceptBytes: { // Possibly, a spurious event from CONNECT handshake. if (!CFWriteStreamCanAcceptBytes(m_writeStream.get())) return; if (m_connectingSubstate == WaitingForCredentials) break; if (m_connectingSubstate == WaitingForConnect) { m_connectingSubstate = Connected; m_state = Open; m_client->didOpenSocketStream(this); break; } ASSERT(m_state == Open); ASSERT(m_connectingSubstate == Connected); sendPendingData(); break; } case kCFStreamEventErrorOccurred: { RetainPtr<CFErrorRef> error(AdoptCF, CFWriteStreamCopyError(m_writeStream.get())); reportErrorToClient(error.get()); break; } case kCFStreamEventEndEncountered: // FIXME: Currently, we handle closing in read callback, but these can come independently (e.g. a server can stop listening, but keep sending data). break; } }
// Internal function, write provided buffer as websocket frame [0x00 buffer 0xff] // CFIndex __WebSocketClientWriteFrame (WebSocketClientRef client, const UInt8 *buffer, CFIndex length) { CFIndex result = 0; if (client) { if (buffer) { if (length > 0) { if (CFWriteStreamCanAcceptBytes(client->write)) { CFIndex didWrite = CFWriteStreamWrite(client->write, (UInt8[]) { (UInt8) 0x00 }, 1); if (didWrite == 1) { result += didWrite; didWrite = CFWriteStreamWrite(client->write, buffer, length); if (didWrite == length) { result += didWrite; didWrite = CFWriteStreamWrite(client->write, (UInt8[]) { (UInt8) 0xff }, 1); if (didWrite == 1) { result += didWrite; } } } } }
static int wait_runloop(mailstream_low * s, int wait_state) { struct mailstream_cfstream_data * cfstream_data; int read_scheduled; int write_scheduled; int error; setup_runloop(s); cfstream_data = (struct mailstream_cfstream_data *) s->data; cfstream_data->state = wait_state; read_scheduled = 0; write_scheduled = 0; error = WAIT_RUNLOOP_EXIT_NO_ERROR; switch (wait_state) { case STATE_WAIT_OPEN: //fprintf(stderr, "wait open\n"); CFReadStreamScheduleWithRunLoop(cfstream_data->readStream, cfstream_data->runloop, kCFRunLoopDefaultMode); CFWriteStreamScheduleWithRunLoop(cfstream_data->writeStream, cfstream_data->runloop, kCFRunLoopDefaultMode); read_scheduled = 1; write_scheduled = 1; break; case STATE_WAIT_READ: //fprintf(stderr, "wait read\n"); CFReadStreamScheduleWithRunLoop(cfstream_data->readStream, cfstream_data->runloop, kCFRunLoopDefaultMode); read_scheduled = 1; break; case STATE_WAIT_WRITE: //fprintf(stderr, "wait write\n"); CFWriteStreamScheduleWithRunLoop(cfstream_data->writeStream, cfstream_data->runloop, kCFRunLoopDefaultMode); write_scheduled = 1; break; case STATE_WAIT_IDLE: //fprintf(stderr, "wait idle\n"); CFReadStreamScheduleWithRunLoop(cfstream_data->readStream, cfstream_data->runloop, kCFRunLoopDefaultMode); read_scheduled = 1; break; case STATE_WAIT_SSL: //fprintf(stderr, "wait ssl\n"); CFReadStreamScheduleWithRunLoop(cfstream_data->readStream, cfstream_data->runloop, kCFRunLoopDefaultMode); CFWriteStreamScheduleWithRunLoop(cfstream_data->writeStream, cfstream_data->runloop, kCFRunLoopDefaultMode); read_scheduled = 1; write_scheduled = 1; break; } if (read_scheduled) { if (CFReadStreamHasBytesAvailable(cfstream_data->readStream)) { readStreamCallback(cfstream_data->readStream, kCFStreamEventHasBytesAvailable, s); } } if (write_scheduled) { if (CFWriteStreamCanAcceptBytes(cfstream_data->writeStream)) { writeStreamCallback(cfstream_data->writeStream, kCFStreamEventCanAcceptBytes, s); } } while (1) { struct timeval timeout; CFTimeInterval delay; int r; int done; if (cfstream_data->cancelled) { error = WAIT_RUNLOOP_EXIT_CANCELLED; break; } if (cfstream_data->state == STATE_WAIT_IDLE) { if (cfstream_data->idleInterrupted) { error = WAIT_RUNLOOP_EXIT_INTERRUPTED; break; } } done = 0; switch (cfstream_data->state) { case STATE_OPEN_READ_DONE: CFReadStreamUnscheduleFromRunLoop(cfstream_data->readStream, cfstream_data->runloop, kCFRunLoopDefaultMode); read_scheduled = 0; break; case STATE_OPEN_WRITE_DONE: CFWriteStreamUnscheduleFromRunLoop(cfstream_data->writeStream, cfstream_data->runloop, kCFRunLoopDefaultMode); write_scheduled = 0; break; case STATE_OPEN_READ_WRITE_DONE: done = 1; break; case STATE_OPEN_WRITE_READ_DONE: done = 1; break; case STATE_READ_DONE: done = 1; break; case STATE_WRITE_DONE: done = 1; break; case STATE_IDLE_DONE: done = 1; break; case STATE_SSL_READ_DONE: done = 1; break; case STATE_SSL_WRITE_DONE: done = 1; break; case STATE_SSL_READ_WRITE_DONE: done = 1; break; case STATE_SSL_WRITE_READ_DONE: done = 1; break; } if (done) { break; } if (wait_state == STATE_WAIT_IDLE) { timeout.tv_sec = cfstream_data->idleMaxDelay; timeout.tv_usec = 0; } else { if (s->timeout == 0) { timeout = mailstream_network_delay; } else { timeout.tv_sec = s->timeout; timeout.tv_usec = 0; } } delay = (CFTimeInterval) timeout.tv_sec + (CFTimeInterval) timeout.tv_usec / (CFTimeInterval) 1e6; r = CFRunLoopRunInMode(kCFRunLoopDefaultMode, delay, true); if (r == kCFRunLoopRunTimedOut) { error = WAIT_RUNLOOP_EXIT_TIMEOUT; break; } } if (read_scheduled) { CFReadStreamUnscheduleFromRunLoop(cfstream_data->readStream, cfstream_data->runloop, kCFRunLoopDefaultMode); } if (write_scheduled) { CFWriteStreamUnscheduleFromRunLoop(cfstream_data->writeStream, cfstream_data->runloop, kCFRunLoopDefaultMode); } unsetup_runloop(s); if (error != WAIT_RUNLOOP_EXIT_NO_ERROR) return error; return WAIT_RUNLOOP_EXIT_NO_ERROR; }