diff options
-rw-r--r-- | src/idevice.c | 106 | ||||
-rw-r--r-- | src/idevice.h | 2 |
2 files changed, 66 insertions, 42 deletions
diff --git a/src/idevice.c b/src/idevice.c index ecc0418..a2a4d0b 100644 --- a/src/idevice.c +++ b/src/idevice.c | |||
@@ -432,6 +432,8 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connect(idevice_t device, uint16_t | |||
432 | new_connection->data = (void*)(long)sfd; | 432 | new_connection->data = (void*)(long)sfd; |
433 | new_connection->ssl_data = NULL; | 433 | new_connection->ssl_data = NULL; |
434 | new_connection->device = device; | 434 | new_connection->device = device; |
435 | new_connection->ssl_recv_timeout = (unsigned int)-1; | ||
436 | new_connection->status = IDEVICE_E_SUCCESS; | ||
435 | *connection = new_connection; | 437 | *connection = new_connection; |
436 | return IDEVICE_E_SUCCESS; | 438 | return IDEVICE_E_SUCCESS; |
437 | } else if (device->conn_type == CONNECTION_NETWORK) { | 439 | } else if (device->conn_type == CONNECTION_NETWORK) { |
@@ -478,6 +480,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connect(idevice_t device, uint16_t | |||
478 | new_connection->data = (void*)(long)sfd; | 480 | new_connection->data = (void*)(long)sfd; |
479 | new_connection->ssl_data = NULL; | 481 | new_connection->ssl_data = NULL; |
480 | new_connection->device = device; | 482 | new_connection->device = device; |
483 | new_connection->ssl_recv_timeout = (unsigned int)-1; | ||
481 | 484 | ||
482 | *connection = new_connection; | 485 | *connection = new_connection; |
483 | 486 | ||
@@ -558,15 +561,10 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_send(idevice_connection_ | |||
558 | } | 561 | } |
559 | 562 | ||
560 | if (connection->ssl_data) { | 563 | if (connection->ssl_data) { |
564 | connection->status = IDEVICE_E_SUCCESS; | ||
561 | uint32_t sent = 0; | 565 | uint32_t sent = 0; |
562 | while (sent < len) { | 566 | while (sent < len) { |
563 | #ifdef HAVE_OPENSSL | 567 | #ifdef HAVE_OPENSSL |
564 | int c = socket_check_fd((int)(long)connection->data, FDM_WRITE, 100); | ||
565 | if (c == 0 || c == -ETIMEDOUT || c == -EAGAIN) { | ||
566 | continue; | ||
567 | } else if (c < 0) { | ||
568 | break; | ||
569 | } | ||
570 | int s = SSL_write(connection->ssl_data->session, (const void*)(data+sent), (int)(len-sent)); | 568 | int s = SSL_write(connection->ssl_data->session, (const void*)(data+sent), (int)(len-sent)); |
571 | if (s <= 0) { | 569 | if (s <= 0) { |
572 | int sslerr = SSL_get_error(connection->ssl_data->session, s); | 570 | int sslerr = SSL_get_error(connection->ssl_data->session, s); |
@@ -586,7 +584,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_send(idevice_connection_ | |||
586 | debug_info("SSL_write %d, sent %d", len, sent); | 584 | debug_info("SSL_write %d, sent %d", len, sent); |
587 | if (sent < len) { | 585 | if (sent < len) { |
588 | *sent_bytes = 0; | 586 | *sent_bytes = 0; |
589 | return IDEVICE_E_SSL_ERROR; | 587 | return connection->status == IDEVICE_E_SUCCESS ? IDEVICE_E_SSL_ERROR : connection->status; |
590 | } | 588 | } |
591 | *sent_bytes = sent; | 589 | *sent_bytes = sent; |
592 | return IDEVICE_E_SUCCESS; | 590 | return IDEVICE_E_SUCCESS; |
@@ -670,30 +668,17 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_receive_timeout(idevice_ | |||
670 | 668 | ||
671 | if (connection->ssl_data) { | 669 | if (connection->ssl_data) { |
672 | uint32_t received = 0; | 670 | uint32_t received = 0; |
673 | int do_select = 1; | ||
674 | idevice_error_t error = IDEVICE_E_SSL_ERROR; | ||
675 | 671 | ||
672 | if (connection->ssl_recv_timeout != (unsigned int)-1) { | ||
673 | debug_info("WARNING: ssl_recv_timeout was not properly reset in idevice_connection_receive_timeout"); | ||
674 | } | ||
675 | |||
676 | // this should be reset after the SSL_read call on all codepaths, as | ||
677 | // the supplied timeout should only apply to the current read. | ||
678 | connection->ssl_recv_timeout = timeout; | ||
679 | connection->status = IDEVICE_E_SUCCESS; | ||
676 | while (received < len) { | 680 | while (received < len) { |
677 | #ifdef HAVE_OPENSSL | 681 | #ifdef HAVE_OPENSSL |
678 | do_select = (SSL_pending(connection->ssl_data->session) == 0); | ||
679 | #endif | ||
680 | if (do_select) { | ||
681 | int conn_error = socket_check_fd((int)(long)connection->data, FDM_READ, timeout); | ||
682 | error = socket_recv_to_idevice_error(conn_error, len, received); | ||
683 | switch (error) { | ||
684 | case IDEVICE_E_SUCCESS: | ||
685 | case IDEVICE_E_TIMEOUT: | ||
686 | break; | ||
687 | case IDEVICE_E_UNKNOWN_ERROR: | ||
688 | default: | ||
689 | debug_info("ERROR: socket_check_fd returned %d (%s)", conn_error, strerror(-conn_error)); | ||
690 | return error; | ||
691 | } | ||
692 | } | ||
693 | if (error == IDEVICE_E_TIMEOUT) { | ||
694 | break; | ||
695 | } | ||
696 | #ifdef HAVE_OPENSSL | ||
697 | int r = SSL_read(connection->ssl_data->session, (void*)((char*)(data+received)), (int)len-received); | 682 | int r = SSL_read(connection->ssl_data->session, (void*)((char*)(data+received)), (int)len-received); |
698 | if (r > 0) { | 683 | if (r > 0) { |
699 | received += r; | 684 | received += r; |
@@ -713,11 +698,12 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_receive_timeout(idevice_ | |||
713 | } | 698 | } |
714 | #endif | 699 | #endif |
715 | } | 700 | } |
701 | connection->ssl_recv_timeout = (unsigned int)-1; | ||
716 | 702 | ||
717 | debug_info("SSL_read %d, received %d", len, received); | 703 | debug_info("SSL_read %d, received %d", len, received); |
718 | if (received < len) { | 704 | if (received < len) { |
719 | *recv_bytes = received; | 705 | *recv_bytes = received; |
720 | return error; | 706 | return connection->status == IDEVICE_E_SUCCESS ? IDEVICE_E_SSL_ERROR : connection->status; |
721 | } | 707 | } |
722 | 708 | ||
723 | *recv_bytes = received; | 709 | *recv_bytes = received; |
@@ -763,6 +749,10 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_receive(idevice_connecti | |||
763 | } | 749 | } |
764 | 750 | ||
765 | if (connection->ssl_data) { | 751 | if (connection->ssl_data) { |
752 | if (connection->ssl_recv_timeout != (unsigned int)-1) { | ||
753 | debug_info("WARNING: ssl_recv_timeout was not properly reset in idevice_connection_receive_timeout"); | ||
754 | connection->ssl_recv_timeout = (unsigned int)-1; | ||
755 | } | ||
766 | #ifdef HAVE_OPENSSL | 756 | #ifdef HAVE_OPENSSL |
767 | int received = SSL_read(connection->ssl_data->session, (void*)data, (int)len); | 757 | int received = SSL_read(connection->ssl_data->session, (void*)data, (int)len); |
768 | debug_info("SSL_read %d, received %d", len, received); | 758 | debug_info("SSL_read %d, received %d", len, received); |
@@ -816,28 +806,36 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_get_udid(idevice_t device, char **u | |||
816 | return IDEVICE_E_SUCCESS; | 806 | return IDEVICE_E_SUCCESS; |
817 | } | 807 | } |
818 | 808 | ||
819 | #ifndef HAVE_OPENSSL | ||
820 | /** | 809 | /** |
821 | * Internally used gnutls callback function for receiving encrypted data. | 810 | * Internally used SSL callback function for receiving encrypted data. |
822 | */ | 811 | */ |
823 | static ssize_t internal_ssl_read(gnutls_transport_ptr_t transport, char *buffer, size_t length) | 812 | static ssize_t internal_ssl_read(idevice_connection_t connection, char *buffer, size_t length) |
824 | { | 813 | { |
825 | int bytes = 0, pos_start_fill = 0; | 814 | int bytes = 0, pos_start_fill = 0; |
826 | size_t tbytes = 0; | 815 | size_t tbytes = 0; |
827 | int this_len = length; | 816 | int this_len = length; |
828 | idevice_error_t res; | 817 | idevice_error_t res; |
829 | idevice_connection_t connection = (idevice_connection_t)transport; | ||
830 | char *recv_buffer; | 818 | char *recv_buffer; |
831 | 819 | ||
832 | debug_info("pre-read client wants %zi bytes", length); | 820 | debug_info("pre-read client wants %zi bytes", length); |
833 | 821 | ||
834 | recv_buffer = (char *)malloc(sizeof(char) * this_len); | 822 | recv_buffer = (char *)malloc(sizeof(char) * this_len); |
835 | 823 | ||
824 | unsigned int timeout = connection->ssl_recv_timeout; | ||
825 | |||
836 | /* repeat until we have the full data or an error occurs */ | 826 | /* repeat until we have the full data or an error occurs */ |
837 | do { | 827 | do { |
838 | if ((res = internal_connection_receive(connection, recv_buffer, this_len, (uint32_t*)&bytes)) != IDEVICE_E_SUCCESS) { | 828 | if (timeout == (unsigned int)-1) { |
839 | debug_info("ERROR: idevice_connection_receive returned %d", res); | 829 | res = internal_connection_receive(connection, recv_buffer, this_len, (uint32_t*)&bytes); |
840 | return res; | 830 | } else { |
831 | res = internal_connection_receive_timeout(connection, recv_buffer, this_len, (uint32_t*)&bytes, (unsigned int)timeout); | ||
832 | } | ||
833 | if (res != IDEVICE_E_SUCCESS) { | ||
834 | if (res != IDEVICE_E_TIMEOUT) { | ||
835 | debug_info("ERROR: %s returned %d", (timeout == (unsigned int)-1) ? "internal_connection_receive" : "internal_connection_receive_timeout", res); | ||
836 | } | ||
837 | connection->status = res; | ||
838 | return -1; | ||
841 | } | 839 | } |
842 | debug_info("post-read we got %i bytes", bytes); | 840 | debug_info("post-read we got %i bytes", bytes); |
843 | 841 | ||
@@ -863,22 +861,21 @@ static ssize_t internal_ssl_read(gnutls_transport_ptr_t transport, char *buffer, | |||
863 | } | 861 | } |
864 | 862 | ||
865 | /** | 863 | /** |
866 | * Internally used gnutls callback function for sending encrypted data. | 864 | * Internally used SSL callback function for sending encrypted data. |
867 | */ | 865 | */ |
868 | static ssize_t internal_ssl_write(gnutls_transport_ptr_t transport, char *buffer, size_t length) | 866 | static ssize_t internal_ssl_write(idevice_connection_t connection, const char *buffer, size_t length) |
869 | { | 867 | { |
870 | uint32_t bytes = 0; | 868 | uint32_t bytes = 0; |
871 | idevice_error_t res; | 869 | idevice_error_t res; |
872 | idevice_connection_t connection = (idevice_connection_t)transport; | ||
873 | debug_info("pre-send length = %zi", length); | 870 | debug_info("pre-send length = %zi", length); |
874 | if ((res = internal_connection_send(connection, buffer, length, &bytes)) != IDEVICE_E_SUCCESS) { | 871 | if ((res = internal_connection_send(connection, buffer, length, &bytes)) != IDEVICE_E_SUCCESS) { |
875 | debug_info("ERROR: internal_connection_send returned %d", res); | 872 | debug_info("ERROR: internal_connection_send returned %d", res); |
873 | connection->status = res; | ||
876 | return -1; | 874 | return -1; |
877 | } | 875 | } |
878 | debug_info("post-send sent %i bytes", bytes); | 876 | debug_info("post-send sent %i bytes", bytes); |
879 | return bytes; | 877 | return bytes; |
880 | } | 878 | } |
881 | #endif | ||
882 | 879 | ||
883 | /** | 880 | /** |
884 | * Internally used function for cleaning up SSL stuff. | 881 | * Internally used function for cleaning up SSL stuff. |
@@ -918,6 +915,32 @@ static void internal_ssl_cleanup(ssl_data_t ssl_data) | |||
918 | } | 915 | } |
919 | 916 | ||
920 | #ifdef HAVE_OPENSSL | 917 | #ifdef HAVE_OPENSSL |
918 | static long ssl_idevice_bio_callback(BIO *b, int oper, const char *argp, int argi, long argl, long retvalue) | ||
919 | { | ||
920 | idevice_connection_t conn = (idevice_connection_t)BIO_get_callback_arg(b); | ||
921 | size_t len = (size_t)argi; | ||
922 | switch (oper) { | ||
923 | case (BIO_CB_READ|BIO_CB_RETURN): | ||
924 | return argp ? (long)internal_ssl_read(conn, (char *)argp, len) : 0; | ||
925 | case (BIO_CB_PUTS|BIO_CB_RETURN): | ||
926 | len = strlen(argp); | ||
927 | // fallthrough | ||
928 | case (BIO_CB_WRITE|BIO_CB_RETURN): | ||
929 | return (long)internal_ssl_write(conn, argp, len); | ||
930 | default: | ||
931 | return retvalue; | ||
932 | } | ||
933 | } | ||
934 | |||
935 | static BIO *ssl_idevice_bio_new(idevice_connection_t conn) | ||
936 | { | ||
937 | BIO *b = BIO_new(BIO_s_null()); | ||
938 | if (!b) return NULL; | ||
939 | BIO_set_callback_arg(b, (char *)conn); | ||
940 | BIO_set_callback(b, ssl_idevice_bio_callback); | ||
941 | return b; | ||
942 | } | ||
943 | |||
921 | static int ssl_verify_callback(int ok, X509_STORE_CTX *ctx) | 944 | static int ssl_verify_callback(int ok, X509_STORE_CTX *ctx) |
922 | { | 945 | { |
923 | return 1; | 946 | return 1; |
@@ -1009,12 +1032,11 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_enable_ssl(idevice_conne | |||
1009 | if (pair_record) | 1032 | if (pair_record) |
1010 | plist_free(pair_record); | 1033 | plist_free(pair_record); |
1011 | 1034 | ||
1012 | BIO *ssl_bio = BIO_new(BIO_s_socket()); | 1035 | BIO *ssl_bio = ssl_idevice_bio_new(connection); |
1013 | if (!ssl_bio) { | 1036 | if (!ssl_bio) { |
1014 | debug_info("ERROR: Could not create SSL bio."); | 1037 | debug_info("ERROR: Could not create SSL bio."); |
1015 | return ret; | 1038 | return ret; |
1016 | } | 1039 | } |
1017 | BIO_set_fd(ssl_bio, (int)(long)connection->data, BIO_NOCLOSE); | ||
1018 | 1040 | ||
1019 | SSL_CTX *ssl_ctx = SSL_CTX_new(TLS_method()); | 1041 | SSL_CTX *ssl_ctx = SSL_CTX_new(TLS_method()); |
1020 | if (ssl_ctx == NULL) { | 1042 | if (ssl_ctx == NULL) { |
diff --git a/src/idevice.h b/src/idevice.h index 8709c9a..4e53a7f 100644 --- a/src/idevice.h +++ b/src/idevice.h | |||
@@ -68,6 +68,8 @@ struct idevice_connection_private { | |||
68 | enum idevice_connection_type type; | 68 | enum idevice_connection_type type; |
69 | void *data; | 69 | void *data; |
70 | ssl_data_t ssl_data; | 70 | ssl_data_t ssl_data; |
71 | unsigned int ssl_recv_timeout; | ||
72 | idevice_error_t status; | ||
71 | }; | 73 | }; |
72 | 74 | ||
73 | struct idevice_private { | 75 | struct idevice_private { |