static ssize_t mailstream_low_cfstream_read(mailstream_low * s,
                                            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->readBuffer = buf;
  cfstream_data->readBufferSize = count;
  
  if (cfstream_data->cancelled) {
    return -1;
  }
  
  if (CFReadStreamHasBytesAvailable(cfstream_data->readStream)) {
    readDataFromStream(s);
    return cfstream_data->readResult;
  }
  
  r = wait_runloop(s, STATE_WAIT_READ);
  if (r != WAIT_RUNLOOP_EXIT_NO_ERROR) {
    return -1;
  }
  
  return cfstream_data->readResult;
#else
  return -1;
#endif
}
static Boolean formCanRead(CFReadStreamRef stream, void* context)
{
    FormStreamFields* form = static_cast<FormStreamFields*>(context);

    while (form->currentStream && CFReadStreamGetStatus(form->currentStream) == kCFStreamStatusAtEnd)
        openNextStream(form);

    if (!form->currentStream) {
        CFReadStreamSignalEvent(stream, kCFStreamEventEndEncountered, 0);
        return FALSE;
    }
    return CFReadStreamHasBytesAvailable(form->currentStream);
}
    std::vector<UInt8> TCPStream_CFNetwork::readDataSecurely()
    {
        UInt8 buffer[1024];
        std::vector<UInt8> data;

        while (CFReadStreamHasBytesAvailable(inputStream)) {
            size_t bytesRead = 0;
            OSStatus status = SSLRead(secureLayerContext, buffer, sizeof(buffer), &bytesRead);
            //TODO: Handle any errors here

            data.reserve((data.size() + bytesRead));
            data.insert(data.end(), buffer, buffer + bytesRead);
        }

        return data;
    }
    std::vector<UInt8> TCPStream_CFNetwork::readData()
    {
        UInt8 buffer[1024];
        std::vector<UInt8> data;

        while (CFReadStreamHasBytesAvailable(inputStream)) {
            CFIndex bytesRead = CFReadStreamRead(inputStream, buffer, sizeof(buffer) - 1);
            if (bytesRead == -1) {
                break;
            }

            data.reserve((data.size() + bytesRead));
            data.insert(data.end(), buffer, buffer + bytesRead);
        }

        return data;
    }
CFDictionaryRef download_file(int socket, CFDictionaryRef dict)
{
    UInt8 buffer[8192];
    CFIndex bytesRead;

    CFStringRef path = CFDictionaryGetValue(dict, CFSTR("Path"));
    if(path == NULL || CFGetTypeID(path) != CFStringGetTypeID())
        return NULL;
    CFMutableDictionaryRef out  = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);	

    CFURLRef fileURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path, kCFURLPOSIXPathStyle, FALSE);
    CFReadStreamRef stream = CFReadStreamCreateWithFile(kCFAllocatorDefault, fileURL);
    CFRelease(fileURL);
    if(!CFReadStreamOpen(stream))
    {
        CFErrorRef error = CFReadStreamCopyError(stream);
        if (error != NULL)
        {
            CFStringRef errorDesc = CFErrorCopyDescription(error);
            CFDictionaryAddValue(out, CFSTR("Error"), errorDesc);
            CFRelease(errorDesc);
            CFRelease(error);
        }
        CFRelease(stream);
        return out;
    }
    CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 0);

    while(CFReadStreamHasBytesAvailable(stream))
    {
        if((bytesRead = CFReadStreamRead(stream, buffer, 8192)) <= 0)
            break;
        CFDataAppendBytes(data, buffer, bytesRead);
    }
    CFReadStreamClose(stream);
    CFRelease(stream);

    CFDictionaryAddValue(out, CFSTR("Data"), data);
    CFRelease(data);

    return out;
}
    OSStatus TCPStream_CFNetwork::secureTransportReadCallback (SSLConnectionRef connection,
                                                 void *data,
                                                 size_t *dataLength)
    {
        auto actualStream = reinterpret_cast<TCPStream_CFNetwork const *>(connection);

        if (!CFReadStreamHasBytesAvailable(actualStream->inputStream)) {
            *dataLength = 0;
            return errSSLWouldBlock;
        }

        auto bytesRead = CFReadStreamRead(actualStream->inputStream, reinterpret_cast<UInt8 *>(data), *dataLength);

        if (bytesRead < *dataLength) {
            *dataLength = bytesRead;
            return errSSLWouldBlock;
        }

        return noErr;
    }
