/** * Receive data from a device via the given connection. * This function is like idevice_connection_receive_timeout, but with a * predefined reasonable timeout. * * @param connection The connection to receive data from. * @param data Buffer that will be filled with the received data. * This buffer has to be large enough to hold len bytes. * @param len Buffer size or number of bytes to receive. * @param recv_bytes Number of bytes actually received. * * @return IDEVICE_E_SUCCESS if ok, otherwise an error code. */ idevice_error_t idevice_connection_receive(idevice_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes) { if (!connection || (connection->ssl_data && !connection->ssl_data->session)) { return IDEVICE_E_INVALID_ARG; } if (connection->ssl_data) { ssize_t received = gnutls_record_recv(connection->ssl_data->session, (void*)data, (size_t)len); if (received > 0) { *recv_bytes = received; return IDEVICE_E_SUCCESS; } *recv_bytes = 0; return IDEVICE_E_SSL_ERROR; } return internal_connection_receive(connection, data, len, recv_bytes); }
/** * Internally used gnutls callback function for receiving encrypted data. */ static ssize_t internal_ssl_read(gnutls_transport_ptr_t transport, char *buffer, size_t length) { int bytes = 0, pos_start_fill = 0; size_t tbytes = 0; int this_len = length; idevice_error_t res; idevice_connection_t connection = (idevice_connection_t)transport; char *recv_buffer; debug_info("pre-read client wants %zi bytes", length); recv_buffer = (char *)malloc(sizeof(char) * this_len); /* repeat until we have the full data or an error occurs */ do { if ((res = internal_connection_receive(connection, recv_buffer, this_len, (uint32_t*)&bytes)) != IDEVICE_E_SUCCESS) { debug_info("ERROR: idevice_connection_receive returned %d", res); return res; } debug_info("post-read we got %i bytes", bytes); /* increase read count */ tbytes += bytes; /* fill the buffer with what we got right now */ memcpy(buffer + pos_start_fill, recv_buffer, bytes); pos_start_fill += bytes; if (tbytes >= length) { break; } this_len = length - tbytes; debug_info("re-read trying to read missing %i bytes", this_len); } while (tbytes < length); if (recv_buffer) { free(recv_buffer); } return tbytes; }
idevice_error_t idevice_connection_receive(idevice_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes) { if (!connection || (connection->ssl_data && !connection->ssl_data->session)) { return IDEVICE_E_INVALID_ARG; } if (connection->ssl_data) { #ifdef HAVE_OPENSSL int received = SSL_read(connection->ssl_data->session, (void*)data, (int)len); debug_info("SSL_read %d, received %d", len, received); #else ssize_t received = gnutls_record_recv(connection->ssl_data->session, (void*)data, (size_t)len); #endif if (received > 0) { *recv_bytes = received; return IDEVICE_E_SUCCESS; } *recv_bytes = 0; return IDEVICE_E_SSL_ERROR; } return internal_connection_receive(connection, data, len, recv_bytes); }