Beispiel #7
0
ssize_t SSLImpl::recv(char *buf, size_t size, int *wouldblock, void *storage)
{
    ssl_data_t *data = (ssl_data_t*)storage;
    
    if (!CFReadStreamHasBytesAvailable(data->readStream)) {
        *wouldblock = 1;
        return -1;
    }
    
    *wouldblock = 0;
    
    CFIndex rc = CFReadStreamRead(data->readStream, (UInt8*)buf, size);
    if (rc < 0) {
        CFStreamError err = CFReadStreamGetError(data->readStream);
        report_error("SSL recv failed", &err);
        return -1;
    }
    
    return rc;
    
}
static void handle_server_response(CFReadStreamRef stream,
    CFStreamEventType type, void *info) {
    asynchttp_t *http = (asynchttp_t *)info;
    if (!http->stream) {
        secerror("Avoiding crash due to CFReadStream invoking us after we called CFReadStreamSetDispatchQueue(stream, NULL) on a different block on our serial queue");
        return;
    }

    switch (type) {
    case kCFStreamEventHasBytesAvailable:
    {
        UInt8 buffer[POST_BUFSIZE];
        CFIndex length;
        do {
#if 1
            length = CFReadStreamRead(stream, buffer, sizeof(buffer));
#else
            const UInt8 *buffer = CFReadStreamGetBuffer(stream, -1, &length);
#endif
            secdebug("http",
                "stream: %@ kCFStreamEventHasBytesAvailable read: %lu bytes",
                stream, length);
            if (length < 0) {
                /* Negative length == error */
                asynchttp_complete(http);
                break;
            } else if (length > 0) {
                //CFHTTPMessageAppendBytes(http->response, buffer, length);
                CFDataAppendBytes(http->data, buffer, length);
            } else {
                /* Read 0 bytes, are we are done or do we wait for
                   kCFStreamEventEndEncountered? */
                asynchttp_complete(http);
                break;
            }
        } while (CFReadStreamHasBytesAvailable(stream));
        break;
    }
    case kCFStreamEventErrorOccurred:
    {
        CFStreamError error = CFReadStreamGetError(stream);

        secdebug("http",
            "stream: %@ kCFStreamEventErrorOccurred domain: %ld error: %ld",
            stream, error.domain, (long) error.error);

        if (error.domain == kCFStreamErrorDomainPOSIX) {
            ocspdErrorLog("CFReadStream posix: %s", strerror(error.error));
        } else if (error.domain == kCFStreamErrorDomainMacOSStatus) {
            ocspdErrorLog("CFReadStream osstatus: %"PRIstatus, error.error);
        } else {
            ocspdErrorLog("CFReadStream domain: %ld error: %"PRIstatus,
                error.domain, error.error);
        }
        asynchttp_complete(http);
        break;
    }
    case kCFStreamEventEndEncountered:
    {
        http->response = (CFHTTPMessageRef)CFReadStreamCopyProperty(
            stream, kCFStreamPropertyHTTPResponseHeader);
        secdebug("http", "stream: %@ kCFStreamEventEndEncountered hdr: %@",
            stream, http->response);
        CFHTTPMessageSetBody(http->response, http->data);
        asynchttp_complete(http);
        break;
    }
    default:
        ocspdErrorLog("handle_server_response unexpected event type: %lu",
            type);
        break;
    }
}
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;
}
Beispiel #10
0
void HTTP_Stream::readCallBack(CFReadStreamRef stream, CFStreamEventType eventType, void *clientCallBackInfo)
{
    HTTP_Stream *THIS = static_cast<HTTP_Stream*>(clientCallBackInfo);
    
    switch (eventType) {
        case kCFStreamEventHasBytesAvailable: {
            if (!THIS->m_httpReadBuffer) {
                THIS->m_httpReadBuffer = new UInt8[STREAM_BUFSIZ];
            }
            
            while (CFReadStreamHasBytesAvailable(stream)) {
                if (!THIS->m_scheduledInRunLoop) {
                    /*
                     * This is critical - though the stream has data available,
                     * do not try to feed the audio queue with data, if it has
                     * indicated that it doesn't want more data due to buffers
                     * full.
                     */
                    THIS->m_readPending = true;
                    break;
                }
                
                CFIndex bytesRead = CFReadStreamRead(stream, THIS->m_httpReadBuffer, STREAM_BUFSIZ);
                
                if (CFReadStreamGetStatus(stream) == kCFStreamStatusError ||
                    bytesRead < 0) {
                    if (THIS->m_delegate) {
                        THIS->m_delegate->streamErrorOccurred();
                    }
                    break;
                }
                
                if (bytesRead > 0) {
                    THIS->parseHttpHeadersIfNeeded(THIS->m_httpReadBuffer, bytesRead);
                    
    #ifdef INCLUDE_ID3TAG_SUPPORT
                    if (THIS->m_id3Parser->wantData()) {
                        THIS->m_id3Parser->feedData(THIS->m_httpReadBuffer, (UInt32)bytesRead);
                    }
    #endif
                    
                    if (THIS->m_icyStream) {
                        THIS->parseICYStream(THIS->m_httpReadBuffer, bytesRead);
                    } else {
                        if (THIS->m_delegate) {
                            THIS->m_delegate->streamHasBytesAvailable(THIS->m_httpReadBuffer, (UInt32)bytesRead);
                        }
                    }
                }
            }
                
            break;
        }
        case kCFStreamEventEndEncountered: {
            if (THIS->m_delegate) {
                THIS->m_delegate->streamEndEncountered();
            }
            break;
        }
        case kCFStreamEventErrorOccurred: {
            if (THIS->m_delegate) {
                THIS->m_delegate->streamErrorOccurred();
            }
            break;
        }
    }
}
void HTTP_Stream::readCallBack(CFReadStreamRef stream, CFStreamEventType eventType, void *clientCallBackInfo)
{
    HTTP_Stream *THIS = static_cast<HTTP_Stream*>(clientCallBackInfo);
    
    Stream_Configuration *config = Stream_Configuration::configuration();
    
    switch (eventType) {
        case kCFStreamEventHasBytesAvailable: {
            if (!THIS->m_httpReadBuffer) {
                THIS->m_httpReadBuffer = new UInt8[config->httpConnectionBufferSize];
            }
            
            while (CFReadStreamHasBytesAvailable(stream)) {
                if (!THIS->m_scheduledInRunLoop) {
                    /*
                     * This is critical - though the stream has data available,
                     * do not try to feed the audio queue with data, if it has
                     * indicated that it doesn't want more data due to buffers
                     * full.
                     */
                    THIS->m_readPending = true;
                    break;
                }
                
                CFIndex bytesRead = CFReadStreamRead(stream, THIS->m_httpReadBuffer, config->httpConnectionBufferSize);
                
                if (CFReadStreamGetStatus(stream) == kCFStreamStatusError ||
                    bytesRead < 0) {
                    
#if defined (HS_DEBUG)
                    CFErrorRef streamError = CFReadStreamCopyError(stream);
                    
                    if (streamError) {
                        CFStringRef errorDesc = CFErrorCopyDescription(streamError);
                        
                        if (errorDesc) {
                            HS_TRACE_CFSTRING(errorDesc);
                            
                            CFRelease(errorDesc);
                        }
                        
                        CFRelease(streamError);
                    }
#endif /* HS_DEBUG */
                    
                    if (THIS->m_delegate) {
                        THIS->m_delegate->streamErrorOccurred();
                    }
                    break;
                }
                
                if (bytesRead > 0) {
                    HS_TRACE("Read %li bytes\n", bytesRead);
                    
                    THIS->parseHttpHeadersIfNeeded(THIS->m_httpReadBuffer, bytesRead);
                    
    #ifdef INCLUDE_ID3TAG_SUPPORT
                    if (!THIS->m_icyStream && THIS->m_id3Parser->wantData()) {
                        THIS->m_id3Parser->feedData(THIS->m_httpReadBuffer, (UInt32)bytesRead);
                    }
    #endif
                    
                    if (THIS->m_icyStream) {
                        HS_TRACE("Parsing ICY stream\n");
                        
                        THIS->parseICYStream(THIS->m_httpReadBuffer, bytesRead);
                    } else {
                        if (THIS->m_delegate) {
                            HS_TRACE("Not an ICY stream; calling the delegate back\n");
                            
                            THIS->m_delegate->streamHasBytesAvailable(THIS->m_httpReadBuffer, (UInt32)bytesRead);
                        }
                    }
                }
            }
                
            break;
        }
        case kCFStreamEventEndEncountered: {
            if (THIS->m_delegate) {
                THIS->m_delegate->streamEndEncountered();
            }
            break;
        }
        case kCFStreamEventErrorOccurred: {
            if (THIS->m_delegate) {
                THIS->m_delegate->streamErrorOccurred();
            }
            break;
        }
    }
}