From 42b25a4d3e2fe66f03cbd8c866d8af7bd4f6e5a7 Mon Sep 17 00:00:00 2001 From: mannol Date: Sun, 27 Apr 2014 19:21:26 +0200 Subject: Yeah many calls --- toxav/msi.h | 66 +++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 38 insertions(+), 28 deletions(-) (limited to 'toxav/msi.h') diff --git a/toxav/msi.h b/toxav/msi.h index 37fc07a3..c74f9f11 100755 --- a/toxav/msi.h +++ b/toxav/msi.h @@ -33,7 +33,7 @@ #define CALL_ID_LEN 12 -typedef void ( *MSICallback ) ( void *arg ); +typedef void ( *MSICallback ) ( uint32_t, void *arg ); /** @@ -62,32 +62,34 @@ typedef enum { * @brief The call struct. * */ -typedef struct _MSICall { /* Call info structure */ - MSICallState state; +typedef struct _MSICall { /* Call info structure */ + struct _MSISession* session; /* Session pointer */ + + MSICallState state; - MSICallType type_local; /* Type of payload user is ending */ - MSICallType *type_peer; /* Type of payload others are sending */ + MSICallType type_local; /* Type of payload user is ending */ + MSICallType *type_peer; /* Type of payload others are sending */ - uint8_t id[CALL_ID_LEN]; /* Random value identifying the call */ + uint8_t id[CALL_ID_LEN]; /* Random value identifying the call */ - uint8_t *key_local; /* The key for encryption */ - uint8_t *key_peer; /* The key for decryption */ + uint8_t *key_local; /* The key for encryption */ + uint8_t *key_peer; /* The key for decryption */ - uint8_t *nonce_local; /* Local nonce */ - uint8_t *nonce_peer; /* Peer nonce */ + uint8_t *nonce_local; /* Local nonce */ + uint8_t *nonce_peer; /* Peer nonce */ - int ringing_tout_ms; /* Ringing timeout in ms */ + int ringing_tout_ms; /* Ringing timeout in ms */ - int request_timer_id; /* Timer id for outgoing request/action */ - int ringing_timer_id; /* Timer id for ringing timeout */ - - pthread_mutex_t mutex; /* It's to be assumed that call will have - * seperate thread so add mutex - */ - uint32_t *peers; - uint16_t peer_count; + int request_timer_id; /* Timer id for outgoing request/action */ + int ringing_timer_id; /* Timer id for ringing timeout */ + pthread_mutex_t mutex; /* It's to be assumed that call will have + * seperate thread so add mutex + */ + uint32_t *peers; + uint16_t peer_count; + uint32_t call_idx; /* Index of this call in MSISession */ } MSICall; @@ -97,8 +99,9 @@ typedef struct _MSICall { /* Call info structure */ */ typedef struct _MSISession { - /* Call handler */ - struct _MSICall *call; + /* Call handlers */ + struct _MSICall **calls; + uint32_t max_calls; int last_error_id; /* Determine the last error */ const uint8_t *last_error_str; @@ -151,10 +154,11 @@ void msi_register_callback(MSICallback callback, MSICallbackID id, void* userdat * @brief Start the control session. * * @param messenger Tox* object. + * @param max_calls Amount of calls possible * @return MSISession* The created session. * @retval NULL Error occured. */ -MSISession *msi_init_session ( Messenger *messenger ); +MSISession *msi_init_session ( Messenger *messenger, uint32_t max_calls ); /** @@ -170,62 +174,68 @@ int msi_terminate_session ( MSISession *session ); * @brief Send invite request to friend_id. * * @param session Control session. + * @param call_index Set to new call index. * @param call_type Type of the call. Audio or Video(both audio and video) * @param rngsec Ringing timeout. * @param friend_id The friend. * @return int */ -int msi_invite ( MSISession *session, MSICallType call_type, uint32_t rngsec, uint32_t friend_id ); +int msi_invite ( MSISession *session, uint32_t* call_index, MSICallType call_type, uint32_t rngsec, uint32_t friend_id ); /** * @brief Hangup active call. * * @param session Control session. + * @param call_index To which call is this action handled. * @return int * @retval -1 Error occured. * @retval 0 Success. */ -int msi_hangup ( MSISession *session ); +int msi_hangup ( MSISession *session, uint32_t call_index ); /** * @brief Answer active call request. * * @param session Control session. + * @param call_index To which call is this action handled. * @param call_type Answer with Audio or Video(both). * @return int */ -int msi_answer ( MSISession *session, MSICallType call_type ); +int msi_answer ( MSISession *session, uint32_t call_index, MSICallType call_type ); /** * @brief Cancel request. * * @param session Control session. + * @param call_index To which call is this action handled. * @param peer To which peer. * @param reason Set optional reason header. Pass NULL if none. * @return int */ -int msi_cancel ( MSISession* session, uint32_t peer, const char* reason ); +int msi_cancel ( MSISession* session, uint32_t call_index, uint32_t peer, const char* reason ); /** * @brief Reject request. * * @param session Control session. + * @param call_index To which call is this action handled. * @param reason Set optional reason header. Pass NULL if none. * @return int */ -int msi_reject ( MSISession *session, const uint8_t *reason ); +int msi_reject ( MSISession *session, uint32_t call_index, const uint8_t *reason ); /** * @brief Terminate the current call. * * @param session Control session. + * @param call_index To which call is this action handled. * @return int */ -int msi_stopcall ( MSISession *session ); +int msi_stopcall ( MSISession *session, uint32_t call_index ); #endif /* __TOXMSI */ -- cgit v1.2.3 From 843171fbc8e0cb12c14fac39bef15e596f44bef1 Mon Sep 17 00:00:00 2001 From: mannol Date: Fri, 16 May 2014 19:56:40 +0200 Subject: This works. --- auto_tests/toxav_basic_test.c | 20 +++--- auto_tests/toxav_many_test.c | 20 +++--- toxav/media.c | 5 +- toxav/msi.c | 156 ++++++++++++++++++------------------------ toxav/msi.h | 20 +++--- toxav/rtp.c | 36 ++-------- toxav/toxav.c | 72 ++++++++++++------- toxav/toxav.h | 44 ++++++------ toxcore/Messenger.c | 10 +-- toxcore/logger.c | 12 ++-- toxcore/logger.h | 2 +- toxcore/network.c | 2 +- 12 files changed, 185 insertions(+), 214 deletions(-) (limited to 'toxav/msi.h') diff --git a/auto_tests/toxav_basic_test.c b/auto_tests/toxav_basic_test.c index c8ebd497..c0162582 100644 --- a/auto_tests/toxav_basic_test.c +++ b/auto_tests/toxav_basic_test.c @@ -58,7 +58,7 @@ void accept_friend_request(Tox *m, uint8_t *public_key, uint8_t *data, uint16_t /******************************************************************************/ -void callback_recv_invite ( uint32_t call_index, void *_arg ) +void callback_recv_invite ( int32_t call_index, void *_arg ) { Status *cast = _arg; @@ -66,14 +66,14 @@ void callback_recv_invite ( uint32_t call_index, void *_arg ) cast->Bob.status = Ringing; cast->Bob.call_index = call_index; } -void callback_recv_ringing ( uint32_t call_index, void *_arg ) +void callback_recv_ringing ( int32_t call_index, void *_arg ) { Status *cast = _arg; /* Alice always sends invite */ cast->Alice.status = Ringing; } -void callback_recv_starting ( uint32_t call_index, void *_arg ) +void callback_recv_starting ( int32_t call_index, void *_arg ) { Status *cast = _arg; @@ -82,7 +82,7 @@ void callback_recv_starting ( uint32_t call_index, void *_arg ) cast->Alice.status = InCall; toxav_prepare_transmission(cast->Alice.av, call_index, &muhcaps, 1); } -void callback_recv_ending ( uint32_t call_index, void *_arg ) +void callback_recv_ending ( int32_t call_index, void *_arg ) { Status *cast = _arg; @@ -95,12 +95,12 @@ void callback_recv_ending ( uint32_t call_index, void *_arg ) } } -void callback_recv_error ( uint32_t call_index, void *_arg ) +void callback_recv_error ( int32_t call_index, void *_arg ) { ck_assert_msg(0, "AV internal error"); } -void callback_call_started ( uint32_t call_index, void *_arg ) +void callback_call_started ( int32_t call_index, void *_arg ) { Status *cast = _arg; @@ -109,14 +109,14 @@ void callback_call_started ( uint32_t call_index, void *_arg ) cast->Bob.status = InCall; toxav_prepare_transmission(cast->Bob.av, call_index, &muhcaps, 1); } -void callback_call_canceled ( uint32_t call_index, void *_arg ) +void callback_call_canceled ( int32_t call_index, void *_arg ) { Status *cast = _arg; printf ( "Call Canceled for Bob!\n" ); cast->Bob.status = Cancel; } -void callback_call_rejected ( uint32_t call_index, void *_arg ) +void callback_call_rejected ( int32_t call_index, void *_arg ) { Status *cast = _arg; @@ -125,7 +125,7 @@ void callback_call_rejected ( uint32_t call_index, void *_arg ) /* If Bob rejects, call is ended for alice and she sends ending */ cast->Alice.status = Rejected; } -void callback_call_ended ( uint32_t call_index, void *_arg ) +void callback_call_ended ( int32_t call_index, void *_arg ) { Status *cast = _arg; @@ -133,7 +133,7 @@ void callback_call_ended ( uint32_t call_index, void *_arg ) cast->Bob.status = Ended; } -void callback_requ_timeout ( uint32_t call_index, void *_arg ) +void callback_requ_timeout ( int32_t call_index, void *_arg ) { ck_assert_msg(0, "No answer!"); } diff --git a/auto_tests/toxav_many_test.c b/auto_tests/toxav_many_test.c index 77f3717e..b499b439 100644 --- a/auto_tests/toxav_many_test.c +++ b/auto_tests/toxav_many_test.c @@ -60,62 +60,62 @@ void accept_friend_request(Tox *m, uint8_t *public_key, uint8_t *data, uint16_t /******************************************************************************/ -void callback_recv_invite ( uint32_t call_index, void *_arg ) +void callback_recv_invite ( int32_t call_index, void *_arg ) {/* Status *cast = _arg; cast->calls[call_index].Callee.status = Ringing;*/ } -void callback_recv_ringing ( uint32_t call_index, void *_arg ) +void callback_recv_ringing ( int32_t call_index, void *_arg ) { Status *cast = _arg; cast->calls[call_index].Caller.status = Ringing; } -void callback_recv_starting ( uint32_t call_index, void *_arg ) +void callback_recv_starting ( int32_t call_index, void *_arg ) { Status *cast = _arg; cast->calls[call_index].Caller.status = InCall; } -void callback_recv_ending ( uint32_t call_index, void *_arg ) +void callback_recv_ending ( int32_t call_index, void *_arg ) { Status *cast = _arg; cast->calls[call_index].Caller.status = Ended; } -void callback_recv_error ( uint32_t call_index, void *_arg ) +void callback_recv_error ( int32_t call_index, void *_arg ) { ck_assert_msg(0, "AV internal error"); } -void callback_call_started ( uint32_t call_index, void *_arg ) +void callback_call_started ( int32_t call_index, void *_arg ) {/* Status *cast = _arg; cast->calls[call_index].Callee.status = InCall;*/ } -void callback_call_canceled ( uint32_t call_index, void *_arg ) +void callback_call_canceled ( int32_t call_index, void *_arg ) {/* Status *cast = _arg; cast->calls[call_index].Callee.status = Cancel;*/ } -void callback_call_rejected ( uint32_t call_index, void *_arg ) +void callback_call_rejected ( int32_t call_index, void *_arg ) { Status *cast = _arg; cast->calls[call_index].Caller.status = Rejected; } -void callback_call_ended ( uint32_t call_index, void *_arg ) +void callback_call_ended ( int32_t call_index, void *_arg ) {/* Status *cast = _arg; cast->calls[call_index].Callee.status = Ended;*/ } -void callback_requ_timeout ( uint32_t call_index, void *_arg ) +void callback_requ_timeout ( int32_t call_index, void *_arg ) { ck_assert_msg(0, "No answer!"); } diff --git a/toxav/media.c b/toxav/media.c index 5700c2f2..a6590e00 100644 --- a/toxav/media.c +++ b/toxav/media.c @@ -71,10 +71,7 @@ JitterBuffer *create_queue(int capacity) void terminate_queue(JitterBuffer* q) { - int i; - for ( i = 0; i < q->capacity; i ++ ) { - rtp_free_msg(NULL, q->queue[i]); - } + empty_queue(q); free(q->queue); free(q); } diff --git a/toxav/msi.c b/toxav/msi.c index 8d4e6964..c2d50302 100755 --- a/toxav/msi.c +++ b/toxav/msi.c @@ -122,7 +122,7 @@ static struct _Callbacks { void* data; } callbacks[11] = {0}; -inline__ void invoke_callback(uint32_t call_index, MSICallbackID id) +inline__ void invoke_callback(int32_t call_index, MSICallbackID id) { /*if ( callbacks[id].function ) event.rise ( callbacks[id].function, callbacks[id].data );*/ if ( callbacks[id].function ) { @@ -209,18 +209,7 @@ static inline__ const uint8_t *stringify_response ( MSIResponse response ) } -#define ON_HEADER(iterator, header, descriptor, size_const) \ -( memcmp(iterator, descriptor, size_const) == 0){ /* Okay */ \ - iterator += size_const; /* Set iterator at begining of value part */ \ - if ( *iterator != value_byte ) { assert(0); return -1; }\ - iterator ++;\ - uint16_t _value_size = (uint16_t) *(iterator ) << 8 | \ - (uint16_t) *(iterator + 1); \ - header.header_value = calloc(sizeof(uint8_t), _value_size); \ - header.size = _value_size; \ - memcpy(header.header_value, iterator + 2, _value_size);\ - iterator = iterator + 2 + _value_size; /* set iterator at new header or end_byte */ \ -} + /** * @brief Parse raw 'data' received from socket into MSIMessage struct. @@ -235,6 +224,19 @@ static inline__ const uint8_t *stringify_response ( MSIResponse response ) */ int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t length ) { + +#define ON_HEADER(iterator, header, descriptor, size_const) \ +( memcmp(iterator, descriptor, size_const) == 0){ /* Okay */ \ +iterator += size_const; /* Set iterator at begining of value part */ \ +if ( *iterator != value_byte ) { assert(0); return -1; }\ + iterator ++;\ + uint16_t _value_size = (uint16_t) *(iterator ) << 8 | \ + (uint16_t) *(iterator + 1); \ + header.header_value = calloc(sizeof(uint8_t), _value_size); \ + header.size = _value_size; \ + memcpy(header.header_value, iterator + 2, _value_size);\ + iterator = iterator + 2 + _value_size; /* set iterator at new header or end_byte */ } + if ( msg == NULL ) { LOGGER_ERROR("Could not parse message: no storage!"); } @@ -537,10 +539,6 @@ uint8_t *append_header_to_string ( } -#define CLEAN_ASSIGN(added, var, field, header)\ -if ( header.header_value ) { var = append_header_to_string(var, (const uint8_t*)field, header.header_value, header.size, &added); } - - /** * @brief Convert MSIMessage struct to _sendable_ string. * @@ -550,6 +548,9 @@ if ( header.header_value ) { var = append_header_to_string(var, (const uint8_t*) */ uint16_t message_to_send ( MSIMessage *msg, uint8_t *dest ) { + #define CLEAN_ASSIGN(added, var, field, header)\ + if ( header.header_value ) { var = append_header_to_string(var, (const uint8_t*)field, header.header_value, header.size, &added); } + if (msg == NULL) { LOGGER_ERROR("Empty message!"); return 0; @@ -856,35 +857,6 @@ int has_call_error ( MSISession *session, MSICall* call, MSIMessage *msg ) } -/** - * @brief Function called at request timeout. If not called in thread it might cause trouble - * - * @param arg Control session - * @return void* - */ -void *handle_timeout ( void *arg ) -{ - /* TODO: Cancel might not arrive there; set up - * timers on these cancels and terminate call on - * their timeout - */ - MSICall *_call = arg; - - LOGGER_DEBUG("[Call: %s] Request timed out!", _call->id); - - invoke_callback(_call->call_idx, MSI_OnRequestTimeout); - - if ( _call && _call->session ) { - - /* TODO: Cancel all? */ - /* uint16_t _it = 0; - for ( ; _it < _session->call->peer_count; _it++ ) */ - msi_cancel ( _call->session, _call->call_idx, _call->peers [0], "Request timed out" ); - } - - pthread_exit(NULL); -} - /** * @brief Add peer to peer list. * @@ -903,6 +875,8 @@ void add_peer( MSICall *call, int peer_id ) } call->peers[call->peer_count - 1] = peer_id; + + LOGGER_DEBUG("Added peer: %d", peer_id); } @@ -922,7 +896,7 @@ MSICall *init_call ( MSISession *session, int peers, int ringing_timeout ) return NULL; } - uint32_t _call_idx = 0; + int32_t _call_idx = 0; for (; _call_idx < session->max_calls; _call_idx ++) { if ( !session->calls[_call_idx] ) { session->calls[_call_idx] = calloc ( sizeof ( MSICall ), 1 ); @@ -1015,6 +989,37 @@ int terminate_call ( MSISession *session, MSICall *call ) } +/** + * @brief Function called at request timeout. If not called in thread it might cause trouble + * + * @param arg Control session + * @return void* + */ +void *handle_timeout ( void *arg ) +{ + /* TODO: Cancel might not arrive there; set up + * timers on these cancels and terminate call on + * their timeout + */ + MSICall *_call = arg; + + LOGGER_DEBUG("[Call: %s] Request timed out!", _call->id); + + invoke_callback(_call->call_idx, MSI_OnRequestTimeout); + + if ( _call && _call->session ) { + + /* TODO: Cancel all? */ + /* uint16_t _it = 0; + * for ( ; _it < _session->call->peer_count; _it++ ) */ + msi_cancel ( _call->session, _call->call_idx, _call->peers [0], "Request timed out" ); + terminate_call(_call->session, _call); + } + + pthread_exit(NULL); +} + + /********** Request handlers **********/ int handle_recv_invite ( MSISession *session, MSICall* call, MSIMessage *msg ) { @@ -1072,7 +1077,7 @@ int handle_recv_invite ( MSISession *session, MSICall* call, MSIMessage *msg ) } int handle_recv_start ( MSISession *session, MSICall* call, MSIMessage *msg ) { - LOGGER_DEBUG("Session: %p Handling 'start' on call: %s", session, call->id ); + LOGGER_DEBUG("Session: %p Handling 'start' on call: %s, friend id: %d", session, call->id, msg->friend_id ); if ( has_call_error ( session, call, msg ) == 0 ) return -1; @@ -1125,10 +1130,10 @@ int handle_recv_cancel ( MSISession *session, MSICall* call, MSIMessage *msg ) return 0; /* Act as end message */ - + /* MSIMessage *_msg_ending = msi_new_message ( TYPE_RESPONSE, stringify_response ( ending ) ); send_message ( session, call, _msg_ending, msg->friend_id ); - free_message ( _msg_ending ); + free_message ( _msg_ending );*/ invoke_callback(call->call_idx, MSI_OnCancel); @@ -1383,31 +1388,6 @@ void msi_handle_packet ( Messenger *messenger, int source, uint8_t *data, uint16 } -/******************************************************************************************************************** - * ******************************************************************************************************************* - ******************************************************************************************************************** - ******************************************************************************************************************** - ******************************************************************************************************************** - * - * - * - * PUBLIC API FUNCTIONS IMPLEMENTATIONS - * - * - * - ******************************************************************************************************************** - ******************************************************************************************************************** - ******************************************************************************************************************** - ******************************************************************************************************************** - ********************************************************************************************************************/ - - - - - - - - /** * @brief Callback setter. * @@ -1430,7 +1410,7 @@ void msi_register_callback ( MSICallback callback, MSICallbackID id, void* userd * @return MSISession* The created session. * @retval NULL Error occured. */ -MSISession *msi_init_session ( Messenger* messenger, uint32_t max_calls ) +MSISession *msi_init_session ( Messenger* messenger, int32_t max_calls ) { if (messenger == NULL) { LOGGER_ERROR("Could not init session on empty messenger!"); @@ -1507,13 +1487,13 @@ int msi_terminate_session ( MSISession *session ) * @param friend_id The friend. * @return int */ -int msi_invite ( MSISession* session, uint32_t* call_index, MSICallType call_type, uint32_t rngsec, uint32_t friend_id ) +int msi_invite ( MSISession* session, int32_t* call_index, MSICallType call_type, uint32_t rngsec, uint32_t friend_id ) { LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_id); MSIMessage *_msg_invite = msi_new_message ( TYPE_REQUEST, stringify_request ( invite ) ); - MSICall* _call = init_call ( session, 1, rngsec ); /* Just one for now */ + MSICall* _call = init_call ( session, 1, rngsec ); /* Just one peer for now */ if ( !_call ) return -1; /* Cannot handle more calls */ *call_index = _call->call_idx; @@ -1553,11 +1533,11 @@ int msi_invite ( MSISession* session, uint32_t* call_index, MSICallType call_typ * @retval -1 Error occured. * @retval 0 Success. */ -int msi_hangup ( MSISession* session, uint32_t call_index ) +int msi_hangup ( MSISession* session, int32_t call_index ) { LOGGER_DEBUG("Session: %p Hanging up call: %u", session, call_index); - if ( call_index >= session->max_calls || !session->calls[call_index] ) { + if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) { LOGGER_ERROR("Invalid call index!"); return -1; } @@ -1592,11 +1572,11 @@ int msi_hangup ( MSISession* session, uint32_t call_index ) * @param call_type Answer with Audio or Video(both). * @return int */ -int msi_answer ( MSISession* session, uint32_t call_index, MSICallType call_type ) +int msi_answer ( MSISession* session, int32_t call_index, MSICallType call_type ) { LOGGER_DEBUG("Session: %p Answering call: %u", session, call_index); - if ( call_index >= session->max_calls || !session->calls[call_index] ){ + if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ){ LOGGER_ERROR("Invalid call index!"); return -1; } @@ -1641,11 +1621,11 @@ int msi_answer ( MSISession* session, uint32_t call_index, MSICallType call_type * @param reason Set optional reason header. Pass NULL if none. * @return int */ -int msi_cancel ( MSISession *session, uint32_t call_index, uint32_t peer, const char *reason ) +int msi_cancel ( MSISession* session, int32_t call_index, uint32_t peer, const char* reason ) { LOGGER_DEBUG("Session: %p Canceling call: %u; reason:", session, call_index, reason? reason : "Unknown"); - if ( call_index >= session->max_calls || !session->calls[call_index] ){ + if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ){ LOGGER_ERROR("Invalid call index!"); return -1; } @@ -1670,11 +1650,11 @@ int msi_cancel ( MSISession *session, uint32_t call_index, uint32_t peer, const * @param call_id To which call is this action handled. * @return int */ -int msi_reject ( MSISession *session, uint32_t call_index, const uint8_t *reason ) +int msi_reject ( MSISession* session, int32_t call_index, const uint8_t* reason ) { LOGGER_DEBUG("Session: %p Rejecting call: %u; reason:", session, call_index, reason? (char*)reason : "Unknown"); - if ( call_index >= session->max_calls || !session->calls[call_index] ){ + if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ){ LOGGER_ERROR("Invalid call index!"); return -1; } @@ -1699,11 +1679,11 @@ int msi_reject ( MSISession *session, uint32_t call_index, const uint8_t *reason * @param call_id To which call is this action handled. * @return int */ -int msi_stopcall ( MSISession *session, uint32_t call_index ) +int msi_stopcall ( MSISession* session, int32_t call_index ) { LOGGER_DEBUG("Session: %p Stopping call index: %u", session, call_index); - if ( call_index >= session->max_calls || !session->calls[call_index] ) + if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) return -1; /* just terminate it */ diff --git a/toxav/msi.h b/toxav/msi.h index c74f9f11..2a7c5ba8 100755 --- a/toxav/msi.h +++ b/toxav/msi.h @@ -33,7 +33,7 @@ #define CALL_ID_LEN 12 -typedef void ( *MSICallback ) ( uint32_t, void *arg ); +typedef void ( *MSICallback ) ( int32_t, void *arg ); /** @@ -89,7 +89,7 @@ typedef struct _MSICall { /* Call info structure */ uint32_t *peers; uint16_t peer_count; - uint32_t call_idx; /* Index of this call in MSISession */ + int32_t call_idx; /* Index of this call in MSISession */ } MSICall; @@ -101,7 +101,7 @@ typedef struct _MSISession { /* Call handlers */ struct _MSICall **calls; - uint32_t max_calls; + int32_t max_calls; int last_error_id; /* Determine the last error */ const uint8_t *last_error_str; @@ -158,7 +158,7 @@ void msi_register_callback(MSICallback callback, MSICallbackID id, void* userdat * @return MSISession* The created session. * @retval NULL Error occured. */ -MSISession *msi_init_session ( Messenger *messenger, uint32_t max_calls ); +MSISession *msi_init_session ( Messenger *messenger, int32_t max_calls ); /** @@ -180,7 +180,7 @@ int msi_terminate_session ( MSISession *session ); * @param friend_id The friend. * @return int */ -int msi_invite ( MSISession *session, uint32_t* call_index, MSICallType call_type, uint32_t rngsec, uint32_t friend_id ); +int msi_invite ( MSISession *session, int32_t* call_index, MSICallType call_type, uint32_t rngsec, uint32_t friend_id ); /** @@ -192,7 +192,7 @@ int msi_invite ( MSISession *session, uint32_t* call_index, MSICallType call_typ * @retval -1 Error occured. * @retval 0 Success. */ -int msi_hangup ( MSISession *session, uint32_t call_index ); +int msi_hangup ( MSISession *session, int32_t call_index ); /** @@ -203,7 +203,7 @@ int msi_hangup ( MSISession *session, uint32_t call_index ); * @param call_type Answer with Audio or Video(both). * @return int */ -int msi_answer ( MSISession *session, uint32_t call_index, MSICallType call_type ); +int msi_answer ( MSISession *session, int32_t call_index, MSICallType call_type ); /** @@ -215,7 +215,7 @@ int msi_answer ( MSISession *session, uint32_t call_index, MSICallType call_type * @param reason Set optional reason header. Pass NULL if none. * @return int */ -int msi_cancel ( MSISession* session, uint32_t call_index, uint32_t peer, const char* reason ); +int msi_cancel ( MSISession* session, int32_t call_index, uint32_t peer, const char* reason ); /** @@ -226,7 +226,7 @@ int msi_cancel ( MSISession* session, uint32_t call_index, uint32_t peer, const * @param reason Set optional reason header. Pass NULL if none. * @return int */ -int msi_reject ( MSISession *session, uint32_t call_index, const uint8_t *reason ); +int msi_reject ( MSISession *session, int32_t call_index, const uint8_t *reason ); /** @@ -236,6 +236,6 @@ int msi_reject ( MSISession *session, uint32_t call_index, const uint8_t *reason * @param call_index To which call is this action handled. * @return int */ -int msi_stopcall ( MSISession *session, uint32_t call_index ); +int msi_stopcall ( MSISession *session, int32_t call_index ); #endif /* __TOXMSI */ diff --git a/toxav/rtp.c b/toxav/rtp.c index 1e6296b0..8b2768f1 100755 --- a/toxav/rtp.c +++ b/toxav/rtp.c @@ -652,36 +652,6 @@ RTPMessage *rtp_new_message ( RTPSession *session, const uint8_t *data, uint32_t - - - - -/******************************************************************************************************************** - ******************************************************************************************************************** - ******************************************************************************************************************** - ******************************************************************************************************************** - ******************************************************************************************************************** - * - * - * - * PUBLIC API FUNCTIONS IMPLEMENTATIONS - * - * - * - ******************************************************************************************************************** - ******************************************************************************************************************** - ******************************************************************************************************************** - ******************************************************************************************************************** - ********************************************************************************************************************/ - - - - - - - - - /** * @brief Release all messages held by session. * @@ -757,6 +727,7 @@ RTPMessage *rtp_recv_msg ( RTPSession *session ) pthread_mutex_lock(&session->mutex); if ( session->queue_size == 0 ) { + pthread_mutex_unlock(&session->mutex); return NULL; } @@ -890,12 +861,13 @@ RTPSession *rtp_init_session ( int payload_type, assert(_retu); if ( -1 == custom_user_packet_registerhandler(messenger, friend_num, payload_type, rtp_handle_packet, _retu) || - !encrypt_key, !decrypt_key, !encrypt_nonce, !decrypt_nonce - ) { + !encrypt_key || !decrypt_key || !encrypt_nonce || !decrypt_nonce) { LOGGER_ERROR("Error setting custom register handler for rtp session"); free(_retu); return NULL; } + + LOGGER_DEBUG("Registered packet handler: pt: %d; fid: %d", payload_type, friend_num); _retu->version = RTP_VERSION; /* It's always 2 */ _retu->padding = 0; /* If some additional data is needed about the packet */ diff --git a/toxav/toxav.c b/toxav/toxav.c index 3a41754a..015c6565 100755 --- a/toxav/toxav.c +++ b/toxav/toxav.c @@ -92,7 +92,7 @@ const ToxAvCodecSettings av_DefaultSettings = { * @return ToxAv* * @retval NULL On error. */ -ToxAv *toxav_new( Tox* messenger, uint32_t max_calls) +ToxAv *toxav_new( Tox* messenger, int32_t max_calls) { ToxAv *av = calloc ( sizeof(ToxAv), 1); @@ -171,7 +171,7 @@ void toxav_register_callstate_callback ( ToxAVCallback callback, ToxAvCallbackID * @retval 0 Success. * @retval ToxAvError On error. */ -int toxav_call (ToxAv* av, uint32_t* call_index, int user, ToxAvCallType call_type, int ringing_seconds ) +int toxav_call (ToxAv* av, int32_t* call_index, int user, ToxAvCallType call_type, int ringing_seconds ) { return msi_invite(av->msi_session, call_index, call_type, ringing_seconds * 1000, user); } @@ -184,7 +184,7 @@ int toxav_call (ToxAv* av, uint32_t* call_index, int user, ToxAvCallType call_ty * @retval 0 Success. * @retval ToxAvError On error. */ -int toxav_hangup ( ToxAv* av, uint32_t call_index ) +int toxav_hangup ( ToxAv* av, int32_t call_index ) { if ( !av->msi_session->calls[call_index] ) { return ErrorNoCall; @@ -206,7 +206,7 @@ int toxav_hangup ( ToxAv* av, uint32_t call_index ) * @retval 0 Success. * @retval ToxAvError On error. */ -int toxav_answer ( ToxAv* av, uint32_t call_index, ToxAvCallType call_type ) +int toxav_answer ( ToxAv* av, int32_t call_index, ToxAvCallType call_type ) { if ( !av->msi_session->calls[call_index] ) { return ErrorNoCall; @@ -228,7 +228,7 @@ int toxav_answer ( ToxAv* av, uint32_t call_index, ToxAvCallType call_type ) * @retval 0 Success. * @retval ToxAvError On error. */ -int toxav_reject ( ToxAv* av, uint32_t call_index, const char* reason ) +int toxav_reject ( ToxAv* av, int32_t call_index, const char* reason ) { if ( !av->msi_session->calls[call_index] ) { return ErrorNoCall; @@ -251,7 +251,7 @@ int toxav_reject ( ToxAv* av, uint32_t call_index, const char* reason ) * @retval 0 Success. * @retval ToxAvError On error. */ -int toxav_cancel ( ToxAv* av, uint32_t call_index, int peer_id, const char* reason ) +int toxav_cancel ( ToxAv* av, int32_t call_index, int peer_id, const char* reason ) { if ( !av->msi_session->calls[call_index] ) { return ErrorNoCall; @@ -268,7 +268,7 @@ int toxav_cancel ( ToxAv* av, uint32_t call_index, int peer_id, const char* reas * @retval 0 Success. * @retval ToxAvError On error. */ -int toxav_stop_call ( ToxAv* av, uint32_t call_index ) +int toxav_stop_call ( ToxAv* av, int32_t call_index ) { if ( !av->msi_session->calls[call_index] ) { return ErrorNoCall; @@ -285,7 +285,7 @@ int toxav_stop_call ( ToxAv* av, uint32_t call_index ) * @retval 0 Success. * @retval ToxAvError On error. */ -int toxav_prepare_transmission ( ToxAv* av, uint32_t call_index, ToxAvCodecSettings* codec_settings, int support_video ) +int toxav_prepare_transmission ( ToxAv* av, int32_t call_index, ToxAvCodecSettings* codec_settings, int support_video ) { if ( !av->msi_session || av->msi_session->max_calls <= call_index || !av->msi_session->calls[call_index] ) { /*fprintf(stderr, "Error while starting audio RTP session: invalid call!\n");*/ @@ -350,7 +350,7 @@ int toxav_prepare_transmission ( ToxAv* av, uint32_t call_index, ToxAvCodecSetti * @retval 0 Success. * @retval ToxAvError On error. */ -int toxav_kill_transmission ( ToxAv *av, uint32_t call_index ) +int toxav_kill_transmission ( ToxAv *av, int32_t call_index ) { CallSpecific* call = &av->calls[call_index]; @@ -370,12 +370,16 @@ int toxav_kill_transmission ( ToxAv *av, uint32_t call_index ) if ( call->j_buf ) { terminate_queue(call->j_buf); call->j_buf = NULL; + LOGGER_DEBUG("Terminated j queue"); } + else LOGGER_DEBUG("No j queue"); if ( call->cs ) { codec_terminate_session(call->cs); call->cs = NULL; + LOGGER_DEBUG("Terminated codec session"); } + else LOGGER_DEBUG("No codec session"); return ErrorNone; } @@ -392,7 +396,7 @@ int toxav_kill_transmission ( ToxAv *av, uint32_t call_index ) * @retval 0 Success. * @retval -1 Failure. */ -inline__ int toxav_send_rtp_payload ( ToxAv *av, uint32_t call_index, ToxAvCallType type, const uint8_t *payload, uint16_t length ) +inline__ int toxav_send_rtp_payload ( ToxAv *av, int32_t call_index, ToxAvCallType type, const uint8_t *payload, uint16_t length ) { if ( av->calls[call_index].crtps[type - TypeAudio] ) return rtp_send_msg ( av->calls[call_index].crtps[type - TypeAudio], av->msi_session->messenger_handle, payload, length ); @@ -409,7 +413,7 @@ inline__ int toxav_send_rtp_payload ( ToxAv *av, uint32_t call_index, ToxAvCallT * @retval ToxAvError On Error. * @retval >=0 Size of received payload. */ -inline__ int toxav_recv_rtp_payload ( ToxAv *av, uint32_t call_index, ToxAvCallType type, uint8_t *dest ) +inline__ int toxav_recv_rtp_payload ( ToxAv *av, int32_t call_index, ToxAvCallType type, uint8_t *dest ) { if ( !dest ) return ErrorInternal; @@ -460,7 +464,7 @@ inline__ int toxav_recv_rtp_payload ( ToxAv *av, uint32_t call_index, ToxAvCallT * @retval 0 Success. * @retval ToxAvError On Error. */ -inline__ int toxav_recv_video ( ToxAv *av, uint32_t call_index, vpx_image_t **output) +inline__ int toxav_recv_video ( ToxAv *av, int32_t call_index, vpx_image_t **output) { if ( !output ) return ErrorInternal; @@ -496,7 +500,7 @@ inline__ int toxav_recv_video ( ToxAv *av, uint32_t call_index, vpx_image_t **ou * @retval 0 Success. * @retval ToxAvError On error. */ -inline__ int toxav_send_video ( ToxAv *av, uint32_t call_index, const uint8_t* frame, int frame_size) +inline__ int toxav_send_video ( ToxAv *av, int32_t call_index, const uint8_t* frame, int frame_size) { return toxav_send_rtp_payload(av, call_index, TypeVideo, frame, frame_size); } @@ -512,7 +516,7 @@ inline__ int toxav_send_video ( ToxAv *av, uint32_t call_index, const uint8_t* f * @retval ToxAvError On error. * @retval >0 On success */ -inline__ int toxav_prepare_video_frame(ToxAv* av, uint32_t call_index, uint8_t* dest, int dest_max, vpx_image_t* input) +inline__ int toxav_prepare_video_frame(ToxAv* av, int32_t call_index, uint8_t* dest, int dest_max, vpx_image_t* input) { CallSpecific* call = &av->calls[call_index]; @@ -551,7 +555,7 @@ inline__ int toxav_prepare_video_frame(ToxAv* av, uint32_t call_index, uint8_t* * @retval >=0 Size of received data in frames/samples. * @retval ToxAvError On error. */ -inline__ int toxav_recv_audio ( ToxAv *av, uint32_t call_index, int frame_size, int16_t *dest ) +inline__ int toxav_recv_audio ( ToxAv *av, int32_t call_index, int frame_size, int16_t *dest ) { if ( !dest ) return ErrorInternal; @@ -592,7 +596,7 @@ inline__ int toxav_recv_audio ( ToxAv *av, uint32_t call_index, int frame_size, * @retval 0 Success. * @retval ToxAvError On error. */ -inline__ int toxav_send_audio ( ToxAv *av, uint32_t call_index, const uint8_t *frame, int frame_size) +inline__ int toxav_send_audio ( ToxAv *av, int32_t call_index, const uint8_t *frame, int frame_size) { return toxav_send_rtp_payload(av, call_index, TypeAudio, frame, frame_size); } @@ -609,7 +613,7 @@ inline__ int toxav_send_audio ( ToxAv *av, uint32_t call_index, const uint8_t *f * @retval ToxAvError On error. * @retval >0 On success */ -inline__ int toxav_prepare_audio_frame ( ToxAv* av, uint32_t call_index, uint8_t* dest, int dest_max, const int16_t* frame, int frame_size) +inline__ int toxav_prepare_audio_frame ( ToxAv* av, int32_t call_index, uint8_t* dest, int dest_max, const int16_t* frame, int frame_size) { int32_t rc = opus_encode(av->calls[call_index].cs->audio_encoder, frame, frame_size, dest, dest_max); @@ -629,7 +633,7 @@ inline__ int toxav_prepare_audio_frame ( ToxAv* av, uint32_t call_index, uint8_t * @retval ToxAvCallType On success. * @retval ToxAvError On error. */ -int toxav_get_peer_transmission_type ( ToxAv *av, uint32_t call_index, int peer ) +int toxav_get_peer_transmission_type ( ToxAv *av, int32_t call_index, int peer ) { assert(av->msi_session); @@ -647,7 +651,7 @@ int toxav_get_peer_transmission_type ( ToxAv *av, uint32_t call_index, int peer * @return int * @retval ToxAvError No peer id */ -int toxav_get_peer_id ( ToxAv* av, uint32_t call_index, int peer ) +int toxav_get_peer_id ( ToxAv* av, int32_t call_index, int peer ) { assert(av->msi_session); @@ -665,9 +669,10 @@ int toxav_get_peer_id ( ToxAv* av, uint32_t call_index, int peer ) * @retval 1 Yes. * @retval 0 No. */ -inline__ int toxav_capability_supported ( ToxAv* av, uint32_t call_index, ToxAvCapabilities capability ) +inline__ int toxav_capability_supported ( ToxAv* av, int32_t call_index, ToxAvCapabilities capability ) { - return av->calls[call_index].cs->capabilities & (Capabilities) capability; + return av->calls[call_index].cs ? av->calls[call_index].cs->capabilities & (Capabilities) capability : 0; + /* 0 is error here */ } /** @@ -678,9 +683,14 @@ inline__ int toxav_capability_supported ( ToxAv* av, uint32_t call_index, ToxAvC * @param limit the limit * @return void */ -void toxav_set_audio_queue_limit(ToxAv* av, uint32_t call_index, uint64_t limit) +inline__ int toxav_set_audio_queue_limit(ToxAv* av, int32_t call_index, uint64_t limit) { - rtp_queue_adjust_limit(av->calls[call_index].crtps[audio_index], limit); + if ( av->calls[call_index].crtps[audio_index] ) + rtp_queue_adjust_limit(av->calls[call_index].crtps[audio_index], limit); + else + return ErrorNoRtpSession; + + return ErrorNone; } /** @@ -691,7 +701,17 @@ void toxav_set_audio_queue_limit(ToxAv* av, uint32_t call_index, uint64_t limit) * @param limit the limit * @return void */ -void toxav_set_video_queue_limit(ToxAv* av, uint32_t call_index, uint64_t limit) -{ - rtp_queue_adjust_limit(av->calls[call_index].crtps[video_index], limit); +inline__ int toxav_set_video_queue_limit(ToxAv* av, int32_t call_index, uint64_t limit) +{ + if ( av->calls[call_index].crtps[video_index] ) + rtp_queue_adjust_limit(av->calls[call_index].crtps[video_index], limit); + else + return ErrorNoRtpSession; + + return ErrorNone; } + +inline__ Tox* toxav_get_tox(ToxAv* av) +{ + return (Tox*)av->messenger; +} \ No newline at end of file diff --git a/toxav/toxav.h b/toxav/toxav.h index 6dac966b..74f2333b 100755 --- a/toxav/toxav.h +++ b/toxav/toxav.h @@ -29,7 +29,7 @@ /* vpx_image_t */ #include -typedef void ( *ToxAVCallback ) ( uint32_t, void *arg ); +typedef void ( *ToxAVCallback ) ( int32_t, void *arg ); typedef struct _ToxAv ToxAv; #ifndef __TOX_DEFINED__ @@ -133,7 +133,7 @@ extern const ToxAvCodecSettings av_DefaultSettings; * @return ToxAv* * @retval NULL On error. */ -ToxAv *toxav_new(Tox *messenger, uint32_t max_calls); +ToxAv *toxav_new(Tox *messenger, int32_t max_calls); /** * @brief Remove A/V session. @@ -163,7 +163,7 @@ void toxav_register_callstate_callback (ToxAVCallback callback, ToxAvCallbackID * @retval 0 Success. * @retval ToxAvError On error. */ -int toxav_call(ToxAv *av, uint32_t* call_index, int user, ToxAvCallType call_type, int ringing_seconds); +int toxav_call(ToxAv *av, int32_t* call_index, int user, ToxAvCallType call_type, int ringing_seconds); /** * @brief Hangup active call. @@ -173,7 +173,7 @@ int toxav_call(ToxAv *av, uint32_t* call_index, int user, ToxAvCallType call_typ * @retval 0 Success. * @retval ToxAvError On error. */ -int toxav_hangup(ToxAv *av, uint32_t call_index); +int toxav_hangup(ToxAv *av, int32_t call_index); /** * @brief Answer incomming call. @@ -184,7 +184,7 @@ int toxav_hangup(ToxAv *av, uint32_t call_index); * @retval 0 Success. * @retval ToxAvError On error. */ -int toxav_answer(ToxAv *av, uint32_t call_index, ToxAvCallType call_type ); +int toxav_answer(ToxAv *av, int32_t call_index, ToxAvCallType call_type ); /** * @brief Reject incomming call. @@ -195,7 +195,7 @@ int toxav_answer(ToxAv *av, uint32_t call_index, ToxAvCallType call_type ); * @retval 0 Success. * @retval ToxAvError On error. */ -int toxav_reject(ToxAv *av, uint32_t call_index, const char *reason); +int toxav_reject(ToxAv *av, int32_t call_index, const char *reason); /** * @brief Cancel outgoing request. @@ -207,7 +207,7 @@ int toxav_reject(ToxAv *av, uint32_t call_index, const char *reason); * @retval 0 Success. * @retval ToxAvError On error. */ -int toxav_cancel(ToxAv* av, uint32_t call_index, int peer_id, const char* reason); +int toxav_cancel(ToxAv* av, int32_t call_index, int peer_id, const char* reason); /** * @brief Terminate transmission. Note that transmission will be terminated without informing remote peer. @@ -217,7 +217,7 @@ int toxav_cancel(ToxAv* av, uint32_t call_index, int peer_id, const char* reason * @retval 0 Success. * @retval ToxAvError On error. */ -int toxav_stop_call(ToxAv *av, uint32_t call_index); +int toxav_stop_call(ToxAv *av, int32_t call_index); /** * @brief Must be call before any RTP transmission occurs. @@ -228,7 +228,7 @@ int toxav_stop_call(ToxAv *av, uint32_t call_index); * @retval 0 Success. * @retval ToxAvError On error. */ -int toxav_prepare_transmission(ToxAv* av, uint32_t call_index, ToxAvCodecSettings* codec_settings, int support_video); +int toxav_prepare_transmission(ToxAv* av, int32_t call_index, ToxAvCodecSettings* codec_settings, int support_video); /** * @brief Call this at the end of the transmission. @@ -238,7 +238,7 @@ int toxav_prepare_transmission(ToxAv* av, uint32_t call_index, ToxAvCodecSetting * @retval 0 Success. * @retval ToxAvError On error. */ -int toxav_kill_transmission(ToxAv *av, uint32_t call_index); +int toxav_kill_transmission(ToxAv* av, int32_t call_index); /** * @brief Receive decoded video packet. @@ -249,7 +249,7 @@ int toxav_kill_transmission(ToxAv *av, uint32_t call_index); * @retval 0 Success. * @retval ToxAvError On Error. */ -int toxav_recv_video ( ToxAv* av, uint32_t call_index, vpx_image_t** output); +int toxav_recv_video ( ToxAv* av, int32_t call_index, vpx_image_t** output); /** * @brief Receive decoded audio frame. @@ -263,7 +263,7 @@ int toxav_recv_video ( ToxAv* av, uint32_t call_index, vpx_image_t** output); * @retval >=0 Size of received data in frames/samples. * @retval ToxAvError On error. */ -int toxav_recv_audio( ToxAv* av, uint32_t call_index, int frame_size, int16_t* dest ); +int toxav_recv_audio( ToxAv* av, int32_t call_index, int frame_size, int16_t* dest ); /** * @brief Encode and send video packet. @@ -275,7 +275,7 @@ int toxav_recv_audio( ToxAv* av, uint32_t call_index, int frame_size, int16_t* d * @retval 0 Success. * @retval ToxAvError On error. */ -int toxav_send_video ( ToxAv* av, uint32_t call_index, const uint8_t* frame, int frame_size); +int toxav_send_video ( ToxAv* av, int32_t call_index, const uint8_t* frame, int frame_size); /** * @brief Send audio frame. @@ -288,7 +288,7 @@ int toxav_send_video ( ToxAv* av, uint32_t call_index, const uint8_t* frame, int * @retval 0 Success. * @retval ToxAvError On error. */ -int toxav_send_audio ( ToxAv* av, uint32_t call_index, const uint8_t* frame, int frame_size); +int toxav_send_audio ( ToxAv* av, int32_t call_index, const uint8_t* frame, int frame_size); /** * @brief Encode video frame @@ -301,7 +301,7 @@ int toxav_send_audio ( ToxAv* av, uint32_t call_index, const uint8_t* frame, int * @retval ToxAvError On error. * @retval >0 On success */ -int toxav_prepare_video_frame ( ToxAv* av, uint32_t call_index, uint8_t* dest, int dest_max, vpx_image_t* input ); +int toxav_prepare_video_frame ( ToxAv* av, int32_t call_index, uint8_t* dest, int dest_max, vpx_image_t* input ); /** * @brief Encode audio frame @@ -315,7 +315,7 @@ int toxav_prepare_video_frame ( ToxAv* av, uint32_t call_index, uint8_t* dest, i * @retval ToxAvError On error. * @retval >0 On success */ -int toxav_prepare_audio_frame ( ToxAv* av, uint32_t call_index, uint8_t* dest, int dest_max, const int16_t* frame, int frame_size); +int toxav_prepare_audio_frame ( ToxAv* av, int32_t call_index, uint8_t* dest, int dest_max, const int16_t* frame, int frame_size); /** * @brief Get peer transmission type. It can either be audio or video. @@ -326,7 +326,7 @@ int toxav_prepare_audio_frame ( ToxAv* av, uint32_t call_index, uint8_t* dest, i * @retval ToxAvCallType On success. * @retval ToxAvError On error. */ -int toxav_get_peer_transmission_type ( ToxAv *av, uint32_t call_index, int peer ); +int toxav_get_peer_transmission_type ( ToxAv* av, int32_t call_index, int peer ); /** * @brief Get id of peer participating in conversation @@ -336,7 +336,7 @@ int toxav_get_peer_transmission_type ( ToxAv *av, uint32_t call_index, int peer * @return int * @retval ToxAvError No peer id */ -int toxav_get_peer_id ( ToxAv* av, uint32_t call_index, int peer ); +int toxav_get_peer_id ( ToxAv* av, int32_t call_index, int peer ); /** * @brief Is certain capability supported @@ -346,7 +346,7 @@ int toxav_get_peer_id ( ToxAv* av, uint32_t call_index, int peer ); * @retval 1 Yes. * @retval 0 No. */ -int toxav_capability_supported ( ToxAv* av, uint32_t call_index, ToxAvCapabilities capability ); +int toxav_capability_supported ( ToxAv* av, int32_t call_index, ToxAvCapabilities capability ); /** * @brief Set queue limit @@ -356,7 +356,7 @@ int toxav_capability_supported ( ToxAv* av, uint32_t call_index, ToxAvCapabiliti * @param limit the limit * @return void */ -void toxav_set_audio_queue_limit ( ToxAv* av, uint32_t call_index, uint64_t limit ); +int toxav_set_audio_queue_limit ( ToxAv* av, int32_t call_index, uint64_t limit ); /** * @brief Set queue limit @@ -366,6 +366,8 @@ void toxav_set_audio_queue_limit ( ToxAv* av, uint32_t call_index, uint64_t limi * @param limit the limit * @return void */ -void toxav_set_video_queue_limit ( ToxAv* av, uint32_t call_index, uint64_t limit ); +int toxav_set_video_queue_limit ( ToxAv* av, int32_t call_index, uint64_t limit ); + +Tox* toxav_get_tox(ToxAv* av); #endif /* __TOXAV */ \ No newline at end of file diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c index 2033e6a9..f5ed14b1 100644 --- a/toxcore/Messenger.c +++ b/toxcore/Messenger.c @@ -2275,7 +2275,7 @@ void do_messenger(Messenger *m) if (last_pinged > 999) last_pinged = 999; - LOGGER_DEBUG("C[%2u] %s:%u [%3u] %s", + LOGGER_INFO("C[%2u] %s:%u [%3u] %s", client, ip_ntoa(&assoc->ip_port.ip), ntohs(assoc->ip_port.port), last_pinged, ID2String(cptr->client_id)); } @@ -2308,7 +2308,7 @@ void do_messenger(Messenger *m) dht2m[m2dht[friend]] = friend; if (m->numfriends != m->dht->num_friends) { - LOGGER_DEBUG("Friend num in DHT %u != friend num in msger %u\n", m->dht->num_friends, m->numfriends); + LOGGER_INFO("Friend num in DHT %u != friend num in msger %u\n", m->dht->num_friends, m->numfriends); } uint32_t ping_lastrecv; @@ -2329,11 +2329,11 @@ void do_messenger(Messenger *m) if (ping_lastrecv > 999) ping_lastrecv = 999; - LOGGER_DEBUG("F[%2u:%2u] <%s> %02i [%03u] %s", + LOGGER_INFO("F[%2u:%2u] <%s> %02i [%03u] %s", dht2m[friend], friend, msgfptr->name, msgfptr->crypt_connection_id, ping_lastrecv, ID2String(msgfptr->client_id)); } else { - LOGGER_DEBUG("F[--:%2u] %s", friend, ID2String(dhtfptr->client_id)); + LOGGER_INFO("F[--:%2u] %s", friend, ID2String(dhtfptr->client_id)); } for (client = 0; client < MAX_FRIEND_CLIENTS; client++) { @@ -2348,7 +2348,7 @@ void do_messenger(Messenger *m) if (last_pinged > 999) last_pinged = 999; - LOGGER_DEBUG("F[%2u] => C[%2u] %s:%u [%3u] %s", + LOGGER_INFO("F[%2u] => C[%2u] %s:%u [%3u] %s", friend, client, ip_ntoa(&assoc->ip_port.ip), ntohs(assoc->ip_port.port), last_pinged, ID2String(cptr->client_id)); diff --git a/toxcore/logger.c b/toxcore/logger.c index e700fe71..ff9146d4 100644 --- a/toxcore/logger.c +++ b/toxcore/logger.c @@ -60,8 +60,8 @@ void __attribute__((destructor)) terminate_logger() time_t tim = time(NULL); - logger_write(ERROR, "============== Closing logger ==============\n" - "Time: %s", asctime(localtime(&tim))); + logger_write(ERROR, "\n============== Closing logger [%u] ==============\n" + "Time: %s", logger_get_pid(), asctime(localtime(&tim))); fclose(logger.log_file); } @@ -96,12 +96,12 @@ int logger_init(const char* file_name, LoggerLevel level) sprintf(final_l, "%s"/*.%u"*/, file_name, logger_get_pid()); if ( logger.log_file ) { - fprintf(stderr, "Error opening logger name: %s with level %d: already opened!\n", final_l, level); + fprintf(stderr, "Error opening logger name: %s with level %d: %s!\n", final_l, level, strerror(errno)); free (final_l); return -1; } - logger.log_file = fopen(final_l, "wb"); + logger.log_file = fopen(final_l, "ab"); if ( logger.log_file == NULL ) { char error[1000]; @@ -120,8 +120,8 @@ int logger_init(const char* file_name, LoggerLevel level) time_t tim = time(NULL); - logger_write(ERROR, "============== Starting logger ==============\n" - "Time: %s", asctime(localtime(&tim))); + logger_write(ERROR, "\n============== Starting logger [%u] ==============\n" + "Time: %s", logger_get_pid(), asctime(localtime(&tim))); diff --git a/toxcore/logger.h b/toxcore/logger.h index abef4b84..d8292f31 100644 --- a/toxcore/logger.h +++ b/toxcore/logger.h @@ -53,7 +53,7 @@ char* logger_timestr (char* dest); #define _SFILE (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) #endif -#define WRITE_FORMAT(__LEVEL__, format) char* the_str = calloc(sizeof(char), strlen(format)+ 500); sprintf(the_str, "[%u] [%s] [%s] [%s:%d %s()] %s\n", \ +#define WRITE_FORMAT(__LEVEL__, format) char* the_str = calloc(sizeof(char), strlen(format)+ 500); sprintf(the_str, "\n[%u] [%s] [%s] [%s:%d %s()] %s", \ logger_get_pid(), logger_stringify_level(__LEVEL__), logger_timestr(__time__), _SFILE, __LINE__, __func__, format) /* Use these macros */ diff --git a/toxcore/network.c b/toxcore/network.c index 7262f352..5980abe3 100644 --- a/toxcore/network.c +++ b/toxcore/network.c @@ -374,7 +374,7 @@ void networking_poll(Networking_Core *net) if (length < 1) continue; if (!(net->packethandlers[data[0]].function)) { - LOGGER_WARNING("[%02u] -- Packet has no handler.\n", data[0]); + LOGGER_WARNING("[%02u] -- Packet has no handler", data[0]); continue; } -- cgit v1.2.3 From a1f2a18ae4146ebea11fbd3f83df803b715813da Mon Sep 17 00:00:00 2001 From: mannol Date: Tue, 20 May 2014 00:10:40 +0200 Subject: Merge upstream and other stuff --- auto_tests/Makefile.inc | 1 + configure.ac | 11 + other/DHT_bootstrap.c | 44 +- other/DHTnodes | 2 +- testing/DHT_test.c | 6 +- testing/Lossless_UDP_testclient.c | 260 ---- testing/Lossless_UDP_testserver.c | 237 ---- testing/Makefile.inc | 36 - testing/crypto_speed_test.c | 4 +- toxav/Makefile.inc | 3 + toxav/event.c | 7 +- toxav/media.h | 2 +- toxav/msi.c | 22 +- toxav/msi.h | 6 +- toxav/rtp.c | 45 +- toxcore/DHT.c | 587 +++++---- toxcore/DHT.h | 64 +- toxcore/LAN_discovery.c | 4 +- toxcore/Lossless_UDP.c | 1168 ----------------- toxcore/Lossless_UDP.h | 261 ---- toxcore/Makefile.inc | 7 +- toxcore/Messenger.c | 855 ++++++------ toxcore/Messenger.h | 41 +- toxcore/TCP_client.c | 398 +++++- toxcore/TCP_client.h | 71 +- toxcore/TCP_server.c | 216 ++- toxcore/TCP_server.h | 19 +- toxcore/assoc.c | 2 +- toxcore/crypto_core.c | 262 ++++ toxcore/crypto_core.h | 142 ++ toxcore/friend_requests.c | 22 +- toxcore/friend_requests.h | 5 +- toxcore/group_chats.c | 15 +- toxcore/group_chats.h | 2 - toxcore/net_crypto.c | 2625 +++++++++++++++++++++++++++++-------- toxcore/net_crypto.h | 332 +++-- toxcore/network.c | 128 +- toxcore/network.h | 80 +- toxcore/onion.c | 174 +-- toxcore/onion.h | 17 +- toxcore/onion_announce.c | 54 +- toxcore/onion_announce.h | 13 +- toxcore/onion_client.c | 356 +++-- toxcore/onion_client.h | 56 +- toxcore/ping.c | 247 ++-- toxcore/ping_array.c | 162 +++ toxcore/ping_array.h | 75 ++ toxcore/tox.c | 65 +- toxcore/tox.h | 73 +- toxcore/util.c | 37 +- 50 files changed, 5170 insertions(+), 4151 deletions(-) delete mode 100644 testing/Lossless_UDP_testclient.c delete mode 100644 testing/Lossless_UDP_testserver.c delete mode 100644 toxcore/Lossless_UDP.c delete mode 100644 toxcore/Lossless_UDP.h create mode 100644 toxcore/crypto_core.c create mode 100644 toxcore/crypto_core.h create mode 100644 toxcore/ping_array.c create mode 100644 toxcore/ping_array.h (limited to 'toxav/msi.h') diff --git a/auto_tests/Makefile.inc b/auto_tests/Makefile.inc index 1f0f6697..5e101f60 100644 --- a/auto_tests/Makefile.inc +++ b/auto_tests/Makefile.inc @@ -15,6 +15,7 @@ AUTOTEST_LDADD = \ $(NACL_LDFLAGS) \ libtoxcore.la \ $(LIBSODIUM_LIBS) \ + $(NACL_OBJECTS) \ $(NACL_LIBS) \ $(CHECK_LIBS) diff --git a/configure.ac b/configure.ac index 8650e197..7456617a 100644 --- a/configure.ac +++ b/configure.ac @@ -427,6 +427,17 @@ AC_C_BIGENDIAN # Checks for library functions. AC_FUNC_FORK AC_CHECK_FUNCS([gettimeofday memset socket strchr malloc]) +if test "x$WIN32" != "xyes"; then + AC_CHECK_LIB(rt, clock_gettime, + [ + RT_LIBS="-lrt" + AC_SUBST(RT_LIBS) + ], + [ + AC_MSG_ERROR([required library rt was not found on your system]) + ] + ) +fi if test "x$BUILD_AV" = "xyes"; then AX_PTHREAD( diff --git a/other/DHT_bootstrap.c b/other/DHT_bootstrap.c index 291d6589..462360c3 100644 --- a/other/DHT_bootstrap.c +++ b/other/DHT_bootstrap.c @@ -31,6 +31,12 @@ #include "../toxcore/friend_requests.h" #include "../toxcore/util.h" +#define TCP_RELAY_ENABLED + +#ifdef TCP_RELAY_ENABLED +#include "../toxcore/TCP_server.h" +#endif + #include "../testing/misc_tools.c" #ifdef DHT_NODE_EXTRA_PACKETS @@ -69,11 +75,12 @@ void manage_keys(DHT *dht) exit(1); } - load_keys(dht->c, keys); + memcpy(dht->self_public_key, keys, crypto_box_PUBLICKEYBYTES); + memcpy(dht->self_secret_key, keys + crypto_box_PUBLICKEYBYTES, crypto_box_SECRETKEYBYTES); printf("Keys loaded successfully.\n"); } else { - new_keys(dht->c); - save_keys(dht->c, keys); + memcpy(keys, dht->self_public_key, crypto_box_PUBLICKEYBYTES); + memcpy(keys + crypto_box_PUBLICKEYBYTES, dht->self_secret_key, crypto_box_SECRETKEYBYTES); keys_file = fopen("key", "w"); if (fwrite(keys, sizeof(uint8_t), KEYS_SIZE, keys_file) != KEYS_SIZE) { @@ -107,7 +114,7 @@ int main(int argc, char *argv[]) IP ip; ip_init(&ip, ipv6enabled); - DHT *dht = new_DHT(new_net_crypto(new_networking(ip, PORT))); + DHT *dht = new_DHT(new_networking(ip, PORT)); Onion *onion = new_onion(dht); Onion_Announce *onion_a = new_onion_announce(dht); @@ -123,27 +130,33 @@ int main(int argc, char *argv[]) perror("Initialization"); manage_keys(dht); - /* We want our DHT public key to be the same as our internal one since this is a bootstrap node */ - memcpy(dht->self_public_key, dht->c->self_public_key, crypto_box_PUBLICKEYBYTES); - memcpy(dht->self_secret_key, dht->c->self_secret_key, crypto_box_SECRETKEYBYTES); printf("Public key: "); uint32_t i; +#ifdef TCP_RELAY_ENABLED +#define NUM_PORTS 3 + uint16_t ports[NUM_PORTS] = {443, 3389, PORT}; + TCP_Server *tcp_s = new_TCP_server(ipv6enabled, NUM_PORTS, ports, dht->self_public_key, dht->self_secret_key, onion); + + if (tcp_s == NULL) { + printf("TCP server failed to initialize.\n"); + exit(1); + } + +#endif + FILE *file; file = fopen("PUBLIC_ID.txt", "w"); for (i = 0; i < 32; i++) { - if (dht->c->self_public_key[i] < 16) - printf("0"); - - printf("%hhX", dht->c->self_public_key[i]); - fprintf(file, "%hhX", dht->c->self_public_key[i]); + printf("%02hhX", dht->self_public_key[i]); + fprintf(file, "%02hhX", dht->self_public_key[i]); } fclose(file); printf("\n"); - printf("Port: %u\n", ntohs(dht->c->lossless_udp->net->port)); + printf("Port: %u\n", ntohs(dht->net->port)); if (argc > argvoffset + 3) { printf("Trying to bootstrap into the network...\n"); @@ -177,7 +190,10 @@ int main(int argc, char *argv[]) last_LANdiscovery = unix_time(); } - networking_poll(dht->c->lossless_udp->net); +#ifdef TCP_RELAY_ENABLED + do_TCP_server(tcp_s); +#endif + networking_poll(dht->net); c_sleep(1); } diff --git a/other/DHTnodes b/other/DHTnodes index 35509931..0abdbbd9 100644 --- a/other/DHTnodes +++ b/other/DHTnodes @@ -1,3 +1,3 @@ -As maintaining 2 seperate lists of the same information seemed redundant, this list has been phased out. +As maintaining 2 separate lists of the same information seemed redundant, this list has been phased out. For a current DHT node list please visit http://wiki.tox.im/nodes diff --git a/testing/DHT_test.c b/testing/DHT_test.c index 3f8b58bd..2636ed02 100644 --- a/testing/DHT_test.c +++ b/testing/DHT_test.c @@ -187,9 +187,7 @@ int main(int argc, char *argv[]) IP ip; ip_init(&ip, ipv6enabled); - DHT *dht = new_DHT(new_net_crypto(new_networking(ip, PORT))); - - new_keys(dht->c); + DHT *dht = new_DHT(new_networking(ip, PORT)); printf("OUR ID: "); uint32_t i; @@ -245,7 +243,7 @@ int main(int argc, char *argv[]) } } */ - networking_poll(dht->c->lossless_udp->net); + networking_poll(dht->net); print_clientlist(dht); print_friendlist(dht); diff --git a/testing/Lossless_UDP_testclient.c b/testing/Lossless_UDP_testclient.c deleted file mode 100644 index 535509e0..00000000 --- a/testing/Lossless_UDP_testclient.c +++ /dev/null @@ -1,260 +0,0 @@ -/* Lossless_UDP testclient - * A program that connects and sends a file using our lossless UDP algorithm. - * NOTE: this program simulates a 33% packet loss. - * - * Best used in combination with Lossless_UDP_testserver - * - * Compile with: gcc -O2 -Wall -lsodium -o testclient ../toxcore/network.c ../toxcore/Lossless_UDP.c ../toxcore/util.c Lossless_UDP_testclient.c - * - * Command line arguments are the ip and port to connect and send the file to. - * EX: ./testclient --ipv4 127.0.0.1 33445 filename.txt - * - * Copyright (C) 2013 Tox project All Rights Reserved. - * - * This file is part of Tox. - * - * Tox is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tox is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tox. If not, see . - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "../toxcore/network.h" -#include "../toxcore/Lossless_UDP.h" -#include "../toxcore/util.h" -#include "misc_tools.c" - -#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) - -#define c_sleep(x) Sleep(1*x) - -#else -#include -#include -#define c_sleep(x) usleep(1000*x) - -#endif - -#define PORT 33446 - -void printpacket(uint8_t *data, uint32_t length, IP_Port ip_port) -{ - uint32_t i; - printf("UNHANDLED PACKET RECEIVED\nLENGTH:%u\nCONTENTS:\n", length); - printf("--------------------BEGIN-----------------------------\n"); - - for (i = 0; i < length; i++) { - if (data[i] < 16) - printf("0"); - - printf("%hhX", data[i]); - } - - printf("\n--------------------END-----------------------------\n\n\n"); -} - -void printip(IP_Port ip_port) -{ - printf("\nIP: %s Port: %u", ip_ntoa(&ip_port.ip), ntohs(ip_port.port)); -} -/* -void printpackets(Data test) -{ - int i; - if(test.size == 0) - return; - printf("SIZE: %u\n", test.size); - for(i =0; i < test.size; i++) - { - printf("%hhX", test.data[i]); - } - printf("\n"); -} - -void printconnection(int connection_id) -{ - printf("--------------------BEGIN---------------------\n"); - IP_Port ip_port = connections[connection_id].ip_port; - printf("IP: %u.%u.%u.%u Port: %u\n",ip_port.ip.c[0],ip_port.ip.c[1],ip_port.ip.c[2],ip_port.ip.c[3],ntohs(ip_port.port)); - printf("status: %u, inbound: %u, SYNC_rate: %u\n", connections[connection_id].status, - connections[connection_id].inbound, connections[connection_id].SYNC_rate); - printf("data rate: %u, last sync: %llu, last sent: %llu, last recv: %llu \n", connections[connection_id].data_rate, - connections[connection_id].last_SYNC, connections[connection_id].last_sent, connections[connection_id].last_recv); - int i; - for(i =0; i < MAX_QUEUE_NUM; i++) - { - printf(" %u ",i); - printpackets(connections[connection_id].sendbuffer[i]); - } - for(i =0; i < MAX_QUEUE_NUM; i++) - { - printf(" %u ",i); - printpackets(connections[connection_id].recvbuffer[i]); - } - Data sendbuffer[MAX_QUEUE_NUM]; - Data recvbuffer[MAX_QUEUE_NUM]; - printf("recv_num: %u, orecv_num: %u, sent_packetnum %u, osent_packetnum: %u, successful_sent: %u, successful_read: %u\n", - connections[connection_id].recv_packetnum, - connections[connection_id].orecv_packetnum, connections[connection_id].sent_packetnum, connections[connection_id].osent_packetnum, - connections[connection_id].successful_sent, - connections[connection_id].successful_read); - - printf("req packets: \n"); - for(i = 0; i < BUFFER_PACKET_NUM; i++) - { - printf(" %u ", connections[connection_id].req_packets[i]); - } - printf("\nNumber: %u recv_counter: %u, send_counter: %u\n", connections[connection_id].num_req_paquets, - connections[connection_id].recv_counter, connections[connection_id].send_counter); - - printf("--------------------END---------------------\n"); - -} -*/ - -/*( receive packets and send them to the packethandler */ -/*run doLossless_UDP(); */ -//void Lossless_UDP() -//{ -/* IP_Port ip_port; - uint8_t data[MAX_UDP_PACKET_SIZE]; - uint32_t length; - while (receivepacket(&ip_port, data, &length) != -1) { - printf("packet with length: %u\n", length); */ -/* if(rand() % 3 != 1)//add packet loss - { */ -/* - if (LosslessUDP_handlepacket(data, length, ip_port)) - printpacket(data, length, ip_port); - else - printf("Received handled packet with length: %u\n", length); //printconnection(0); */ - -/* } */ -/* }*/ - -//networking_poll(); - -//doLossless_UDP(); - -//} - -int main(int argc, char *argv[]) -{ - /* let user override default by cmdline */ - uint8_t ipv6enabled = TOX_ENABLE_IPV6_DEFAULT; /* x */ - int argvoffset = cmdline_parsefor_ipv46(argc, argv, &ipv6enabled); - - if (argvoffset < 0) - exit(1); - - if (argc < argvoffset + 4) { - printf("Usage: %s [--ipv4|--ipv6] ip port filename\n", argv[0]); - exit(0); - } - - uint8_t buffer[MAX_DATA_SIZE]; - int read; - - FILE *file = fopen(argv[argvoffset + 3], "rb"); - - if (file == NULL) { - printf("Failed to open file \"%s\".\n", argv[argvoffset + 3]); - return 1; - } - - - /* initialize networking */ - /* bind to ip 0.0.0.0:PORT */ - IP ip; - ip_init(&ip, ipv6enabled); - - Lossless_UDP *ludp = new_lossless_udp(new_networking(ip, PORT)); - perror("Initialization"); - - IP_Port serverip; - ip_init(&serverip.ip, ipv6enabled); - - if (!addr_resolve(argv[argvoffset + 1], &serverip.ip, NULL)) { - printf("Failed to convert \"%s\" into an IP address.\n", argv[argvoffset + 1]); - return 1; - } - - serverip.port = htons(atoi(argv[argvoffset + 2])); - printip(serverip); - - int connection = new_connection(ludp, serverip); - uint64_t timer = current_time(); - - while (1) { - /* printconnection(connection); */ - networking_poll(ludp->net); - do_lossless_udp(ludp); - - if (is_connected(ludp, connection) == LUDP_ESTABLISHED) { - printf("Connecting took: %llu us\n", (unsigned long long)(current_time() - timer)); - break; - } - - if (is_connected(ludp, connection) == LUDP_NO_CONNECTION) { - printf("Connection timeout after: %llu us\n", (unsigned long long)(current_time() - timer)); - return 1; - } - - c_sleep(1); - } - - timer = current_time(); - unsigned long long bytes_sent = 0; - - /*read first part of file */ - read = fread(buffer, 1, MAX_DATA_SIZE, file); - - while (1) { - /* printconnection(connection); */ - networking_poll(ludp->net); - do_lossless_udp(ludp); - - if (is_connected(ludp, connection) == LUDP_ESTABLISHED) { - - while (write_packet(ludp, connection, buffer, read)) { - bytes_sent += read; - /* printf("Wrote data.\n"); */ - read = fread(buffer, 1, MAX_DATA_SIZE, file); - - } - - /* printf("%u\n", sendqueue(connection)); */ - if (sendqueue(ludp, connection) == 0) { - if (read == 0) { - unsigned long long us = (unsigned long long)(current_time() - timer); - printf("Sent file successfully in: %llu us = %llu seconds. Average speed: %llu KB/s\n", us, us / 1000000UL, - bytes_sent / (us / 1024UL)); - //printf("Total bytes sent: %llu B, Total data sent: %llu B, overhead: %llu B\n", total_bytes_sent, bytes_sent, total_bytes_sent-bytes_sent); - break; - } - } - } else { - printf("%u Client Connecting Lost after: %llu us\n", is_connected(ludp, connection), - (unsigned long long)(current_time() - timer)); - return 0; - } - - } - - c_sleep(25); - - return 0; -} diff --git a/testing/Lossless_UDP_testserver.c b/testing/Lossless_UDP_testserver.c deleted file mode 100644 index dd4612f5..00000000 --- a/testing/Lossless_UDP_testserver.c +++ /dev/null @@ -1,237 +0,0 @@ -/* Lossless_UDP testserver - * A program that waits for a lossless UDP connection and then saves all the data received to a file. - * NOTE: this program simulates a 33% packet loss. - * - * Best used in combination with Lossless_UDP_testclient - * - * Compile with: gcc -O2 -Wall -lsodium -o testserver ../toxcore/network.c ../toxcore/Lossless_UDP.c ../toxcore/util.c Lossless_UDP_testserver.c - * - * Command line argument is the name of the file to save what we receive to. - * EX: ./testserver filename1.txt - * - * Copyright (C) 2013 Tox project All Rights Reserved. - * - * This file is part of Tox. - * - * Tox is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tox is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tox. If not, see . - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "../toxcore/network.h" -#include "../toxcore/Lossless_UDP.h" -#include "../toxcore/util.h" -#include "misc_tools.c" - -//Sleep function (x = milliseconds) -#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) - -#define c_sleep(x) Sleep(1*x) - -#else -#include -#include -#define c_sleep(x) usleep(1000*x) - -#endif - -#define PORT 33445 - -void printpacket(uint8_t *data, uint32_t length, IP_Port ip_port) -{ - uint32_t i; - printf("UNHANDLED PACKET RECEIVED\nLENGTH:%u\nCONTENTS:\n", length); - printf("--------------------BEGIN-----------------------------\n"); - - for (i = 0; i < length; i++) { - if (data[i] < 16) - printf("0"); - - printf("%hhX", data[i]); - } - - printf("\n--------------------END-----------------------------\n\n\n"); -} - -/* -void printpackets(Data test) -{ - int i; - if(test.size == 0) - return; - printf("SIZE: %u\n", test.size); - for(i =0; i < test.size; i++) - { - printf("%hhX", test.data[i]); - } - printf("\n"); -} - -void printconnection(int connection_id) -{ - printf("--------------------BEGIN---------------------\n"); - IP_Port ip_port = connections[connection_id].ip_port; - printf("IP: %u.%u.%u.%u Port: %u\n",ip_port.ip.c[0],ip_port.ip.c[1],ip_port.ip.c[2],ip_port.ip.c[3],ntohs(ip_port.port)); - printf("status: %u, inbound: %u, SYNC_rate: %u\n", connections[connection_id].status, - connections[connection_id].inbound, connections[connection_id].SYNC_rate); - printf("data rate: %u, last sync: %llu, last sent: %llu, last recv: %llu \n", connections[connection_id].data_rate, - connections[connection_id].last_SYNC, connections[connection_id].last_sent, connections[connection_id].last_recv); - int i; - for(i =0; i < MAX_QUEUE_NUM; i++) - { - printf(" %u ",i); - printpackets(connections[connection_id].sendbuffer[i]); - } - for(i =0; i < MAX_QUEUE_NUM; i++) - { - printf(" %u ",i); - printpackets(connections[connection_id].recvbuffer[i]); - } - Data sendbuffer[MAX_QUEUE_NUM]; - Data recvbuffer[MAX_QUEUE_NUM]; - printf("recv_num: %u, orecv_num: %u, sent_packetnum %u, osent_packetnum: %u, successful_sent: %u, successful_read: %u\n", - connections[connection_id].recv_packetnum, - connections[connection_id].orecv_packetnum, connections[connection_id].sent_packetnum, connections[connection_id].osent_packetnum, - connections[connection_id].successful_sent, - connections[connection_id].successful_read); - - printf("req packets: \n"); - for(i = 0; i < BUFFER_PACKET_NUM; i++) - { - printf(" %u ", connections[connection_id].req_packets[i]); - } - printf("\nNumber: %u recv_counter: %u, send_counter: %u\n", connections[connection_id].num_req_paquets, - connections[connection_id].recv_counter, connections[connection_id].send_counter); - - printf("--------------------END---------------------\n"); - -} -*/ - -/* receive packets and send them to the packethandler - * run doLossless_UDP(); */ -//void Lossless_UDP() -//{ -// IP_Port ip_port; -// uint8_t data[MAX_UDP_PACKET_SIZE]; -// uint32_t length; -// while (receivepacket(&ip_port, data, &length) != -1) { -//if(rand() % 3 != 1)//add packet loss -//{ -// if (LosslessUDP_handlepacket(data, length, ip_port)) { -// printpacket(data, length, ip_port); -// } else { -//printconnection(0); -// printf("Received handled packet with length: %u\n", length); -// } -//} -// } - -// networking_poll(); - -//doLossless_UDP(); -//} - - -int main(int argc, char *argv[]) -{ - /* let user override default by cmdline */ - uint8_t ipv6enabled = TOX_ENABLE_IPV6_DEFAULT; /* x */ - int argvoffset = cmdline_parsefor_ipv46(argc, argv, &ipv6enabled); - - if (argvoffset < 0) - exit(1); - - if (argc < argvoffset + 2) { - printf("Usage: %s [--ipv4|--ipv6] filename\n", argv[0]); - exit(0); - } - - uint8_t buffer[MAX_DATA_SIZE]; - int read; - - FILE *file = fopen(argv[argvoffset + 1], "wb"); - - if (file == NULL) { - printf("Failed to open file \"%s\".\n", argv[argvoffset + 1]); - return 1; - } - - - //initialize networking - //bind to ip 0.0.0.0:PORT - IP ip; - ip_init(&ip, ipv6enabled); - - Lossless_UDP *ludp = new_lossless_udp(new_networking(ip, PORT)); - perror("Initialization"); - - int connection; - uint64_t timer = current_time(); - - while (1) { - networking_poll(ludp->net); - do_lossless_udp(ludp); - connection = incoming_connection(ludp, 0); - - if (connection != -1) { - if (is_connected(ludp, connection) == LUDP_NOT_CONFIRMED) { - printf("Received the connection.\n"); - - } - - break; - } - - c_sleep(1); - } - - timer = current_time(); - - while (1) { - //printconnection(0); - networking_poll(ludp->net); - - if (is_connected(ludp, connection) >= LUDP_NOT_CONFIRMED) { - confirm_connection(ludp, connection); - - while (1) { - read = read_packet(ludp, connection, buffer); - - if (read != 0) { - // printf("Received data.\n"); - if (!fwrite(buffer, read, 1, file)) - printf("file write error\n"); - } else { - break; - } - } - } - - do_lossless_udp(ludp); - - if (is_connected(ludp, connection) == LUDP_TIMED_OUT) { - printf("Server Connecting Lost after: %llu us\n", (unsigned long long)(current_time() - timer)); - fclose(file); - return 1; - } - - c_sleep(25); - } - - return 0; -} diff --git a/testing/Makefile.inc b/testing/Makefile.inc index 812a5be1..b3912033 100644 --- a/testing/Makefile.inc +++ b/testing/Makefile.inc @@ -22,8 +22,6 @@ endif if BUILD_TESTING noinst_PROGRAMS += DHT_test \ - Lossless_UDP_testclient \ - Lossless_UDP_testserver \ Messenger_test \ crypto_speed_test @@ -41,40 +39,6 @@ DHT_test_LDADD = $(LIBSODIUM_LDFLAGS) \ $(WINSOCK2_LIBS) -Lossless_UDP_testclient_SOURCES = \ - ../testing/Lossless_UDP_testclient.c - -Lossless_UDP_testclient_CFLAGS = \ - $(LIBSODIUM_CFLAGS) \ - $(NACL_CFLAGS) - -Lossless_UDP_testclient_LDADD = \ - $(LIBSODIUM_LDFLAGS) \ - $(NACL_LDFLAGS) \ - libtoxcore.la \ - $(LIBSODIUM_LIBS) \ - $(NACL_OBJECTS) \ - $(NACL_LIBS) \ - $(WINSOCK2_LIBS) - - -Lossless_UDP_testserver_SOURCES = \ - ../testing/Lossless_UDP_testserver.c - -Lossless_UDP_testserver_CFLAGS = \ - $(LIBSODIUM_CFLAGS) \ - $(NACL_CFLAGS) - -Lossless_UDP_testserver_LDADD = \ - $(LIBSODIUM_LDFLAGS) \ - $(NACL_LDFLAGS) \ - libtoxcore.la \ - $(LIBSODIUM_LIBS) \ - $(NACL_OBJECTS) \ - $(NACL_LIBS) \ - $(WINSOCK2_LIBS) - - Messenger_test_SOURCES = \ ../testing/Messenger_test.c diff --git a/testing/crypto_speed_test.c b/testing/crypto_speed_test.c index 60ff1937..3e81a46b 100644 --- a/testing/crypto_speed_test.c +++ b/testing/crypto_speed_test.c @@ -97,8 +97,8 @@ int main(int argc, char *argv[]) starttime = get_time(); for (trialno = 0; trialno < numtrials; trialno++) { - encrypt_data_fast(k1, n, m, sizeof(m), c); - decrypt_data_fast(k2, n, c, sizeof(c), m); + encrypt_data_symmetric(k1, n, m, sizeof(m), c); + decrypt_data_symmetric(k2, n, c, sizeof(c), m); } endtime = get_time(); diff --git a/toxav/Makefile.inc b/toxav/Makefile.inc index 060a760c..2d48d210 100644 --- a/toxav/Makefile.inc +++ b/toxav/Makefile.inc @@ -18,15 +18,18 @@ libtoxav_la_SOURCES = ../toxav/event.h \ libtoxav_la_CFLAGS = -I../toxcore \ -I../toxav \ + $(LIBSODIUM_CFLAGS) \ $(NACL_CFLAGS) \ $(AV_CFLAGS) \ $(PTHREAD_CFLAGS) libtoxav_la_LDFLAGS = $(TOXAV_LT_LDFLAGS) \ + $(LIBSODIUM_LDFLAGS) \ $(NACL_LDFLAGS) \ $(EXTRA_LT_LDFLAGS) libtoxav_la_LIBADD = libtoxcore.la \ + $(LIBSODIUM_LIBS) \ $(NACL_LIBS) \ $(PTHREAD_LIBS) \ $(AV_LIBS) diff --git a/toxav/event.c b/toxav/event.c index ffda35ec..35af98bb 100644 --- a/toxav/event.c +++ b/toxav/event.c @@ -27,6 +27,7 @@ #endif /* HAVE_CONFIG_H */ #include +#include "../toxcore/network.h" /* current_time_monotonic() */ #include "event.h" #define _GNU_SOURCE @@ -199,7 +200,7 @@ void *event_poll( void *arg ) if ( _event_handler->timed_events ) { - uint32_t _time = ((uint32_t)(current_time() / 1000)); + uint32_t _time = ((uint32_t)current_time_monotonic()); if ( _event_handler->timed_events[0].timeout < _time ) { @@ -249,7 +250,7 @@ int throw_timer_event ( void * (func)(void *), void *arg, unsigned timeout) size_t _counter = event_handler.timed_events_count; - event_handler.timed_events[_counter - 1].timeout = timeout + ((uint32_t)(current_time() / 1000)); + event_handler.timed_events[_counter - 1].timeout = timeout + ((uint32_t)current_time_monotonic()); event_handler.timed_events[_counter - 1].id = _unique_id; ++_unique_id; @@ -330,7 +331,7 @@ int reset_timer_event ( int id, uint32_t timeout ) /* Find it and change */ for ( ; _i; _i-- ) { if ( _it->id == id ) { - _it->timeout = timeout + ((uint32_t)(current_time() / 1000)); + _it->timeout = timeout + ((uint32_t)current_time_monotonic()); break; } diff --git a/toxav/media.h b/toxav/media.h index a1193aae..8dc495ed 100644 --- a/toxav/media.h +++ b/toxav/media.h @@ -36,7 +36,7 @@ #define VIDEO_CODEC_ENCODER_INTERFACE (vpx_codec_vp8_cx()) /* Audio encoding/decoding */ -#include +#include typedef enum _Capabilities { diff --git a/toxav/msi.c b/toxav/msi.c index c2d50302..aab13471 100755 --- a/toxav/msi.c +++ b/toxav/msi.c @@ -28,8 +28,6 @@ #include "../toxcore/logger.h" -/*#define _BSD_SOURCE*/ - #include "msi.h" #include "event.h" @@ -219,7 +217,7 @@ static inline__ const uint8_t *stringify_response ( MSIResponse response ) * @param msg Container. * @param data The data. * @return int - * @retval -1 Error occured. + * @retval -1 Error occurred. * @retval 0 Success. */ int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t length ) @@ -354,7 +352,7 @@ void free_message ( MSIMessage *msg ) * @param type Request or response. * @param type_id Type of request/response. * @return MSIMessage* Created message. - * @retval NULL Error occured. + * @retval NULL Error occurred. */ MSIMessage *msi_new_message ( uint8_t type, const uint8_t *type_id ) { @@ -387,7 +385,7 @@ MSIMessage *msi_new_message ( uint8_t type, const uint8_t *type_id ) * * @param data The data. * @return MSIMessage* Parsed message. - * @retval NULL Error occured. + * @retval NULL Error occurred. */ MSIMessage *parse_message ( const uint8_t *data, uint16_t length ) { @@ -495,7 +493,7 @@ uint8_t *append_header_to_string ( *dest = field_byte; /* Set the first byte */ - uint8_t *_getback_byte = dest + 1; /* remeber the byte we were on */ + uint8_t *_getback_byte = dest + 1; /* remember the byte we were on */ dest += 3; /* swith to 4th byte where field value starts */ /* Now set the field value and calculate it's length */ @@ -685,7 +683,7 @@ static inline__ const uint8_t *stringify_error_code ( MSICallError error_code ) * @param msg The message. * @param to Where to. * @return int - * @retval -1 Error occured. + * @retval -1 Error occurred. * @retval 0 Success. */ int send_message ( MSISession *session, MSICall* call, MSIMessage *msg, uint32_t to ) @@ -838,7 +836,7 @@ int handle_error ( MSISession *session, MSICall* call, MSICallError errid, uint3 * @param msg The message. * @return int * @retval -1 No error. - * @retval 0 Error occured and response sent. + * @retval 0 Error occurred and response sent. */ int has_call_error ( MSISession *session, MSICall* call, MSIMessage *msg ) { @@ -951,7 +949,7 @@ MSICall *init_call ( MSISession *session, int peers, int ringing_timeout ) * * @param session Control session. * @return int - * @retval -1 Error occured. + * @retval -1 Error occurred. * @retval 0 Success. */ int terminate_call ( MSISession *session, MSICall *call ) @@ -1031,7 +1029,7 @@ int handle_recv_invite ( MSISession *session, MSICall* call, MSIMessage *msg ) * B calls A. Who has advantage is set bey calculating * 'bigger' Call id and then that call id is being used in * future. User with 'bigger' Call id has the advantage - * as in he will wait the reponse from the other. + * as in he will wait the response from the other. */ if ( call_id_bigger (call->id, msg->callid.header_value) == 1 ) { /* Peer has advantage */ @@ -1408,7 +1406,7 @@ void msi_register_callback ( MSICallback callback, MSICallbackID id, void* userd * @param messenger Tox* object. * @param max_calls Amount of calls possible * @return MSISession* The created session. - * @retval NULL Error occured. + * @retval NULL Error occurred. */ MSISession *msi_init_session ( Messenger* messenger, int32_t max_calls ) { @@ -1530,7 +1528,7 @@ int msi_invite ( MSISession* session, int32_t* call_index, MSICallType call_type * @param session Control session. * @param call_id To which call is this action handled. * @return int - * @retval -1 Error occured. + * @retval -1 Error occurred. * @retval 0 Success. */ int msi_hangup ( MSISession* session, int32_t call_index ) diff --git a/toxav/msi.h b/toxav/msi.h index 2a7c5ba8..e9e1b4d7 100755 --- a/toxav/msi.h +++ b/toxav/msi.h @@ -84,7 +84,7 @@ typedef struct _MSICall { /* Call info structure */ int ringing_timer_id; /* Timer id for ringing timeout */ pthread_mutex_t mutex; /* It's to be assumed that call will have - * seperate thread so add mutex + * separate thread so add mutex */ uint32_t *peers; uint16_t peer_count; @@ -156,7 +156,7 @@ void msi_register_callback(MSICallback callback, MSICallbackID id, void* userdat * @param messenger Tox* object. * @param max_calls Amount of calls possible * @return MSISession* The created session. - * @retval NULL Error occured. + * @retval NULL Error occurred. */ MSISession *msi_init_session ( Messenger *messenger, int32_t max_calls ); @@ -189,7 +189,7 @@ int msi_invite ( MSISession *session, int32_t* call_index, MSICallType call_type * @param session Control session. * @param call_index To which call is this action handled. * @return int - * @retval -1 Error occured. + * @retval -1 Error occurred. * @retval 0 Success. */ int msi_hangup ( MSISession *session, int32_t call_index ); diff --git a/toxav/rtp.c b/toxav/rtp.c index 8b2768f1..cdaabd3a 100755 --- a/toxav/rtp.c +++ b/toxav/rtp.c @@ -170,8 +170,8 @@ inline__ void increase_nonce(uint8_t *nonce, uint16_t target) uint16_t _nonce_counter; uint8_t _reverse_bytes[2]; - _reverse_bytes[0] = nonce[crypto_secretbox_NONCEBYTES - 1]; - _reverse_bytes[1] = nonce[crypto_secretbox_NONCEBYTES - 2]; + _reverse_bytes[0] = nonce[crypto_box_NONCEBYTES - 1]; + _reverse_bytes[1] = nonce[crypto_box_NONCEBYTES - 2]; bytes_to_U16(&_nonce_counter, _reverse_bytes ); @@ -179,8 +179,8 @@ inline__ void increase_nonce(uint8_t *nonce, uint16_t target) if (_nonce_counter > UINT16_MAX - target ) { /* 2 bytes are not long enough */ uint8_t _it = 3; - while ( _it <= crypto_secretbox_NONCEBYTES ) _it += ++nonce[crypto_secretbox_NONCEBYTES - _it] ? - crypto_secretbox_NONCEBYTES : 1; + while ( _it <= crypto_box_NONCEBYTES ) _it += ++nonce[crypto_box_NONCEBYTES - _it] ? + crypto_box_NONCEBYTES : 1; _nonce_counter = _nonce_counter - (UINT16_MAX - target ); /* Assign the rest of it */ } else { /* Increase nonce */ @@ -191,8 +191,8 @@ inline__ void increase_nonce(uint8_t *nonce, uint16_t target) /* Assign the last bytes */ U16_to_bytes( _reverse_bytes, _nonce_counter); - nonce [crypto_secretbox_NONCEBYTES - 1] = _reverse_bytes[0]; - nonce [crypto_secretbox_NONCEBYTES - 2] = _reverse_bytes[1]; + nonce [crypto_box_NONCEBYTES - 1] = _reverse_bytes[0]; + nonce [crypto_box_NONCEBYTES - 2] = _reverse_bytes[1]; } @@ -416,7 +416,7 @@ RTPHeader *build_header ( RTPSession *session ) ADD_SETTING_PAYLOAD ( _retu, session->payload_type ); _retu->sequnum = session->sequnum; - _retu->timestamp = ((uint32_t)(current_time() / 1000)); /* micro to milli */ + _retu->timestamp = current_time_monotonic(); /* milliseconds */ _retu->ssrc = session->ssrc; int i; @@ -505,7 +505,7 @@ int rtp_handle_packet ( void *object, IP_Port ip_port, uint8_t *data, uint32_t l RTPSession *_session = object; RTPMessage *_msg; - if ( !_session || length < 13 + crypto_secretbox_MACBYTES) { /* 12 is the minimum length for rtp + desc. byte */ + if ( !_session || length < 13 + crypto_box_MACBYTES) { /* 12 is the minimum length for rtp + desc. byte */ LOGGER_WARNING("No session or invalid length of received buffer!"); return -1; } @@ -521,12 +521,13 @@ int rtp_handle_packet ( void *object, IP_Port ip_port, uint8_t *data, uint32_t l bytes_to_U16(&_sequnum, data + 1); /* Clculate the right nonce */ - uint8_t _calculated[crypto_secretbox_NONCEBYTES]; - memcpy(_calculated, _session->decrypt_nonce, crypto_secretbox_NONCEBYTES); + uint8_t _calculated[crypto_box_NONCEBYTES]; + memcpy(_calculated, _session->decrypt_nonce, crypto_box_NONCEBYTES); increase_nonce ( _calculated, _sequnum ); /* Decrypt message */ - int _decrypted_length = decrypt_data_symmetric((uint8_t *)_session->decrypt_key, _calculated, data + 3, length - 3, _plain ); + int _decrypted_length = decrypt_data_symmetric( + (uint8_t *)_session->decrypt_key, _calculated, data + 3, length - 3, _plain ); /* This packet is either not encrypted properly or late */ @@ -557,8 +558,8 @@ int rtp_handle_packet ( void *object, IP_Port ip_port, uint8_t *data, uint32_t l } /* A new cycle setting. */ - memcpy(_session->nonce_cycle, _session->decrypt_nonce, crypto_secretbox_NONCEBYTES); - memcpy(_session->decrypt_nonce, _calculated, crypto_secretbox_NONCEBYTES); + memcpy(_session->nonce_cycle, _session->decrypt_nonce, crypto_box_NONCEBYTES); + memcpy(_session->decrypt_nonce, _calculated, crypto_box_NONCEBYTES); } } @@ -774,8 +775,8 @@ int rtp_send_msg ( RTPSession *session, Messenger *messenger, const uint8_t *dat _send_data[0] = session->prefix; /* Generate the right nonce */ - uint8_t _calculated[crypto_secretbox_NONCEBYTES]; - memcpy(_calculated, session->encrypt_nonce, crypto_secretbox_NONCEBYTES); + uint8_t _calculated[crypto_box_NONCEBYTES]; + memcpy(_calculated, session->encrypt_nonce, crypto_box_NONCEBYTES); increase_nonce ( _calculated, msg->header->sequnum ); /* Need to skip 2 bytes that are for sequnum */ @@ -798,7 +799,7 @@ int rtp_send_msg ( RTPSession *session, Messenger *messenger, const uint8_t *dat /* Set sequ number */ if ( session->sequnum >= MAX_SEQU_NUM ) { session->sequnum = 0; - memcpy(session->encrypt_nonce, _calculated, crypto_secretbox_NONCEBYTES); + memcpy(session->encrypt_nonce, _calculated, crypto_box_NONCEBYTES); } else { session->sequnum++; } @@ -888,16 +889,16 @@ RTPSession *rtp_init_session ( int payload_type, _retu->decrypt_key = decrypt_key; /* Need to allocate new memory */ - _retu->encrypt_nonce = calloc ( crypto_secretbox_NONCEBYTES, sizeof (uint8_t) ); + _retu->encrypt_nonce = calloc ( crypto_box_NONCEBYTES, sizeof (uint8_t) ); assert(_retu->encrypt_nonce); - _retu->decrypt_nonce = calloc ( crypto_secretbox_NONCEBYTES, sizeof (uint8_t) ); + _retu->decrypt_nonce = calloc ( crypto_box_NONCEBYTES, sizeof (uint8_t) ); assert(_retu->decrypt_nonce); - _retu->nonce_cycle = calloc ( crypto_secretbox_NONCEBYTES, sizeof (uint8_t) ); + _retu->nonce_cycle = calloc ( crypto_box_NONCEBYTES, sizeof (uint8_t) ); assert(_retu->nonce_cycle); - memcpy(_retu->encrypt_nonce, encrypt_nonce, crypto_secretbox_NONCEBYTES); - memcpy(_retu->decrypt_nonce, decrypt_nonce, crypto_secretbox_NONCEBYTES); - memcpy(_retu->nonce_cycle , decrypt_nonce, crypto_secretbox_NONCEBYTES); + memcpy(_retu->encrypt_nonce, encrypt_nonce, crypto_box_NONCEBYTES); + memcpy(_retu->decrypt_nonce, decrypt_nonce, crypto_box_NONCEBYTES); + memcpy(_retu->nonce_cycle , decrypt_nonce, crypto_box_NONCEBYTES); _retu->csrc = calloc(1, sizeof (uint32_t)); assert(_retu->csrc); diff --git a/toxcore/DHT.c b/toxcore/DHT.c index 870e6ca2..7534387a 100644 --- a/toxcore/DHT.c +++ b/toxcore/DHT.c @@ -165,15 +165,15 @@ void get_shared_key(Shared_Keys *shared_keys, uint8_t *shared_key, uint8_t *secr } } -/* Copy shared_key to decrypt DHT packet from client_id into shared_key - * for packets that we recieve. +/* Copy shared_key to encrypt/decrypt DHT packet from client_id into shared_key + * for packets that we receive. */ void DHT_get_shared_key_recv(DHT *dht, uint8_t *shared_key, uint8_t *client_id) { return get_shared_key(&dht->shared_keys_recv, shared_key, dht->self_secret_key, client_id); } -/* Copy shared_key to decrypt DHT packet from client_id into shared_key +/* Copy shared_key to encrypt/decrypt DHT packet from client_id into shared_key * for packets that we send. */ void DHT_get_shared_key_sent(DHT *dht, uint8_t *shared_key, uint8_t *client_id) @@ -181,6 +181,155 @@ void DHT_get_shared_key_sent(DHT *dht, uint8_t *shared_key, uint8_t *client_id) return get_shared_key(&dht->shared_keys_sent, shared_key, dht->self_secret_key, client_id); } +void to_net_family(IP *ip) +{ + if (ip->family == AF_INET) + ip->family = TOX_AF_INET; + else if (ip->family == AF_INET6) + ip->family = TOX_AF_INET6; +} + +void to_host_family(IP *ip) +{ + if (ip->family == TOX_AF_INET) + ip->family = AF_INET; + else if (ip->family == TOX_AF_INET6) + ip->family = AF_INET6; +} + +/* Pack number of nodes into data of maxlength length. + * + * return length of packed nodes on success. + * return -1 on failure. + */ +int pack_nodes(uint8_t *data, uint16_t length, Node_format *nodes, uint16_t number) +{ + uint32_t i, packed_length = 0; + + for (i = 0; i < number; ++i) { + int ipv6 = -1; + uint8_t net_family; + + if (nodes[i].ip_port.ip.family == AF_INET) { + ipv6 = 0; + net_family = TOX_AF_INET; + } else if (nodes[i].ip_port.ip.family == TCP_INET) { + ipv6 = 0; + net_family = TOX_TCP_INET; + } else if (nodes[i].ip_port.ip.family == AF_INET6) { + ipv6 = 1; + net_family = TOX_AF_INET6; + } else if (nodes[i].ip_port.ip.family == TCP_INET6) { + ipv6 = 1; + net_family = TOX_TCP_INET6; + } else { + return -1; + } + + if (ipv6 == 0) { + uint32_t size = 1 + sizeof(IP4) + sizeof(uint16_t) + CLIENT_ID_SIZE; + + if (packed_length + size > length) + return -1; + + data[packed_length] = net_family; + memcpy(data + packed_length + 1, &nodes[i].ip_port.ip.ip4, sizeof(IP4)); + memcpy(data + packed_length + 1 + sizeof(IP4), &nodes[i].ip_port.port, sizeof(uint16_t)); + memcpy(data + packed_length + 1 + sizeof(IP4) + sizeof(uint16_t), nodes[i].client_id, CLIENT_ID_SIZE); + packed_length += size; + } else if (ipv6 == 1) { + uint32_t size = 1 + sizeof(IP6) + sizeof(uint16_t) + CLIENT_ID_SIZE; + + if (packed_length + size > length) + return -1; + + data[packed_length] = net_family; + memcpy(data + packed_length + 1, &nodes[i].ip_port.ip.ip6, sizeof(IP6)); + memcpy(data + packed_length + 1 + sizeof(IP6), &nodes[i].ip_port.port, sizeof(uint16_t)); + memcpy(data + packed_length + 1 + sizeof(IP6) + sizeof(uint16_t), nodes[i].client_id, CLIENT_ID_SIZE); + packed_length += size; + } else { + return -1; + } + } + + return packed_length; +} + +/* Unpack data of length into nodes of size max_num_nodes. + * Put the length of the data processed in processed_data_len. + * tcp_enabled sets if TCP nodes are expected (true) or not (false). + * + * return number of unpacked nodes on success. + * return -1 on failure. + */ +int unpack_nodes(Node_format *nodes, uint16_t max_num_nodes, uint16_t *processed_data_len, uint8_t *data, + uint16_t length, uint8_t tcp_enabled) +{ + uint32_t num = 0, len_processed = 0; + + while (num < max_num_nodes && len_processed < length) { + int ipv6 = -1; + uint8_t host_family; + + if (data[len_processed] == TOX_AF_INET) { + ipv6 = 0; + host_family = AF_INET; + } else if (data[len_processed] == TOX_TCP_INET) { + if (!tcp_enabled) + return -1; + + ipv6 = 0; + host_family = TCP_INET; + } else if (data[len_processed] == TOX_AF_INET6) { + ipv6 = 1; + host_family = AF_INET6; + } else if (data[len_processed] == TOX_TCP_INET6) { + if (!tcp_enabled) + return -1; + + ipv6 = 1; + host_family = TCP_INET6; + } else { + return -1; + } + + if (ipv6 == 0) { + uint32_t size = 1 + sizeof(IP4) + sizeof(uint16_t) + CLIENT_ID_SIZE; + + if (len_processed + size > length) + return -1; + + nodes[num].ip_port.ip.family = host_family; + memcpy(&nodes[num].ip_port.ip.ip4, data + len_processed + 1, sizeof(IP4)); + memcpy(&nodes[num].ip_port.port, data + len_processed + 1 + sizeof(IP4), sizeof(uint16_t)); + memcpy(nodes[num].client_id, data + len_processed + 1 + sizeof(IP4) + sizeof(uint16_t), CLIENT_ID_SIZE); + len_processed += size; + ++num; + } else if (ipv6 == 1) { + uint32_t size = 1 + sizeof(IP6) + sizeof(uint16_t) + CLIENT_ID_SIZE; + + if (len_processed + size > length) + return -1; + + nodes[num].ip_port.ip.family = host_family; + memcpy(&nodes[num].ip_port.ip.ip6, data + len_processed + 1, sizeof(IP6)); + memcpy(&nodes[num].ip_port.port, data + len_processed + 1 + sizeof(IP6), sizeof(uint16_t)); + memcpy(nodes[num].client_id, data + len_processed + 1 + sizeof(IP6) + sizeof(uint16_t), CLIENT_ID_SIZE); + len_processed += size; + ++num; + } else { + return -1; + } + } + + if (processed_data_len) + *processed_data_len = len_processed; + + return num; +} + + /* Check if client with client_id is already in list of length length. * If it is then set its corresponding timestamp to current time. @@ -266,7 +415,7 @@ static int client_or_ip_port_in_list(Client_data *list, uint32_t length, uint8_t /* Check if client with client_id is already in node format list of length length. * * return 1 if true. - * return 2 if false. + * return 0 if false. */ static int client_in_nodelist(Node_format *list, uint32_t length, uint8_t *client_id) { @@ -310,15 +459,15 @@ static uint8_t hardening_correct(Hardening *h) /* * helper for get_close_nodes(). argument list is a monster :D */ -static void get_close_nodes_inner(DHT *dht, uint8_t *client_id, Node_format *nodes_list, +static void get_close_nodes_inner(uint8_t *client_id, Node_format *nodes_list, sa_family_t sa_family, Client_data *client_list, uint32_t client_list_length, uint32_t *num_nodes_ptr, uint8_t is_LAN, uint8_t want_good) { - if ((sa_family != AF_INET) && (sa_family != AF_INET6)) + if ((sa_family != AF_INET) && (sa_family != AF_INET6) && (sa_family != 0)) return; uint32_t num_nodes = *num_nodes_ptr; - int ipv46x, j, closest; + int j, closest; uint32_t i; for (i = 0; i < client_list_length; i++) { @@ -330,39 +479,22 @@ static void get_close_nodes_inner(DHT *dht, uint8_t *client_id, Node_format *nod IPPTsPng *ipptp = NULL; - if (sa_family == AF_INET) + if (sa_family == AF_INET) { ipptp = &client->assoc4; - else + } else if (sa_family == AF_INET6) { ipptp = &client->assoc6; + } else { + if (client->assoc4.timestamp >= client->assoc6.timestamp) { + ipptp = &client->assoc4; + } else { + ipptp = &client->assoc6; + } + } /* node not in a good condition? */ if (is_timeout(ipptp->timestamp, BAD_NODE_TIMEOUT)) continue; - IP *client_ip = &ipptp->ip_port.ip; - - /* - * Careful: AF_INET isn't seen as AF_INET on dual-stack sockets for - * our connections, instead we have to look if it is an embedded - * IPv4-in-IPv6 here and convert it down in sendnodes(). - */ - sa_family_t ip_treat_as_family = client_ip->family; - - if ((dht->net->family == AF_INET6) && - (client_ip->family == AF_INET6)) { - /* socket is AF_INET6, address claims AF_INET6: - * check for embedded IPv4-in-IPv6 (shouldn't happen anymore, - * all storing functions should already convert down to IPv4) */ - if (IN6_IS_ADDR_V4MAPPED(&client_ip->ip6.in6_addr)) - ip_treat_as_family = AF_INET; - } - - ipv46x = !(sa_family == ip_treat_as_family); - - /* node address of the wrong family? */ - if (ipv46x) - continue; - /* don't send LAN ips to non LAN peers */ if (LAN_ip(ipptp->ip_port.ip) == 0 && !is_LAN) continue; @@ -416,7 +548,7 @@ static int get_somewhat_close_nodes(DHT *dht, uint8_t *client_id, Node_format *n uint8_t is_LAN, uint8_t want_good) { uint32_t num_nodes = 0, i; - get_close_nodes_inner(dht, client_id, nodes_list, sa_family, + get_close_nodes_inner(client_id, nodes_list, sa_family, dht->close_clientlist, LCLIENT_LIST, &num_nodes, is_LAN, want_good); /*TODO uncomment this when hardening is added to close friend clients @@ -426,7 +558,7 @@ static int get_somewhat_close_nodes(DHT *dht, uint8_t *client_id, Node_format *n &num_nodes, is_LAN, want_good); */ for (i = 0; i < dht->num_friends; ++i) - get_close_nodes_inner(dht, client_id, nodes_list, sa_family, + get_close_nodes_inner(client_id, nodes_list, sa_family, dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, &num_nodes, is_LAN, 0); @@ -444,6 +576,7 @@ int get_close_nodes(DHT *dht, uint8_t *client_id, Node_format *nodes_list, sa_fa return get_somewhat_close_nodes(dht, client_id, nodes_list, sa_family, is_LAN, want_good); #ifdef ENABLE_ASSOC_DHT + //TODO: assoc, sa_family 0 (don't care if ipv4 or ipv6) support. Client_data *result[MAX_SENT_NODES]; Assoc_close_entries request; @@ -581,7 +714,7 @@ static int replace_possible_bad( Client_data *list, sort_list(list, length, comp_client_id); - /* TODO: decide if the folowing lines should stay commented or not. + /* TODO: decide if the following lines should stay commented or not. if (id_closest(comp_client_id, list[0].client_id, client_id) == 1) return 0;*/ @@ -823,7 +956,7 @@ end: return 0; } -#define NODES_ENCRYPTED_MESSAGE_LENGTH (crypto_secretbox_NONCEBYTES + sizeof(uint64_t) + sizeof(Node_format) + sizeof(Node_format) + crypto_secretbox_MACBYTES) +#define NODES_ENCRYPTED_MESSAGE_LENGTH (crypto_box_NONCEBYTES + sizeof(uint64_t) + sizeof(Node_format) + sizeof(Node_format) + crypto_box_MACBYTES) /* Send a getnodes request. sendback_node is the node that it will send back the response to (set to NULL to disable this) */ @@ -842,23 +975,23 @@ static int getnodes(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *cli uint64_t temp_time = unix_time(); memcpy(plain_message, &temp_time, sizeof(temp_time)); - Node_format reciever; - memcpy(reciever.client_id, public_key, CLIENT_ID_SIZE); - reciever.ip_port = ip_port; - memcpy(plain_message + sizeof(temp_time), &reciever, sizeof(reciever)); + Node_format receiver; + memcpy(receiver.client_id, public_key, CLIENT_ID_SIZE); + receiver.ip_port = ip_port; + memcpy(plain_message + sizeof(temp_time), &receiver, sizeof(receiver)); if (sendback_node != NULL) - memcpy(plain_message + sizeof(temp_time) + sizeof(reciever), sendback_node, sizeof(Node_format)); + memcpy(plain_message + sizeof(temp_time) + sizeof(receiver), sendback_node, sizeof(Node_format)); else - memset(plain_message + sizeof(temp_time) + sizeof(reciever), 0, sizeof(Node_format)); + memset(plain_message + sizeof(temp_time) + sizeof(receiver), 0, sizeof(Node_format)); int len_m = encrypt_data_symmetric(dht->secret_symmetric_key, nonce, plain_message, - sizeof(temp_time) + sizeof(reciever) + sizeof(Node_format), - encrypted_message + crypto_secretbox_NONCEBYTES); + sizeof(temp_time) + sizeof(receiver) + sizeof(Node_format), + encrypted_message + crypto_box_NONCEBYTES); - if (len_m != NODES_ENCRYPTED_MESSAGE_LENGTH - crypto_secretbox_NONCEBYTES) + if (len_m != NODES_ENCRYPTED_MESSAGE_LENGTH - crypto_box_NONCEBYTES) return -1; uint8_t data[1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + CLIENT_ID_SIZE + NODES_ENCRYPTED_MESSAGE_LENGTH + crypto_box_MACBYTES]; @@ -871,11 +1004,11 @@ static int getnodes(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *cli uint8_t shared_key[crypto_box_BEFORENMBYTES]; DHT_get_shared_key_sent(dht, shared_key, public_key); - int len = encrypt_data_fast( shared_key, - nonce, - plain, - CLIENT_ID_SIZE + NODES_ENCRYPTED_MESSAGE_LENGTH, - encrypt ); + int len = encrypt_data_symmetric( shared_key, + nonce, + plain, + CLIENT_ID_SIZE + NODES_ENCRYPTED_MESSAGE_LENGTH, + encrypt ); if (len != CLIENT_ID_SIZE + NODES_ENCRYPTED_MESSAGE_LENGTH + crypto_box_MACBYTES) return -1; @@ -888,132 +1021,46 @@ static int getnodes(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *cli return sendpacket(dht->net, ip_port, data, sizeof(data)); } -/* Send a send nodes response. */ -/* because of BINARY compatibility, the Node_format MUST BE Node4_format, - * IPv6 nodes are sent in a different message - * encrypted_data must be of size NODES_ENCRYPTED_MESSAGE_LENGTH */ -static int sendnodes(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *client_id, uint8_t *encrypted_data, - uint8_t *shared_encryption_key) +/* Send a send nodes response: message for IPv6 nodes */ +static int sendnodes_ipv6(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *client_id, uint8_t *sendback_data, + uint16_t length, uint8_t *shared_encryption_key) { /* Check if packet is going to be sent to ourself. */ if (id_equal(public_key, dht->self_public_key)) return -1; - size_t Node4_format_size = sizeof(Node4_format); - uint8_t data[1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES - + Node4_format_size * MAX_SENT_NODES + NODES_ENCRYPTED_MESSAGE_LENGTH + crypto_box_MACBYTES]; - - Node_format nodes_list[MAX_SENT_NODES]; - uint32_t num_nodes = get_close_nodes(dht, client_id, nodes_list, AF_INET, LAN_ip(ip_port.ip) == 0, 1); - - if (num_nodes == 0) - return 0; - - uint8_t plain[Node4_format_size * MAX_SENT_NODES + NODES_ENCRYPTED_MESSAGE_LENGTH]; - uint8_t encrypt[Node4_format_size * MAX_SENT_NODES + NODES_ENCRYPTED_MESSAGE_LENGTH + crypto_box_MACBYTES]; - uint8_t nonce[crypto_box_NONCEBYTES]; - new_nonce(nonce); - - Node4_format *nodes4_list = (Node4_format *)(plain); - uint32_t i, num_nodes_ok = 0; - - for (i = 0; i < num_nodes; i++) { - memcpy(nodes4_list[num_nodes_ok].client_id, nodes_list[i].client_id, CLIENT_ID_SIZE); - nodes4_list[num_nodes_ok].ip_port.port = nodes_list[i].ip_port.port; - - IP *node_ip = &nodes_list[i].ip_port.ip; - - if ((node_ip->family == AF_INET6) && IN6_IS_ADDR_V4MAPPED(&node_ip->ip6.in6_addr)) - /* embedded IPv4-in-IPv6 address: return it in regular sendnodes packet */ - nodes4_list[num_nodes_ok].ip_port.ip.uint32 = node_ip->ip6.uint32[3]; - else if (node_ip->family == AF_INET) - nodes4_list[num_nodes_ok].ip_port.ip.uint32 = node_ip->ip4.uint32; - else /* shouldn't happen */ - continue; - - num_nodes_ok++; - } - - if (num_nodes_ok < num_nodes) { - /* shouldn't happen */ - num_nodes = num_nodes_ok; - } - - memcpy(plain + num_nodes * Node4_format_size, encrypted_data, NODES_ENCRYPTED_MESSAGE_LENGTH); - int len = encrypt_data_fast( shared_encryption_key, - nonce, - plain, - num_nodes * Node4_format_size + NODES_ENCRYPTED_MESSAGE_LENGTH, - encrypt ); - - if ((unsigned int)len != num_nodes * Node4_format_size + NODES_ENCRYPTED_MESSAGE_LENGTH + - crypto_box_MACBYTES) - return -1; - - data[0] = NET_PACKET_SEND_NODES; - memcpy(data + 1, dht->self_public_key, CLIENT_ID_SIZE); - memcpy(data + 1 + CLIENT_ID_SIZE, nonce, crypto_box_NONCEBYTES); - memcpy(data + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, encrypt, len); - - return sendpacket(dht->net, ip_port, data, 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + len); -} - -void to_net_family(IP *ip) -{ - ip->padding[0] = 0; - ip->padding[1] = 0; - ip->padding[2] = 0; - - if (ip->family == AF_INET) - ip->family = TOX_AF_INET; - else if (ip->family == AF_INET6) - ip->family = TOX_AF_INET6; -} - -void to_host_family(IP *ip) -{ - if (ip->family == TOX_AF_INET) - ip->family = AF_INET; - else if (ip->family == TOX_AF_INET6) - ip->family = AF_INET6; -} -/* Send a send nodes response: message for IPv6 nodes */ -static int sendnodes_ipv6(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *client_id, uint8_t *encrypted_data, - uint8_t *shared_encryption_key) -{ - /* Check if packet is going to be sent to ourself. */ - if (id_equal(public_key, dht->self_public_key)) + if (length > NODES_ENCRYPTED_MESSAGE_LENGTH || length == 0) return -1; size_t Node_format_size = sizeof(Node_format); uint8_t data[1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES - + Node_format_size * MAX_SENT_NODES + NODES_ENCRYPTED_MESSAGE_LENGTH + crypto_box_MACBYTES]; + + Node_format_size * MAX_SENT_NODES + length + crypto_box_MACBYTES]; Node_format nodes_list[MAX_SENT_NODES]; - uint32_t num_nodes = get_close_nodes(dht, client_id, nodes_list, AF_INET6, LAN_ip(ip_port.ip) == 0, 1); + uint32_t num_nodes = get_close_nodes(dht, client_id, nodes_list, 0, LAN_ip(ip_port.ip) == 0, 1); if (num_nodes == 0) return 0; - uint8_t plain[Node_format_size * MAX_SENT_NODES + NODES_ENCRYPTED_MESSAGE_LENGTH]; - uint8_t encrypt[Node_format_size * MAX_SENT_NODES + NODES_ENCRYPTED_MESSAGE_LENGTH + crypto_box_MACBYTES]; + uint8_t plain[1 + Node_format_size * MAX_SENT_NODES + length]; + uint8_t encrypt[sizeof(plain) + crypto_box_MACBYTES]; uint8_t nonce[crypto_box_NONCEBYTES]; new_nonce(nonce); - uint32_t i; + int nodes_length = pack_nodes(plain + 1, Node_format_size * MAX_SENT_NODES, nodes_list, num_nodes); - for (i = 0; i < num_nodes; ++i) - to_net_family(&nodes_list[i].ip_port.ip); + if (nodes_length <= 0) + return -1; - memcpy(plain, nodes_list, num_nodes * Node_format_size); - memcpy(plain + num_nodes * Node_format_size, encrypted_data, NODES_ENCRYPTED_MESSAGE_LENGTH); - int len = encrypt_data_fast( shared_encryption_key, - nonce, - plain, - num_nodes * Node_format_size + NODES_ENCRYPTED_MESSAGE_LENGTH, - encrypt ); + plain[0] = num_nodes; + memcpy(plain + 1 + nodes_length, sendback_data, length); + int len = encrypt_data_symmetric( shared_encryption_key, + nonce, + plain, + 1 + nodes_length + length, + encrypt ); - if ((unsigned int)len != num_nodes * Node_format_size + NODES_ENCRYPTED_MESSAGE_LENGTH + crypto_box_MACBYTES) + if (len != 1 + nodes_length + length + crypto_box_MACBYTES) return -1; data[0] = NET_PACKET_SEND_NODES_IPV6; @@ -1026,35 +1073,38 @@ static int sendnodes_ipv6(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_ static int handle_getnodes(void *object, IP_Port source, uint8_t *packet, uint32_t length) { - DHT *dht = object; + uint32_t cmp_len = 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + CLIENT_ID_SIZE + crypto_box_MACBYTES; + + if (length <= cmp_len) + return 1; - if (length != ( 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + CLIENT_ID_SIZE + NODES_ENCRYPTED_MESSAGE_LENGTH + - crypto_box_MACBYTES )) + if (length > cmp_len + NODES_ENCRYPTED_MESSAGE_LENGTH) return 1; + uint16_t sendback_data_length = length - cmp_len; + + DHT *dht = object; + /* Check if packet is from ourself. */ if (id_equal(packet + 1, dht->self_public_key)) return 1; - uint8_t plain[CLIENT_ID_SIZE + NODES_ENCRYPTED_MESSAGE_LENGTH]; + uint8_t plain[CLIENT_ID_SIZE + sendback_data_length]; uint8_t shared_key[crypto_box_BEFORENMBYTES]; DHT_get_shared_key_recv(dht, shared_key, packet + 1); - int len = decrypt_data_fast( shared_key, - packet + 1 + CLIENT_ID_SIZE, - packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, - CLIENT_ID_SIZE + NODES_ENCRYPTED_MESSAGE_LENGTH + crypto_box_MACBYTES, - plain ); + int len = decrypt_data_symmetric( shared_key, + packet + 1 + CLIENT_ID_SIZE, + packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, + CLIENT_ID_SIZE + sendback_data_length + crypto_box_MACBYTES, + plain ); - if (len != CLIENT_ID_SIZE + NODES_ENCRYPTED_MESSAGE_LENGTH) + if (len != CLIENT_ID_SIZE + sendback_data_length) return 1; - sendnodes(dht, source, packet + 1, plain, plain + CLIENT_ID_SIZE, shared_key); - sendnodes_ipv6(dht, source, packet + 1, plain, - plain + CLIENT_ID_SIZE, shared_key); /* TODO: prevent possible amplification attacks */ + sendnodes_ipv6(dht, source, packet + 1, plain, plain + CLIENT_ID_SIZE, sendback_data_length, shared_key); add_to_ping(dht->ping, packet + 1, source); - //send_ping_request(dht, source, packet + 1); /* TODO: make this smarter? */ return 0; } @@ -1066,8 +1116,8 @@ static uint8_t sent_getnode_to_node(DHT *dht, uint8_t *client_id, IP_Port node_i { uint8_t plain_message[NODES_ENCRYPTED_MESSAGE_LENGTH]; - if (decrypt_data_symmetric(dht->secret_symmetric_key, encrypted_data, encrypted_data + crypto_secretbox_NONCEBYTES, - NODES_ENCRYPTED_MESSAGE_LENGTH - crypto_secretbox_NONCEBYTES, + if (decrypt_data_symmetric(dht->secret_symmetric_key, encrypted_data, encrypted_data + crypto_box_NONCEBYTES, + NODES_ENCRYPTED_MESSAGE_LENGTH - crypto_box_NONCEBYTES, plain_message) != sizeof(uint64_t) + sizeof(Node_format) * 2) return 0; @@ -1089,124 +1139,87 @@ static uint8_t sent_getnode_to_node(DHT *dht, uint8_t *client_id, IP_Port node_i } /* Function is needed in following functions. */ -static int send_hardening_getnode_res(DHT *dht, Node_format *sendto, uint8_t *queried_client_id, Node_format *list, - uint16_t num_nodes); +static int send_hardening_getnode_res(DHT *dht, Node_format *sendto, uint8_t *queried_client_id, uint8_t *nodes_data, + uint16_t nodes_data_length); static int handle_sendnodes_core(void *object, IP_Port source, uint8_t *packet, uint32_t length, - size_t node_format_size, uint8_t *plain, uint16_t plain_length, uint32_t *num_nodes_out, Node_format *sendback_node) + Node_format *plain_nodes, uint16_t size_plain_nodes, uint32_t *num_nodes_out) { - if (plain_length != MAX_SENT_NODES * node_format_size + NODES_ENCRYPTED_MESSAGE_LENGTH) - return 1; - DHT *dht = object; - uint32_t cid_size = 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + NODES_ENCRYPTED_MESSAGE_LENGTH + crypto_box_MACBYTES; + uint32_t cid_size = 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + 1 + NODES_ENCRYPTED_MESSAGE_LENGTH + + crypto_box_MACBYTES; if (length <= cid_size) /* too short */ return 1; uint32_t data_size = length - cid_size; - if ((data_size % node_format_size) != 0) /* invalid length */ + if (data_size == 0) return 1; - uint32_t num_nodes = data_size / node_format_size; - - if (num_nodes > MAX_SENT_NODES) /* too long */ + if (data_size > sizeof(Node_format) * MAX_SENT_NODES) /* invalid length */ return 1; + uint8_t plain[1 + data_size + NODES_ENCRYPTED_MESSAGE_LENGTH]; uint8_t shared_key[crypto_box_BEFORENMBYTES]; DHT_get_shared_key_sent(dht, shared_key, packet + 1); - int len = decrypt_data_fast( + int len = decrypt_data_symmetric( shared_key, packet + 1 + CLIENT_ID_SIZE, packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, - num_nodes * node_format_size + NODES_ENCRYPTED_MESSAGE_LENGTH + crypto_box_MACBYTES, + 1 + data_size + NODES_ENCRYPTED_MESSAGE_LENGTH + crypto_box_MACBYTES, plain); - if ((unsigned int)len != num_nodes * node_format_size + NODES_ENCRYPTED_MESSAGE_LENGTH) + if ((unsigned int)len != sizeof(plain)) return 1; - if (!sent_getnode_to_node(dht, packet + 1, source, plain + num_nodes * node_format_size, sendback_node)) + if (plain[0] > size_plain_nodes || plain[0] == 0) return 1; - /* store the address the *request* was sent to */ - addto_lists(dht, source, packet + 1); - - *num_nodes_out = num_nodes; - - return 0; -} - -static int handle_sendnodes(void *object, IP_Port source, uint8_t *packet, uint32_t length) -{ - DHT *dht = object; - size_t node4_format_size = sizeof(Node4_format); - uint8_t plain[node4_format_size * MAX_SENT_NODES + NODES_ENCRYPTED_MESSAGE_LENGTH]; - uint32_t num_nodes; - Node_format sendback_node; - if (handle_sendnodes_core(object, source, packet, length, node4_format_size, plain, sizeof(plain), &num_nodes, - &sendback_node)) + if (!sent_getnode_to_node(dht, packet + 1, source, plain + 1 + data_size, &sendback_node)) return 1; - if (num_nodes == 0) - return 0; - - Node4_format *nodes4_list = (Node4_format *)(plain); - - uint64_t time_now = unix_time(); - IPPTs ippts; - ippts.ip_port.ip.family = AF_INET; - ippts.timestamp = time_now; - - uint32_t i; + uint16_t length_nodes = 0; + int num_nodes = unpack_nodes(plain_nodes, plain[0], &length_nodes, plain + 1, data_size, 0); - Node_format nodes_list[MAX_SENT_NODES]; + if (length_nodes != data_size) + return 1; - for (i = 0; i < num_nodes; i++) - if ((nodes4_list[i].ip_port.ip.uint32 != 0) && (nodes4_list[i].ip_port.ip.uint32 != (uint32_t)~0)) { - ippts.ip_port.ip.ip4.uint32 = nodes4_list[i].ip_port.ip.uint32; - ippts.ip_port.port = nodes4_list[i].ip_port.port; + if (num_nodes != plain[0]) + return 1; - send_ping_request(dht->ping, ippts.ip_port, nodes4_list[i].client_id); - returnedip_ports(dht, ippts.ip_port, nodes4_list[i].client_id, packet + 1); + if (num_nodes <= 0) + return 1; - memcpy(nodes_list[i].client_id, nodes4_list[i].client_id, CLIENT_ID_SIZE); - ipport_copy(&nodes_list[i].ip_port, &ippts.ip_port); + /* store the address the *request* was sent to */ + addto_lists(dht, source, packet + 1); - } + *num_nodes_out = num_nodes; - send_hardening_getnode_res(dht, &sendback_node, packet + 1, nodes_list, num_nodes); + send_hardening_getnode_res(dht, &sendback_node, packet + 1, plain + 1, data_size); return 0; } static int handle_sendnodes_ipv6(void *object, IP_Port source, uint8_t *packet, uint32_t length) { DHT *dht = object; - size_t node_format_size = sizeof(Node_format); - uint8_t plain[node_format_size * MAX_SENT_NODES + NODES_ENCRYPTED_MESSAGE_LENGTH]; + Node_format plain_nodes[MAX_SENT_NODES]; uint32_t num_nodes; - Node_format sendback_node; - - if (handle_sendnodes_core(object, source, packet, length, node_format_size, plain, sizeof(plain), &num_nodes, - &sendback_node)) + if (handle_sendnodes_core(object, source, packet, length, plain_nodes, MAX_SENT_NODES, &num_nodes)) return 1; if (num_nodes == 0) return 0; - Node_format *nodes_list = (Node_format *)(plain); uint32_t i; - send_hardening_getnode_res(dht, &sendback_node, packet + 1, nodes_list, num_nodes); for (i = 0; i < num_nodes; i++) { - to_host_family(&nodes_list[i].ip_port.ip); - - if (ipport_isset(&nodes_list[i].ip_port)) { - send_ping_request(dht->ping, nodes_list[i].ip_port, nodes_list[i].client_id); - returnedip_ports(dht, nodes_list[i].ip_port, nodes_list[i].client_id, packet + 1); + if (ipport_isset(&plain_nodes[i].ip_port)) { + send_ping_request(dht->ping, plain_nodes[i].ip_port, plain_nodes[i].client_id); + returnedip_ports(dht, plain_nodes[i].ip_port, plain_nodes[i].client_id, packet + 1); } } @@ -1595,7 +1608,7 @@ static int friend_iplist(DHT *dht, IP_Port *ip_portlist, uint16_t friend_num) /* Send the following packet to everyone who tells us they are connected to friend_id. * * return ip for friend. - * return number of nodes the packet was sent to. (Only works if more than (MAX_FRIEND_CLIENTS / 2). + * return number of nodes the packet was sent to. (Only works if more than (MAX_FRIEND_CLIENTS / 4). */ int route_tofriend(DHT *dht, uint8_t *friend_id, uint8_t *packet, uint32_t length) { @@ -1724,7 +1737,7 @@ int friend_ips(DHT *dht, IP_Port *ip_portlist, uint8_t *friend_id) static int send_NATping(DHT *dht, uint8_t *public_key, uint64_t ping_id, uint8_t type) { uint8_t data[sizeof(uint64_t) + 1]; - uint8_t packet[MAX_DATA_SIZE]; + uint8_t packet[MAX_CRYPTO_REQUEST_SIZE]; int num = 0; @@ -1935,7 +1948,7 @@ static int send_hardening_req(DHT *dht, Node_format *sendto, uint8_t type, uint8 if (length > HARDREQ_DATA_SIZE - 1) return -1; - uint8_t packet[MAX_DATA_SIZE]; + uint8_t packet[MAX_CRYPTO_REQUEST_SIZE]; uint8_t data[HARDREQ_DATA_SIZE] = {0}; data[0] = type; memcpy(data + 1, contents, length); @@ -1958,17 +1971,17 @@ static int send_hardening_getnode_req(DHT *dht, Node_format *dest, Node_format * } /* Send a get node hardening response */ -static int send_hardening_getnode_res(DHT *dht, Node_format *sendto, uint8_t *queried_client_id, Node_format *list, - uint16_t num_nodes) +static int send_hardening_getnode_res(DHT *dht, Node_format *sendto, uint8_t *queried_client_id, uint8_t *nodes_data, + uint16_t nodes_data_length) { if (!ip_isset(&sendto->ip_port.ip)) return -1; - uint8_t packet[MAX_DATA_SIZE]; - uint8_t data[1 + CLIENT_ID_SIZE + num_nodes * sizeof(Node_format)]; + uint8_t packet[MAX_CRYPTO_REQUEST_SIZE]; + uint8_t data[1 + CLIENT_ID_SIZE + nodes_data_length]; data[0] = CHECK_TYPE_GETNODE_RES; memcpy(data + 1, queried_client_id, CLIENT_ID_SIZE); - memcpy(data + 1 + CLIENT_ID_SIZE, list, num_nodes * sizeof(Node_format)); + memcpy(data + 1 + CLIENT_ID_SIZE, nodes_data, nodes_data_length); int len = create_request(dht->self_public_key, dht->self_secret_key, packet, sendto->client_id, data, sizeof(data), CRYPTO_PACKET_HARDENING); @@ -2056,28 +2069,22 @@ static int handle_hardening(void *object, IP_Port source, uint8_t *source_pubkey if (length <= CLIENT_ID_SIZE + 1) return 1; - if ((length - 1 - CLIENT_ID_SIZE) % sizeof(Node_format) != 0) + if (length > 1 + CLIENT_ID_SIZE + sizeof(Node_format) * MAX_SENT_NODES) return 1; - uint16_t num = (length - 1 - CLIENT_ID_SIZE) / sizeof(Node_format); + uint16_t length_nodes = length - 1 - CLIENT_ID_SIZE; + Node_format nodes[MAX_SENT_NODES]; + int num_nodes = unpack_nodes(nodes, MAX_SENT_NODES, 0, packet + 1 + CLIENT_ID_SIZE, length_nodes, 0); /* TODO: MAX_SENT_NODES nodes should be returned at all times (right now we have a small network size so it could cause problems for testing and etc..) */ - if (num > MAX_SENT_NODES || num == 0) + if (num_nodes <= 0) return 1; - Node_format nodes[num]; - memcpy(nodes, packet + 1 + CLIENT_ID_SIZE, sizeof(Node_format)*num); - uint32_t i; - - for (i = 0; i < num; ++i) - to_host_family(&nodes[i].ip_port.ip); - /* NOTE: This should work for now but should be changed to something better. */ - if (have_nodes_closelist(dht, nodes, num) < (uint32_t)((num + 2) / 2)) + if (have_nodes_closelist(dht, nodes, num_nodes) < (uint32_t)((num_nodes + 2) / 2)) return 1; - IPPTsPng *temp = get_closelist_IPPTsPng(dht, packet + 1, nodes[0].ip_port.ip.family); if (temp == NULL) @@ -2204,6 +2211,8 @@ static int random_node_fromlist(Client_data *list, uint16_t list_size, Node_form * return the number of nodes. * * NOTE:this is used to pick nodes for paths. + * + * TODO: remove the LAN stuff from this. */ uint16_t random_nodes_path(DHT *dht, Node_format *nodes, uint16_t max_num) { @@ -2287,12 +2296,54 @@ void do_hardening(DHT *dht) /*----------------------------------------------------------------------------------*/ -DHT *new_DHT(Net_Crypto *c) +void cryptopacket_registerhandler(DHT *dht, uint8_t byte, cryptopacket_handler_callback cb, void *object) +{ + dht->cryptopackethandlers[byte].function = cb; + dht->cryptopackethandlers[byte].object = object; +} + +static int cryptopacket_handle(void *object, IP_Port source, uint8_t *packet, uint32_t length) +{ + DHT *dht = object; + + if (packet[0] == NET_PACKET_CRYPTO) { + if (length <= crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1 + crypto_box_MACBYTES || + length > MAX_CRYPTO_REQUEST_SIZE + crypto_box_MACBYTES) + return 1; + + if (memcmp(packet + 1, dht->self_public_key, crypto_box_PUBLICKEYBYTES) == 0) { // Check if request is for us. + uint8_t public_key[crypto_box_PUBLICKEYBYTES]; + uint8_t data[MAX_CRYPTO_REQUEST_SIZE]; + uint8_t number; + int len = handle_request(dht->self_public_key, dht->self_secret_key, public_key, data, &number, packet, length); + + if (len == -1 || len == 0) + return 1; + + if (!dht->cryptopackethandlers[number].function) return 1; + + return dht->cryptopackethandlers[number].function(dht->cryptopackethandlers[number].object, source, public_key, + data, len); + + } else { /* If request is not for us, try routing it. */ + int retval = route_packet(dht, packet + 1, packet, length); + + if ((unsigned int)retval == length) + return 0; + } + } + + return 1; +} + +/*----------------------------------------------------------------------------------*/ + +DHT *new_DHT(Networking_Core *net) { /* init time */ unix_time_update(); - if (c == NULL) + if (net == NULL) return NULL; DHT *dht = calloc(1, sizeof(DHT)); @@ -2300,8 +2351,7 @@ DHT *new_DHT(Net_Crypto *c) if (dht == NULL) return NULL; - dht->c = c; - dht->net = c->lossless_udp->net; + dht->net = net; dht->ping = new_ping(dht); if (dht->ping == NULL) { @@ -2310,11 +2360,10 @@ DHT *new_DHT(Net_Crypto *c) } networking_registerhandler(dht->net, NET_PACKET_GET_NODES, &handle_getnodes, dht); - networking_registerhandler(dht->net, NET_PACKET_SEND_NODES, &handle_sendnodes, dht); networking_registerhandler(dht->net, NET_PACKET_SEND_NODES_IPV6, &handle_sendnodes_ipv6, dht); - init_cryptopackets(dht); - cryptopacket_registerhandler(c, CRYPTO_PACKET_NAT_PING, &handle_NATping, dht); - cryptopacket_registerhandler(c, CRYPTO_PACKET_HARDENING, &handle_hardening, dht); + networking_registerhandler(dht->net, NET_PACKET_CRYPTO, &cryptopacket_handle, dht); + cryptopacket_registerhandler(dht, CRYPTO_PACKET_NAT_PING, &handle_NATping, dht); + cryptopacket_registerhandler(dht, CRYPTO_PACKET_HARDENING, &handle_hardening, dht); new_symmetric_key(dht->secret_symmetric_key); crypto_box_keypair(dht->self_public_key, dht->self_secret_key); @@ -2361,8 +2410,8 @@ void kill_DHT(DHT *dht) networking_registerhandler(dht->net, NET_PACKET_GET_NODES, NULL, NULL); networking_registerhandler(dht->net, NET_PACKET_SEND_NODES, NULL, NULL); networking_registerhandler(dht->net, NET_PACKET_SEND_NODES_IPV6, NULL, NULL); - cryptopacket_registerhandler(dht->c, CRYPTO_PACKET_NAT_PING, NULL, NULL); - cryptopacket_registerhandler(dht->c, CRYPTO_PACKET_HARDENING, NULL, NULL); + cryptopacket_registerhandler(dht, CRYPTO_PACKET_NAT_PING, NULL, NULL); + cryptopacket_registerhandler(dht, CRYPTO_PACKET_HARDENING, NULL, NULL); kill_ping(dht->ping); free(dht->friends_list); free(dht); diff --git a/toxcore/DHT.h b/toxcore/DHT.h index 3d2722f8..41fe99c9 100644 --- a/toxcore/DHT.h +++ b/toxcore/DHT.h @@ -24,7 +24,8 @@ #ifndef DHT_H #define DHT_H -#include "net_crypto.h" +#include "crypto_core.h" +#include "network.h" /* Size of the client_id in bytes. */ #define CLIENT_ID_SIZE crypto_box_PUBLICKEYBYTES @@ -36,7 +37,7 @@ #define LCLIENT_LIST 32 /* The max number of nodes to send with send nodes. */ -#define MAX_SENT_NODES 8 +#define MAX_SENT_NODES 4 /* Ping timeout in seconds */ #define PING_TIMEOUT 3 @@ -52,6 +53,8 @@ /* Redefinitions of variables for safe transfer over wire. */ #define TOX_AF_INET 2 #define TOX_AF_INET6 10 +#define TOX_TCP_INET 130 +#define TOX_TCP_INET6 138 /* The number of "fake" friends to add (for optimization purposes and so our paths for the onion part are more random) */ #define DHT_FAKE_FRIEND_NUMBER 4 @@ -128,16 +131,30 @@ typedef struct { NAT nat; } DHT_Friend; -/* this must be kept even if IP_Port is expanded: wire compatibility */ -typedef struct { - uint8_t client_id[CLIENT_ID_SIZE]; - IP4_Port ip_port; -} Node4_format; - -typedef struct { +typedef struct __attribute__ ((__packed__)) +{ uint8_t client_id[CLIENT_ID_SIZE]; IP_Port ip_port; -} Node_format; +} +Node_format; + +/* Pack number of nodes into data of maxlength length. + * + * return length of packed nodes on success. + * return -1 on failure. + */ +int pack_nodes(uint8_t *data, uint16_t length, Node_format *nodes, uint16_t number); + +/* Unpack data of length into nodes of size max_num_nodes. + * Put the length of the data processed in processed_data_len. + * tcp_enabled sets if TCP nodes are expected (true) or not (false). + * + * return number of unpacked nodes on success. + * return -1 on failure. + */ +int unpack_nodes(Node_format *nodes, uint16_t max_num_nodes, uint16_t *processed_data_len, uint8_t *data, + uint16_t length, uint8_t tcp_enabled); + /*----------------------------------------------------------------------------------*/ /* struct to store some shared keys so we don't have to regenerate them for each request. */ @@ -155,8 +172,15 @@ typedef struct { /*----------------------------------------------------------------------------------*/ +typedef int (*cryptopacket_handler_callback)(void *object, IP_Port ip_port, uint8_t *source_pubkey, uint8_t *data, + uint32_t len); + +typedef struct { + cryptopacket_handler_callback function; + void *object; +} Cryptopacket_Handles; + typedef struct { - Net_Crypto *c; Networking_Core *net; Client_data close_clientlist[LCLIENT_LIST]; @@ -164,7 +188,7 @@ typedef struct { uint32_t close_bootstrap_times; /* Note: this key should not be/is not used to transmit any sensitive materials */ - uint8_t secret_symmetric_key[crypto_secretbox_KEYBYTES]; + uint8_t secret_symmetric_key[crypto_box_KEYBYTES]; /* DHT keypair */ uint8_t self_public_key[crypto_box_PUBLICKEYBYTES]; uint8_t self_secret_key[crypto_box_SECRETKEYBYTES]; @@ -180,6 +204,8 @@ typedef struct { struct Assoc *assoc; #endif uint64_t last_run; + + Cryptopacket_Handles cryptopackethandlers[256]; } DHT; /*----------------------------------------------------------------------------------*/ @@ -191,12 +217,12 @@ typedef struct { */ void get_shared_key(Shared_Keys *shared_keys, uint8_t *shared_key, uint8_t *secret_key, uint8_t *client_id); -/* Copy shared_key to decrypt DHT packet from client_id into shared_key - * for packets that we recieve. +/* Copy shared_key to encrypt/decrypt DHT packet from client_id into shared_key + * for packets that we receive. */ void DHT_get_shared_key_recv(DHT *dht, uint8_t *shared_key, uint8_t *client_id); -/* Copy shared_key to decrypt DHT packet from client_id into shared_key +/* Copy shared_key to encrypt/decrypt DHT packet from client_id into shared_key * for packets that we send. */ void DHT_get_shared_key_sent(DHT *dht, uint8_t *shared_key, uint8_t *client_id); @@ -251,7 +277,7 @@ int id_closest(uint8_t *id, uint8_t *id1, uint8_t *id2); /* Get the (maximum MAX_SENT_NODES) closest nodes to client_id we know * and put them in nodes_list (must be MAX_SENT_NODES big). * - * sa_family = family (IPv4 or IPv6)? + * sa_family = family (IPv4 or IPv6) (0 if we don't care)? * is_LAN = return some LAN ips (true or false) * want_good = do we want tested nodes or not? (TODO) * @@ -315,6 +341,10 @@ int route_packet(DHT *dht, uint8_t *client_id, uint8_t *packet, uint32_t length) */ int route_tofriend(DHT *dht, uint8_t *friend_id, uint8_t *packet, uint32_t length); +/* Function to handle crypto packets. + */ +void cryptopacket_registerhandler(DHT *dht, uint8_t byte, cryptopacket_handler_callback cb, void *object); + /* NAT PUNCHING FUNCTIONS */ /* Puts all the different ips returned by the nodes for a friend_id into array ip_portlist. @@ -341,7 +371,7 @@ void DHT_save(DHT *dht, uint8_t *data); int DHT_load(DHT *dht, uint8_t *data, uint32_t length); /* Initialize DHT. */ -DHT *new_DHT(Net_Crypto *c); +DHT *new_DHT(Networking_Core *net); void kill_DHT(DHT *dht); diff --git a/toxcore/LAN_discovery.c b/toxcore/LAN_discovery.c index bed14754..9d1f055e 100644 --- a/toxcore/LAN_discovery.c +++ b/toxcore/LAN_discovery.c @@ -78,8 +78,10 @@ static void fetch_broadcast_info(uint16_t port) struct sockaddr_in *sock4 = (struct sockaddr_in *)&i_faces[i].ifr_broadaddr; - if (broadcast_count >= MAX_INTERFACES) + if (broadcast_count >= MAX_INTERFACES) { + close(sock); return; + } IP_Port *ip_port = &broadcast_ip_port[broadcast_count]; ip_port->ip.family = AF_INET; diff --git a/toxcore/Lossless_UDP.c b/toxcore/Lossless_UDP.c deleted file mode 100644 index c0db8a10..00000000 --- a/toxcore/Lossless_UDP.c +++ /dev/null @@ -1,1168 +0,0 @@ -/* Lossless_UDP.c - * - * An implementation of the Lossless_UDP protocol as seen in http://wiki.tox.im/index.php/Lossless_UDP - * - * Copyright (C) 2013 Tox project All Rights Reserved. - * - * This file is part of Tox. - * - * Tox is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tox is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tox. If not, see . - * - */ - -/* - * TODO: clean this file a bit. - * There are a couple of useless variables to get rid of. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "Lossless_UDP.h" - -#define LUDP_CONNECTION_OUTBOUND 0 -#define LUDP_CONNECTION_INBOUND_HANDLED 1 -#define LUDP_CONNECTION_INBOUND 2 - -/* Functions */ - -/* - * Get connection id from IP_Port. - * - * return -1 if there are no connections like we are looking for. - * return id if it found it. - */ -int getconnection_id(Lossless_UDP *ludp, IP_Port ip_port) -{ - tox_array_for_each(&ludp->connections, Connection, tmp) { - if (tmp->status != LUDP_NO_CONNECTION && ipport_equal(&tmp->ip_port, &ip_port)) { - return tmp_i; - } - } - - return -1; -} - -/* Resize a queue - * return length of queue on success. - * return ~0 on failure. - */ -uint32_t resize_queue(Data **buffer, uint32_t length, uint32_t new_length, uint32_t min_packetnum, - uint32_t max_packetnum) -{ - if (MAX_QUEUE_NUM < new_length) - new_length = MAX_QUEUE_NUM; - - if (max_packetnum - min_packetnum > new_length) - return ~0; - - if (length == new_length) - return new_length; - - Data *temp = calloc(1, sizeof(Data) * new_length); - - if (temp == NULL) - return ~0; - - if (*buffer == NULL) { - *buffer = temp; - return new_length; - } - - uint32_t i; - - for (i = min_packetnum; i != max_packetnum; ++i) - memcpy(temp + (i % new_length), *buffer + (i % length), sizeof(Data)); - - free(*buffer); - *buffer = temp; - return new_length; -} - - - -/* - * Generate a handshake_id which depends on the ip_port. - * This function will always give one unique handshake_id per ip_port. - * - * TODO: make this better - */ - -static uint32_t randtable_initget(Lossless_UDP *ludp, uint32_t index, uint8_t value) -{ - if (ludp->randtable[index][value] == 0) - ludp->randtable[index][value] = random_int(); - - return ludp->randtable[index][value]; -} - -static uint32_t handshake_id(Lossless_UDP *ludp, IP_Port source) -{ - uint32_t id = 0, i = 0; - - uint8_t *uint8; - uint8 = (uint8_t *)&source.port; - id ^= randtable_initget(ludp, i, *uint8); - i++, uint8++; - id ^= randtable_initget(ludp, i, *uint8); - i++; - - if (source.ip.family == AF_INET) { - int k; - - for (k = 0; k < 4; k++) { - id ^= randtable_initget(ludp, i++, source.ip.ip4.uint8[k]); - } - } - - if (source.ip.family == AF_INET6) { - int k; - - for (k = 0; k < 16; k++) { - id ^= randtable_initget(ludp, i++, source.ip.ip6.uint8[k]); - } - } - - /* id can't be zero. */ - if (id == 0) - id = 1; - - return id; -} - -/* - * Change the handshake id associated with that ip_port. - * - * TODO: Make this better - */ -static void change_handshake(Lossless_UDP *ludp, IP_Port source) -{ - uint8_t rand; - - if (source.ip.family == AF_INET) { - rand = random_int() % 4; - } else if (source.ip.family == AF_INET6) { - rand = random_int() % 16; - } else { - return; - } - - /* Forced to be more robust against strange definitions of sa_family_t */ - ludp->randtable[2 + rand][((uint8_t *)&source.ip.ip6)[rand]] = random_int(); -} - -/* - * Initialize a new connection to ip_port - * - * return an integer corresponding to the connection id. - * return -1 if it could not initialize the connectiont - * If there already was an existing connection to that ip_port return its number. - */ -int new_connection(Lossless_UDP *ludp, IP_Port ip_port) -{ - int connection_id = getconnection_id(ludp, ip_port); - - if (connection_id != -1) { - confirm_connection(ludp, connection_id); - return connection_id; - } - - tox_array_for_each(&ludp->connections, Connection, tmp) { - if (tmp->status == LUDP_NO_CONNECTION) { - connection_id = tmp_i; - break; - } - } - - if (connection_id == -1) { - if (tox_array_push_ptr(&ludp->connections, 0) == 0) - return -1; - - connection_id = ludp->connections.len - 1; - } - - Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); - - memset(connection, 0, sizeof(Connection)); - - uint32_t handshake_id1 = handshake_id(ludp, ip_port); - /* Add randomness to timeout to prevent connections getting stuck in a loop. */ - uint8_t timeout = CONNECTION_TIMEOUT + rand() % CONNECTION_TIMEOUT; - - *connection = (Connection) { - .ip_port = ip_port, - .status = LUDP_HANDSHAKE_SENDING, - .inbound = LUDP_CONNECTION_OUTBOUND, - .handshake_id1 = handshake_id1, - .sent_packetnum = handshake_id1, - .sendbuff_packetnum = handshake_id1, - .successful_sent = handshake_id1, - .SYNC_rate = SYNC_RATE, - .data_rate = DATA_SYNC_RATE, - .last_recvSYNC = current_time(), - .last_sent = current_time(), - .killat = ~0, - .send_counter = 0, - .timeout = timeout, - .confirmed = 1 - }; - connection->sendbuffer_length = resize_queue(&connection->sendbuffer, 0, DEFAULT_QUEUE_NUM, 0, 0); - connection->recvbuffer_length = resize_queue(&connection->recvbuffer, 0, DEFAULT_QUEUE_NUM, 0, 0); - - if (connection->sendbuffer_length == (uint32_t)~0 || connection->recvbuffer_length == (uint32_t)~0) { - free(connection->sendbuffer); - free(connection->recvbuffer); - memset(connection, 0, sizeof(Connection)); - return -1; - } - - return connection_id; -} - -/* - * Initialize a new inbound connection from ip_port. - * - * return an integer corresponding to the connection id. - * return -1 if it could not initialize the connection. - */ -static int new_inconnection(Lossless_UDP *ludp, IP_Port ip_port) -{ - if (getconnection_id(ludp, ip_port) != -1) - return -1; /* TODO: return existing connection instead? */ - - int connection_id = -1; - tox_array_for_each(&ludp->connections, Connection, tmp) { - if (tmp->status == LUDP_NO_CONNECTION) { - connection_id = tmp_i; - break; - } - } - - if (connection_id == -1) { - if (tox_array_push_ptr(&ludp->connections, 0) == 0) - return -1; - - connection_id = ludp->connections.len - 1; - } - - Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); - memset(connection, 0, sizeof(Connection)); - /* Add randomness to timeout to prevent connections getting stuck in a loop. */ - uint8_t timeout = CONNECTION_TIMEOUT + rand() % CONNECTION_TIMEOUT; - - *connection = (Connection) { - .ip_port = ip_port, - .status = LUDP_NOT_CONFIRMED, - .inbound = LUDP_CONNECTION_INBOUND, - .SYNC_rate = SYNC_RATE, - .data_rate = DATA_SYNC_RATE, - .last_recvSYNC = current_time(), - .last_sent = current_time(), - .send_counter = 127, - - .timeout = timeout, - - /* If this connection isn't handled within the timeout kill it. */ - .killat = current_time() + 1000000ULL * timeout, - .confirmed = 0 - }; - connection->sendbuffer_length = resize_queue(&connection->sendbuffer, 0, DEFAULT_QUEUE_NUM, 0, 0); - connection->recvbuffer_length = resize_queue(&connection->recvbuffer, 0, DEFAULT_QUEUE_NUM, 0, 0); - - if (connection->sendbuffer_length == (uint32_t)~0 || connection->recvbuffer_length == (uint32_t)~0) { - free(connection->sendbuffer); - free(connection->recvbuffer); - memset(connection, 0, sizeof(Connection)); - return -1; - } - - return connection_id; -} - -/* - * return an integer corresponding to the next connection in our incoming connection list with at least numpackets in the recieve queue. - * return -1 if there are no new incoming connections in the list. - */ -int incoming_connection(Lossless_UDP *ludp, uint32_t numpackets) -{ - tox_array_for_each(&ludp->connections, Connection, tmp) { - if (tmp->inbound == LUDP_CONNECTION_INBOUND && tmp->recv_packetnum - tmp->successful_read >= numpackets) { - tmp->inbound = LUDP_CONNECTION_INBOUND_HANDLED; - return tmp_i; - } - } - return -1; -} -/* Try to free some memory from the connections array. */ -static void free_connections(Lossless_UDP *ludp) -{ - uint32_t i; - - for (i = ludp->connections.len; i != 0; --i) { - Connection *connection = &tox_array_get(&ludp->connections, i - 1, Connection); - - if (connection->status != LUDP_NO_CONNECTION) - break; - } - - if (ludp->connections.len == i) - return; - - return tox_array_pop(&ludp->connections, ludp->connections.len - i); -} -/* return -1 if it could not kill the connection. - * return 0 if killed successfully. - */ -int kill_connection(Lossless_UDP *ludp, int connection_id) -{ - if ((unsigned int)connection_id < ludp->connections.len) { - Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); - - if (connection->status != LUDP_NO_CONNECTION) { - connection->status = LUDP_NO_CONNECTION; - change_handshake(ludp, connection->ip_port); - free(connection->sendbuffer); - free(connection->recvbuffer); - memset(connection, 0, sizeof(Connection)); - free_connections(ludp); - return 0; - } - } - - return -1; -} - -/* - * timeout connection in seconds. - * - * return -1 if it can not kill the connection. - * return 0 if it will kill it. - */ -int timeout_connection_in(Lossless_UDP *ludp, int connection_id, uint32_t seconds) -{ - if ((unsigned int)connection_id < ludp->connections.len) { - Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); - - if (connection->status != LUDP_NO_CONNECTION) { - connection->killat = current_time() + 1000000ULL * seconds; - return 0; - } - } - - return -1; -} - -/* - * Check if connection is connected: - * - * return LUDP_NO_CONNECTION if not. - * return LUDP_HANDSHAKE_SENDING if attempting handshake. - * return LUDP_NOT_CONFIRMED if handshake is done. - * return LUDP_ESTABLISHED if fully connected. - * return LUDP_TIMED_OUT if timed out and waiting to be killed. - */ -int is_connected(Lossless_UDP *ludp, int connection_id) -{ - if ((unsigned int)connection_id < ludp->connections.len) - return tox_array_get(&ludp->connections, connection_id, Connection).status; - - return 0; -} - -/* Check if connection is confirmed. - * - * returns 1 if yes. - * returns 0 if no/failure. - */ -int connection_confirmed(Lossless_UDP *ludp, int connection_id) -{ - if ((unsigned int)connection_id >= ludp->connections.len) - return 0; - - Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); - - if (connection->status == LUDP_NO_CONNECTION) - return 0; - - if (connection->confirmed == 1) - return 1; - - return 0; -} - -/* Confirm an incoming connection. - * Also disable the auto kill timeout on incomming connections. - * - * return 0 on success - * return -1 on failure. - */ -int confirm_connection(Lossless_UDP *ludp, int connection_id) -{ - if ((unsigned int)connection_id >= ludp->connections.len) - return -1; - - Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); - - if (connection->status == LUDP_NO_CONNECTION) - return -1; - - connection->killat = ~0; - connection->confirmed = 1; - connection->inbound = LUDP_CONNECTION_OUTBOUND; - return 0; -} - -/* return the ip_port of the corresponding connection. */ -IP_Port connection_ip(Lossless_UDP *ludp, int connection_id) -{ - if ((unsigned int)connection_id < ludp->connections.len) - return tox_array_get(&ludp->connections, connection_id, Connection).ip_port; - - IP_Port zero; - ip_reset(&zero.ip); - zero.port = 0; - return zero; -} - -/* return the number of packets in the queue waiting to be successfully sent. */ -uint32_t sendqueue(Lossless_UDP *ludp, int connection_id) -{ - if ((unsigned int)connection_id >= ludp->connections.len) - return 0; - - Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); - - if (connection->status == LUDP_NO_CONNECTION) - return 0; - - return connection->sendbuff_packetnum - connection->successful_sent; -} - -/* return number of packets in all queues waiting to be successfully sent. */ -uint32_t sendqueue_total(Lossless_UDP *ludp) -{ - uint32_t i, total = 0; - - for (i = 0; i < ludp->connections.len; i++) { - Connection *connection = &tox_array_get(&ludp->connections, i, Connection); - - if (connection->status != 0) - total += connection->sendbuff_packetnum - connection->successful_sent; - } - - return total; -} - -/* return the number of packets in the queue waiting to be successfully read with read_packet(...). */ -uint32_t recvqueue(Lossless_UDP *ludp, int connection_id) -{ - if ((unsigned int)connection_id >= ludp->connections.len) - return 0; - - Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); - - if (connection->status == LUDP_NO_CONNECTION) - return 0; - - return connection->recv_packetnum - connection->successful_read; -} - -/* return the id of the next packet in the queue. - * return ~0 if no packet in queue. - */ -uint8_t id_packet(Lossless_UDP *ludp, int connection_id) -{ - if (recvqueue(ludp, connection_id) == 0) - return ~0; - - Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); - - if (connection->status != LUDP_NO_CONNECTION) - return connection->recvbuffer[connection->successful_read % connection->recvbuffer_length].data[0]; - - return ~0; -} - -/* return 0 if there is no received data in the buffer. - * return length of received packet if successful. - */ -int read_packet(Lossless_UDP *ludp, int connection_id, uint8_t *data) -{ - if (recvqueue(ludp, connection_id) == 0) - return 0; - - Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); - - if (connection->status == LUDP_NO_CONNECTION) - return 0; - - uint16_t index = connection->successful_read % connection->recvbuffer_length; - uint16_t size = connection->recvbuffer[index].size; - memcpy(data, connection->recvbuffer[index].data, size); - ++connection->successful_read; - connection->recvbuffer[index].size = 0; - return size; -} - -/* Like read_packet() but does leaves the queue as is. - * return 0 if there is no received data in the buffer. - * return length of received packet if successful. - */ -int read_packet_silent(Lossless_UDP *ludp, int connection_id, uint8_t *data) -{ - if (recvqueue(ludp, connection_id) == 0) - return 0; - - Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); - - if (connection->status == LUDP_NO_CONNECTION) - return 0; - - uint16_t index = connection->successful_read % connection->recvbuffer_length; - uint16_t size = connection->recvbuffer[index].size; - memcpy(data, connection->recvbuffer[index].data, size); - return size; -} -/* Discard the next packet to be read from the queue - * return 0 if success. - * return -1 if failure. - */ -int discard_packet(Lossless_UDP *ludp, int connection_id) -{ - if (recvqueue(ludp, connection_id) == 0) - return -1; - - Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); - uint16_t index = connection->successful_read % connection->recvbuffer_length; - ++connection->successful_read; - connection->recvbuffer[index].size = 0; - return 0; -} - -#define MAX_SYNC_RATE 20 -#define MIN_SLOTS 16 -/* returns the number of packet slots left in the sendbuffer. - * return 0 if failure. - */ -uint32_t num_free_sendqueue_slots(Lossless_UDP *ludp, int connection_id) -{ - if ((unsigned int)connection_id >= ludp->connections.len) - return 0; - - Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); - uint32_t max_slots = (connection->data_rate / MAX_SYNC_RATE) * 1.5; - - if (max_slots > MAX_QUEUE_NUM) - max_slots = MAX_QUEUE_NUM; - - if (max_slots < MIN_SLOTS) - max_slots = MIN_SLOTS; - - if (sendqueue(ludp, connection_id) > max_slots) - return 0; - - return max_slots - sendqueue(ludp, connection_id); -} - - -/* return 0 if data could not be put in packet queue. - * return 1 if data was put into the queue. - */ -int write_packet(Lossless_UDP *ludp, int connection_id, uint8_t *data, uint32_t length) -{ - if ((unsigned int)connection_id >= ludp->connections.len) - return 0; - - Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); - - if (connection->status == LUDP_NO_CONNECTION) - return 0; - - if (length > MAX_DATA_SIZE || length == 0 || sendqueue(ludp, connection_id) >= MAX_QUEUE_NUM) - return 0; - - if (num_free_sendqueue_slots(ludp, connection_id) == 0) - return 0; - - if (sendqueue(ludp, connection_id) >= connection->sendbuffer_length && connection->sendbuffer_length != 0) { - uint32_t newlen = connection->sendbuffer_length = resize_queue(&connection->sendbuffer, connection->sendbuffer_length, - connection->sendbuffer_length * 2, connection->successful_sent, connection->sendbuff_packetnum); - - if (newlen == (uint32_t)~0) - return 0; - - connection->sendbuffer_length = newlen; - return write_packet(ludp, connection_id, data, length); - } - - uint32_t index = connection->sendbuff_packetnum % connection->sendbuffer_length; - memcpy(connection->sendbuffer[index].data, data, length); - connection->sendbuffer[index].size = length; - connection->sendbuff_packetnum++; - return 1; -} - -/* Put the packet numbers the we are missing in requested and return the number. */ -static uint32_t missing_packets(Lossless_UDP *ludp, int connection_id, uint32_t *requested) -{ - if ((unsigned int)connection_id >= ludp->connections.len) - return 0; - - Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); - - /* Don't request packets if the buffer is full. */ - if (recvqueue(ludp, connection_id) >= (connection->recvbuffer_length - 1)) - return 0; - - uint32_t number = 0; - uint32_t i; - uint32_t temp; - - for (i = connection->recv_packetnum; - i != connection->osent_packetnum; - i++) { - if (connection->recvbuffer[i % connection->recvbuffer_length].size == 0) { - temp = htonl(i); - memcpy(requested + number, &temp, 4); - ++number; - } - - if (number >= MAX_REQUESTED_PACKETS) - return number; - } - - if (number == 0) - connection->recv_packetnum = connection->osent_packetnum; - - return number; -} - -/* - * BEGIN Packet sending functions. - * One per packet type. - * See http://wiki.tox.im/index.php/Lossless_UDP for more information. - */ - -static int send_handshake(Lossless_UDP *ludp, IP_Port ip_port, uint32_t handshake_id1, uint32_t handshake_id2) -{ - uint8_t packet[1 + 4 + 4]; - uint32_t temp; - - packet[0] = NET_PACKET_HANDSHAKE; - temp = htonl(handshake_id1); - memcpy(packet + 1, &temp, 4); - temp = htonl(handshake_id2); - memcpy(packet + 5, &temp, 4); - - return sendpacket(ludp->net, ip_port, packet, sizeof(packet)); -} - -static int send_SYNC(Lossless_UDP *ludp, int connection_id) -{ - Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); - uint8_t packet[(MAX_REQUESTED_PACKETS * 4 + 4 + 4 + 2)]; - uint16_t index = 0; - - IP_Port ip_port = connection->ip_port; - uint8_t counter = connection->send_counter; - uint32_t recv_packetnum = htonl(connection->recv_packetnum); - uint32_t sent_packetnum = htonl(connection->sent_packetnum); - - uint32_t requested[MAX_REQUESTED_PACKETS]; - uint32_t number = missing_packets(ludp, connection_id, requested); - - packet[0] = NET_PACKET_SYNC; - index += 1; - memcpy(packet + index, &counter, 1); - index += 1; - memcpy(packet + index, &recv_packetnum, 4); - index += 4; - memcpy(packet + index, &sent_packetnum, 4); - index += 4; - memcpy(packet + index, requested, 4 * number); - - return sendpacket(ludp->net, ip_port, packet, (number * 4 + 4 + 4 + 2)); - -} - -static int send_data_packet(Lossless_UDP *ludp, int connection_id, uint32_t packet_num) -{ - Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); - - uint32_t index = packet_num % connection->sendbuffer_length; - uint32_t temp; - uint8_t packet[1 + 4 + MAX_DATA_SIZE]; - packet[0] = NET_PACKET_DATA; - temp = htonl(packet_num); - memcpy(packet + 1, &temp, 4); - memcpy(packet + 5, connection->sendbuffer[index].data, connection->sendbuffer[index].size); - return sendpacket(ludp->net, connection->ip_port, packet, 1 + 4 + connection->sendbuffer[index].size); -} - -/* Sends 1 data packet. */ -static int send_DATA(Lossless_UDP *ludp, int connection_id) -{ - Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); - int ret; - uint32_t buffer[MAX_REQUESTED_PACKETS]; - - if (connection->num_req_paquets > 0) { - ret = send_data_packet(ludp, connection_id, connection->req_packets[0]); - connection->num_req_paquets--; - memcpy(buffer, connection->req_packets + 1, connection->num_req_paquets * 4); - memcpy(connection->req_packets, buffer, connection->num_req_paquets * 4); - return ret; - } - - if (connection->sendbuff_packetnum != connection->sent_packetnum) { - ret = send_data_packet(ludp, connection_id, connection->sent_packetnum); - connection->sent_packetnum++; - return ret; - } - - return 0; -} - -/* - * END of packet sending functions. - * - * - * BEGIN Packet handling functions. - * One to handle each type of packets we receive. - */ - - -/* return 0 if handled correctly. - * return 1 if packet is bad. - */ -static int handle_handshake(void *object, IP_Port source, uint8_t *packet, uint32_t length) -{ - Lossless_UDP *ludp = object; - - if (length != (1 + 4 + 4)) - return 1; - - uint32_t temp; - uint32_t handshake_id1, handshake_id2; - int connection_id = getconnection_id(ludp, source); - - memcpy(&temp, packet + 1, 4); - handshake_id1 = ntohl(temp); - memcpy(&temp, packet + 5, 4); - handshake_id2 = ntohl(temp); - - - if (handshake_id2 == 0 && is_connected(ludp, connection_id) != LUDP_ESTABLISHED && - is_connected(ludp, connection_id) != LUDP_TIMED_OUT) { - send_handshake(ludp, source, handshake_id(ludp, source), handshake_id1); - return 0; - } - - if (is_connected(ludp, connection_id) != LUDP_HANDSHAKE_SENDING) - return 1; - - Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); - - /* if handshake_id2 is what we sent previously as handshake_id1 */ - if (handshake_id2 == connection->handshake_id1) { - connection->status = LUDP_NOT_CONFIRMED; - /* NOTE: Is this necessary? - connection->handshake_id2 = handshake_id1; */ - connection->orecv_packetnum = handshake_id2; - connection->osent_packetnum = handshake_id1; - connection->recv_packetnum = handshake_id1; - connection->successful_read = handshake_id1; - } - - return 0; -} - -/* return 1 if sync packet is valid. - * return 0 if not. - */ -static int SYNC_valid(uint32_t length) -{ - if (length < 4 + 4 + 2) - return 0; - - if (length > (MAX_REQUESTED_PACKETS * 4 + 4 + 4 + 2) || - ((length - 4 - 4 - 2) % 4) != 0) - return 0; - - return 1; -} - -/* case 1 in handle_SYNC: */ -static int handle_SYNC1(Lossless_UDP *ludp, IP_Port source, uint32_t recv_packetnum, uint32_t sent_packetnum) -{ - if (handshake_id(ludp, source) == recv_packetnum) { - int connection_id = new_inconnection(ludp, source); - - if (connection_id != -1) { - Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); - connection->orecv_packetnum = recv_packetnum; - connection->sent_packetnum = recv_packetnum; - connection->sendbuff_packetnum = recv_packetnum; - connection->successful_sent = recv_packetnum; - connection->osent_packetnum = sent_packetnum; - connection->recv_packetnum = sent_packetnum; - connection->successful_read = sent_packetnum; - - return connection_id; - } - } - - return -1; -} - -/* case 2 in handle_SYNC: */ -static int handle_SYNC2(Lossless_UDP *ludp, int connection_id, uint8_t counter, uint32_t recv_packetnum, - uint32_t sent_packetnum) -{ - Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); - - if (recv_packetnum == connection->orecv_packetnum && sent_packetnum == connection->osent_packetnum) { - connection->status = LUDP_ESTABLISHED; - connection->recv_counter = counter; - ++connection->send_counter; - send_SYNC(ludp, connection_id); - return 0; - } - - return 1; -} - -/* - * Automatically adjusts send rates of data packets for optimal transmission. - * - * TODO: Improve this. - */ -static void adjust_datasendspeed(Connection *connection, uint32_t req_packets) -{ - /* if there are no packets in send buffer */ - if (connection->sendbuff_packetnum - connection->successful_sent == 0) { - connection->data_rate -= connection->data_rate / 8; - - if (connection->data_rate < DATA_SYNC_RATE) - connection->data_rate = DATA_SYNC_RATE; - - return; - } - - if (req_packets <= (connection->data_rate / connection->SYNC_rate) / 4 || req_packets <= 10) { - connection->data_rate += (connection->data_rate / 4) + 1; - - if (connection->data_rate > connection->sendbuffer_length * connection->SYNC_rate) - connection->data_rate = connection->sendbuffer_length * connection->SYNC_rate; - } else { - connection->data_rate -= connection->data_rate / 8; - } -} - - -/* case 3 in handle_SYNC: */ -static int handle_SYNC3(Lossless_UDP *ludp, int connection_id, uint8_t counter, uint32_t recv_packetnum, - uint32_t sent_packetnum, - uint32_t *req_packets, - uint16_t number) -{ - Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); - - uint8_t comp_counter = (counter - connection->recv_counter); - uint32_t i, temp; - /* uint32_t comp_1 = (recv_packetnum - connection->successful_sent); - uint32_t comp_2 = (sent_packetnum - connection->successful_read); */ - uint32_t comp_1 = (recv_packetnum - connection->orecv_packetnum); - uint32_t comp_2 = (sent_packetnum - connection->osent_packetnum); - - /* Packet valid. */ - if (comp_1 <= connection->sendbuffer_length && - comp_2 <= MAX_QUEUE_NUM && - comp_counter != 0 && comp_counter < 8) { - connection->orecv_packetnum = recv_packetnum; - connection->osent_packetnum = sent_packetnum; - connection->successful_sent = recv_packetnum; - connection->last_recvSYNC = current_time(); - - connection->recv_counter = counter; - - ++connection->send_counter; - - for (i = 0; i < number; ++i) { - temp = ntohl(req_packets[i]); - memcpy(connection->req_packets + i, &temp, sizeof(uint32_t)); - } - - connection->num_req_paquets = number; - adjust_datasendspeed(connection, number); - return 0; - } - - return 1; -} - -static int handle_SYNC(void *object, IP_Port source, uint8_t *packet, uint32_t length) -{ - Lossless_UDP *ludp = object; - - if (!SYNC_valid(length)) - return 1; - - uint8_t counter; - uint32_t temp; - uint32_t recv_packetnum, sent_packetnum; - uint16_t number = (length - 4 - 4 - 2) / 4; - uint32_t req_packets[number]; - - memcpy(&counter, packet + 1, 1); - memcpy(&temp, packet + 2, 4); - recv_packetnum = ntohl(temp); - memcpy(&temp, packet + 6, 4); - sent_packetnum = ntohl(temp); - - if (number != 0) - memcpy(req_packets, packet + 10, 4 * number); - - int connection_id = getconnection_id(ludp, source); - - if (connection_id == -1) - return handle_SYNC1(ludp, source, recv_packetnum, sent_packetnum); - - Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); - - if (connection->status == LUDP_NOT_CONFIRMED) - return handle_SYNC2(ludp, connection_id, counter, - recv_packetnum, sent_packetnum); - - if (connection->status == LUDP_ESTABLISHED) - return handle_SYNC3(ludp, connection_id, counter, recv_packetnum, - sent_packetnum, req_packets, number); - - return 0; -} - -/* - * Add a packet to the received buffer and set the recv_packetnum of the - * connection to its proper value. - * - * return 1 if data was too big. - * return 0 if not. - */ -static int add_recv(Lossless_UDP *ludp, int connection_id, uint32_t data_num, uint8_t *data, uint16_t size) -{ - if (size > MAX_DATA_SIZE) - return 1; - - Connection *connection = &tox_array_get(&ludp->connections, connection_id, Connection); - uint32_t i; - uint32_t test = data_num - connection->recv_packetnum; - - if (test > MAX_QUEUE_NUM) - return 0; - - if (test > connection->recvbuffer_length) { - if (connection->confirmed == 0) - return 0; - - uint32_t len = resize_queue(&connection->recvbuffer, connection->recvbuffer_length, test * 2, - connection->successful_read, connection->successful_read + connection->recvbuffer_length); - - if (len == (uint32_t)~0) - return 0; - - connection->recvbuffer_length = len; - } - - uint32_t maxnum = connection->successful_read + connection->recvbuffer_length; - uint32_t sent_packet = data_num - connection->osent_packetnum; - - for (i = connection->recv_packetnum; i != maxnum; ++i) { - if (i == data_num) { - memcpy(connection->recvbuffer[data_num % connection->recvbuffer_length].data, data, size); - - connection->recvbuffer[data_num % connection->recvbuffer_length].size = size; - connection->last_recvdata = current_time(); - - if (sent_packet < connection->recvbuffer_length) - connection->osent_packetnum = data_num; - - break; - } - } - - for (i = connection->recv_packetnum; i != maxnum; ++i) { - if (connection->recvbuffer[i % connection->recvbuffer_length].size != 0) - connection->recv_packetnum = i; - else - break; - } - - return 0; -} - -static int handle_data(void *object, IP_Port source, uint8_t *packet, uint32_t length) -{ - Lossless_UDP *ludp = object; - int connection_id = getconnection_id(ludp, source); - - /* Drop the data packet if connection is not connected. */ - if (connection_id == -1) - return 1; - - if (tox_array_get(&ludp->connections, connection_id, Connection).status != LUDP_ESTABLISHED) - return 1; - - if (length > 1 + 4 + MAX_DATA_SIZE || length < 1 + 4 + 1) - return 1; - - uint32_t temp; - uint32_t number; - uint16_t size = length - 1 - 4; - - memcpy(&temp, packet + 1, 4); - number = ntohl(temp); - - return add_recv(ludp, connection_id, number, packet + 5, size); -} - -/* - * END of packet handling functions. - */ - -Lossless_UDP *new_lossless_udp(Networking_Core *net) -{ - if (net == NULL) - return NULL; - - Lossless_UDP *temp = calloc(1, sizeof(Lossless_UDP)); - - if (temp == NULL) - return NULL; - - tox_array_init(&temp->connections, sizeof(Connection)); - - temp->net = net; - networking_registerhandler(net, NET_PACKET_HANDSHAKE, &handle_handshake, temp); - networking_registerhandler(net, NET_PACKET_SYNC, &handle_SYNC, temp); - networking_registerhandler(net, NET_PACKET_DATA, &handle_data, temp); - return temp; -} - -/* - * Send handshake requests. - * Handshake packets are sent at the same rate as SYNC packets. - */ -static void do_new(Lossless_UDP *ludp) -{ - uint64_t temp_time = current_time(); - - tox_array_for_each(&ludp->connections, Connection, tmp) { - if (tmp->status == LUDP_HANDSHAKE_SENDING && (tmp->last_sent + (1000000ULL / tmp->SYNC_rate)) <= temp_time) { - send_handshake(ludp, tmp->ip_port, tmp->handshake_id1, 0); - tmp->last_sent = temp_time; - } - - /* kill all timed out connections */ - if (tmp->status != LUDP_NO_CONNECTION && (tmp->last_recvSYNC + tmp->timeout * 1000000ULL) < temp_time - && tmp->status != LUDP_TIMED_OUT) { - tmp->status = LUDP_TIMED_OUT; - /* kill_connection(i); */ - } - - if (tmp->status != LUDP_NO_CONNECTION && tmp->killat < temp_time) - tmp->status = LUDP_TIMED_OUT; - - if (tmp->inbound == LUDP_CONNECTION_INBOUND && tmp->status == LUDP_TIMED_OUT) - kill_connection(ludp, tmp_i); - } -} - -static void do_SYNC(Lossless_UDP *ludp) -{ - uint64_t temp_time = current_time(); - - tox_array_for_each(&ludp->connections, Connection, tmp) { - if (tmp->status == LUDP_NOT_CONFIRMED || tmp->status == LUDP_ESTABLISHED) - if ((tmp->last_SYNC + (1000000ULL / tmp->SYNC_rate)) <= temp_time) { - send_SYNC(ludp, tmp_i); - tmp->last_SYNC = temp_time; - } - } -} - -static void do_data(Lossless_UDP *ludp) -{ - uint64_t j; - uint64_t temp_time = current_time(); - - tox_array_for_each(&ludp->connections, Connection, tmp) { - if (tmp->status == LUDP_ESTABLISHED && sendqueue(ludp, tmp_i) != 0 && - (tmp->last_sent + (1000000ULL / tmp->data_rate)) <= temp_time) { - for (j = tmp->last_sent; j < temp_time; j += (1000000ULL / tmp->data_rate)) - if (send_DATA(ludp, tmp_i) <= 0) - break; - - tmp->last_sent = temp_time; - - } - } -} - - - -/* - * Automatically adjusts send rates of packets for optimal transmission. - * - * TODO: Flow control. - */ -static void adjust_rates(Lossless_UDP *ludp) -{ - uint64_t temp_time = current_time(); - - tox_array_for_each(&ludp->connections, Connection, tmp) { - if (tmp->status == LUDP_HANDSHAKE_SENDING || tmp->status == LUDP_NOT_CONFIRMED) - tmp->SYNC_rate = MAX_SYNC_RATE; - - if (tmp->status == LUDP_ESTABLISHED) { - if (sendqueue(ludp, tmp_i) != 0) { - tmp->SYNC_rate = MAX_SYNC_RATE; - } else if (tmp->last_recvdata + 200000ULL > temp_time) { /* 200 ms */ - tmp->SYNC_rate = MAX_SYNC_RATE; - } else { - tmp->SYNC_rate = SYNC_RATE; - } - } - } -} - -/* Call this function a couple times per second. It is the main loop. */ -void do_lossless_udp(Lossless_UDP *ludp) -{ - do_new(ludp); - do_SYNC(ludp); - do_data(ludp); - adjust_rates(ludp); -} - -void kill_lossless_udp(Lossless_UDP *ludp) -{ - uint32_t i; - - for (i = 0; i < ludp->connections.len; ++i) - kill_connection(ludp, i); - - tox_array_delete(&ludp->connections); - free(ludp); -} diff --git a/toxcore/Lossless_UDP.h b/toxcore/Lossless_UDP.h deleted file mode 100644 index b23d602a..00000000 --- a/toxcore/Lossless_UDP.h +++ /dev/null @@ -1,261 +0,0 @@ -/* Lossless_UDP.h - * - * An implementation of the Lossless_UDP protocol as seen in http://wiki.tox.im/index.php/Lossless_UDP - * - * Copyright (C) 2013 Tox project All Rights Reserved. - * - * This file is part of Tox. - * - * Tox is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tox is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tox. If not, see . - * - */ - -#ifndef LOSSLESS_UDP_H -#define LOSSLESS_UDP_H - -#include "network.h" -#include "misc_tools.h" - - -/* Maximum length of the data in the data packets. */ -#define MAX_DATA_SIZE 1024 - -/* Maximum data packets in sent and receive queues. */ -#define MAX_QUEUE_NUM 1024 -#define DEFAULT_QUEUE_NUM 4 - -/* Maximum number of data packets in the buffer. */ -#define MAX_REQUESTED_PACKETS 256 - -/* Timeout per connection is randomly set between CONNECTION_TIMEOUT and 2*CONNECTION_TIMEOUT. */ -#define CONNECTION_TIMEOUT 5 - -/* Initial amount of sync/handshake packets to send per second. */ -#define SYNC_RATE 2 - -/* Initial send rate of data. */ -#define DATA_SYNC_RATE 30 - -typedef struct { - uint8_t data[MAX_DATA_SIZE]; - uint16_t size; -} Data; - -#define LUDP_NO_CONNECTION 0 -#define LUDP_HANDSHAKE_SENDING 1 -#define LUDP_NOT_CONFIRMED 2 -#define LUDP_ESTABLISHED 3 -#define LUDP_TIMED_OUT 4 - -typedef struct { - IP_Port ip_port; - - /* - * return LUDP_NO_CONNECTION if connection is dead. - * return LUDP_HANDSHAKE_SENDING if attempting handshake. - * return LUDP_NOT_CONFIRMED if handshake is done (we start sending SYNC packets). - * return LUDP_ESTABLISHED if we are sending SYNC packets and can send data. - * return LUDP_TIMED_OUT if the connection has timed out. - */ - uint8_t status; - - /* - * return 0 if connection was not initiated by someone else. - * return 1 if incoming_connection() has returned. - * return 2 if it has not. - */ - uint8_t inbound; - - uint16_t SYNC_rate; /* Current SYNC packet send rate packets per second. */ - uint32_t data_rate; /* Current data packet send rate packets per second. */ - - uint64_t last_SYNC; /* Time our last SYNC packet was sent. */ - uint64_t last_sent; /* Time our last data or handshake packet was sent. */ - uint64_t last_recvSYNC; /* Time we last received a SYNC packet from the other. */ - uint64_t last_recvdata; /* Time we last received a DATA packet from the other. */ - uint64_t killat; /* Time to kill the connection. */ - - Data *sendbuffer; /* packet send buffer. */ - uint32_t sendbuffer_length; - Data *recvbuffer; /* packet receive buffer. */ - uint32_t recvbuffer_length; - uint32_t handshake_id1; - uint32_t handshake_id2; - - /* Number of data packets received (also used as handshake_id1). */ - uint32_t recv_packetnum; - - /* Number of packets received by the other peer. */ - uint32_t orecv_packetnum; - - /* Number of data packets sent. */ - uint32_t sent_packetnum; - - /* Number of packets sent by the other peer. */ - uint32_t osent_packetnum; - - /* Number of latest packet written onto the sendbuffer. */ - uint32_t sendbuff_packetnum; - - /* We know all packets before that number were successfully sent. */ - uint32_t successful_sent; - - /* Packet number of last packet read with the read_packet function. */ - uint32_t successful_read; - - /* List of currently requested packet numbers(by the other person). */ - uint32_t req_packets[MAX_REQUESTED_PACKETS]; - - /* Total number of currently requested packets(by the other person). */ - uint16_t num_req_paquets; - - uint8_t recv_counter; - uint8_t send_counter; - uint8_t timeout; /* connection timeout in seconds. */ - - /* Is the connection confirmed or not? 1 if yes, 0 if no */ - uint8_t confirmed; -} Connection; - -typedef struct { - Networking_Core *net; - - tox_array connections; - - /* Table of random numbers used in handshake_id. */ - /* IPv6 (16) + port (2)*/ - uint32_t randtable[18][256]; -} Lossless_UDP; - -/* - * Initialize a new connection to ip_port. - * - * return an integer corresponding to the connection id. - * return -1 if it could not initialize the connection. - * return number if there already was an existing connection to that ip_port. - */ -int new_connection(Lossless_UDP *ludp, IP_Port ip_port); - -/* - * Get connection id from IP_Port. - * - * return -1 if there are no connections like we are looking for. - * return id if it found it . - */ -int getconnection_id(Lossless_UDP *ludp, IP_Port ip_port); - -/* - * return an integer corresponding to the next connection in our incoming connection list with at least numpackets in the recieve queue. - * return -1 if there are no new incoming connections in the list. - */ -int incoming_connection(Lossless_UDP *ludp, uint32_t numpackets); - -/* return -1 if it could not kill the connection. - * return 0 if killed successfully. - */ -int kill_connection(Lossless_UDP *ludp, int connection_id); - -/* - * timeout connection in seconds seconds. - * - * return -1 if it can not kill the connection. - * return 0 if it will kill it. - */ -int timeout_connection_in(Lossless_UDP *ludp, int connection_id, uint32_t seconds); - - -/* Check if connection is confirmed. - * - * returns 1 if yes. - * returns 0 if no. - */ -int connection_confirmed(Lossless_UDP *ludp, int connection_id); - -/* Confirm an incoming connection. - * Also disables the auto kill timeout on incomming connections. - * - * return 0 on success - * return -1 on failure. - */ -int confirm_connection(Lossless_UDP *ludp, int connection_id); - -/* returns the ip_port of the corresponding connection. - * return 0 if there is no such connection. - */ -IP_Port connection_ip(Lossless_UDP *ludp, int connection_id); - -/* returns the id of the next packet in the queue. - * return -1 if no packet in queue. - */ -uint8_t id_packet(Lossless_UDP *ludp, int connection_id); - -/* return 0 if there is no received data in the buffer. - * return length of received packet if successful. - */ -int read_packet(Lossless_UDP *ludp, int connection_id, uint8_t *data); - -/* Like read_packet() but does leaves the queue as is. - * return 0 if there is no received data in the buffer. - * return length of received packet if successful. - */ -int read_packet_silent(Lossless_UDP *ludp, int connection_id, uint8_t *data); - -/* Discard the next packet to be read from the queue - * return 0 if success. - * return -1 if failure. - */ -int discard_packet(Lossless_UDP *ludp, int connection_id); - -/* returns the number of packet slots left in the sendbuffer. - * return 0 if failure. - */ -uint32_t num_free_sendqueue_slots(Lossless_UDP *ludp, int connection_id); - -/* return 0 if data could not be put in packet queue. - * return 1 if data was put into the queue. - */ -int write_packet(Lossless_UDP *ludp, int connection_id, uint8_t *data, uint32_t length); - -/* return number of packets in the queue waiting to be successfully sent. */ -uint32_t sendqueue(Lossless_UDP *ludp, int connection_id); - -/* return number of packets in all queues waiting to be successfully sent. */ -uint32_t sendqueue_total(Lossless_UDP *ludp); - -/* - * return number of packets in the queue waiting to be successfully - * read with read_packet(...). - */ -uint32_t recvqueue(Lossless_UDP *ludp, int connection_id); - -/* Check if connection is connected: - * - * return LUDP_NO_CONNECTION if not. - * return LUDP_HANDSHAKE_SENDING if attempting handshake. - * return LUDP_NOT_CONFIRMED if handshake is done. - * return LUDP_ESTABLISHED if fully connected. - * return LUDP_TIMED_OUT if timed out and wating to be killed. - */ -int is_connected(Lossless_UDP *ludp, int connection_id); - -/* Call this function a couple times per second. It is the main loop. */ -void do_lossless_udp(Lossless_UDP *ludp); - -/* This function sets up LosslessUDP packet handling. */ -Lossless_UDP *new_lossless_udp(Networking_Core *net); - -void kill_lossless_udp(Lossless_UDP *ludp); - - -#endif diff --git a/toxcore/Makefile.inc b/toxcore/Makefile.inc index 5f9ab0d7..0760952a 100644 --- a/toxcore/Makefile.inc +++ b/toxcore/Makefile.inc @@ -9,8 +9,10 @@ libtoxcore_la_SOURCES = ../toxcore/DHT.h \ ../toxcore/DHT.c \ ../toxcore/network.h \ ../toxcore/network.c \ - ../toxcore/Lossless_UDP.h \ - ../toxcore/Lossless_UDP.c \ + ../toxcore/crypto_core.h \ + ../toxcore/crypto_core.c \ + ../toxcore/ping_array.h \ + ../toxcore/ping_array.c \ ../toxcore/net_crypto.h \ ../toxcore/net_crypto.c \ ../toxcore/friend_requests.h \ @@ -52,6 +54,7 @@ libtoxcore_la_LDFLAGS = $(TOXCORE_LT_LDFLAGS) \ $(EXTRA_LT_LDFLAGS) \ $(LIBSODIUM_LDFLAGS) \ $(NACL_LDFLAGS) \ + $(RT_LIBS) \ $(WINSOCK2_LIBS) libtoxcore_la_LIBADD = $(LIBSODIUM_LIBS) \ diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c index f5ed14b1..28c8845a 100644 --- a/toxcore/Messenger.c +++ b/toxcore/Messenger.c @@ -38,6 +38,8 @@ static void set_friend_status(Messenger *m, int32_t friendnumber, uint8_t status); static int write_cryptpacket_id(Messenger *m, int32_t friendnumber, uint8_t packet_id, uint8_t *data, uint32_t length); +static IP_Port get_friend_ipport(Messenger *m, int32_t friendnumber); + // friend_not_valid determines if the friendnumber passed is valid in the Messenger object static uint8_t friend_not_valid(Messenger *m, int32_t friendnumber) { @@ -194,6 +196,21 @@ void getaddress(Messenger *m, uint8_t *address) memcpy(address + crypto_box_PUBLICKEYBYTES + sizeof(nospam), &checksum, sizeof(checksum)); } +/* callback for recv TCP relay nodes. */ +static int tcp_relay_node_callback(void *object, uint32_t number, IP_Port ip_port, uint8_t *public_key) +{ + Messenger *m = object; + + if (friend_not_valid(m, number)) + return -1; + + if (m->friendlist[number].crypt_connection_id != -1) { + return add_tcp_relay_peer(m->net_crypto, m->friendlist[number].crypt_connection_id, ip_port, public_key); + } else { + return add_tcp_relay(m->net_crypto, ip_port, public_key); + } +} + /* * Add a friend. * Set the data that will be sent along with friend request. @@ -213,9 +230,7 @@ void getaddress(Messenger *m, uint8_t *address) */ int32_t m_addfriend(Messenger *m, uint8_t *address, uint8_t *data, uint16_t length) { - if (length >= (MAX_DATA_SIZE - crypto_box_PUBLICKEYBYTES - - crypto_box_NONCEBYTES - crypto_box_BOXZEROBYTES - + crypto_box_ZEROBYTES)) + if (length > MAX_FRIEND_REQUEST_DATA_SIZE) return FAERR_TOOLONG; uint8_t client_id[crypto_box_PUBLICKEYBYTES]; @@ -278,6 +293,7 @@ int32_t m_addfriend(Messenger *m, uint8_t *address, uint8_t *data, uint16_t leng m->friendlist[i].message_id = 0; m->friendlist[i].receives_read_receipts = 1; /* Default: YES. */ memcpy(&(m->friendlist[i].friendrequest_nospam), address + crypto_box_PUBLICKEYBYTES, sizeof(uint32_t)); + recv_tcp_relay_handler(m->onion_c, onion_friendnum, &tcp_relay_node_callback, m, i); if (m->numfriends == i) ++m->numfriends; @@ -323,6 +339,7 @@ int32_t m_addfriend_norequest(Messenger *m, uint8_t *client_id) m->friendlist[i].is_typing = 0; m->friendlist[i].message_id = 0; m->friendlist[i].receives_read_receipts = 1; /* Default: YES. */ + recv_tcp_relay_handler(m->onion_c, onion_friendnum, &tcp_relay_node_callback, m, i); if (m->numfriends == i) ++m->numfriends; @@ -407,10 +424,10 @@ uint32_t m_sendmessage(Messenger *m, int32_t friendnumber, uint8_t *message, uin uint32_t m_sendmessage_withid(Messenger *m, int32_t friendnumber, uint32_t theid, uint8_t *message, uint32_t length) { - if (length >= (MAX_DATA_SIZE - sizeof(theid))) + if (length >= (MAX_CRYPTO_DATA_SIZE - sizeof(theid))) return 0; - uint8_t temp[MAX_DATA_SIZE]; + uint8_t temp[MAX_CRYPTO_DATA_SIZE]; theid = htonl(theid); memcpy(temp, &theid, sizeof(theid)); memcpy(temp + sizeof(theid), message, length); @@ -441,10 +458,10 @@ uint32_t m_sendaction(Messenger *m, int32_t friendnumber, uint8_t *action, uint3 uint32_t m_sendaction_withid(Messenger *m, int32_t friendnumber, uint32_t theid, uint8_t *action, uint32_t length) { - if (length >= (MAX_DATA_SIZE - sizeof(theid))) + if (length >= (MAX_CRYPTO_DATA_SIZE - sizeof(theid))) return 0; - uint8_t temp[MAX_DATA_SIZE]; + uint8_t temp[MAX_CRYPTO_DATA_SIZE]; theid = htonl(theid); memcpy(temp, &theid, sizeof(theid)); memcpy(temp + sizeof(theid), action, length); @@ -690,7 +707,7 @@ static int send_user_istyping(Messenger *m, int32_t friendnumber, uint8_t is_typ static int send_ping(Messenger *m, int32_t friendnumber) { - int ret = write_cryptpacket_id(m, friendnumber, PACKET_ID_PING, 0, 0); + int ret = write_cryptpacket_id(m, friendnumber, PACKET_ID_ALIVE, 0, 0); if (ret == 1) m->friendlist[friendnumber].ping_lastsent = unix_time(); @@ -841,7 +858,7 @@ int write_cryptpacket_id(Messenger *m, int32_t friendnumber, uint8_t packet_id, if (friend_not_valid(m, friendnumber)) return 0; - if (length >= MAX_DATA_SIZE || m->friendlist[friendnumber].status != FRIEND_ONLINE) + if (length >= MAX_CRYPTO_DATA_SIZE || m->friendlist[friendnumber].status != FRIEND_ONLINE) return 0; uint8_t packet[length + 1]; @@ -850,7 +867,7 @@ int write_cryptpacket_id(Messenger *m, int32_t friendnumber, uint8_t packet_id, if (length != 0) memcpy(packet + 1, data, length); - return write_cryptpacket(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id, packet, length + 1); + return write_cryptpacket(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id, packet, length + 1) != -1; } /**********GROUP CHATS************/ @@ -876,7 +893,7 @@ static uint8_t groupnumber_not_valid(Messenger *m, int groupnumber) /* returns valid ip port of connected friend on success * returns zeroed out IP_Port on failure */ -IP_Port get_friend_ipport(Messenger *m, int32_t friendnumber) +static IP_Port get_friend_ipport(Messenger *m, int32_t friendnumber) { IP_Port zero; memset(&zero, 0, sizeof(zero)); @@ -886,10 +903,15 @@ IP_Port get_friend_ipport(Messenger *m, int32_t friendnumber) int crypt_id = m->friendlist[friendnumber].crypt_connection_id; - if (is_cryptoconnected(m->net_crypto, crypt_id) != CRYPTO_CONN_ESTABLISHED) + uint8_t direct_connected; + + if (crypto_connection_status(m->net_crypto, crypt_id, &direct_connected) != CRYPTO_CONN_ESTABLISHED) return zero; - return connection_ip(m->net_crypto->lossless_udp, m->net_crypto->crypto_connections[crypt_id].number); + if (direct_connected == 0) + return zero; + + return m->net_crypto->crypto_connections[crypt_id].ip_port; } /* returns the group number of the chat with public key group_public_key. @@ -1396,7 +1418,7 @@ int new_filesender(Messenger *m, int32_t friendnumber, uint64_t filesize, uint8_ int file_control(Messenger *m, int32_t friendnumber, uint8_t send_receive, uint8_t filenumber, uint8_t message_id, uint8_t *data, uint16_t length) { - if (length > MAX_DATA_SIZE - 3) + if (length > MAX_CRYPTO_DATA_SIZE - 3) return -1; if (friend_not_valid(m, friendnumber)) @@ -1413,7 +1435,7 @@ int file_control(Messenger *m, int32_t friendnumber, uint8_t send_receive, uint8 if (send_receive > 1) return -1; - uint8_t packet[MAX_DATA_SIZE]; + uint8_t packet[MAX_CRYPTO_DATA_SIZE]; packet[0] = send_receive; packet[1] = filenumber; packet[2] = message_id; @@ -1483,7 +1505,7 @@ int file_control(Messenger *m, int32_t friendnumber, uint8_t send_receive, uint8 */ int file_data(Messenger *m, int32_t friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length) { - if (length > MAX_DATA_SIZE - 1) + if (length > MAX_CRYPTO_DATA_SIZE - 1) return -1; if (friend_not_valid(m, friendnumber)) @@ -1496,7 +1518,7 @@ int file_data(Messenger *m, int32_t friendnumber, uint8_t filenumber, uint8_t *d if (crypto_num_free_sendqueue_slots(m->net_crypto, m->friendlist[friendnumber].crypt_connection_id) < MIN_SLOTS_FREE) return -1; - uint8_t packet[MAX_DATA_SIZE]; + uint8_t packet[MAX_CRYPTO_DATA_SIZE]; packet[0] = filenumber; memcpy(packet + 1, data, length); @@ -1739,6 +1761,30 @@ static void LANdiscovery(Messenger *m) } } +static int handle_status(void *object, int i, uint8_t status); +static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len); + +static int handle_new_connections(void *object, New_Connection *n_c) +{ + Messenger *m = object; + int friend_id = getfriend_id(m, n_c->public_key); + + if (friend_id != -1) { + if (m->friendlist[friend_id].crypt_connection_id != -1) + return -1; + + int id = accept_crypto_connection(m->net_crypto, n_c); + connection_status_handler(m->net_crypto, id, &handle_status, m, friend_id); + connection_data_handler(m->net_crypto, id, &handle_packet, m, friend_id); + m->friendlist[friend_id].crypt_connection_id = id; + set_friend_status(m, friend_id, FRIEND_CONFIRMED); + return 0; + } + + return -1; +} + + /* Run this at startup. */ Messenger *new_messenger(uint8_t ipv6enabled) { @@ -1756,26 +1802,28 @@ Messenger *new_messenger(uint8_t ipv6enabled) return NULL; } - m->net_crypto = new_net_crypto(m->net); + m->dht = new_DHT(m->net); - if (m->net_crypto == NULL) { + if (m->dht == NULL) { kill_networking(m->net); free(m); return NULL; } - m->dht = new_DHT(m->net_crypto); + m->net_crypto = new_net_crypto(m->dht); - if (m->dht == NULL) { - kill_net_crypto(m->net_crypto); + if (m->net_crypto == NULL) { kill_networking(m->net); + kill_DHT(m->dht); free(m); return NULL; } + new_connection_handler(m->net_crypto, &handle_new_connections, m); + m->onion = new_onion(m->dht); m->onion_a = new_onion_announce(m->dht); - m->onion_c = new_onion_client(m->dht); + m->onion_c = new_onion_client(m->net_crypto); if (!(m->onion && m->onion_a && m->onion_c)) { kill_onion(m->onion); @@ -1814,9 +1862,15 @@ void kill_messenger(Messenger *m) kill_onion(m->onion); kill_onion_announce(m->onion_a); kill_onion_client(m->onion_c); - kill_DHT(m->dht); kill_net_crypto(m->net_crypto); + kill_DHT(m->dht); kill_networking(m->net); + + for (i = 0; i < m->numfriends; ++i) { + if (m->friendlist[i].statusmessage) + free(m->friendlist[i].statusmessage); + } + free(m->friendlist); free(m); } @@ -1839,379 +1893,395 @@ static void check_friend_request_timed_out(Messenger *m, uint32_t i, uint64_t t) } } -/* TODO: Make this function not suck. */ -void do_friends(Messenger *m) +static int handle_status(void *object, int i, uint8_t status) { - uint32_t i; - int len; - uint8_t temp[MAX_DATA_SIZE]; uint64_t temp_time = unix_time(); + Messenger *m = object; - for (i = 0; i < m->numfriends; ++i) { - if (m->friendlist[i].status == FRIEND_ADDED) { - int fr = send_friendrequest(m->onion_c, m->friendlist[i].client_id, m->friendlist[i].friendrequest_nospam, - m->friendlist[i].info, - m->friendlist[i].info_size); + if (status) { /* Went online. */ + set_friend_status(m, i, FRIEND_ONLINE); + m->friendlist[i].name_sent = 0; + m->friendlist[i].userstatus_sent = 0; + m->friendlist[i].statusmessage_sent = 0; + m->friendlist[i].ping_lastrecv = temp_time; + } else { /* Went offline. */ + m->friendlist[i].crypt_connection_id = -1; - if (fr >= 0) { - set_friend_status(m, i, FRIEND_REQUESTED); - m->friendlist[i].friendrequest_lastsent = temp_time; - } + if (m->friendlist[i].status == FRIEND_ONLINE) { + set_friend_status(m, i, FRIEND_CONFIRMED); } + } - if (m->friendlist[i].status == FRIEND_REQUESTED - || m->friendlist[i].status == FRIEND_CONFIRMED) { /* friend is not online. */ - if (m->friendlist[i].status == FRIEND_REQUESTED) { - /* If we didn't connect to friend after successfully sending him a friend request the request is deemed - * unsuccessful so we set the status back to FRIEND_ADDED and try again. - */ - check_friend_request_timed_out(m, i, temp_time); - } + return 0; +} - IP_Port friendip; - int friendok = onion_getfriendip(m->onion_c, m->friendlist[i].onion_friendnum, &friendip); +static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len) +{ + if (len == 0) + return -1; - switch (is_cryptoconnected(m->net_crypto, m->friendlist[i].crypt_connection_id)) { - case CRYPTO_CONN_NO_CONNECTION: - if (friendok == 1) - m->friendlist[i].crypt_connection_id = crypto_connect(m->net_crypto, m->friendlist[i].client_id, friendip); + Messenger *m = object; + uint64_t temp_time = unix_time(); + uint8_t packet_id = temp[0]; + uint8_t *data = temp + 1; + uint32_t data_length = len - 1; - break; + if (m->friendlist[i].status != FRIEND_ONLINE) + return -1; - case CRYPTO_CONN_ESTABLISHED: /* Connection is established. */ - set_friend_status(m, i, FRIEND_ONLINE); - m->friendlist[i].name_sent = 0; - m->friendlist[i].userstatus_sent = 0; - m->friendlist[i].statusmessage_sent = 0; - m->friendlist[i].ping_lastrecv = temp_time; - break; + switch (packet_id) { + case PACKET_ID_ALIVE: { + m->friendlist[i].ping_lastrecv = temp_time; + break; + } - case CRYPTO_CONN_TIMED_OUT: - crypto_kill(m->net_crypto, m->friendlist[i].crypt_connection_id); - m->friendlist[i].crypt_connection_id = -1; - break; + case PACKET_ID_NICKNAME: { + if (data_length > MAX_NAME_LENGTH || data_length == 0) + break; - default: - break; - } + /* Make sure the NULL terminator is present. */ + uint8_t data_terminated[data_length + 1]; + memcpy(data_terminated, data, data_length); + data_terminated[data_length] = 0; + + /* inform of namechange before we overwrite the old name */ + if (m->friend_namechange) + m->friend_namechange(m, i, data_terminated, data_length, m->friend_namechange_userdata); + + memcpy(m->friendlist[i].name, data_terminated, data_length); + m->friendlist[i].name_length = data_length; + + break; } - while (m->friendlist[i].status == FRIEND_ONLINE) { /* friend is online. */ - if (m->friendlist[i].name_sent == 0) { - if (m_sendname(m, i, m->name, m->name_length)) - m->friendlist[i].name_sent = 1; - } + case PACKET_ID_STATUSMESSAGE: { + if (data_length == 0 || data_length > MAX_STATUSMESSAGE_LENGTH) + break; - if (m->friendlist[i].statusmessage_sent == 0) { - if (send_statusmessage(m, i, m->statusmessage, m->statusmessage_length)) - m->friendlist[i].statusmessage_sent = 1; - } + /* Make sure the NULL terminator is present. */ + uint8_t data_terminated[data_length + 1]; + memcpy(data_terminated, data, data_length); + data_terminated[data_length] = 0; - if (m->friendlist[i].userstatus_sent == 0) { - if (send_userstatus(m, i, m->userstatus)) - m->friendlist[i].userstatus_sent = 1; - } + if (m->friend_statusmessagechange) + m->friend_statusmessagechange(m, i, data_terminated, data_length, + m->friend_statuschange_userdata); - if (m->friendlist[i].user_istyping_sent == 0) { - if (send_user_istyping(m, i, m->friendlist[i].user_istyping)) - m->friendlist[i].user_istyping_sent = 1; - } + set_friend_statusmessage(m, i, data_terminated, data_length); + break; + } - if (m->friendlist[i].ping_lastsent + FRIEND_PING_INTERVAL < temp_time) { - send_ping(m, i); - } + case PACKET_ID_USERSTATUS: { + if (data_length != 1) + break; - len = read_cryptpacket(m->net_crypto, m->friendlist[i].crypt_connection_id, temp); + USERSTATUS status = data[0]; - if (len > 0) { - uint8_t packet_id = temp[0]; - uint8_t *data = temp + 1; - uint32_t data_length = len - 1; + if (status >= USERSTATUS_INVALID) + break; - switch (packet_id) { - case PACKET_ID_PING: { - m->friendlist[i].ping_lastrecv = temp_time; - break; - } + if (m->friend_userstatuschange) + m->friend_userstatuschange(m, i, status, m->friend_userstatuschange_userdata); - case PACKET_ID_NICKNAME: { - if (data_length > MAX_NAME_LENGTH || data_length == 0) - break; + set_friend_userstatus(m, i, status); + break; + } - /* Make sure the NULL terminator is present. */ - uint8_t data_terminated[data_length + 1]; - memcpy(data_terminated, data, data_length); - data_terminated[data_length] = 0; + case PACKET_ID_TYPING: { + if (data_length != 1) + break; - /* inform of namechange before we overwrite the old name */ - if (m->friend_namechange) - m->friend_namechange(m, i, data_terminated, data_length, m->friend_namechange_userdata); + uint8_t typing = data[0]; - memcpy(m->friendlist[i].name, data_terminated, data_length); - m->friendlist[i].name_length = data_length; + set_friend_typing(m, i, typing); - break; - } + if (m->friend_typingchange) + m->friend_typingchange(m, i, typing, m->friend_typingchange_userdata); - case PACKET_ID_STATUSMESSAGE: { - if (data_length == 0 || data_length > MAX_STATUSMESSAGE_LENGTH) - break; + break; + } - /* Make sure the NULL terminator is present. */ - uint8_t data_terminated[data_length + 1]; - memcpy(data_terminated, data, data_length); - data_terminated[data_length] = 0; + case PACKET_ID_MESSAGE: { + uint8_t *message_id = data; + uint8_t message_id_length = 4; - if (m->friend_statusmessagechange) - m->friend_statusmessagechange(m, i, data_terminated, data_length, - m->friend_statuschange_userdata); + if (data_length <= message_id_length) + break; - set_friend_statusmessage(m, i, data_terminated, data_length); - break; - } + uint8_t *message = data + message_id_length; + uint16_t message_length = data_length - message_id_length; - case PACKET_ID_USERSTATUS: { - if (data_length != 1) - break; + /* Make sure the NULL terminator is present. */ + uint8_t message_terminated[message_length + 1]; + memcpy(message_terminated, message, message_length); + message_terminated[message_length] = 0; - USERSTATUS status = data[0]; + if (m->friendlist[i].receives_read_receipts) { + write_cryptpacket_id(m, i, PACKET_ID_RECEIPT, message_id, message_id_length); + } - if (status >= USERSTATUS_INVALID) - break; + if (m->friend_message) + (*m->friend_message)(m, i, message_terminated, message_length, m->friend_message_userdata); - if (m->friend_userstatuschange) - m->friend_userstatuschange(m, i, status, m->friend_userstatuschange_userdata); + break; + } - set_friend_userstatus(m, i, status); - break; - } + case PACKET_ID_ACTION: { + uint8_t *message_id = data; + uint8_t message_id_length = 4; - case PACKET_ID_TYPING: { - if (data_length != 1) - break; + if (data_length <= message_id_length) + break; - uint8_t typing = data[0]; + uint8_t *action = data + message_id_length; + uint16_t action_length = data_length - message_id_length; - set_friend_typing(m, i, typing); + /* Make sure the NULL terminator is present. */ + uint8_t action_terminated[action_length + 1]; + memcpy(action_terminated, action, action_length); + action_terminated[action_length] = 0; - if (m->friend_typingchange) - m->friend_typingchange(m, i, typing, m->friend_typingchange_userdata); + if (m->friendlist[i].receives_read_receipts) { + write_cryptpacket_id(m, i, PACKET_ID_RECEIPT, message_id, message_id_length); + } - break; - } + if (m->friend_action) + (*m->friend_action)(m, i, action_terminated, action_length, m->friend_action_userdata); - case PACKET_ID_MESSAGE: { - uint8_t *message_id = data; - uint8_t message_id_length = 4; + break; + } - if (data_length <= message_id_length) - break; + case PACKET_ID_RECEIPT: { + uint32_t msgid; - uint8_t *message = data + message_id_length; - uint16_t message_length = data_length - message_id_length; + if (data_length < sizeof(msgid)) + break; - /* Make sure the NULL terminator is present. */ - uint8_t message_terminated[message_length + 1]; - memcpy(message_terminated, message, message_length); - message_terminated[message_length] = 0; + memcpy(&msgid, data, sizeof(msgid)); + msgid = ntohl(msgid); - if (m->friendlist[i].receives_read_receipts) { - write_cryptpacket_id(m, i, PACKET_ID_RECEIPT, message_id, message_id_length); - } + if (m->read_receipt) + (*m->read_receipt)(m, i, msgid, m->read_receipt_userdata); - if (m->friend_message) - (*m->friend_message)(m, i, message_terminated, message_length, m->friend_message_userdata); + break; + } - break; - } + case PACKET_ID_INVITE_GROUPCHAT: { + if (data_length != crypto_box_PUBLICKEYBYTES) + break; - case PACKET_ID_ACTION: { - uint8_t *message_id = data; - uint8_t message_id_length = 4; + if (m->group_invite) + (*m->group_invite)(m, i, data, m->group_invite_userdata); - if (data_length <= message_id_length) - break; + break; + } - uint8_t *action = data + message_id_length; - uint16_t action_length = data_length - message_id_length; + case PACKET_ID_JOIN_GROUPCHAT: { + if (data_length != crypto_box_PUBLICKEYBYTES * 2) + break; - /* Make sure the NULL terminator is present. */ - uint8_t action_terminated[action_length + 1]; - memcpy(action_terminated, action, action_length); - action_terminated[action_length] = 0; + int groupnum = group_num(m, data); - if (m->friendlist[i].receives_read_receipts) { - write_cryptpacket_id(m, i, PACKET_ID_RECEIPT, message_id, message_id_length); - } + if (groupnum == -1) + break; - if (m->friend_action) - (*m->friend_action)(m, i, action_terminated, action_length, m->friend_action_userdata); + if (!group_invited(m, i, groupnum)) + break; - break; - } + group_newpeer(m->chats[groupnum], data + crypto_box_PUBLICKEYBYTES); + /* This is just there to speedup joining. */ + chat_bootstrap(m->chats[groupnum], get_friend_ipport(m, i), data + crypto_box_PUBLICKEYBYTES); + break; + } - case PACKET_ID_RECEIPT: { - uint32_t msgid; + case PACKET_ID_FILE_SENDREQUEST: { + if (data_length < 1 + sizeof(uint64_t) + 1) + break; - if (data_length < sizeof(msgid)) - break; + uint8_t filenumber = data[0]; + uint64_t filesize; + net_to_host(data + 1, sizeof(filesize)); + memcpy(&filesize, data + 1, sizeof(filesize)); + m->friendlist[i].file_receiving[filenumber].status = FILESTATUS_NOT_ACCEPTED; + m->friendlist[i].file_receiving[filenumber].size = filesize; + m->friendlist[i].file_receiving[filenumber].transferred = 0; - memcpy(&msgid, data, sizeof(msgid)); - msgid = ntohl(msgid); + /* Force NULL terminate file name. */ + uint8_t filename_terminated[data_length - 1 - sizeof(uint64_t) + 1]; + memcpy(filename_terminated, data + 1 + sizeof(uint64_t), data_length - 1 - sizeof(uint64_t)); + filename_terminated[data_length - 1 - sizeof(uint64_t)] = 0; - if (m->read_receipt) - (*m->read_receipt)(m, i, msgid, m->read_receipt_userdata); + if (m->file_sendrequest) + (*m->file_sendrequest)(m, i, filenumber, filesize, filename_terminated, data_length - 1 - sizeof(uint64_t), + m->file_sendrequest_userdata); - break; - } + break; + } - case PACKET_ID_INVITE_GROUPCHAT: { - if (data_length != crypto_box_PUBLICKEYBYTES) - break; + case PACKET_ID_FILE_CONTROL: { + if (data_length < 3) + break; - if (m->group_invite) - (*m->group_invite)(m, i, data, m->group_invite_userdata); + uint8_t send_receive = data[0]; + uint8_t filenumber = data[1]; + uint8_t control_type = data[2]; - break; - } + if (handle_filecontrol(m, i, send_receive, filenumber, control_type, data + 3, data_length - 3) == -1) + break; - case PACKET_ID_JOIN_GROUPCHAT: { - if (data_length != crypto_box_PUBLICKEYBYTES * 2) - break; + if (m->file_filecontrol) + (*m->file_filecontrol)(m, i, send_receive, filenumber, control_type, data + 3, data_length - 3, + m->file_filecontrol_userdata); - int groupnum = group_num(m, data); + break; + } - if (groupnum == -1) - break; + case PACKET_ID_FILE_DATA: { + if (data_length < 2) + break; - if (!group_invited(m, i, groupnum)) - break; + uint8_t filenumber = data[0]; - group_newpeer(m->chats[groupnum], data + crypto_box_PUBLICKEYBYTES); - /* This is just there to speedup joining. */ - chat_bootstrap(m->chats[groupnum], get_friend_ipport(m, i), data + crypto_box_PUBLICKEYBYTES); - break; - } + if (m->friendlist[i].file_receiving[filenumber].status == FILESTATUS_NONE) + break; - case PACKET_ID_FILE_SENDREQUEST: { - if (data_length < 1 + sizeof(uint64_t) + 1) - break; + m->friendlist[i].file_receiving[filenumber].transferred += (data_length - 1); - uint8_t filenumber = data[0]; - uint64_t filesize; - net_to_host(data + 1, sizeof(filesize)); - memcpy(&filesize, data + 1, sizeof(filesize)); - m->friendlist[i].file_receiving[filenumber].status = FILESTATUS_NOT_ACCEPTED; - m->friendlist[i].file_receiving[filenumber].size = filesize; - m->friendlist[i].file_receiving[filenumber].transferred = 0; + if (m->file_filedata) + (*m->file_filedata)(m, i, filenumber, data + 1, data_length - 1, m->file_filedata_userdata); - /* Force NULL terminate file name. */ - uint8_t filename_terminated[data_length - 1 - sizeof(uint64_t) + 1]; - memcpy(filename_terminated, data + 1 + sizeof(uint64_t), data_length - 1 - sizeof(uint64_t)); - filename_terminated[data_length - 1 - sizeof(uint64_t)] = 0; + break; + } - if (m->file_sendrequest) - (*m->file_sendrequest)(m, i, filenumber, filesize, filename_terminated, data_length - 1 - sizeof(uint64_t), - m->file_sendrequest_userdata); + case PACKET_ID_MSI: { + if (data_length == 0) + break; - break; - } + if (m->msi_packet) + (*m->msi_packet)(m, i, data, data_length, m->msi_packet_userdata); + } - case PACKET_ID_FILE_CONTROL: { - if (data_length < 3) - break; + default: { + break; + } + } - uint8_t send_receive = data[0]; - uint8_t filenumber = data[1]; - uint8_t control_type = data[2]; + return 0; +} - if (handle_filecontrol(m, i, send_receive, filenumber, control_type, data + 3, data_length - 3) == -1) - break; +static int friend_new_connection(Messenger *m, int32_t friendnumber, uint8_t *real_public_key) +{ + if (friend_not_valid(m, friendnumber)) + return -1; - if (m->file_filecontrol) - (*m->file_filecontrol)(m, i, send_receive, filenumber, control_type, data + 3, data_length - 3, - m->file_filecontrol_userdata); + if (m->friendlist[friendnumber].crypt_connection_id != -1) { + return -1; + } - break; - } + int id = new_crypto_connection(m->net_crypto, real_public_key); - case PACKET_ID_FILE_DATA: { - if (data_length < 2) - break; + if (id == -1) + return -1; - uint8_t filenumber = data[0]; + m->friendlist[friendnumber].crypt_connection_id = id; + connection_status_handler(m->net_crypto, id, &handle_status, m, friendnumber); + connection_data_handler(m->net_crypto, id, &handle_packet, m, friendnumber); + return 0; - if (m->friendlist[i].file_receiving[filenumber].status == FILESTATUS_NONE) - break; +} - m->friendlist[i].file_receiving[filenumber].transferred += (data_length - 1); +/* TODO: Make this function not suck. */ +void do_friends(Messenger *m) +{ + uint32_t i; + uint64_t temp_time = unix_time(); - if (m->file_filedata) - (*m->file_filedata)(m, i, filenumber, data + 1, data_length - 1, m->file_filedata_userdata); + for (i = 0; i < m->numfriends; ++i) { + if (m->friendlist[i].status == FRIEND_ADDED) { + int fr = send_friendrequest(m->onion_c, m->friendlist[i].client_id, m->friendlist[i].friendrequest_nospam, + m->friendlist[i].info, + m->friendlist[i].info_size); - break; - } + if (fr >= 0) { + set_friend_status(m, i, FRIEND_REQUESTED); + m->friendlist[i].friendrequest_lastsent = temp_time; + } + } + + if (m->friendlist[i].status == FRIEND_REQUESTED + || m->friendlist[i].status == FRIEND_CONFIRMED) { /* friend is not online. */ + if (m->friendlist[i].status == FRIEND_REQUESTED) { + /* If we didn't connect to friend after successfully sending him a friend request the request is deemed + * unsuccessful so we set the status back to FRIEND_ADDED and try again. + */ + check_friend_request_timed_out(m, i, temp_time); + } - case PACKET_ID_MSI: { - if (data_length == 0) - break; + friend_new_connection(m, i, m->friendlist[i].client_id); + } - if (m->msi_packet) - (*m->msi_packet)(m, i, data, data_length, m->msi_packet_userdata); - } + if (m->friendlist[i].crypt_connection_id != -1) { + uint8_t dht_public_key1[crypto_box_PUBLICKEYBYTES]; + uint64_t timestamp1 = onion_getfriend_DHT_pubkey(m->onion_c, m->friendlist[i].onion_friendnum, dht_public_key1); + uint8_t dht_public_key2[crypto_box_PUBLICKEYBYTES]; + uint64_t timestamp2 = get_connection_dht_key(m->net_crypto, m->friendlist[i].crypt_connection_id, dht_public_key2); - default: { - break; - } - } - } else { - if (is_cryptoconnected(m->net_crypto, - m->friendlist[i].crypt_connection_id) == CRYPTO_CONN_TIMED_OUT) { /* If the connection timed out, kill it. */ - crypto_kill(m->net_crypto, m->friendlist[i].crypt_connection_id); - m->friendlist[i].crypt_connection_id = -1; - set_friend_status(m, i, FRIEND_CONFIRMED); - } + if (timestamp1 > timestamp2) { + set_connection_dht_public_key(m->net_crypto, m->friendlist[i].crypt_connection_id, dht_public_key1, timestamp1); + } else if (timestamp1 < timestamp2) { + onion_set_friend_DHT_pubkey(m->onion_c, m->friendlist[i].onion_friendnum, dht_public_key2, timestamp2); + } - if (m->friendlist[i].ping_lastrecv + FRIEND_CONNECTION_TIMEOUT < temp_time) { - /* If we stopped recieving ping packets, kill it. */ - crypto_kill(m->net_crypto, m->friendlist[i].crypt_connection_id); - m->friendlist[i].crypt_connection_id = -1; - set_friend_status(m, i, FRIEND_CONFIRMED); - } + uint8_t direct_connected; + unsigned int status = crypto_connection_status(m->net_crypto, m->friendlist[i].crypt_connection_id, &direct_connected); - break; + if (direct_connected == 0 || status == CRYPTO_CONN_COOKIE_REQUESTING) { + IP_Port friendip; + + if (onion_getfriendip(m->onion_c, m->friendlist[i].onion_friendnum, &friendip) == 1) { + set_direct_ip_port(m->net_crypto, m->friendlist[i].crypt_connection_id, friendip); + } } } - } -} -void do_inbound(Messenger *m) -{ - uint8_t secret_nonce[crypto_box_NONCEBYTES]; - uint8_t public_key[crypto_box_PUBLICKEYBYTES]; - uint8_t session_key[crypto_box_PUBLICKEYBYTES]; - int inconnection = crypto_inbound(m->net_crypto, public_key, secret_nonce, session_key); + if (m->friendlist[i].status == FRIEND_ONLINE) { /* friend is online. */ + if (m->friendlist[i].name_sent == 0) { + if (m_sendname(m, i, m->name, m->name_length)) + m->friendlist[i].name_sent = 1; + } - if (inconnection != -1) { - int friend_id = getfriend_id(m, public_key); + if (m->friendlist[i].statusmessage_sent == 0) { + if (send_statusmessage(m, i, m->statusmessage, m->statusmessage_length)) + m->friendlist[i].statusmessage_sent = 1; + } - if (friend_id != -1) { - if (m_get_friend_connectionstatus(m, friend_id) == 1) { - kill_connection(m->net_crypto->lossless_udp, inconnection); - return; + if (m->friendlist[i].userstatus_sent == 0) { + if (send_userstatus(m, i, m->userstatus)) + m->friendlist[i].userstatus_sent = 1; + } + + if (m->friendlist[i].user_istyping_sent == 0) { + if (send_user_istyping(m, i, m->friendlist[i].user_istyping)) + m->friendlist[i].user_istyping_sent = 1; } - crypto_kill(m->net_crypto, m->friendlist[friend_id].crypt_connection_id); - m->friendlist[friend_id].crypt_connection_id = - accept_crypto_inbound(m->net_crypto, inconnection, public_key, secret_nonce, session_key); + if (m->friendlist[i].ping_lastsent + FRIEND_PING_INTERVAL < temp_time) { + send_ping(m, i); + } - set_friend_status(m, friend_id, FRIEND_CONFIRMED); - } else { - kill_connection(m->net_crypto->lossless_udp, inconnection); + if (m->friendlist[i].ping_lastrecv + FRIEND_CONNECTION_TIMEOUT < temp_time) { + /* If we stopped receiving ping packets, kill it. */ + crypto_kill(m->net_crypto, m->friendlist[i].crypt_connection_id); + m->friendlist[i].crypt_connection_id = -1; + set_friend_status(m, i, FRIEND_CONFIRMED); + } } } } + + + #ifdef LOGGING #define DUMPING_CLIENTS_FRIENDS_EVERY_N_SECONDS 60UL static time_t lastdump = 0; @@ -2239,7 +2309,6 @@ void do_messenger(Messenger *m) do_net_crypto(m->net_crypto); do_onion_client(m->onion_c); do_friends(m); - do_inbound(m); do_allgroupchats(m); LANdiscovery(m); @@ -2369,7 +2438,9 @@ size_t wait_data_size() int wait_prepare_messenger(Messenger *m, uint8_t *data) { - return networking_wait_prepare(m->net, sendqueue_total(m->net_crypto->lossless_udp), data); + //TODO + //return networking_wait_prepare(m->net, sendqueue_total(m->net_crypto->lossless_udp), data); + return networking_wait_prepare(m->net, 1024, data); } int wait_execute_messenger(uint8_t *data, long seconds, long microseconds) @@ -2394,11 +2465,14 @@ int wait_cleanup_messenger(Messenger *m, uint8_t *data) #define MESSENGER_STATE_TYPE_NAME 4 #define MESSENGER_STATE_TYPE_STATUSMESSAGE 5 #define MESSENGER_STATE_TYPE_STATUS 6 +#define MESSENGER_STATE_TYPE_TCP_RELAY 10 +#define SAVED_FRIEND_REQUEST_SIZE 1024 +#define NUM_SAVED_TCP_RELAYS 8 struct SAVED_FRIEND { uint8_t status; uint8_t client_id[CLIENT_ID_SIZE]; - uint8_t info[MAX_DATA_SIZE]; // the data that is sent during the friend requests we do. + uint8_t info[SAVED_FRIEND_REQUEST_SIZE]; // the data that is sent during the friend requests we do. uint16_t info_size; // Length of the info. uint8_t name[MAX_NAME_LENGTH]; uint16_t name_length; @@ -2414,7 +2488,7 @@ struct SAVED_FRIEND { struct SAVED_FRIEND_OLD { uint8_t status; uint8_t client_id[CLIENT_ID_SIZE]; - uint8_t info[MAX_DATA_SIZE]; + uint8_t info[1024]; uint16_t info_size; uint8_t name[MAX_NAME_LENGTH]; uint16_t name_length; @@ -2442,7 +2516,12 @@ static uint32_t friends_list_save(Messenger *m, uint8_t *data) memcpy(temp.client_id, m->friendlist[i].client_id, CLIENT_ID_SIZE); if (temp.status < 3) { - memcpy(temp.info, m->friendlist[i].info, m->friendlist[i].info_size); + if (m->friendlist[i].info_size > SAVED_FRIEND_REQUEST_SIZE) { + memcpy(temp.info, m->friendlist[i].info, SAVED_FRIEND_REQUEST_SIZE); + } else { + memcpy(temp.info, m->friendlist[i].info, m->friendlist[i].info_size); + } + temp.info_size = htons(m->friendlist[i].info_size); temp.friendrequest_nospam = m->friendlist[i].friendrequest_nospam; } else { @@ -2524,6 +2603,7 @@ uint32_t messenger_size(Messenger *m) + sizesubhead + m->name_length // Own nickname. + sizesubhead + m->statusmessage_length // status message + sizesubhead + 1 // status + + sizesubhead + NUM_SAVED_TCP_RELAYS * sizeof(Node_format) //TCP relays ; } @@ -2588,74 +2668,15 @@ void messenger_save(Messenger *m, uint8_t *data) data = z_state_save_subheader(data, len, type); *data = m->userstatus; data += len; -} - -static int messenger_load_state_callback_old(void *outer, uint8_t *data, uint32_t length, uint16_t type) -{ - Messenger *m = outer; - - switch (type) { - case MESSENGER_STATE_TYPE_NOSPAMKEYS: - if (length == crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES + sizeof(uint32_t)) { - set_nospam(&(m->fr), *(uint32_t *)data); - load_keys(m->net_crypto, &data[sizeof(uint32_t)]); -#ifdef ENABLE_ASSOC_DHT - - if (m->dht->assoc) - Assoc_self_client_id_changed(m->dht->assoc, m->net_crypto->self_public_key); -#endif - } else - return -1; /* critical */ - - break; - - case MESSENGER_STATE_TYPE_DHT: - DHT_load(m->dht, data, length); - break; - - case MESSENGER_STATE_TYPE_FRIENDS: - if (!(length % sizeof(Friend))) { - uint16_t num = length / sizeof(Friend); - Friend *friends = (Friend *)data; - uint32_t i; - - for (i = 0; i < num; ++i) { - if (friends[i].status >= 3) { - int fnum = m_addfriend_norequest(m, friends[i].client_id); - setfriendname(m, fnum, friends[i].name, friends[i].name_length); - /* set_friend_statusmessage(fnum, temp[i].statusmessage, temp[i].statusmessage_length); */ - } else if (friends[i].status != 0) { - /* TODO: This is not a good way to do this. */ - uint8_t address[FRIEND_ADDRESS_SIZE]; - id_copy(address, friends[i].client_id); - memcpy(address + crypto_box_PUBLICKEYBYTES, &(friends[i].friendrequest_nospam), sizeof(uint32_t)); - uint16_t checksum = address_checksum(address, FRIEND_ADDRESS_SIZE - sizeof(checksum)); - memcpy(address + crypto_box_PUBLICKEYBYTES + sizeof(uint32_t), &checksum, sizeof(checksum)); - m_addfriend(m, address, friends[i].info, friends[i].info_size); - } - } - } - - break; - - case MESSENGER_STATE_TYPE_NAME: - if ((length > 0) && (length < MAX_NAME_LENGTH)) { - setname(m, data, length); - } - - break; - -#ifdef DEBUG - - default: - fprintf(stderr, "Load state: contains unrecognized part (len %u, type %u)\n", - length, type); - break; -#endif - } - - return 0; + Node_format relays[NUM_SAVED_TCP_RELAYS]; + len = sizeof(relays); + type = MESSENGER_STATE_TYPE_TCP_RELAY; + data = z_state_save_subheader(data, len, type); + memset(relays, 0, len); + copy_connected_tcp_relays(m->net_crypto, relays, NUM_SAVED_TCP_RELAYS); + memcpy(data, relays, len); + data += len; } static int messenger_load_state_callback(void *outer, uint8_t *data, uint32_t length, uint16_t type) @@ -2706,6 +2727,22 @@ static int messenger_load_state_callback(void *outer, uint8_t *data, uint32_t le } break; + + case MESSENGER_STATE_TYPE_TCP_RELAY: { + Node_format relays[NUM_SAVED_TCP_RELAYS]; + + if (length != sizeof(relays)) { + return -1; + } + + memcpy(relays, data, length); + uint32_t i; + + for (i = 0; i < NUM_SAVED_TCP_RELAYS; ++i) { + add_tcp_relay(m->net_crypto, relays[i].ip_port, relays[i].client_id); + } + } + break; #ifdef DEBUG default: @@ -2721,93 +2758,21 @@ static int messenger_load_state_callback(void *outer, uint8_t *data, uint32_t le /* Load the messenger from data of size length. */ int messenger_load(Messenger *m, uint8_t *data, uint32_t length) { - uint32_t cookie_len = 2 * sizeof(uint32_t); + uint32_t data32[2]; + uint32_t cookie_len = sizeof(data32); if (length < cookie_len) return -1; - uint32_t *data32 = (uint32_t *)data; + memcpy(data32, data, sizeof(data32)); if (!data32[0] && (data32[1] == MESSENGER_STATE_COOKIE_GLOBAL)) return load_state(messenger_load_state_callback, m, data + cookie_len, length - cookie_len, MESSENGER_STATE_COOKIE_TYPE); - - else if (!data32[0] && (data32[1] == MESSENGER_STATE_COOKIE_GLOBAL_OLD)) - return load_state(messenger_load_state_callback_old, m, data + cookie_len, - length - cookie_len, MESSENGER_STATE_COOKIE_TYPE); - else /* old state file */ + else return -1; } -/* return the size of data to pass to messenger_save_encrypted(...) - * - */ -uint32_t messenger_size_encrypted(Messenger *m) -{ - return messenger_size(m) + crypto_secretbox_MACBYTES + crypto_secretbox_NONCEBYTES; -} - -/* Save the messenger, encrypting the data with key of length key_length - * - * return 0 on success. - * return -1 on failure. - */ -int messenger_save_encrypted(Messenger *m, uint8_t *data, uint8_t *key, uint16_t key_length) -{ - uint32_t m_size = messenger_size(m); - uint8_t *plain_messenger = malloc(m_size); - - if (plain_messenger == NULL) - return -1; - - messenger_save(m, plain_messenger); - - /* Hash the key with SHA256 to get a 32byte key. */ - uint8_t hash[crypto_hash_sha256_BYTES]; - crypto_hash_sha256(hash, key, key_length); - random_nonce(data); - encrypt_data_symmetric(hash, data, plain_messenger, m_size, data + crypto_secretbox_NONCEBYTES); - - memset(plain_messenger, 0, m_size); - free(plain_messenger); - memset(hash, 0, crypto_hash_sha256_BYTES); - return 0; -} - -/* Load the messenger from data of size length encrypted with key of key_length. - * - * return 0 on success. - * return -1 on failure. - */ -int messenger_load_encrypted(Messenger *m, uint8_t *data, uint32_t length, uint8_t *key, uint16_t key_length) -{ - if (length <= crypto_secretbox_MACBYTES + crypto_secretbox_NONCEBYTES) - return -1; - - uint8_t *plain_messenger = malloc(length); - - if (plain_messenger == NULL) - return -1; - - /* Hash the key with SHA256 to get a 32byte key. */ - uint8_t hash[crypto_hash_sha256_BYTES]; - crypto_hash_sha256(hash, key, key_length); - int len = decrypt_data_symmetric(hash, data, data + crypto_secretbox_NONCEBYTES, length - crypto_secretbox_NONCEBYTES, - plain_messenger); - int ret; - - if ((uint32_t)len == length - crypto_secretbox_NONCEBYTES - crypto_secretbox_MACBYTES) { - ret = messenger_load(m, plain_messenger, length - crypto_secretbox_NONCEBYTES - crypto_secretbox_MACBYTES); - } else { - ret = -1; - } - - memset(plain_messenger, 0, length); - free(plain_messenger); - memset(hash, 0, crypto_hash_sha256_BYTES); - return ret; -} - /* Return the number of friends in the instance m. * You should use this to determine how much memory to allocate * for copy_friendlist. */ diff --git a/toxcore/Messenger.h b/toxcore/Messenger.h index c29b6594..b72a0831 100644 --- a/toxcore/Messenger.h +++ b/toxcore/Messenger.h @@ -34,18 +34,20 @@ #include "onion_client.h" #define MAX_NAME_LENGTH 128 +/* TODO: this must depend on other variable. */ #define MAX_STATUSMESSAGE_LENGTH 1007 #define FRIEND_ADDRESS_SIZE (crypto_box_PUBLICKEYBYTES + sizeof(uint32_t) + sizeof(uint16_t)) -#define PACKET_ID_PING 0 +/* NOTE: Packet ids below 16 must never be used. */ +#define PACKET_ID_ALIVE 16 #define PACKET_ID_NICKNAME 48 #define PACKET_ID_STATUSMESSAGE 49 #define PACKET_ID_USERSTATUS 50 #define PACKET_ID_TYPING 51 -#define PACKET_ID_RECEIPT 65 +#define PACKET_ID_RECEIPT 63 #define PACKET_ID_MESSAGE 64 -#define PACKET_ID_ACTION 63 +#define PACKET_ID_ACTION 65 #define PACKET_ID_MSI 69 #define PACKET_ID_FILE_SENDREQUEST 80 #define PACKET_ID_FILE_CONTROL 81 @@ -80,17 +82,13 @@ enum { FAERR_NOMEM = -8 }; -/* Don't assume MAX_STATUSMESSAGE_LENGTH will stay at 128, it may be increased - * to an absurdly large number later. - */ - /* Default start timeout in seconds between friend requests. */ #define FRIENDREQUEST_TIMEOUT 5; /* Interval between the sending of ping packets. */ #define FRIEND_PING_INTERVAL 5 -/* If no packets are recieved from friend in this time interval, kill the connection. */ +/* If no packets are received from friend in this time interval, kill the connection. */ #define FRIEND_CONNECTION_TIMEOUT (FRIEND_PING_INTERVAL * 2) /* USERSTATUS - @@ -137,7 +135,7 @@ typedef struct { uint64_t friendrequest_lastsent; // Time at which the last friend request was sent. uint32_t friendrequest_timeout; // The timeout between successful friendrequest sending attempts. uint8_t status; // 0 if no friend, 1 if added, 2 if friend request sent, 3 if confirmed friend, 4 if online. - uint8_t info[MAX_DATA_SIZE]; // the data that is sent during the friend requests we do. + uint8_t info[MAX_FRIEND_REQUEST_DATA_SIZE]; // the data that is sent during the friend requests we do. uint8_t name[MAX_NAME_LENGTH]; uint16_t name_length; uint8_t name_sent; // 0 if we didn't send our name to this friend 1 if we have. @@ -354,7 +352,7 @@ int setname(Messenger *m, uint8_t *name, uint16_t length); /* * Get your nickname. - * m - The messanger context to use. + * m - The messenger context to use. * name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH bytes. * * return length of the name. @@ -376,11 +374,6 @@ int getname(Messenger *m, int32_t friendnumber, uint8_t *name); int m_get_name_size(Messenger *m, int32_t friendnumber); int m_get_self_name_size(Messenger *m); -/* returns valid ip port of connected friend on success - * returns zeroed out IP_Port on failure - */ -IP_Port get_friend_ipport(Messenger *m, int32_t friendnumber); - /* Set our user status. * You are responsible for freeing status after. * @@ -739,24 +732,6 @@ void messenger_save(Messenger *m, uint8_t *data); /* Load the messenger from data of size length. */ int messenger_load(Messenger *m, uint8_t *data, uint32_t length); -/* return the size of data to pass to messenger_save_encrypted(...) - */ -uint32_t messenger_size_encrypted(Messenger *m); - -/* Save the messenger, encrypting the data with key of length key_length - * - * return 0 on success. - * return -1 on failure. - */ -int messenger_save_encrypted(Messenger *m, uint8_t *data, uint8_t *key, uint16_t key_length); - -/* Load the messenger from data of size length encrypted with key of key_length. - * - * return 0 on success. - * return -1 on failure. - */ -int messenger_load_encrypted(Messenger *m, uint8_t *data, uint32_t length, uint8_t *key, uint16_t key_length); - /* Return the number of friends in the instance m. * You should use this to determine how much memory to allocate * for copy_friendlist. */ diff --git a/toxcore/TCP_client.c b/toxcore/TCP_client.c index 437429b9..e4845852 100644 --- a/toxcore/TCP_client.c +++ b/toxcore/TCP_client.c @@ -20,6 +20,9 @@ * */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include "TCP_client.h" @@ -71,8 +74,8 @@ static int generate_handshake(TCP_Client_Connection *TCP_conn, uint8_t *self_pub memcpy(plain + crypto_box_PUBLICKEYBYTES, TCP_conn->sent_nonce, crypto_box_NONCEBYTES); memcpy(TCP_conn->last_packet, self_public_key, crypto_box_PUBLICKEYBYTES); new_nonce(TCP_conn->last_packet + crypto_box_PUBLICKEYBYTES); - int len = encrypt_data_fast(TCP_conn->shared_key, TCP_conn->last_packet + crypto_box_PUBLICKEYBYTES, plain, - sizeof(plain), TCP_conn->last_packet + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES); + int len = encrypt_data_symmetric(TCP_conn->shared_key, TCP_conn->last_packet + crypto_box_PUBLICKEYBYTES, plain, + sizeof(plain), TCP_conn->last_packet + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES); if (len != sizeof(plain) + crypto_box_MACBYTES) return -1; @@ -90,8 +93,8 @@ static int generate_handshake(TCP_Client_Connection *TCP_conn, uint8_t *self_pub static int handle_handshake(TCP_Client_Connection *TCP_conn, uint8_t *data) { uint8_t plain[crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES]; - int len = decrypt_data_fast(TCP_conn->shared_key, data, data + crypto_box_NONCEBYTES, - TCP_SERVER_HANDSHAKE_SIZE - crypto_box_NONCEBYTES, plain); + int len = decrypt_data_symmetric(TCP_conn->shared_key, data, data + crypto_box_NONCEBYTES, + TCP_SERVER_HANDSHAKE_SIZE - crypto_box_NONCEBYTES, plain); if (len != sizeof(plain)) return -1; @@ -130,6 +133,206 @@ static int send_pending_data(TCP_Client_Connection *con) return -1; } +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure (connection must be killed). + */ +static int write_packet_TCP_secure_connection(TCP_Client_Connection *con, uint8_t *data, uint16_t length) +{ + if (length + crypto_box_MACBYTES > MAX_PACKET_SIZE) + return -1; + + if (send_pending_data(con) == -1) + return 0; + + uint8_t packet[sizeof(uint16_t) + length + crypto_box_MACBYTES]; + + uint16_t c_length = htons(length + crypto_box_MACBYTES); + memcpy(packet, &c_length, sizeof(uint16_t)); + int len = encrypt_data_symmetric(con->shared_key, con->sent_nonce, data, length, packet + sizeof(uint16_t)); + + if ((unsigned int)len != (sizeof(packet) - sizeof(uint16_t))) + return -1; + + increment_nonce(con->sent_nonce); + + len = send(con->sock, packet, sizeof(packet), MSG_NOSIGNAL); + + if ((unsigned int)len == sizeof(packet)) + return 1; + + if (len <= 0) + return 0; + + memcpy(con->last_packet, packet, length); + con->last_packet_length = sizeof(packet); + con->last_packet_sent = len; + return 1; +} + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure (connection must be killed). + */ +int send_routing_request(TCP_Client_Connection *con, uint8_t *public_key) +{ + uint8_t packet[1 + crypto_box_PUBLICKEYBYTES]; + packet[0] = TCP_PACKET_ROUTING_REQUEST; + memcpy(packet + 1, public_key, crypto_box_PUBLICKEYBYTES); + return write_packet_TCP_secure_connection(con, packet, sizeof(packet)); +} + +void routing_response_handler(TCP_Client_Connection *con, int (*response_callback)(void *object, uint8_t connection_id, + uint8_t *public_key), void *object) +{ + con->response_callback = response_callback; + con->response_callback_object = object; +} + +void routing_status_handler(TCP_Client_Connection *con, int (*status_callback)(void *object, uint32_t number, + uint8_t connection_id, uint8_t status), void *object) +{ + con->status_callback = status_callback; + con->status_callback_object = object; +} + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure. + */ +int send_data(TCP_Client_Connection *con, uint8_t con_id, uint8_t *data, uint16_t length) +{ + if (con_id >= NUM_CLIENT_CONNECTIONS) + return -1; + + if (con->connections[con_id].status != 2) + return -1; + + uint8_t packet[1 + length]; + packet[0] = con_id + NUM_RESERVED_PORTS; + memcpy(packet + 1, data, length); + return write_packet_TCP_secure_connection(con, packet, sizeof(packet)); +} + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure. + */ +int send_oob_packet(TCP_Client_Connection *con, uint8_t *public_key, uint8_t *data, uint16_t length) +{ + if (length == 0 || length > TCP_MAX_OOB_DATA_LENGTH) + return -1; + + uint8_t packet[1 + crypto_box_PUBLICKEYBYTES + length]; + packet[0] = TCP_PACKET_OOB_SEND; + memcpy(packet + 1, public_key, crypto_box_PUBLICKEYBYTES); + memcpy(packet + 1 + crypto_box_PUBLICKEYBYTES, data, length); + return write_packet_TCP_secure_connection(con, packet, sizeof(packet)); +} + + +/* Set the number that will be used as an argument in the callbacks related to con_id. + * + * When not set by this function, the number is ~0. + * + * return 0 on success. + * return -1 on failure. + */ +int set_tcp_connection_number(TCP_Client_Connection *con, uint8_t con_id, uint32_t number) +{ + if (con_id >= NUM_CLIENT_CONNECTIONS) + return -1; + + if (con->connections[con_id].status == 0) + return -1; + + con->connections[con_id].number = number; + return 0; +} + +void routing_data_handler(TCP_Client_Connection *con, int (*data_callback)(void *object, uint32_t number, + uint8_t connection_id, uint8_t *data, uint16_t length), void *object) +{ + con->data_callback = data_callback; + con->data_callback_object = object; +} + +void oob_data_handler(TCP_Client_Connection *con, int (*oob_data_callback)(void *object, uint8_t *public_key, + uint8_t *data, uint16_t length), void *object) +{ + con->oob_data_callback = oob_data_callback; + con->oob_data_callback_object = object; +} + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure (connection must be killed). + */ +static int send_disconnect_notification(TCP_Client_Connection *con, uint8_t id) +{ + uint8_t packet[1 + 1]; + packet[0] = TCP_PACKET_DISCONNECT_NOTIFICATION; + packet[1] = id; + return write_packet_TCP_secure_connection(con, packet, sizeof(packet)); +} + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure (connection must be killed). + */ +static int send_ping_request(TCP_Client_Connection *con, uint64_t ping_id) +{ + uint8_t packet[1 + sizeof(uint64_t)]; + packet[0] = TCP_PACKET_PING; + memcpy(packet + 1, &ping_id, sizeof(uint64_t)); + return write_packet_TCP_secure_connection(con, packet, sizeof(packet)); +} + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure (connection must be killed). + */ +static int send_ping_response(TCP_Client_Connection *con, uint64_t ping_id) +{ + uint8_t packet[1 + sizeof(uint64_t)]; + packet[0] = TCP_PACKET_PONG; + memcpy(packet + 1, &ping_id, sizeof(uint64_t)); + return write_packet_TCP_secure_connection(con, packet, sizeof(packet)); +} + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure (connection must be killed). + */ +int send_disconnect_request(TCP_Client_Connection *con, uint8_t con_id) +{ + if (con_id >= NUM_CLIENT_CONNECTIONS) + return -1; + + con->connections[con_id].status = 0; + con->connections[con_id].number = 0; + return send_disconnect_notification(con, con_id + NUM_RESERVED_PORTS); +} + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure (connection must be killed). + */ +int send_onion_request(TCP_Client_Connection *con, uint8_t *data, uint16_t length) +{ + uint8_t packet[1 + length]; + packet[0] = TCP_PACKET_ONION_REQUEST; + memcpy(packet + 1, data, length); + return write_packet_TCP_secure_connection(con, packet, sizeof(packet)); +} + +void onion_response_handler(TCP_Client_Connection *con, int (*onion_callback)(void *object, uint8_t *data, + uint16_t length), void *object) +{ + con->onion_callback = onion_callback; + con->onion_callback_object = object; +} + /* Create new TCP connection to ip_port/public_key */ TCP_Client_Connection *new_TCP_connection(IP_Port ip_port, uint8_t *public_key, uint8_t *self_public_key, @@ -149,6 +352,11 @@ TCP_Client_Connection *new_TCP_connection(IP_Port ip_port, uint8_t *public_key, return NULL; } + if (!set_socket_nosigpipe(sock)) { + kill_sock(sock); + return 0; + } + if (!(set_socket_nonblock(sock) && connect_sock_to(sock, ip_port))) { kill_sock(sock); return NULL; @@ -164,6 +372,7 @@ TCP_Client_Connection *new_TCP_connection(IP_Port ip_port, uint8_t *public_key, temp->status = TCP_CLIENT_CONNECTING; temp->sock = sock; memcpy(temp->public_key, public_key, crypto_box_PUBLICKEYBYTES); + temp->ip_port = ip_port; if (generate_handshake(temp, self_public_key, self_secret_key) == -1) { kill_sock(sock); @@ -176,8 +385,181 @@ TCP_Client_Connection *new_TCP_connection(IP_Port ip_port, uint8_t *public_key, return temp; } -static int do_confirmed_TCP(TCP_Client_Connection *TCP_connection) +/* return 0 on success + * return -1 on failure + */ +static int handle_TCP_packet(TCP_Client_Connection *conn, uint8_t *data, uint16_t length) { + if (length <= 1) + return -1; + + switch (data[0]) { + case TCP_PACKET_ROUTING_RESPONSE: { + if (length != 1 + 1 + crypto_box_PUBLICKEYBYTES) + return -1; + + if (data[1] < NUM_RESERVED_PORTS) + return 0; + + uint8_t con_id = data[1] - NUM_RESERVED_PORTS; + + if (conn->connections[con_id].status != 0) + return 0; + + conn->connections[con_id].status = 1; + conn->connections[con_id].number = ~0; + memcpy(conn->connections[con_id].public_key, data + 2, crypto_box_PUBLICKEYBYTES); + + if (conn->response_callback) + conn->response_callback(conn->response_callback_object, con_id, conn->connections[con_id].public_key); + + return 0; + } + + case TCP_PACKET_CONNECTION_NOTIFICATION: { + if (length != 1 + 1) + return -1; + + if (data[1] < NUM_RESERVED_PORTS) + return -1; + + uint8_t con_id = data[1] - NUM_RESERVED_PORTS; + + if (conn->connections[con_id].status != 1) + return -1; + + conn->connections[con_id].status = 2; + + if (conn->status_callback) + conn->status_callback(conn->status_callback_object, conn->connections[con_id].number, con_id, + conn->connections[con_id].status); + + return 0; + } + + case TCP_PACKET_DISCONNECT_NOTIFICATION: { + if (length != 1 + 1) + return -1; + + if (data[1] < NUM_RESERVED_PORTS) + return -1; + + uint8_t con_id = data[1] - NUM_RESERVED_PORTS; + + if (conn->connections[con_id].status == 0) + return 0; + + if (conn->connections[con_id].status != 2) + return -1; + + conn->connections[con_id].status = 1; + + if (conn->status_callback) + conn->status_callback(conn->status_callback_object, conn->connections[con_id].number, con_id, + conn->connections[con_id].status); + + return 0; + } + + case TCP_PACKET_PING: { + if (length != 1 + sizeof(uint64_t)) + return -1; + + uint64_t ping_id; + memcpy(&ping_id, data + 1, sizeof(uint64_t)); + send_ping_response(conn, ping_id); + return 0; + } + + case TCP_PACKET_PONG: { + if (length != 1 + sizeof(uint64_t)) + return -1; + + uint64_t ping_id; + memcpy(&ping_id, data + 1, sizeof(uint64_t)); + + if (ping_id) { + if (ping_id == conn->ping_id) { + conn->ping_id = 0; + } + + return 0; + } else { + return -1; + } + } + + case TCP_PACKET_OOB_RECV: { + if (length <= 1 + crypto_box_PUBLICKEYBYTES) + return -1; + + if (conn->oob_data_callback) + conn->oob_data_callback(conn->oob_data_callback_object, data + 1, data + 1 + crypto_box_PUBLICKEYBYTES, + length - (1 + crypto_box_PUBLICKEYBYTES)); + + return 0; + } + + case TCP_PACKET_ONION_RESPONSE: { + conn->onion_callback(conn->onion_callback_object, data + 1, length - 1); + return 0; + } + + default: { + if (data[0] < NUM_RESERVED_PORTS) + return -1; + + uint8_t con_id = data[0] - NUM_RESERVED_PORTS; + + if (conn->data_callback) + conn->data_callback(conn->data_callback_object, conn->connections[con_id].number, con_id, data + 1, length - 1); + } + } + + return 0; +} + +static int do_confirmed_TCP(TCP_Client_Connection *conn) +{ + send_pending_data(conn); + uint8_t packet[MAX_PACKET_SIZE]; + int len; + + if (is_timeout(conn->last_pinged, TCP_PING_FREQUENCY)) { + uint64_t ping_id = random_64b(); + + if (!ping_id) + ++ping_id; + + int ret = send_ping_request(conn, ping_id); + + if (ret == 1) { + conn->last_pinged = unix_time(); + conn->ping_id = ping_id; + } else { + if (is_timeout(conn->last_pinged, TCP_PING_FREQUENCY + TCP_PING_TIMEOUT)) { + conn->status = TCP_CLIENT_DISCONNECTED; + } + } + } + + if (conn->ping_id && is_timeout(conn->last_pinged, TCP_PING_TIMEOUT)) { + conn->status = TCP_CLIENT_DISCONNECTED; + return 0; + } + + while ((len = read_packet_TCP_secure_connection(conn->sock, &conn->next_packet_length, conn->shared_key, + conn->recv_nonce, packet, sizeof(packet)))) { + if (len == -1) { + conn->status = TCP_CLIENT_DISCONNECTED; + break; + } + + if (handle_TCP_packet(conn, packet, len) == -1) { + conn->status = TCP_CLIENT_DISCONNECTED; + break; + } + } return 0; } @@ -204,6 +586,7 @@ void do_TCP_connection(TCP_Client_Connection *TCP_connection) if (sizeof(data) == len) { if (handle_handshake(TCP_connection, data) == 0) { + TCP_connection->kill_at = ~0; TCP_connection->status = TCP_CLIENT_CONFIRMED; } else { TCP_connection->kill_at = 0; @@ -225,7 +608,10 @@ void do_TCP_connection(TCP_Client_Connection *TCP_connection) */ void kill_TCP_connection(TCP_Client_Connection *TCP_connection) { + if (TCP_connection == NULL) + return; + kill_sock(TCP_connection->sock); memset(TCP_connection, 0, sizeof(TCP_Client_Connection)); free(TCP_connection); -} \ No newline at end of file +} diff --git a/toxcore/TCP_client.h b/toxcore/TCP_client.h index eb2aa39c..afb95392 100644 --- a/toxcore/TCP_client.h +++ b/toxcore/TCP_client.h @@ -24,7 +24,7 @@ #ifndef TCP_CLIENT_H #define TCP_CLIENT_H -#include "net_crypto.h" +#include "crypto_core.h" #include "TCP_server.h" #define TCP_CONNECTION_TIMEOUT 10 @@ -40,6 +40,7 @@ typedef struct { uint8_t status; sock_t sock; uint8_t public_key[crypto_box_PUBLICKEYBYTES]; /* public key of the server */ + IP_Port ip_port; /* The ip and port of the server */ uint8_t recv_nonce[crypto_box_NONCEBYTES]; /* Nonce of received packets. */ uint8_t sent_nonce[crypto_box_NONCEBYTES]; /* Nonce of sent packets. */ uint8_t shared_key[crypto_box_BEFORENMBYTES]; @@ -55,6 +56,25 @@ typedef struct { uint64_t last_pinged; uint64_t ping_id; + + void *net_crypto_pointer; + uint32_t net_crypto_location; + struct { + uint8_t status; /* 0 if not used, 1 if other is offline, 2 if other is online. */ + uint8_t public_key[crypto_box_PUBLICKEYBYTES]; + uint32_t number; + } connections[NUM_CLIENT_CONNECTIONS]; + int (*response_callback)(void *object, uint8_t connection_id, uint8_t *public_key); + void *response_callback_object; + int (*status_callback)(void *object, uint32_t number, uint8_t connection_id, uint8_t status); + void *status_callback_object; + int (*data_callback)(void *object, uint32_t number, uint8_t connection_id, uint8_t *data, uint16_t length); + void *data_callback_object; + int (*oob_data_callback)(void *object, uint8_t *public_key, uint8_t *data, uint16_t length); + void *oob_data_callback_object; + + int (*onion_callback)(void *object, uint8_t *data, uint16_t length); + void *onion_callback_object; } TCP_Client_Connection; /* Create new TCP connection to ip_port/public_key @@ -70,9 +90,54 @@ void do_TCP_connection(TCP_Client_Connection *TCP_connection); */ void kill_TCP_connection(TCP_Client_Connection *TCP_connection); -int get_TCP_connection_status(TCP_Client_Connection *TCP_connection); +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure (connection must be killed). + */ +int send_onion_request(TCP_Client_Connection *con, uint8_t *data, uint16_t length); +void onion_response_handler(TCP_Client_Connection *con, int (*onion_callback)(void *object, uint8_t *data, + uint16_t length), void *object); -int read_TCP_connection(TCP_Client_Connection *TCP_connection, uint8_t *data); +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure (connection must be killed). + */ +int send_routing_request(TCP_Client_Connection *con, uint8_t *public_key); +void routing_response_handler(TCP_Client_Connection *con, int (*response_callback)(void *object, uint8_t connection_id, + uint8_t *public_key), void *object); +void routing_status_handler(TCP_Client_Connection *con, int (*status_callback)(void *object, uint32_t number, + uint8_t connection_id, uint8_t status), void *object); + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure (connection must be killed). + */ +int send_disconnect_request(TCP_Client_Connection *con, uint8_t con_id); + +/* Set the number that will be used as an argument in the callbacks related to con_id. + * + * When not set by this function, the number is ~0. + * + * return 0 on success. + * return -1 on failure. + */ +int set_tcp_connection_number(TCP_Client_Connection *con, uint8_t con_id, uint32_t number); + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure. + */ +int send_data(TCP_Client_Connection *con, uint8_t con_id, uint8_t *data, uint16_t length); +void routing_data_handler(TCP_Client_Connection *con, int (*data_callback)(void *object, uint32_t number, + uint8_t connection_id, uint8_t *data, uint16_t length), void *object); + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure. + */ +int send_oob_packet(TCP_Client_Connection *con, uint8_t *public_key, uint8_t *data, uint16_t length); +void oob_data_handler(TCP_Client_Connection *con, int (*oob_data_callback)(void *object, uint8_t *public_key, + uint8_t *data, uint16_t length), void *object); #endif diff --git a/toxcore/TCP_server.c b/toxcore/TCP_server.c index 4eed1209..ceab5f10 100644 --- a/toxcore/TCP_server.c +++ b/toxcore/TCP_server.c @@ -20,6 +20,10 @@ * */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include "TCP_server.h" #if !defined(_WIN32) && !defined(__WIN32__) && !defined (WIN32) @@ -69,17 +73,46 @@ static int realloc_connection(TCP_Server *TCP_server, uint32_t num) return 0; } + if (num == TCP_server->size_accepted_connections) { + return 0; + } + TCP_Secure_Connection *new_connections = realloc(TCP_server->accepted_connection_array, num * sizeof(TCP_Secure_Connection)); if (new_connections == NULL) return -1; + if (num > TCP_server->size_accepted_connections) { + uint32_t old_size = TCP_server->size_accepted_connections; + uint32_t size_new_entries = (num - old_size) * sizeof(TCP_Secure_Connection); + memset(new_connections + old_size, 0, size_new_entries); + } + TCP_server->accepted_connection_array = new_connections; TCP_server->size_accepted_connections = num; return 0; } +/* return index corresponding to connection with peer on success + * return -1 on failure. + */ +static int get_TCP_connection_index(TCP_Server *TCP_server, uint8_t *public_key) +{ + //TODO optimize this function. + uint32_t i; + + for (i = 0; i < TCP_server->size_accepted_connections; ++i) { + if (memcmp(TCP_server->accepted_connection_array[i].public_key, public_key, crypto_box_PUBLICKEYBYTES) == 0) + return i; + } + + return -1; +} + + +static int kill_accepted(TCP_Server *TCP_server, int index); + /* Add accepted TCP connection to the list. * * return index on success @@ -87,7 +120,12 @@ static int realloc_connection(TCP_Server *TCP_server, uint32_t num) */ static int add_accepted(TCP_Server *TCP_server, TCP_Secure_Connection *con) { - int index = -1; + int index = get_TCP_connection_index(TCP_server, con->public_key); + + if (index != -1) { /* If an old connection to the same public key exists, kill it. */ + kill_accepted(TCP_server, index); + index = -1; + } if (TCP_server->size_accepted_connections == TCP_server->num_accepted_connections) { if (realloc_connection(TCP_server, TCP_server->size_accepted_connections + 4) == -1) @@ -141,22 +179,6 @@ static int del_accepted(TCP_Server *TCP_server, int index) return 0; } -/* return index corresponding to connection with peer on success - * return -1 on failure. - */ -static int get_TCP_connection_index(TCP_Server *TCP_server, uint8_t *public_key) -{ - //TODO optimize this function. - uint32_t i; - - for (i = 0; i < TCP_server->size_accepted_connections; ++i) { - if (memcmp(TCP_server->accepted_connection_array[i].public_key, public_key, crypto_box_PUBLICKEYBYTES) == 0) - return i; - } - - return -1; -} - /* Read the next two bytes in TCP stream then convert them to * length (host byte order). * @@ -224,14 +246,15 @@ int read_TCP_packet(sock_t sock, uint8_t *data, uint16_t length) return -1; } -/* return length of recieved packet on success. +/* return length of received packet on success. * return 0 if could not read any packet. * return -1 on failure (connection must be killed). */ -static int read_packet_TCP_secure_connection(TCP_Secure_Connection *con, uint8_t *data, uint16_t max_len) +int read_packet_TCP_secure_connection(sock_t sock, uint16_t *next_packet_length, uint8_t *shared_key, + uint8_t *recv_nonce, uint8_t *data, uint16_t max_len) { - if (con->next_packet_length == 0) { - uint16_t len = read_TCP_length(con->sock); + if (*next_packet_length == 0) { + uint16_t len = read_TCP_length(sock); if (len == (uint16_t)~0) return -1; @@ -239,26 +262,26 @@ static int read_packet_TCP_secure_connection(TCP_Secure_Connection *con, uint8_t if (len == 0) return 0; - con->next_packet_length = len; + *next_packet_length = len; } - if (max_len + crypto_box_MACBYTES < con->next_packet_length) + if (max_len + crypto_box_MACBYTES < *next_packet_length) return -1; - uint8_t data_encrypted[con->next_packet_length]; - int len_packet = read_TCP_packet(con->sock, data_encrypted, con->next_packet_length); + uint8_t data_encrypted[*next_packet_length]; + int len_packet = read_TCP_packet(sock, data_encrypted, *next_packet_length); - if (len_packet != con->next_packet_length) + if (len_packet != *next_packet_length) return 0; - con->next_packet_length = 0; + *next_packet_length = 0; - int len = decrypt_data_fast(con->shared_key, con->recv_nonce, data_encrypted, len_packet, data); + int len = decrypt_data_symmetric(shared_key, recv_nonce, data_encrypted, len_packet, data); if (len + crypto_box_MACBYTES != len_packet) return -1; - increment_nonce(con->recv_nonce); + increment_nonce(recv_nonce); return len; } @@ -308,7 +331,7 @@ static int write_packet_TCP_secure_connection(TCP_Secure_Connection *con, uint8_ uint16_t c_length = htons(length + crypto_box_MACBYTES); memcpy(packet, &c_length, sizeof(uint16_t)); - int len = encrypt_data_fast(con->shared_key, con->sent_nonce, data, length, packet + sizeof(uint16_t)); + int len = encrypt_data_symmetric(con->shared_key, con->sent_nonce, data, length, packet + sizeof(uint16_t)); if ((unsigned int)len != (sizeof(packet) - sizeof(uint16_t))) return -1; @@ -337,6 +360,33 @@ static void kill_TCP_connection(TCP_Secure_Connection *con) memset(con, 0, sizeof(TCP_Secure_Connection)); } +static int rm_connection_index(TCP_Server *TCP_server, TCP_Secure_Connection *con, uint8_t con_number); + +/* Kill an accepted TCP_Secure_Connection + * + * return -1 on failure. + * return 0 on success. + */ +static int kill_accepted(TCP_Server *TCP_server, int index) +{ + if ((uint32_t)index >= TCP_server->size_accepted_connections) + return -1; + + uint32_t i; + + for (i = 0; i < NUM_CLIENT_CONNECTIONS; ++i) { + rm_connection_index(TCP_server, &TCP_server->accepted_connection_array[index], i); + } + + sock_t sock = TCP_server->accepted_connection_array[index].sock; + + if (del_accepted(TCP_server, index) != 0) + return -1; + + kill_sock(sock); + return 0; +} + /* return 1 if everything went well. * return -1 if the connection must be killed. */ @@ -351,8 +401,8 @@ static int handle_TCP_handshake(TCP_Secure_Connection *con, uint8_t *data, uint1 uint8_t shared_key[crypto_box_BEFORENMBYTES]; encrypt_precompute(data, self_secret_key, shared_key); uint8_t plain[TCP_HANDSHAKE_PLAIN_SIZE]; - int len = decrypt_data_fast(shared_key, data + crypto_box_PUBLICKEYBYTES, - data + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, TCP_HANDSHAKE_PLAIN_SIZE + crypto_box_MACBYTES, plain); + int len = decrypt_data_symmetric(shared_key, data + crypto_box_PUBLICKEYBYTES, + data + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, TCP_HANDSHAKE_PLAIN_SIZE + crypto_box_MACBYTES, plain); if (len != TCP_HANDSHAKE_PLAIN_SIZE) return -1; @@ -368,7 +418,8 @@ static int handle_TCP_handshake(TCP_Secure_Connection *con, uint8_t *data, uint1 uint8_t response[TCP_SERVER_HANDSHAKE_SIZE]; new_nonce(response); - len = encrypt_data_fast(shared_key, response, resp_plain, TCP_HANDSHAKE_PLAIN_SIZE, response + crypto_box_NONCEBYTES); + len = encrypt_data_symmetric(shared_key, response, resp_plain, TCP_HANDSHAKE_PLAIN_SIZE, + response + crypto_box_NONCEBYTES); if (len != TCP_HANDSHAKE_PLAIN_SIZE + crypto_box_MACBYTES) return -1; @@ -449,9 +500,16 @@ static int handle_TCP_routing_req(TCP_Server *TCP_server, uint32_t con_id, uint8 } for (i = 0; i < NUM_CLIENT_CONNECTIONS; ++i) { - if (con->connections[i].status == 0) { + if (con->connections[i].status != 0) { + if (memcmp(public_key, con->connections[i].public_key, crypto_box_PUBLICKEYBYTES) == 0) { + if (send_routing_response(con, i + NUM_RESERVED_PORTS, public_key) == -1) { + return -1; + } else { + return 0; + } + } + } else if (index == (uint32_t)~0) { index = i; - break; } } @@ -502,7 +560,37 @@ static int handle_TCP_routing_req(TCP_Server *TCP_server, uint32_t con_id, uint8 return 0; } -static int disconnect_conection_index(TCP_Server *TCP_server, TCP_Secure_Connection *con, uint8_t con_number) +/* return 0 on success. + * return -1 on failure (connection must be killed). + */ +static int handle_TCP_oob_send(TCP_Server *TCP_server, uint32_t con_id, uint8_t *public_key, uint8_t *data, + uint16_t length) +{ + if (length == 0 || length > TCP_MAX_OOB_DATA_LENGTH) + return -1; + + TCP_Secure_Connection *con = &TCP_server->accepted_connection_array[con_id]; + + int other_index = get_TCP_connection_index(TCP_server, public_key); + + if (other_index != -1) { + uint8_t resp_packet[1 + crypto_box_PUBLICKEYBYTES + length]; + resp_packet[0] = TCP_PACKET_OOB_RECV; + memcpy(resp_packet + 1, con->public_key, crypto_box_PUBLICKEYBYTES); + memcpy(resp_packet + 1 + crypto_box_PUBLICKEYBYTES, data, length); + write_packet_TCP_secure_connection(&TCP_server->accepted_connection_array[other_index], resp_packet, + sizeof(resp_packet)); + } + + return 0; +} + +/* Remove connection with con_number from the connections array of con. + * + * return -1 on failure. + * return 0 on success. + */ +static int rm_connection_index(TCP_Server *TCP_server, TCP_Secure_Connection *con, uint8_t con_number) { if (con_number >= NUM_CLIENT_CONNECTIONS) return -1; @@ -526,8 +614,6 @@ static int disconnect_conection_index(TCP_Server *TCP_server, TCP_Secure_Connect con->connections[con_number].index = 0; con->connections[con_number].other_id = 0; con->connections[con_number].status = 0; - //TODO: return values? - send_disconnect_notification(con, con_number); return 0; } else { return -1; @@ -586,7 +672,7 @@ static int handle_TCP_packet(TCP_Server *TCP_server, uint32_t con_id, uint8_t *d if (length != 2) return -1; - return disconnect_conection_index(TCP_server, con, data[1] - NUM_RESERVED_PORTS); + return rm_connection_index(TCP_server, con, data[1] - NUM_RESERVED_PORTS); } case TCP_PACKET_PING: { @@ -618,6 +704,14 @@ static int handle_TCP_packet(TCP_Server *TCP_server, uint32_t con_id, uint8_t *d } } + case TCP_PACKET_OOB_SEND: { + if (length <= 1 + crypto_box_PUBLICKEYBYTES) + return -1; + + return handle_TCP_oob_send(TCP_server, con_id, data + 1, data + 1 + crypto_box_PUBLICKEYBYTES, + length - (1 + crypto_box_PUBLICKEYBYTES)); + } + case TCP_PACKET_ONION_REQUEST: { if (TCP_server->onion) { if (length <= 1 + crypto_box_NONCEBYTES + ONION_SEND_BASE * 2) @@ -642,22 +736,22 @@ static int handle_TCP_packet(TCP_Server *TCP_server, uint32_t con_id, uint8_t *d if (data[0] < NUM_RESERVED_PORTS) return -1; - uint8_t con_id = data[0] - NUM_RESERVED_PORTS; + uint8_t c_id = data[0] - NUM_RESERVED_PORTS; - if (con_id >= NUM_CLIENT_CONNECTIONS) + if (c_id >= NUM_CLIENT_CONNECTIONS) return -1; - if (con->connections[con_id].status == 0) + if (con->connections[c_id].status == 0) return -1; - if (con->connections[con_id].status != 2) + if (con->connections[c_id].status != 2) return 0; - uint32_t index = con->connections[con_id].index; - uint8_t other_con_id = con->connections[con_id].other_id + NUM_RESERVED_PORTS; + uint32_t index = con->connections[c_id].index; + uint8_t other_c_id = con->connections[c_id].other_id + NUM_RESERVED_PORTS; uint8_t new_data[length]; memcpy(new_data, data, length); - new_data[0] = other_con_id; + new_data[0] = other_c_id; int ret = write_packet_TCP_secure_connection(&TCP_server->accepted_connection_array[index], new_data, length); if (ret == -1) @@ -678,11 +772,8 @@ static int confirm_TCP_connection(TCP_Server *TCP_server, TCP_Secure_Connection if (index == -1) return -1; - TCP_Secure_Connection *conn = &TCP_server->accepted_connection_array[index]; - if (handle_TCP_packet(TCP_server, index, data, length) == -1) { - kill_TCP_connection(conn); - del_accepted(TCP_server, index); + kill_accepted(TCP_server, index); } return 0; @@ -701,6 +792,11 @@ static int accept_connection(TCP_Server *TCP_server, sock_t sock) return 0; } + if (!set_socket_nosigpipe(sock)) { + kill_sock(sock); + return 0; + } + TCP_Secure_Connection *conn = &TCP_server->incomming_connection_queue[TCP_server->incomming_connection_queue_index % MAX_INCOMMING_CONNECTIONS]; @@ -848,7 +944,8 @@ static void do_TCP_unconfirmed(TCP_Server *TCP_server) continue; uint8_t packet[MAX_PACKET_SIZE]; - int len = read_packet_TCP_secure_connection(conn, packet, sizeof(packet)); + int len = read_packet_TCP_secure_connection(conn->sock, &conn->next_packet_length, conn->shared_key, conn->recv_nonce, + packet, sizeof(packet)); if (len == 0) { continue; @@ -889,12 +986,16 @@ static void do_TCP_confirmed(TCP_Server *TCP_server) if (ret == 1) { conn->last_pinged = unix_time(); conn->ping_id = ping_id; + } else { + if (is_timeout(conn->last_pinged, TCP_PING_FREQUENCY + TCP_PING_TIMEOUT)) { + kill_accepted(TCP_server, i); + continue; + } } } if (conn->ping_id && is_timeout(conn->last_pinged, TCP_PING_TIMEOUT)) { - kill_TCP_connection(conn); - del_accepted(TCP_server, i); + kill_accepted(TCP_server, i); continue; } @@ -902,16 +1003,15 @@ static void do_TCP_confirmed(TCP_Server *TCP_server) uint8_t packet[MAX_PACKET_SIZE]; int len; - while ((len = read_packet_TCP_secure_connection(conn, packet, sizeof(packet)))) { + while ((len = read_packet_TCP_secure_connection(conn->sock, &conn->next_packet_length, conn->shared_key, + conn->recv_nonce, packet, sizeof(packet)))) { if (len == -1) { - kill_TCP_connection(conn); - del_accepted(TCP_server, i); + kill_accepted(TCP_server, i); break; } if (handle_TCP_packet(TCP_server, i, packet, len) == -1) { - kill_TCP_connection(conn); - del_accepted(TCP_server, i); + kill_accepted(TCP_server, i); break; } } diff --git a/toxcore/TCP_server.h b/toxcore/TCP_server.h index 3ae0eba4..fc8c234b 100644 --- a/toxcore/TCP_server.h +++ b/toxcore/TCP_server.h @@ -23,10 +23,10 @@ #ifndef TCP_SERVER_H #define TCP_SERVER_H -#include "net_crypto.h" +#include "crypto_core.h" #include "onion.h" -#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) +#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__MACH__) #define MSG_NOSIGNAL 0 #endif @@ -39,6 +39,7 @@ #define TCP_HANDSHAKE_PLAIN_SIZE (crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES) #define TCP_SERVER_HANDSHAKE_SIZE (crypto_box_NONCEBYTES + TCP_HANDSHAKE_PLAIN_SIZE + crypto_box_MACBYTES) #define TCP_CLIENT_HANDSHAKE_SIZE (crypto_box_PUBLICKEYBYTES + TCP_SERVER_HANDSHAKE_SIZE) +#define TCP_MAX_OOB_DATA_LENGTH 1024 #define NUM_RESERVED_PORTS 16 #define NUM_CLIENT_CONNECTIONS (256 - NUM_RESERVED_PORTS) @@ -49,16 +50,16 @@ #define TCP_PACKET_DISCONNECT_NOTIFICATION 3 #define TCP_PACKET_PING 4 #define TCP_PACKET_PONG 5 +#define TCP_PACKET_OOB_SEND 6 +#define TCP_PACKET_OOB_RECV 7 #define TCP_PACKET_ONION_REQUEST 8 #define TCP_PACKET_ONION_RESPONSE 9 #define ARRAY_ENTRY_SIZE 6 -#define TCP_ONION_FAMILY (AF_INET6 + 1) - /* frequency to ping connected nodes and timeout in seconds */ #define TCP_PING_FREQUENCY 30 -#define TCP_PING_TIMEOUT 20 +#define TCP_PING_TIMEOUT 10 enum { TCP_STATUS_NO_STATUS, @@ -140,4 +141,12 @@ uint16_t read_TCP_length(sock_t sock); */ int read_TCP_packet(sock_t sock, uint8_t *data, uint16_t length); +/* return length of received packet on success. + * return 0 if could not read any packet. + * return -1 on failure (connection must be killed). + */ +int read_packet_TCP_secure_connection(sock_t sock, uint16_t *next_packet_length, uint8_t *shared_key, + uint8_t *recv_nonce, uint8_t *data, uint16_t max_len); + + #endif diff --git a/toxcore/assoc.c b/toxcore/assoc.c index c8f58c9c..ed1ec241 100644 --- a/toxcore/assoc.c +++ b/toxcore/assoc.c @@ -29,7 +29,7 @@ * Candidates are kept in buckets of hash tables. The hash * function is calculated from the client_id. Up to * HASH_COLLIDE_COUNT alternative positions are tried if - * the inital position is already used by a different entry. + * the initial position is already used by a different entry. * The collision function is multiplicative, not additive. * * A new candidate can bump an existing candidate, if it is diff --git a/toxcore/crypto_core.c b/toxcore/crypto_core.c new file mode 100644 index 00000000..6e92f5b6 --- /dev/null +++ b/toxcore/crypto_core.c @@ -0,0 +1,262 @@ +/* net_crypto.c + * + * Functions for the core crypto. + * + * NOTE: This code has to be perfect. We don't mess around with encryption. + * + * Copyright (C) 2013 Tox project All Rights Reserved. + * + * This file is part of Tox. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "crypto_core.h" + + +/* Use this instead of memcmp; not vulnerable to timing attacks. + returns 0 if both mem locations of length are equal, + return -1 if they are not. */ +int crypto_cmp(uint8_t *mem1, uint8_t *mem2, uint32_t length) +{ + if (length == 16) { + return crypto_verify_16(mem1, mem2); + } else if (length == 32) { + return crypto_verify_32(mem1, mem2); + } + + unsigned int i, check = 0; + + for (i = 0; i < length; ++i) { + check |= mem1[i] ^ mem2[i]; + } + + return (1 & ((check - 1) >> 8)) - 1; +} + +/* return a random number. + */ +uint32_t random_int(void) +{ + uint32_t randnum; + randombytes((uint8_t *)&randnum , sizeof(randnum)); + return randnum; +} + +uint64_t random_64b(void) +{ + uint64_t randnum; + randombytes((uint8_t *)&randnum, sizeof(randnum)); + return randnum; +} + +/* Precomputes the shared key from their public_key and our secret_key. + * This way we can avoid an expensive elliptic curve scalar multiply for each + * encrypt/decrypt operation. + * enc_key has to be crypto_box_BEFORENMBYTES bytes long. + */ +void encrypt_precompute(uint8_t *public_key, uint8_t *secret_key, uint8_t *enc_key) +{ + crypto_box_beforenm(enc_key, public_key, secret_key); +} + +int encrypt_data_symmetric(uint8_t *secret_key, uint8_t *nonce, uint8_t *plain, uint32_t length, uint8_t *encrypted) +{ + if (length == 0) + return -1; + + uint8_t temp_plain[length + crypto_box_ZEROBYTES]; + uint8_t temp_encrypted[length + crypto_box_MACBYTES + crypto_box_BOXZEROBYTES]; + + memset(temp_plain, 0, crypto_box_ZEROBYTES); + memcpy(temp_plain + crypto_box_ZEROBYTES, plain, length); // Pad the message with 32 0 bytes. + + if (crypto_box_afternm(temp_encrypted, temp_plain, length + crypto_box_ZEROBYTES, nonce, secret_key) != 0) + return -1; + + /* Unpad the encrypted message. */ + memcpy(encrypted, temp_encrypted + crypto_box_BOXZEROBYTES, length + crypto_box_MACBYTES); + return length + crypto_box_MACBYTES; +} + +int decrypt_data_symmetric(uint8_t *secret_key, uint8_t *nonce, uint8_t *encrypted, uint32_t length, uint8_t *plain) +{ + if (length <= crypto_box_BOXZEROBYTES) + return -1; + + uint8_t temp_plain[length + crypto_box_ZEROBYTES]; + uint8_t temp_encrypted[length + crypto_box_BOXZEROBYTES]; + + memset(temp_plain, 0, crypto_box_BOXZEROBYTES); + memcpy(temp_encrypted + crypto_box_BOXZEROBYTES, encrypted, length); // Pad the message with 16 0 bytes. + + if (crypto_box_open_afternm(temp_plain, temp_encrypted, length + crypto_box_BOXZEROBYTES, nonce, secret_key) != 0) + return -1; + + memcpy(plain, temp_plain + crypto_box_ZEROBYTES, length - crypto_box_MACBYTES); + return length - crypto_box_MACBYTES; +} + +int encrypt_data(uint8_t *public_key, uint8_t *secret_key, uint8_t *nonce, + uint8_t *plain, uint32_t length, uint8_t *encrypted) +{ + uint8_t k[crypto_box_BEFORENMBYTES]; + encrypt_precompute(public_key, secret_key, k); + return encrypt_data_symmetric(k, nonce, plain, length, encrypted); +} + +int decrypt_data(uint8_t *public_key, uint8_t *secret_key, uint8_t *nonce, + uint8_t *encrypted, uint32_t length, uint8_t *plain) +{ + uint8_t k[crypto_box_BEFORENMBYTES]; + encrypt_precompute(public_key, secret_key, k); + return decrypt_data_symmetric(k, nonce, encrypted, length, plain); +} + + +/* Increment the given nonce by 1. */ +void increment_nonce(uint8_t *nonce) +{ + uint32_t i; + + for (i = crypto_box_NONCEBYTES; i != 0; --i) { + ++nonce[i - 1]; + + if (nonce[i - 1] != 0) + break; + } +} +/* increment the given nonce by num */ +void increment_nonce_number(uint8_t *nonce, uint32_t num) +{ + uint32_t num1, num2; + memcpy(&num1, nonce + (crypto_box_NONCEBYTES - sizeof(num1)), sizeof(num1)); + num1 = ntohl(num1); + num2 = num + num1; + + if (num2 < num1) { + uint32_t i; + + for (i = crypto_box_NONCEBYTES - sizeof(num1); i != 0; --i) { + ++nonce[i - 1]; + + if (nonce[i - 1] != 0) + break; + } + } + + num2 = htonl(num2); + memcpy(nonce + (crypto_box_NONCEBYTES - sizeof(num2)), &num2, sizeof(num2)); +} + +/* Fill the given nonce with random bytes. */ +void random_nonce(uint8_t *nonce) +{ + randombytes(nonce, crypto_box_NONCEBYTES); +} + +/* Fill a key crypto_box_KEYBYTES big with random bytes */ +void new_symmetric_key(uint8_t *key) +{ + randombytes(key, crypto_box_KEYBYTES); +} + +static uint8_t base_nonce[crypto_box_NONCEBYTES]; +static uint8_t nonce_set = 0; + +/* Gives a nonce guaranteed to be different from previous ones.*/ +void new_nonce(uint8_t *nonce) +{ + if (nonce_set == 0) { + random_nonce(base_nonce); + nonce_set = 1; + } + + increment_nonce(base_nonce); + memcpy(nonce, base_nonce, crypto_box_NONCEBYTES); +} + +/* Create a request to peer. + * send_public_key and send_secret_key are the pub/secret keys of the sender. + * recv_public_key is public key of reciever. + * packet must be an array of MAX_CRYPTO_REQUEST_SIZE big. + * Data represents the data we send with the request with length being the length of the data. + * request_id is the id of the request (32 = friend request, 254 = ping request). + * + * return -1 on failure. + * return the length of the created packet on success. + */ +int create_request(uint8_t *send_public_key, uint8_t *send_secret_key, uint8_t *packet, uint8_t *recv_public_key, + uint8_t *data, uint32_t length, uint8_t request_id) +{ + if (MAX_CRYPTO_REQUEST_SIZE < length + 1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1 + + crypto_box_MACBYTES) + return -1; + + uint8_t nonce[crypto_box_NONCEBYTES]; + uint8_t temp[MAX_CRYPTO_REQUEST_SIZE]; + memcpy(temp + 1, data, length); + temp[0] = request_id; + new_nonce(nonce); + int len = encrypt_data(recv_public_key, send_secret_key, nonce, temp, length + 1, + 1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + packet); + + if (len == -1) + return -1; + + packet[0] = NET_PACKET_CRYPTO; + memcpy(packet + 1, recv_public_key, crypto_box_PUBLICKEYBYTES); + memcpy(packet + 1 + crypto_box_PUBLICKEYBYTES, send_public_key, crypto_box_PUBLICKEYBYTES); + memcpy(packet + 1 + crypto_box_PUBLICKEYBYTES * 2, nonce, crypto_box_NONCEBYTES); + + return len + 1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES; +} + +/* Puts the senders public key in the request in public_key, the data from the request + * in data if a friend or ping request was sent to us and returns the length of the data. + * packet is the request packet and length is its length. + * + * return -1 if not valid request. + */ +int handle_request(uint8_t *self_public_key, uint8_t *self_secret_key, uint8_t *public_key, uint8_t *data, + uint8_t *request_id, uint8_t *packet, uint16_t length) +{ + if (length > crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1 + crypto_box_MACBYTES && + length <= MAX_CRYPTO_REQUEST_SIZE) { + if (memcmp(packet + 1, self_public_key, crypto_box_PUBLICKEYBYTES) == 0) { + memcpy(public_key, packet + 1 + crypto_box_PUBLICKEYBYTES, crypto_box_PUBLICKEYBYTES); + uint8_t nonce[crypto_box_NONCEBYTES]; + uint8_t temp[MAX_CRYPTO_REQUEST_SIZE]; + memcpy(nonce, packet + 1 + crypto_box_PUBLICKEYBYTES * 2, crypto_box_NONCEBYTES); + int len1 = decrypt_data(public_key, self_secret_key, nonce, + packet + 1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES, + length - (crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1), temp); + + if (len1 == -1 || len1 == 0) + return -1; + + request_id[0] = temp[0]; + --len1; + memcpy(data, temp + 1, len1); + return len1; + } + } + + return -1; +} diff --git a/toxcore/crypto_core.h b/toxcore/crypto_core.h new file mode 100644 index 00000000..6b69f917 --- /dev/null +++ b/toxcore/crypto_core.h @@ -0,0 +1,142 @@ +/* crypto_core.h + * + * Functions for the core crypto. + * + * Copyright (C) 2013 Tox project All Rights Reserved. + * + * This file is part of Tox. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + * + */ +#ifndef CORE_CRYPTO_H +#define CORE_CRYPTO_H + +#include "network.h" + +#ifndef VANILLA_NACL +/* We use libsodium by default. */ +#include +#else +#include +#include +#include +#include +#include +#include +#define crypto_box_MACBYTES (crypto_box_ZEROBYTES - crypto_box_BOXZEROBYTES) +#endif + +#define crypto_box_KEYBYTES (crypto_box_BEFORENMBYTES) + +/* Use this instead of memcmp; not vulnerable to timing attacks. + returns 0 if both mem locations of length are equal, + return -1 if they are not. */ +int crypto_cmp(uint8_t *mem1, uint8_t *mem2, uint32_t length); + +/* return a random number. + * + * random_int for a 32bin int. + * random_64b for a 64bit int. + */ +uint32_t random_int(void); +uint64_t random_64b(void); + + +/* Encrypts plain of length length to encrypted of length + 16 using the + * public key(32 bytes) of the receiver and the secret key of the sender and a 24 byte nonce. + * + * return -1 if there was a problem. + * return length of encrypted data if everything was fine. + */ +int encrypt_data(uint8_t *public_key, uint8_t *secret_key, uint8_t *nonce, + uint8_t *plain, uint32_t length, uint8_t *encrypted); + + +/* Decrypts encrypted of length length to plain of length length - 16 using the + * public key(32 bytes) of the sender, the secret key of the receiver and a 24 byte nonce. + * + * return -1 if there was a problem (decryption failed). + * return length of plain data if everything was fine. + */ +int decrypt_data(uint8_t *public_key, uint8_t *secret_key, uint8_t *nonce, + uint8_t *encrypted, uint32_t length, uint8_t *plain); + +/* Fast encrypt/decrypt operations. Use if this is not a one-time communication. + encrypt_precompute does the shared-key generation once so it does not have + to be preformed on every encrypt/decrypt. */ +void encrypt_precompute(uint8_t *public_key, uint8_t *secret_key, uint8_t *enc_key); + +/* Encrypts plain of length length to encrypted of length + 16 using a + * secret key crypto_box_KEYBYTES big and a 24 byte nonce. + * + * return -1 if there was a problem. + * return length of encrypted data if everything was fine. + */ +int encrypt_data_symmetric(uint8_t *secret_key, uint8_t *nonce, uint8_t *plain, uint32_t length, uint8_t *encrypted); + +/* Decrypts encrypted of length length to plain of length length - 16 using a + * secret key crypto_box_KEYBYTES big and a 24 byte nonce. + * + * return -1 if there was a problem (decryption failed). + * return length of plain data if everything was fine. + */ +int decrypt_data_symmetric(uint8_t *secret_key, uint8_t *nonce, uint8_t *encrypted, uint32_t length, uint8_t *plain); + +/* Increment the given nonce by 1. */ +void increment_nonce(uint8_t *nonce); + +/* increment the given nonce by num */ +void increment_nonce_number(uint8_t *nonce, uint32_t num); + +/* Fill the given nonce with random bytes. */ +void random_nonce(uint8_t *nonce); + +/* Fill a key crypto_box_KEYBYTES big with random bytes */ +void new_symmetric_key(uint8_t *key); + +/*Gives a nonce guaranteed to be different from previous ones.*/ +void new_nonce(uint8_t *nonce); + +#define MAX_CRYPTO_REQUEST_SIZE 1024 + +#define CRYPTO_PACKET_FRIEND_REQ 32 /* Friend request crypto packet ID. */ +#define CRYPTO_PACKET_HARDENING 48 /* Hardening crypto packet ID. */ +#define CRYPTO_PACKET_NAT_PING 254 /* NAT ping crypto packet ID. */ +#define CRYPTO_PACKET_GROUP_CHAT_GET_NODES 48 /* Group chat get Nodes packet */ +#define CRYPTO_PACKET_GROUP_CHAT_SEND_NODES 49 /* Group chat send Nodes packet */ +#define CRYPTO_PACKET_GROUP_CHAT_BROADCAST 50 /* Group chat broadcast packet */ + +/* Create a request to peer. + * send_public_key and send_secret_key are the pub/secret keys of the sender. + * recv_public_key is public key of reciever. + * packet must be an array of MAX_CRYPTO_REQUEST_SIZE big. + * Data represents the data we send with the request with length being the length of the data. + * request_id is the id of the request (32 = friend request, 254 = ping request). + * + * return -1 on failure. + * return the length of the created packet on success. + */ +int create_request(uint8_t *send_public_key, uint8_t *send_secret_key, uint8_t *packet, uint8_t *recv_public_key, + uint8_t *data, uint32_t length, uint8_t request_id); + +/* puts the senders public key in the request in public_key, the data from the request + in data if a friend or ping request was sent to us and returns the length of the data. + packet is the request packet and length is its length + return -1 if not valid request. */ +int handle_request(uint8_t *self_public_key, uint8_t *self_secret_key, uint8_t *public_key, uint8_t *data, + uint8_t *request_id, uint8_t *packet, uint16_t length); + + +#endif diff --git a/toxcore/friend_requests.c b/toxcore/friend_requests.c index 469ab02d..eb2a791c 100644 --- a/toxcore/friend_requests.c +++ b/toxcore/friend_requests.c @@ -37,10 +37,10 @@ */ int send_friendrequest(Onion_Client *onion_c, uint8_t *public_key, uint32_t nospam_num, uint8_t *data, uint32_t length) { - if (length + sizeof(nospam_num) > MAX_DATA_SIZE) + if (1 + sizeof(nospam_num) + length > ONION_CLIENT_MAX_DATA_SIZE || length == 0) return -1; - uint8_t temp[MAX_DATA_SIZE]; + uint8_t temp[1 + sizeof(nospam_num) + length]; temp[0] = CRYPTO_PACKET_FRIEND_REQ; memcpy(temp + 1, &nospam_num, sizeof(nospam_num)); memcpy(temp + 1 + sizeof(nospam_num), data, length); @@ -50,7 +50,7 @@ int send_friendrequest(Onion_Client *onion_c, uint8_t *public_key, uint32_t nosp if (friend_num == -1) return -1; - int num = send_onion_data(onion_c, friend_num, temp, 1 + sizeof(nospam_num) + length); + int num = send_onion_data(onion_c, friend_num, temp, sizeof(temp)); if (num <= 0) return -1; @@ -135,20 +135,17 @@ int remove_request_received(Friend_Requests *fr, uint8_t *client_id) static int friendreq_handlepacket(void *object, uint8_t *source_pubkey, uint8_t *packet, uint32_t length) { - if (length == 0) + Friend_Requests *fr = object; + + if (length <= 1 + sizeof(fr->nospam) || length > ONION_CLIENT_MAX_DATA_SIZE) return 1; ++packet; --length; - Friend_Requests *fr = object; - if (fr->handle_friendrequest_isset == 0) return 1; - if (length <= sizeof(fr->nospam)) - return 1; - if (request_received(fr, source_pubkey)) return 1; @@ -161,11 +158,12 @@ static int friendreq_handlepacket(void *object, uint8_t *source_pubkey, uint8_t addto_receivedlist(fr, source_pubkey); - uint8_t message[length - 4 + 1]; - memcpy(message, packet + 4, length - 4); + uint32_t message_len = length - sizeof(fr->nospam); + uint8_t message[message_len + 1]; + memcpy(message, packet + sizeof(fr->nospam), message_len); message[sizeof(message) - 1] = 0; /* Be sure the message is null terminated. */ - (*fr->handle_friendrequest)(fr->handle_friendrequest_object, source_pubkey, message, length - 4, + (*fr->handle_friendrequest)(fr->handle_friendrequest_object, source_pubkey, message, message_len, fr->handle_friendrequest_userdata); return 0; } diff --git a/toxcore/friend_requests.h b/toxcore/friend_requests.h index eab359f0..429ffbad 100644 --- a/toxcore/friend_requests.h +++ b/toxcore/friend_requests.h @@ -25,8 +25,8 @@ #define FRIEND_REQUESTS_H #include "onion_client.h" -#include "net_crypto.h" +#define MAX_FRIEND_REQUEST_DATA_SIZE (ONION_CLIENT_MAX_DATA_SIZE - (1 + sizeof(uint32_t))) typedef struct { uint32_t nospam; @@ -48,7 +48,8 @@ typedef struct { } Friend_Requests; /* Try to send a friendrequest to peer with public_key. - * data is the data in the request and length is the length. + * data is the data in the request and length is the length. + * Maximum length of data is MAX_FRIEND_REQUEST_DATA_SIZE. */ int send_friendrequest(Onion_Client *onion_c, uint8_t *public_key, uint32_t nospam_num, uint8_t *data, uint32_t length); /* Set and get the nospam variable used to prevent one type of friend request spam. */ diff --git a/toxcore/group_chats.c b/toxcore/group_chats.c index de39331e..fbe76d16 100644 --- a/toxcore/group_chats.c +++ b/toxcore/group_chats.c @@ -26,12 +26,13 @@ #include "config.h" #endif -#include "group_chats.h" +#include "DHT.h" #include "assoc.h" +#include "group_chats.h" #include "LAN_discovery.h" #include "util.h" -#define GROUPCHAT_MAXDATA_LENGTH (MAX_DATA_SIZE - (1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES)) +#define GROUPCHAT_MAXDATA_LENGTH (MAX_CRYPTO_REQUEST_SIZE - (1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES)) #define GROUPCHAT_MAXPLAINDATA_LENGTH (GROUPCHAT_MAXDATA_LENGTH - crypto_box_MACBYTES) #define GROUP_MAX_SENDNODES (GROUP_CLOSE_CONNECTIONS * 2) @@ -180,7 +181,7 @@ static int send_groupchatpacket(Group_Chat *chat, IP_Port ip_port, uint8_t *publ if (id_equal(chat->self_public_key, public_key)) return -1; - uint8_t packet[MAX_DATA_SIZE]; + uint8_t packet[MAX_CRYPTO_REQUEST_SIZE]; int len = create_request(chat->self_public_key, chat->self_secret_key, packet, public_key, data, length, request_id); packet[0] = NET_PACKET_GROUP_CHATS; @@ -586,10 +587,10 @@ static int handle_data(Group_Chat *chat, uint8_t *data, uint32_t len) static uint8_t send_data(Group_Chat *chat, uint8_t *data, uint32_t len, uint8_t message_id) { - if (len + GROUP_DATA_MIN_SIZE > MAX_DATA_SIZE) /*NOTE: not the real maximum len.*/ + if (len + GROUP_DATA_MIN_SIZE > MAX_CRYPTO_REQUEST_SIZE) /*NOTE: not the real maximum len.*/ return 1; - uint8_t packet[MAX_DATA_SIZE]; + uint8_t packet[MAX_CRYPTO_REQUEST_SIZE]; ++chat->message_number; if (chat->message_number == 0) @@ -615,11 +616,11 @@ static uint8_t send_data(Group_Chat *chat, uint8_t *data, uint32_t len, uint8_t int handle_groupchatpacket(Group_Chat *chat, IP_Port source, uint8_t *packet, uint32_t length) { - if (length > MAX_DATA_SIZE) + if (length > MAX_CRYPTO_REQUEST_SIZE) return 1; uint8_t public_key[crypto_box_PUBLICKEYBYTES]; - uint8_t data[MAX_DATA_SIZE]; + uint8_t data[MAX_CRYPTO_REQUEST_SIZE]; uint8_t number; int len = handle_request(chat->self_public_key, chat->self_secret_key, public_key, data, &number, packet, length); diff --git a/toxcore/group_chats.h b/toxcore/group_chats.h index f218fe42..d9da54a5 100644 --- a/toxcore/group_chats.h +++ b/toxcore/group_chats.h @@ -25,8 +25,6 @@ #ifndef GROUP_CHATS_H #define GROUP_CHATS_H -#include "net_crypto.h" - #define MAX_NICK_BYTES 128 typedef struct { diff --git a/toxcore/net_crypto.c b/toxcore/net_crypto.c index 17d2e8ff..875c639f 100644 --- a/toxcore/net_crypto.c +++ b/toxcore/net_crypto.c @@ -35,667 +35,2244 @@ static uint8_t crypt_connection_id_not_valid(Net_Crypto *c, int crypt_connection return (uint32_t)crypt_connection_id >= c->crypto_connections_length; } -/* Use this instead of memcmp; not vulnerable to timing attacks. */ -uint8_t crypto_iszero(uint8_t *mem, uint32_t length) +/* return 0 if connection is dead. + * return 1 if connection is alive. + */ +static int is_alive(uint8_t status) { - uint8_t check = 0; - uint32_t i; - - for (i = 0; i < length; ++i) { - check |= mem[i]; + if (status == CRYPTO_CONN_COOKIE_REQUESTING || + status == CRYPTO_CONN_HANDSHAKE_SENT || + status == CRYPTO_CONN_NOT_CONFIRMED || + status == CRYPTO_CONN_ESTABLISHED) { + return 1; } - return check; // We return zero if mem is made out of zeroes. + return 0; } -/* Precomputes the shared key from their public_key and our secret_key. - * This way we can avoid an expensive elliptic curve scalar multiply for each - * encrypt/decrypt operation. - * enc_key has to be crypto_box_BEFORENMBYTES bytes long. +/* cookie timeout in seconds */ +#define COOKIE_TIMEOUT 10 +#define COOKIE_DATA_LENGTH (crypto_box_PUBLICKEYBYTES * 2) +#define COOKIE_CONTENTS_LENGTH (sizeof(uint64_t) + COOKIE_DATA_LENGTH) +#define COOKIE_LENGTH (crypto_box_NONCEBYTES + COOKIE_CONTENTS_LENGTH + crypto_box_MACBYTES) + +#define COOKIE_REQUEST_PLAIN_LENGTH (COOKIE_DATA_LENGTH + sizeof(uint64_t)) +#define COOKIE_REQUEST_LENGTH (1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + COOKIE_REQUEST_PLAIN_LENGTH + crypto_box_MACBYTES) +#define COOKIE_RESPONSE_LENGTH (1 + crypto_box_NONCEBYTES + COOKIE_LENGTH + sizeof(uint64_t) + crypto_box_MACBYTES) + +/* Create a cookie request packet and put it in packet. + * dht_public_key is the dht public key of the other + * + * packet must be of size COOKIE_REQUEST_LENGTH or bigger. + * + * return -1 on failure. + * return COOKIE_REQUEST_LENGTH on success. */ -void encrypt_precompute(uint8_t *public_key, uint8_t *secret_key, uint8_t *enc_key) +static int create_cookie_request(Net_Crypto *c, uint8_t *packet, uint8_t *dht_public_key, uint64_t number, + uint8_t *shared_key) { - crypto_box_beforenm(enc_key, public_key, secret_key); + uint8_t plain[COOKIE_REQUEST_PLAIN_LENGTH]; + uint8_t padding[crypto_box_PUBLICKEYBYTES] = {0}; + + memcpy(plain, c->self_public_key, crypto_box_PUBLICKEYBYTES); + memcpy(plain + crypto_box_PUBLICKEYBYTES, padding, crypto_box_PUBLICKEYBYTES); + memcpy(plain + (crypto_box_PUBLICKEYBYTES * 2), &number, sizeof(uint64_t)); + + DHT_get_shared_key_sent(c->dht, shared_key, dht_public_key); + uint8_t nonce[crypto_box_NONCEBYTES]; + new_nonce(nonce); + packet[0] = NET_PACKET_COOKIE_REQUEST; + memcpy(packet + 1, c->dht->self_public_key, crypto_box_PUBLICKEYBYTES); + memcpy(packet + 1 + crypto_box_PUBLICKEYBYTES, nonce, crypto_box_NONCEBYTES); + int len = encrypt_data_symmetric(shared_key, nonce, plain, sizeof(plain), + packet + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES); + + if (len != COOKIE_REQUEST_PLAIN_LENGTH + crypto_box_MACBYTES) + return -1; + + return (1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + len); } -/* Fast encrypt. Depends on enc_key from encrypt_precompute. */ -int encrypt_data_fast(uint8_t *enc_key, uint8_t *nonce, - uint8_t *plain, uint32_t length, uint8_t *encrypted) +/* Create cookie of length COOKIE_LENGTH from bytes of length COOKIE_DATA_LENGTH using encryption_key + * + * return -1 on failure. + * return 0 on success. + */ +static int create_cookie(uint8_t *cookie, uint8_t *bytes, uint8_t *encryption_key) { - if (length + crypto_box_MACBYTES > MAX_DATA_SIZE || length == 0) + uint8_t contents[COOKIE_CONTENTS_LENGTH]; + uint64_t temp_time = unix_time(); + memcpy(contents, &temp_time, sizeof(temp_time)); + memcpy(contents + sizeof(temp_time), bytes, COOKIE_DATA_LENGTH); + new_nonce(cookie); + int len = encrypt_data_symmetric(encryption_key, cookie, contents, sizeof(contents), cookie + crypto_box_NONCEBYTES); + + if (len != COOKIE_LENGTH - crypto_box_NONCEBYTES) return -1; - uint8_t temp_plain[MAX_DATA_SIZE + crypto_box_ZEROBYTES] = {0}; - uint8_t temp_encrypted[MAX_DATA_SIZE + crypto_box_BOXZEROBYTES]; + return 0; +} + +/* Open cookie of length COOKIE_LENGTH to bytes of length COOKIE_DATA_LENGTH using encryption_key + * + * return -1 on failure. + * return 0 on success. + */ +static int open_cookie(uint8_t *bytes, uint8_t *cookie, uint8_t *encryption_key) +{ + uint8_t contents[COOKIE_CONTENTS_LENGTH]; + int len = decrypt_data_symmetric(encryption_key, cookie, cookie + crypto_box_NONCEBYTES, + COOKIE_LENGTH - crypto_box_NONCEBYTES, contents); - memcpy(temp_plain + crypto_box_ZEROBYTES, plain, length); // Pad the message with 32 0 bytes. + if (len != sizeof(contents)) + return -1; - crypto_box_afternm(temp_encrypted, temp_plain, length + crypto_box_ZEROBYTES, nonce, enc_key); + uint64_t cookie_time; + memcpy(&cookie_time, contents, sizeof(cookie_time)); + uint64_t temp_time = unix_time(); - if (crypto_iszero(temp_encrypted, crypto_box_BOXZEROBYTES) != 0) + if (cookie_time + COOKIE_TIMEOUT < temp_time || temp_time < cookie_time) return -1; - /* Unpad the encrypted message. */ - memcpy(encrypted, temp_encrypted + crypto_box_BOXZEROBYTES, length + crypto_box_MACBYTES); - return length + crypto_box_MACBYTES; + memcpy(bytes, contents + sizeof(cookie_time), COOKIE_DATA_LENGTH); + return 0; } -/* Fast decrypt. Depends on enc_ley from encrypt_precompute. */ -int decrypt_data_fast(uint8_t *enc_key, uint8_t *nonce, - uint8_t *encrypted, uint32_t length, uint8_t *plain) + +/* Create a cookie response packet and put it in packet. + * request_plain must be COOKIE_REQUEST_PLAIN_LENGTH bytes. + * packet must be of size COOKIE_RESPONSE_LENGTH or bigger. + * + * return -1 on failure. + * return COOKIE_RESPONSE_LENGTH on success. + */ +static int create_cookie_response(Net_Crypto *c, uint8_t *packet, uint8_t *request_plain, uint8_t *shared_key, + uint8_t *dht_public_key) { - if (length > MAX_DATA_SIZE || length <= crypto_box_BOXZEROBYTES) + uint8_t cookie_plain[COOKIE_DATA_LENGTH]; + memcpy(cookie_plain, request_plain, crypto_box_PUBLICKEYBYTES); + memcpy(cookie_plain + crypto_box_PUBLICKEYBYTES, dht_public_key, crypto_box_PUBLICKEYBYTES); + uint8_t plain[COOKIE_LENGTH + sizeof(uint64_t)]; + + if (create_cookie(plain, cookie_plain, c->secret_symmetric_key) != 0) return -1; - uint8_t temp_plain[MAX_DATA_SIZE + crypto_box_ZEROBYTES]; - uint8_t temp_encrypted[MAX_DATA_SIZE + crypto_box_BOXZEROBYTES] = {0}; + memcpy(plain + COOKIE_LENGTH, request_plain + COOKIE_DATA_LENGTH, sizeof(uint64_t)); + packet[0] = NET_PACKET_COOKIE_RESPONSE; + new_nonce(packet + 1); + int len = encrypt_data_symmetric(shared_key, packet + 1, plain, sizeof(plain), packet + 1 + crypto_box_NONCEBYTES); + + if (len != COOKIE_RESPONSE_LENGTH - (1 + crypto_box_NONCEBYTES)) + return -1; - memcpy(temp_encrypted + crypto_box_BOXZEROBYTES, encrypted, length); // Pad the message with 16 0 bytes. + return COOKIE_RESPONSE_LENGTH; +} - if (crypto_box_open_afternm(temp_plain, temp_encrypted, length + crypto_box_BOXZEROBYTES, - nonce, enc_key) == -1) +/* Handle the cookie request packet of length length. + * Put what was in the request in request_plain (must be of size COOKIE_REQUEST_PLAIN_LENGTH) + * Put the key used to decrypt the request into shared_key (of size crypto_box_BEFORENMBYTES) for use in the response. + * + * return -1 on failure. + * return 0 on success. + */ +static int handle_cookie_request(Net_Crypto *c, uint8_t *request_plain, uint8_t *shared_key, uint8_t *dht_public_key, + uint8_t *packet, uint16_t length) +{ + if (length != COOKIE_REQUEST_LENGTH) return -1; - /* If decryption is successful the first crypto_box_ZEROBYTES of the message will be zero. - * Apparently memcmp should not be used so we do this instead: - */ - if (crypto_iszero(temp_plain, crypto_box_ZEROBYTES) != 0) + memcpy(dht_public_key, packet + 1, crypto_box_PUBLICKEYBYTES); + DHT_get_shared_key_sent(c->dht, shared_key, dht_public_key); + int len = decrypt_data_symmetric(shared_key, packet + 1 + crypto_box_PUBLICKEYBYTES, + packet + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, COOKIE_REQUEST_PLAIN_LENGTH + crypto_box_MACBYTES, + request_plain); + + if (len != COOKIE_REQUEST_PLAIN_LENGTH) return -1; - /* Unpad the plain message. */ - memcpy(plain, temp_plain + crypto_box_ZEROBYTES, length - crypto_box_MACBYTES); - return length - crypto_box_MACBYTES; + return 0; } -int encrypt_data(uint8_t *public_key, uint8_t *secret_key, uint8_t *nonce, - uint8_t *plain, uint32_t length, uint8_t *encrypted) +/* Handle the cookie request packet (for raw UDP) + */ +static int udp_handle_cookie_request(void *object, IP_Port source, uint8_t *packet, uint32_t length) { - uint8_t k[crypto_box_BEFORENMBYTES]; - encrypt_precompute(public_key, secret_key, k); - return encrypt_data_fast(k, nonce, plain, length, encrypted); + Net_Crypto *c = object; + uint8_t request_plain[COOKIE_REQUEST_PLAIN_LENGTH]; + uint8_t shared_key[crypto_box_BEFORENMBYTES]; + uint8_t dht_public_key[crypto_box_PUBLICKEYBYTES]; + + if (handle_cookie_request(c, request_plain, shared_key, dht_public_key, packet, length) != 0) + return 1; + + uint8_t data[COOKIE_RESPONSE_LENGTH]; + + if (create_cookie_response(c, data, request_plain, shared_key, dht_public_key) != sizeof(data)) + return 1; + + if ((uint32_t)sendpacket(c->dht->net, source, data, sizeof(data)) != sizeof(data)) + return 1; + + return 0; } -int decrypt_data(uint8_t *public_key, uint8_t *secret_key, uint8_t *nonce, - uint8_t *encrypted, uint32_t length, uint8_t *plain) +/* Handle the cookie request packet (for TCP) + */ +static int tcp_handle_cookie_request(Net_Crypto *c, TCP_Client_Connection *TCP_con, uint8_t conn_id, uint8_t *packet, + uint32_t length) { - uint8_t k[crypto_box_BEFORENMBYTES]; - encrypt_precompute(public_key, secret_key, k); - return decrypt_data_fast(k, nonce, encrypted, length, plain); + uint8_t request_plain[COOKIE_REQUEST_PLAIN_LENGTH]; + uint8_t shared_key[crypto_box_BEFORENMBYTES]; + uint8_t dht_public_key[crypto_box_PUBLICKEYBYTES]; + + if (handle_cookie_request(c, request_plain, shared_key, dht_public_key, packet, length) != 0) + return -1; + + uint8_t data[COOKIE_RESPONSE_LENGTH]; + + if (create_cookie_response(c, data, request_plain, shared_key, dht_public_key) != sizeof(data)) + return -1; + + if (send_data(TCP_con, conn_id, data, sizeof(data)) != 1) + return -1; + + return 0; } -int encrypt_data_symmetric(uint8_t *secret_key, uint8_t *nonce, uint8_t *plain, uint32_t length, uint8_t *encrypted) +/* Handle the cookie request packet (for TCP oob packets) + */ +static int tcp_oob_handle_cookie_request(Net_Crypto *c, TCP_Client_Connection *TCP_con, uint8_t *dht_public_key, + uint8_t *packet, uint32_t length) { - if (length == 0) + uint8_t request_plain[COOKIE_REQUEST_PLAIN_LENGTH]; + uint8_t shared_key[crypto_box_BEFORENMBYTES]; + uint8_t dht_public_key_temp[crypto_box_PUBLICKEYBYTES]; + + if (handle_cookie_request(c, request_plain, shared_key, dht_public_key_temp, packet, length) != 0) return -1; - uint8_t temp_plain[length + crypto_secretbox_ZEROBYTES]; - uint8_t temp_encrypted[length + crypto_secretbox_MACBYTES + crypto_secretbox_BOXZEROBYTES]; + if (memcmp(dht_public_key, dht_public_key_temp, crypto_box_PUBLICKEYBYTES) != 0) + return -1; + + uint8_t data[COOKIE_RESPONSE_LENGTH]; + + if (create_cookie_response(c, data, request_plain, shared_key, dht_public_key) != sizeof(data)) + return -1; + + if (send_oob_packet(TCP_con, dht_public_key, data, sizeof(data)) != 1) + return -1; + + return 0; +} + +/* Handle a cookie response packet of length encrypted with shared_key. + * put the cookie in the response in cookie + * + * cookie must be of length COOKIE_LENGTH. + * + * return -1 on failure. + * return COOKIE_LENGTH on success. + */ +static int handle_cookie_response(uint8_t *cookie, uint64_t *number, uint8_t *packet, uint32_t length, + uint8_t *shared_key) +{ + if (length != COOKIE_RESPONSE_LENGTH) + return -1; + + uint8_t plain[COOKIE_LENGTH + sizeof(uint64_t)]; + int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES, + length - (1 + crypto_box_NONCEBYTES), plain); - memset(temp_plain, 0, crypto_secretbox_ZEROBYTES); - memcpy(temp_plain + crypto_secretbox_ZEROBYTES, plain, length); // Pad the message with 32 0 bytes. + if (len != sizeof(plain)) + return -1; + + memcpy(cookie, plain, COOKIE_LENGTH); + memcpy(number, plain + COOKIE_LENGTH, sizeof(uint64_t)); + return COOKIE_LENGTH; +} + +#define HANDSHAKE_PACKET_LENGTH (1 + COOKIE_LENGTH + crypto_box_NONCEBYTES + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + crypto_hash_sha512_BYTES + COOKIE_LENGTH + crypto_box_MACBYTES) + +/* Create a handshake packet and put it in packet. + * cookie must be COOKIE_LENGTH bytes. + * packet must be of size HANDSHAKE_PACKET_LENGTH or bigger. + * + * return -1 on failure. + * return HANDSHAKE_PACKET_LENGTH on success. + */ +static int create_crypto_handshake(Net_Crypto *c, uint8_t *packet, uint8_t *cookie, uint8_t *nonce, uint8_t *session_pk, + uint8_t *peer_real_pk, uint8_t *peer_dht_pubkey) +{ + uint8_t plain[crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + crypto_hash_sha512_BYTES + COOKIE_LENGTH]; + memcpy(plain, nonce, crypto_box_NONCEBYTES); + memcpy(plain + crypto_box_NONCEBYTES, session_pk, crypto_box_PUBLICKEYBYTES); + crypto_hash_sha512(plain + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES, cookie, COOKIE_LENGTH); + uint8_t cookie_plain[COOKIE_DATA_LENGTH]; + memcpy(cookie_plain, peer_real_pk, crypto_box_PUBLICKEYBYTES); + memcpy(cookie_plain + crypto_box_PUBLICKEYBYTES, peer_dht_pubkey, crypto_box_PUBLICKEYBYTES); + + if (create_cookie(plain + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + crypto_hash_sha512_BYTES, cookie_plain, + c->secret_symmetric_key) != 0) + return -1; + + new_nonce(packet + 1 + COOKIE_LENGTH); + int len = encrypt_data(peer_real_pk, c->self_secret_key, packet + 1 + COOKIE_LENGTH, plain, sizeof(plain), + packet + 1 + COOKIE_LENGTH + crypto_box_NONCEBYTES); + + if (len != HANDSHAKE_PACKET_LENGTH - (1 + COOKIE_LENGTH + crypto_box_NONCEBYTES)) + return -1; - crypto_secretbox(temp_encrypted, temp_plain, length + crypto_secretbox_ZEROBYTES, nonce, secret_key); - /* Unpad the encrypted message. */ - memcpy(encrypted, temp_encrypted + crypto_secretbox_BOXZEROBYTES, length + crypto_secretbox_MACBYTES); - return length + crypto_secretbox_MACBYTES; + packet[0] = NET_PACKET_CRYPTO_HS; + memcpy(packet + 1, cookie, COOKIE_LENGTH); + + return HANDSHAKE_PACKET_LENGTH; } -int decrypt_data_symmetric(uint8_t *secret_key, uint8_t *nonce, uint8_t *encrypted, uint32_t length, uint8_t *plain) +/* Handle a crypto handshake packet of length. + * put the nonce contained in the packet in nonce, + * the session public key in session_pk + * the real public key of the peer in peer_real_pk + * the dht public key of the peer in dht_public_key and + * the cookie inside the encrypted part of the packet in cookie. + * + * if expected_real_pk isn't NULL it denotes the real public key + * the packet should be from. + * + * nonce must be at least crypto_box_NONCEBYTES + * session_pk must be at least crypto_box_PUBLICKEYBYTES + * peer_real_pk must be at least crypto_box_PUBLICKEYBYTES + * cookie must be at least COOKIE_LENGTH + * + * return -1 on failure. + * return 0 on success. + */ +static int handle_crypto_handshake(Net_Crypto *c, uint8_t *nonce, uint8_t *session_pk, uint8_t *peer_real_pk, + uint8_t *dht_public_key, uint8_t *cookie, uint8_t *packet, uint32_t length, uint8_t *expected_real_pk) { - if (length <= crypto_secretbox_BOXZEROBYTES) + if (length != HANDSHAKE_PACKET_LENGTH) + return -1; + + uint8_t cookie_plain[COOKIE_DATA_LENGTH]; + + if (open_cookie(cookie_plain, packet + 1, c->secret_symmetric_key) != 0) return -1; - uint8_t temp_plain[length + crypto_secretbox_ZEROBYTES]; - uint8_t temp_encrypted[length + crypto_secretbox_BOXZEROBYTES]; + if (expected_real_pk) + if (crypto_cmp(cookie_plain, expected_real_pk, crypto_box_PUBLICKEYBYTES) != 0) + return -1; + + uint8_t cookie_hash[crypto_hash_sha512_BYTES]; + crypto_hash_sha512(cookie_hash, packet + 1, COOKIE_LENGTH); - memset(temp_plain, 0, crypto_secretbox_BOXZEROBYTES); - memcpy(temp_encrypted + crypto_secretbox_BOXZEROBYTES, encrypted, length); // Pad the message with 16 0 bytes. + uint8_t plain[crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + crypto_hash_sha512_BYTES + COOKIE_LENGTH]; + int len = decrypt_data(cookie_plain, c->self_secret_key, packet + 1 + COOKIE_LENGTH, + packet + 1 + COOKIE_LENGTH + crypto_box_NONCEBYTES, + HANDSHAKE_PACKET_LENGTH - (1 + COOKIE_LENGTH + crypto_box_NONCEBYTES), plain); + + if (len != sizeof(plain)) + return -1; - if (crypto_secretbox_open(temp_plain, temp_encrypted, length + crypto_secretbox_BOXZEROBYTES, nonce, secret_key) == -1) + if (memcmp(cookie_hash, plain + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES, crypto_hash_sha512_BYTES) != 0) return -1; - memcpy(plain, temp_plain + crypto_secretbox_ZEROBYTES, length - crypto_secretbox_MACBYTES); - return length - crypto_secretbox_MACBYTES; + memcpy(nonce, plain, crypto_box_NONCEBYTES); + memcpy(session_pk, plain + crypto_box_NONCEBYTES, crypto_box_PUBLICKEYBYTES); + memcpy(cookie, plain + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + crypto_hash_sha512_BYTES, COOKIE_LENGTH); + memcpy(peer_real_pk, cookie_plain, crypto_box_PUBLICKEYBYTES); + memcpy(dht_public_key, cookie_plain + crypto_box_PUBLICKEYBYTES, crypto_box_PUBLICKEYBYTES); + return 0; +} + + +static Crypto_Connection *get_crypto_connection(Net_Crypto *c, int crypt_connection_id) +{ + if (crypt_connection_id_not_valid(c, crypt_connection_id)) + return 0; + + return &c->crypto_connections[crypt_connection_id]; } -/* Increment the given nonce by 1. */ -void increment_nonce(uint8_t *nonce) + +/* Sends a packet to the peer using the fastest route. + * + * return -1 on failure. + * return 0 on success. + */ +static int send_packet_to(Net_Crypto *c, int crypt_connection_id, uint8_t *data, uint16_t length) { +//TODO TCP, etc... + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) + return -1; + + int direct_send_attempt = 0; + + //TODO: on bad networks, direct connections might not last indefinitely. + if (conn->ip_port.ip.family != 0) { + uint8_t direct_connected = 0; + crypto_connection_status(c, crypt_connection_id, &direct_connected); + + if (direct_connected && (uint32_t)sendpacket(c->dht->net, conn->ip_port, data, length) == length) + return 0; + + //TODO: a better way of sending packets directly to confirm the others ip. + if (length < 96 || data[0] == NET_PACKET_COOKIE_REQUEST || data[0] == NET_PACKET_CRYPTO_HS) { + if ((uint32_t)sendpacket(c->dht->net, conn->ip_port, data, length) == length) + direct_send_attempt = 1; + } + + } + + //TODO: spread packets over many relays, detect and kill bad relays. uint32_t i; - for (i = 0; i < crypto_box_NONCEBYTES; ++i) { - ++nonce[i]; + for (i = 0; i < MAX_TCP_CONNECTIONS; ++i) { + if (conn->status_tcp[i] == STATUS_TCP_ONLINE) {/* friend is connected to this relay. */ + if (send_data(c->tcp_connections[i], conn->con_number_tcp[i], data, length) == 1) + return 0; + } + } + + for (i = 0; i < MAX_TCP_CONNECTIONS; ++i) { + if (conn->status_tcp[i] == STATUS_TCP_INVISIBLE) { + if (send_oob_packet(c->tcp_connections[i], conn->dht_public_key, data, length) == 1) + return 0; + } + } - if (nonce[i] != 0) - break; + if (direct_send_attempt) { + return 0; } + + return -1; } -#if crypto_box_NONCEBYTES != crypto_secretbox_NONCEBYTES -/*if they no longer equal each other, this function must be split into two.*/ -#error random_nonce(): crypto_box_NONCEBYTES must equal crypto_secretbox_NONCEBYTES. -#endif -/* Fill the given nonce with random bytes. */ -void random_nonce(uint8_t *nonce) +/** START: Array Related functions **/ + + +/* Return number of packets in array + * Note that holes are counted too. + */ +static uint32_t num_packets_array(Packets_Array *array) { - randombytes(nonce, crypto_box_NONCEBYTES); + return array->buffer_end - array->buffer_start; } -/* Fill a key crypto_secretbox_KEYBYTES big with random bytes */ -void new_symmetric_key(uint8_t *key) +/* Add data with packet number to array. + * + * return -1 on failure. + * return 0 on success. + */ +static int add_data_to_buffer(Packets_Array *array, uint32_t number, Packet_Data *data) { - randombytes(key, crypto_secretbox_KEYBYTES); + if (number - array->buffer_start > CRYPTO_PACKET_BUFFER_SIZE) + return -1; + + uint32_t num = number % CRYPTO_PACKET_BUFFER_SIZE; + + if (array->buffer[num]) + return -1; + + Packet_Data *new_d = malloc(sizeof(Packet_Data)); + + if (new_d == NULL) + return -1; + + memcpy(new_d, data, sizeof(Packet_Data)); + array->buffer[num] = new_d; + + if ((number - array->buffer_start) >= (array->buffer_end - array->buffer_start)) + array->buffer_end = number + 1; + + return 0; } -static uint8_t base_nonce[crypto_box_NONCEBYTES]; -static uint8_t nonce_set = 0; +/* Get pointer of data with packet number. + * + * return -1 on failure. + * return 0 if data at number is empty. + * return 1 if data pointer was put in data. + */ +static int get_data_pointer(Packets_Array *array, Packet_Data **data, uint32_t number) +{ + uint32_t num_spots = array->buffer_end - array->buffer_start; + + if (array->buffer_end - number > num_spots || number - array->buffer_start >= num_spots) + return -1; + + uint32_t num = number % CRYPTO_PACKET_BUFFER_SIZE; -#if crypto_box_NONCEBYTES != crypto_secretbox_NONCEBYTES -/*if they no longer equal each other, this function must be split into two.*/ -#error new_nonce(): crypto_box_NONCEBYTES must equal crypto_secretbox_NONCEBYTES. -#endif -/* Gives a nonce guaranteed to be different from previous ones.*/ -void new_nonce(uint8_t *nonce) + if (!array->buffer[num]) + return 0; + + *data = array->buffer[num]; + return 1; +} + +/* Add data to end of array. + * + * return -1 on failure. + * return packet number on success. + */ +static int64_t add_data_end_of_buffer(Packets_Array *array, Packet_Data *data) +{ + if (num_packets_array(array) >= CRYPTO_PACKET_BUFFER_SIZE) + return -1; + + Packet_Data *new_d = malloc(sizeof(Packet_Data)); + + if (new_d == NULL) + return -1; + + memcpy(new_d, data, sizeof(Packet_Data)); + uint32_t id = array->buffer_end; + array->buffer[id % CRYPTO_PACKET_BUFFER_SIZE] = new_d; + ++array->buffer_end; + return id; +} + +/* Read data from begginning of array. + * + * return -1 on failure. + * return packet number on success. + */ +static int64_t read_data_beg_buffer(Packets_Array *array, Packet_Data *data) +{ + if (array->buffer_end == array->buffer_start) + return -1; + + uint32_t num = array->buffer_start % CRYPTO_PACKET_BUFFER_SIZE; + + if (!array->buffer[num]) + return -1; + + memcpy(data, array->buffer[num], sizeof(Packet_Data)); + uint32_t id = array->buffer_start; + ++array->buffer_start; + free(array->buffer[num]); + array->buffer[num] = NULL; + return id; +} + +/* Delete all packets in array before number (but not number) + * + * return -1 on failure. + * return 0 on success + */ +static int clear_buffer_until(Packets_Array *array, uint32_t number) { - if (nonce_set == 0) { - random_nonce(base_nonce); - nonce_set = 1; + uint32_t num_spots = array->buffer_end - array->buffer_start; + + if (array->buffer_end - number >= num_spots || number - array->buffer_start > num_spots) + return -1; + + uint32_t i; + + for (i = array->buffer_start; i != number; ++i) { + uint32_t num = i % CRYPTO_PACKET_BUFFER_SIZE; + + if (array->buffer[num]) { + free(array->buffer[num]); + array->buffer[num] = NULL; + } } - increment_nonce(base_nonce); - memcpy(nonce, base_nonce, crypto_box_NONCEBYTES); + array->buffer_start = i; + return 0; } +/* Set array buffer end to number. + * + * return -1 on failure. + * return 0 on success. + */ +static int set_buffer_end(Packets_Array *array, uint32_t number) +{ + if ((number - array->buffer_start) > CRYPTO_PACKET_BUFFER_SIZE) + return -1; + + if ((number - array->buffer_end) > CRYPTO_PACKET_BUFFER_SIZE) + return -1; + + array->buffer_end = number; + return 0; +} -/* return 0 if there is no received data in the buffer. - * return -1 if the packet was discarded. - * return length of received data if successful. +/* Create a packet request packet from recv_array and send_buffer_end into + * data of length. + * + * return -1 on failure. + * return length of packet on success. */ -int read_cryptpacket(Net_Crypto *c, int crypt_connection_id, uint8_t *data) +static int generate_request_packet(uint8_t *data, uint16_t length, Packets_Array *recv_array, uint32_t send_buffer_end) { - if (crypt_connection_id_not_valid(c, crypt_connection_id)) - return 0; + if (length <= (sizeof(uint32_t) * 2)) + return -1; + + uint32_t recv_buffer_start = htonl(recv_array->buffer_start); + send_buffer_end = htonl(send_buffer_end); + memcpy(data, &recv_buffer_start, sizeof(uint32_t)); + memcpy(data + sizeof(uint32_t), &send_buffer_end, sizeof(uint32_t)); + data[sizeof(uint32_t) * 2] = PACKET_ID_REQUEST; + + uint16_t cur_len = sizeof(uint32_t) * 2 + 1; + + if (recv_array->buffer_start == recv_array->buffer_end) + return cur_len; + + if (length <= cur_len) + return cur_len; + + uint32_t i, n = 1; + + for (i = recv_array->buffer_start; i != recv_array->buffer_end; ++i) { + uint32_t num = i % CRYPTO_PACKET_BUFFER_SIZE; + + if (!recv_array->buffer[num]) { + data[cur_len] = n; + n = 0; + ++cur_len; + + if (length <= cur_len) + return cur_len; + + } else if (n == 255) { + data[cur_len] = 0; + n = 0; + ++cur_len; + + if (length <= cur_len) + return cur_len; + } + + ++n; + } + + return cur_len; +} + +/* Handle a request data packet. + * Remove all the packets the other recieved from the array. + * + * return -1 on failure. + * return number of requested packets on success. + */ +static int handle_request_packet(Packets_Array *send_array, uint8_t *data, uint16_t length) +{ + if (length < 1) + return -1; - if (c->crypto_connections[crypt_connection_id].status != CRYPTO_CONN_ESTABLISHED) + if (data[0] != PACKET_ID_REQUEST) + return -1; + + if (length == 1) return 0; - uint8_t temp_data[MAX_DATA_SIZE]; - int length = read_packet(c->lossless_udp, c->crypto_connections[crypt_connection_id].number, temp_data); + ++data; + --length; + + uint32_t i, n = 1; + uint32_t requested = 0; + + for (i = send_array->buffer_start; i != send_array->buffer_end; ++i) { + if (length == 0) + break; + + uint32_t num = i % CRYPTO_PACKET_BUFFER_SIZE; + + if (n == data[0]) { + if (send_array->buffer[num]) { + send_array->buffer[num]->time = 0; + } + + ++data; + --length; + n = 0; + ++requested; + } else { + free(send_array->buffer[num]); + send_array->buffer[num] = NULL; + } + + if (n == 255) { + n = 1; + + if (data[0] != 0) + return -1; + + ++data; + --length; + } else { + ++n; + } + } + + return requested; +} + +/** END: Array Related functions **/ + +#define MAX_DATA_DATA_PACKET_SIZE (MAX_CRYPTO_PACKET_SIZE - (1 + sizeof(uint16_t) + crypto_box_MACBYTES)) + +/* Creates and sends a data packet to the peer using the fastest route. + * + * return -1 on failure. + * return 0 on success. + */ +static int send_data_packet(Net_Crypto *c, int crypt_connection_id, uint8_t *data, uint16_t length) +{ + if (length == 0 || length + (1 + sizeof(uint16_t) + crypto_box_MACBYTES) > MAX_CRYPTO_PACKET_SIZE) + return -1; + + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) + return -1; + + uint8_t packet[1 + sizeof(uint16_t) + length + crypto_box_MACBYTES]; + packet[0] = NET_PACKET_CRYPTO_DATA; + memcpy(packet + 1, conn->sent_nonce + (crypto_box_NONCEBYTES - sizeof(uint16_t)), sizeof(uint16_t)); + int len = encrypt_data_symmetric(conn->shared_key, conn->sent_nonce, data, length, packet + 1 + sizeof(uint16_t)); + + if (len + 1 + sizeof(uint16_t) != sizeof(packet)) + return -1; + + increment_nonce(conn->sent_nonce); + return send_packet_to(c, crypt_connection_id, packet, sizeof(packet)); +} + +/* Creates and sends a data packet with buffer_start and num to the peer using the fastest route. + * + * return -1 on failure. + * return 0 on success. + */ +static int send_data_packet_helper(Net_Crypto *c, int crypt_connection_id, uint32_t buffer_start, uint32_t num, + uint8_t *data, uint32_t length) +{ + num = htonl(num); + buffer_start = htonl(buffer_start); + uint8_t packet[sizeof(uint32_t) + sizeof(uint32_t) + length]; + memcpy(packet, &buffer_start, sizeof(uint32_t)); + memcpy(packet + sizeof(uint32_t), &num, sizeof(uint32_t)); + memcpy(packet + (sizeof(uint32_t) * 2), data, length); + + return send_data_packet(c, crypt_connection_id, packet, sizeof(packet)); +} + +/* return -1 if data could not be put in packet queue. + * return positive packet number if data was put into the queue. + */ +static int64_t send_lossless_packet(Net_Crypto *c, int crypt_connection_id, uint8_t *data, uint32_t length) +{ + if (length == 0 || length > MAX_CRYPTO_DATA_SIZE) + return -1; + + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) + return -1; + + Packet_Data dt; + dt.time = current_time_monotonic(); + dt.length = length; + memcpy(dt.data, data, length); + int64_t packet_num = add_data_end_of_buffer(&conn->send_array, &dt); + + if (packet_num == -1) + return -1; + + if (send_data_packet_helper(c, crypt_connection_id, conn->recv_array.buffer_start, packet_num, data, length) != 0) + fprintf(stderr, "send_data_packet failed\n"); + + return packet_num; +} + +/* Get the lowest 2 bytes from the nonce and convert + * them to host byte format before returning them. + */ +static uint16_t get_nonce_uint16(uint8_t *nonce) +{ + uint16_t num; + memcpy(&num, nonce + (crypto_box_NONCEBYTES - sizeof(uint16_t)), sizeof(uint16_t)); + return ntohs(num); +} + +#define DATA_NUM_THRESHOLD 21845 + +/* Handle a data packet. + * Decrypt packet of length and put it into data. + * data must be at least MAX_DATA_DATA_PACKET_SIZE big. + * + * return -1 on failure. + * return length of data on success. + */ +static int handle_data_packet(Net_Crypto *c, int crypt_connection_id, uint8_t *data, uint8_t *packet, uint16_t length) +{ + if (length <= (1 + sizeof(uint16_t) + crypto_box_MACBYTES) || length > MAX_CRYPTO_PACKET_SIZE) + return -1; + + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) + return -1; + + uint8_t nonce[crypto_box_NONCEBYTES]; + memcpy(nonce, conn->recv_nonce, crypto_box_NONCEBYTES); + uint16_t num_cur_nonce = get_nonce_uint16(nonce); + uint16_t num; + memcpy(&num, packet + 1, sizeof(uint16_t)); + num = ntohs(num); + uint16_t diff = num - num_cur_nonce; + increment_nonce_number(nonce, diff); + int len = decrypt_data_symmetric(conn->shared_key, nonce, packet + 1 + sizeof(uint16_t), + length - (1 + sizeof(uint16_t)), data); + + if ((unsigned int)len != length - (1 + sizeof(uint16_t) + crypto_box_MACBYTES)) + return -1; + + if (diff > DATA_NUM_THRESHOLD * 2) { + increment_nonce_number(conn->recv_nonce, DATA_NUM_THRESHOLD); + } + + return len; +} + +/* Send a request packet. + * + * return -1 on failure. + * return 0 on success. + */ +static int send_request_packet(Net_Crypto *c, int crypt_connection_id) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) + return -1; + + uint8_t packet[MAX_DATA_DATA_PACKET_SIZE]; + int len = generate_request_packet(packet, sizeof(packet), &conn->recv_array, conn->send_array.buffer_end); + + if (len == -1) + return -1; + + return send_data_packet(c, crypt_connection_id, packet, len); +} + +/* Send up to max num previously requested data packets. + * + * return -1 on failure. + * return number of packets sent on success. + */ +static int send_requested_packets(Net_Crypto *c, int crypt_connection_id, uint16_t max_num) +{ + if (max_num == 0) + return -1; + + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) + return -1; + + uint32_t i, num_sent = 0, array_size = num_packets_array(&conn->send_array); + + for (i = 0; i < array_size; ++i) { + Packet_Data *dt; + uint32_t packet_num = (i + conn->send_array.buffer_start); + int ret = get_data_pointer(&conn->send_array, &dt, packet_num); + + if (ret == -1) { + return -1; + } else if (ret == 0) { + continue; + } + + if (dt->time != 0) { + continue; + } + + dt->time = current_time_monotonic(); + + if (send_data_packet_helper(c, crypt_connection_id, conn->recv_array.buffer_start, packet_num, dt->data, + dt->length) == 0) + ++num_sent; + + if (num_sent >= max_num) + break; + } + + return num_sent; +} + + +/* Add a new temp packet to send repeatedly. + * + * return -1 on failure. + * return 0 on success. + */ +static int new_temp_packet(Net_Crypto *c, int crypt_connection_id, uint8_t *packet, uint16_t length) +{ + if (length == 0 || length > MAX_CRYPTO_PACKET_SIZE) + return -1; + + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) + return -1; + + uint8_t *temp_packet = malloc(length); + + if (temp_packet == 0) + return -1; + + if (conn->temp_packet) + free(conn->temp_packet); + + memcpy(temp_packet, packet, length); + conn->temp_packet = temp_packet; + conn->temp_packet_length = length; + conn->temp_packet_sent_time = 0; + conn->temp_packet_num_sent = 0; + return 0; +} + +/* Clear the temp packet. + * + * return -1 on failure. + * return 0 on success. + */ +static int clear_temp_packet(Net_Crypto *c, int crypt_connection_id) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) + return -1; + + if (conn->temp_packet) + free(conn->temp_packet); + + conn->temp_packet = 0; + conn->temp_packet_length = 0; + conn->temp_packet_sent_time = 0; + conn->temp_packet_num_sent = 0; + return 0; +} + + +/* Send the temp packet. + * + * return -1 on failure. + * return 0 on success. + */ +static int send_temp_packet(Net_Crypto *c, int crypt_connection_id) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) + return -1; + + if (!conn->temp_packet) + return -1; + + if (send_packet_to(c, crypt_connection_id, conn->temp_packet, conn->temp_packet_length) != 0) + return -1; + + conn->temp_packet_sent_time = current_time_monotonic(); + ++conn->temp_packet_num_sent; + return 0; +} + +/* Create a handshake packet and set it as a temp packet. + * cookie must be COOKIE_LENGTH. + * + * return -1 on failure. + * return 0 on success. + */ +static int create_send_handshake(Net_Crypto *c, int crypt_connection_id, uint8_t *cookie, uint8_t *dht_public_key) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) + return -1; + + uint8_t handshake_packet[HANDSHAKE_PACKET_LENGTH]; + + if (create_crypto_handshake(c, handshake_packet, cookie, conn->sent_nonce, conn->sessionpublic_key, + conn->public_key, dht_public_key) != sizeof(handshake_packet)) + return -1; + + if (new_temp_packet(c, crypt_connection_id, handshake_packet, sizeof(handshake_packet)) != 0) + return -1; + + send_temp_packet(c, crypt_connection_id); + return 0; +} + +/* Send a kill packet. + * + * return -1 on failure. + * return 0 on success. + */ +static int send_kill_packet(Net_Crypto *c, int crypt_connection_id) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) + return -1; + + uint8_t kill_packet = PACKET_ID_KILL; + return send_data_packet_helper(c, crypt_connection_id, conn->recv_array.buffer_start, conn->send_array.buffer_end, + &kill_packet, sizeof(kill_packet)); +} + +/* Handle a recieved data packet. + * + * return -1 on failure. + * return 0 on success. + */ +static int handle_data_packet_helper(Net_Crypto *c, int crypt_connection_id, uint8_t *packet, uint16_t length) +{ + if (length > MAX_CRYPTO_PACKET_SIZE || length <= CRYPTO_DATA_PACKET_MIN_SIZE) + return -1; + + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) + return -1; + + uint8_t data[MAX_DATA_DATA_PACKET_SIZE]; + int len = handle_data_packet(c, crypt_connection_id, data, packet, length); + + if (len <= (int)(sizeof(uint32_t) * 2)) + return -1; + + uint32_t buffer_start, num; + memcpy(&buffer_start, data, sizeof(uint32_t)); + memcpy(&num, data + sizeof(uint32_t), sizeof(uint32_t)); + buffer_start = ntohl(buffer_start); + num = ntohl(num); + + if (buffer_start != conn->send_array.buffer_start && clear_buffer_until(&conn->send_array, buffer_start) != 0) + return -1; + + uint8_t *real_data = data + (sizeof(uint32_t) * 2); + uint16_t real_length = len - (sizeof(uint32_t) * 2); + + while (real_data[0] == 0) { /* Remove Padding */ + ++real_data; + --real_length; + + if (real_length == 0) + return -1; + } + + if (real_data[0] == PACKET_ID_REQUEST) { + int requested = handle_request_packet(&conn->send_array, real_data, real_length); + + if (requested == -1) { + return -1; + } else { + //TODO? + } + + set_buffer_end(&conn->recv_array, num); + } else if (real_data[0] == PACKET_ID_KILL) { + conn->killed = 1; + return 0; + } else { + Packet_Data dt; + dt.time = current_time_monotonic(); + dt.length = real_length; + memcpy(dt.data, real_data, real_length); + + if (add_data_to_buffer(&conn->recv_array, num, &dt) != 0) + return -1; + + while (read_data_beg_buffer(&conn->recv_array, &dt) != -1) { + if (conn->connection_data_callback) + conn->connection_data_callback(conn->connection_data_callback_object, conn->connection_data_callback_id, dt.data, + dt.length); + } + + /* Packet counter. */ + ++conn->packet_counter; + } + + if (conn->status == CRYPTO_CONN_NOT_CONFIRMED) { + if (conn->connection_status_callback) + conn->connection_status_callback(conn->connection_status_callback_object, conn->connection_status_callback_id, 1); + + clear_temp_packet(c, crypt_connection_id); + conn->status = CRYPTO_CONN_ESTABLISHED; + } + + return 0; +} + +/* Handle a packet that was recieved for the connection. + * + * return -1 on failure. + * return 0 on success. + */ +static int handle_packet_connection(Net_Crypto *c, int crypt_connection_id, uint8_t *packet, uint16_t length) +{ + if (length == 0 || length > MAX_CRYPTO_PACKET_SIZE) + return -1; + + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) + return -1; + + switch (packet[0]) { + case NET_PACKET_COOKIE_RESPONSE: { + if (conn->status != CRYPTO_CONN_COOKIE_REQUESTING) + return -1; + + uint8_t cookie[COOKIE_LENGTH]; + uint64_t number; + + if (handle_cookie_response(cookie, &number, packet, length, conn->shared_key) != sizeof(cookie)) + return -1; + + if (number != conn->cookie_request_number) + return -1; + + if (create_send_handshake(c, crypt_connection_id, cookie, conn->dht_public_key) != 0) + return -1; + + conn->status = CRYPTO_CONN_HANDSHAKE_SENT; + return 0; + } + + case NET_PACKET_CRYPTO_HS: { + if (conn->status == CRYPTO_CONN_COOKIE_REQUESTING || conn->status == CRYPTO_CONN_HANDSHAKE_SENT) { + uint8_t peer_real_pk[crypto_box_PUBLICKEYBYTES]; + uint8_t dht_public_key[crypto_box_PUBLICKEYBYTES]; + uint8_t cookie[COOKIE_LENGTH]; + + if (handle_crypto_handshake(c, conn->recv_nonce, conn->peersessionpublic_key, peer_real_pk, dht_public_key, cookie, + packet, length, conn->public_key) != 0) + return -1; + + encrypt_precompute(conn->peersessionpublic_key, conn->sessionsecret_key, conn->shared_key); + + if (conn->status == CRYPTO_CONN_COOKIE_REQUESTING) { + if (create_send_handshake(c, crypt_connection_id, cookie, dht_public_key) != 0) + return -1; + } + + conn->status = CRYPTO_CONN_NOT_CONFIRMED; + /* Status needs to be CRYPTO_CONN_NOT_CONFIRMED for this to work. */ + set_connection_dht_public_key(c, crypt_connection_id, dht_public_key, current_time_monotonic()); + } else { + return -1; + } + + return 0; + } + + case NET_PACKET_CRYPTO_DATA: { + if (conn->status == CRYPTO_CONN_NOT_CONFIRMED || conn->status == CRYPTO_CONN_ESTABLISHED) { + return handle_data_packet_helper(c, crypt_connection_id, packet, length); + } else { + return -1; + } + + return 0; + } + + default: { + return -1; + } + } + + return 0; +} + +/* Set the size of the friend list to numfriends. + * + * return -1 if realloc fails. + * return 0 if it succeeds. + */ +static int realloc_cryptoconnection(Net_Crypto *c, uint32_t num) +{ + if (num == 0) { + free(c->crypto_connections); + c->crypto_connections = NULL; + return 0; + } + + Crypto_Connection *newcrypto_connections = realloc(c->crypto_connections, num * sizeof(Crypto_Connection)); + + if (newcrypto_connections == NULL) + return -1; + + c->crypto_connections = newcrypto_connections; + return 0; +} + + +/* Create a new empty crypto connection. + * + * return -1 on failure. + * return connection id on success. + */ +static int create_crypto_connection(Net_Crypto *c) +{ + uint32_t i; + + for (i = 0; i < c->crypto_connections_length; ++i) { + if (c->crypto_connections[i].status == CRYPTO_CONN_NO_CONNECTION) + return i; + } + + if (realloc_cryptoconnection(c, c->crypto_connections_length + 1) == -1) + return -1; + + memset(&(c->crypto_connections[c->crypto_connections_length]), 0, sizeof(Crypto_Connection)); + int id = c->crypto_connections_length; + ++c->crypto_connections_length; + return id; +} + +/* Wipe a crypto connection. + * + * return -1 on failure. + * return 0 on success. + */ +static int wipe_crypto_connection(Net_Crypto *c, int crypt_connection_id) +{ + if (crypt_connection_id_not_valid(c, crypt_connection_id)) + return -1; + + uint32_t i; + memset(&(c->crypto_connections[crypt_connection_id]), 0 , sizeof(Crypto_Connection)); + + for (i = c->crypto_connections_length; i != 0; --i) { + if (c->crypto_connections[i - 1].status != CRYPTO_CONN_NO_CONNECTION) + break; + } + + if (c->crypto_connections_length != i) { + c->crypto_connections_length = i; + realloc_cryptoconnection(c, c->crypto_connections_length); + } + + return 0; +} + +/* Get crypto connection id from public key of peer. + * + * return -1 if there are no connections like we are looking for. + * return id if it found it. + */ +static int getcryptconnection_id(Net_Crypto *c, uint8_t *public_key) +{ + uint32_t i; + + for (i = 0; i < c->crypto_connections_length; ++i) { + if (c->crypto_connections[i].status != CRYPTO_CONN_NO_CONNECTION) + if (memcmp(public_key, c->crypto_connections[i].public_key, crypto_box_PUBLICKEYBYTES) == 0) + return i; + } + + return -1; +} + +/* Get crypto connection id from public key of peer. + * + * return -1 if there are no connections like we are looking for. + * return id if it found it. + */ +static int getcryptconnection_id_dht_pubkey(Net_Crypto *c, uint8_t *dht_public_key) +{ + uint32_t i; + + for (i = 0; i < c->crypto_connections_length; ++i) { + if (c->crypto_connections[i].status != CRYPTO_CONN_NO_CONNECTION && c->crypto_connections[i].dht_public_key_set) + if (memcmp(dht_public_key, c->crypto_connections[i].dht_public_key, crypto_box_PUBLICKEYBYTES) == 0) + return i; + } + + return -1; +} + +/* Add a source to the crypto connection. + * This is to be used only when we have recieved a packet from that source. + * + * return -1 on failure. + * return positive number on success. + * 0 if source was a direct UDP connection. + * TODO + */ +static int crypto_connection_add_source(Net_Crypto *c, int crypt_connection_id, IP_Port source) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) + return -1; + + if (source.ip.family == AF_INET || source.ip.family == AF_INET6) { + conn->ip_port = source; + conn->direct_lastrecv_time = current_time_monotonic(); + return 0; + } + + return -1; +} + + +/* Set function to be called when someone requests a new connection to us. + * + * The set function should return -1 on failure and 0 on success. + * + * n_c is only valid for the duration of the function call. + */ +void new_connection_handler(Net_Crypto *c, int (*new_connection_callback)(void *object, New_Connection *n_c), + void *object) +{ + c->new_connection_callback = new_connection_callback; + c->new_connection_callback_object = object; +} + +/* Handle a handshake packet by someone who wants to initiate a new connection with us. + * This calls the callback set by new_connection_handler() if the handshake is ok. + * + * return -1 on failure. + * return 0 on success. + */ +static int handle_new_connection_handshake(Net_Crypto *c, IP_Port source, uint8_t *data, uint16_t length) +{ + New_Connection n_c; + n_c.cookie = malloc(COOKIE_LENGTH); + + if (n_c.cookie == NULL) + return -1; + + n_c.source = source; + n_c.cookie_length = COOKIE_LENGTH; + + if (handle_crypto_handshake(c, n_c.recv_nonce, n_c.peersessionpublic_key, n_c.public_key, n_c.dht_public_key, + n_c.cookie, data, length, 0) != 0) { + free(n_c.cookie); + return -1; + } + + int crypt_connection_id = getcryptconnection_id(c, n_c.public_key); + + if (crypt_connection_id != -1) { + int ret = -1; + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn != 0 && (conn->status == CRYPTO_CONN_COOKIE_REQUESTING || conn->status == CRYPTO_CONN_HANDSHAKE_SENT)) { + memcpy(conn->recv_nonce, n_c.recv_nonce, crypto_box_NONCEBYTES); + memcpy(conn->peersessionpublic_key, n_c.peersessionpublic_key, crypto_box_PUBLICKEYBYTES); + encrypt_precompute(conn->peersessionpublic_key, conn->sessionsecret_key, conn->shared_key); + + crypto_connection_add_source(c, crypt_connection_id, source); + + if (create_send_handshake(c, crypt_connection_id, n_c.cookie, n_c.dht_public_key) == 0) { + conn->status = CRYPTO_CONN_NOT_CONFIRMED; + /* Status needs to be CRYPTO_CONN_NOT_CONFIRMED for this to work. */ + set_connection_dht_public_key(c, crypt_connection_id, n_c.dht_public_key, current_time_monotonic()); + ret = 0; + } + } + + free(n_c.cookie); + return ret; + } + + int ret = c->new_connection_callback(c->new_connection_callback_object, &n_c); + free(n_c.cookie); + return ret; +} + +/* Accept a crypto connection. + * + * return -1 on failure. + * return connection id on success. + */ +int accept_crypto_connection(Net_Crypto *c, New_Connection *n_c) +{ + if (getcryptconnection_id(c, n_c->public_key) != -1) + return -1; + + int crypt_connection_id = create_crypto_connection(c); + + if (crypt_connection_id == -1) + return -1; + + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) + return -1; + + memcpy(conn->public_key, n_c->public_key, crypto_box_PUBLICKEYBYTES); + memcpy(conn->recv_nonce, n_c->recv_nonce, crypto_box_NONCEBYTES); + memcpy(conn->peersessionpublic_key, n_c->peersessionpublic_key, crypto_box_PUBLICKEYBYTES); + random_nonce(conn->sent_nonce); + crypto_box_keypair(conn->sessionpublic_key, conn->sessionsecret_key); + encrypt_precompute(conn->peersessionpublic_key, conn->sessionsecret_key, conn->shared_key); + + if (n_c->cookie_length != COOKIE_LENGTH) + return -1; + + if (create_send_handshake(c, crypt_connection_id, n_c->cookie, n_c->dht_public_key) != 0) + return -1; + + conn->status = CRYPTO_CONN_NOT_CONFIRMED; + /* Status needs to be CRYPTO_CONN_NOT_CONFIRMED for this to work. */ + set_connection_dht_public_key(c, crypt_connection_id, n_c->dht_public_key, current_time_monotonic()); + conn->packet_send_rate = CRYPTO_PACKET_MIN_RATE; + crypto_connection_add_source(c, crypt_connection_id, n_c->source); + return crypt_connection_id; +} + +/* Create a crypto connection. + * If one to that real public key already exists, return it. + * + * return -1 on failure. + * return connection id on success. + */ +int new_crypto_connection(Net_Crypto *c, uint8_t *real_public_key) +{ + int crypt_connection_id = getcryptconnection_id(c, real_public_key); + + if (crypt_connection_id != -1) + return crypt_connection_id; + + crypt_connection_id = create_crypto_connection(c); + + if (crypt_connection_id == -1) + return -1; + + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) + return -1; + + memcpy(conn->public_key, real_public_key, crypto_box_PUBLICKEYBYTES); + random_nonce(conn->sent_nonce); + crypto_box_keypair(conn->sessionpublic_key, conn->sessionsecret_key); + conn->status = CRYPTO_CONN_COOKIE_REQUESTING; + conn->packet_send_rate = CRYPTO_PACKET_MIN_RATE; + return crypt_connection_id; +} + +/* Disconnect peer from all associated TCP connections. + * + * return -1 on failure. + * return 0 on success. + */ +static int disconnect_peer_tcp(Net_Crypto *c, int crypt_connection_id) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) + return -1; + + uint32_t i; + + for (i = 0; i < MAX_TCP_CONNECTIONS; ++i) { + if (conn->status_tcp[i] != STATUS_TCP_NULL) { + send_disconnect_request(c->tcp_connections[i], conn->con_number_tcp[i]); + conn->status_tcp[i] = STATUS_TCP_NULL; + conn->con_number_tcp[i] = 0; + } + } + + return 0; +} + +/* Connect peer to all associated TCP connections. + * + * return -1 on failure. + * return 0 on success. + */ +static int connect_peer_tcp(Net_Crypto *c, int crypt_connection_id) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) + return -1; + + uint32_t i; + + for (i = 0; i < MAX_TCP_CONNECTIONS; ++i) { + if (c->tcp_connections[i] == NULL) + continue; + + //TODO check function return? + send_routing_request(c->tcp_connections[i], conn->dht_public_key); + } + + return 0; +} + +/* Copy friends DHT public key into dht_key. + * + * return 0 on failure (no key copied). + * return timestamp on success (key copied). + */ +uint64_t get_connection_dht_key(Net_Crypto *c, int crypt_connection_id, uint8_t *dht_public_key) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) + return 0; + + if (conn->dht_public_key_set == 0) + return 0; + + memcpy(dht_public_key, conn->dht_public_key, crypto_box_PUBLICKEYBYTES); + return conn->dht_public_key_timestamp; +} + + +/* Set the DHT public key of the crypto connection. + * timestamp is the time (current_time_monotonic()) at which the key was last confirmed belonging to + * the other peer. + * + * return -1 on failure. + * return 0 on success. + */ +int set_connection_dht_public_key(Net_Crypto *c, int crypt_connection_id, uint8_t *dht_public_key, uint64_t timestamp) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) + return -1; + + if (timestamp <= conn->dht_public_key_timestamp) + return -1; + + if (conn->dht_public_key_set == 1 && memcmp(conn->dht_public_key, dht_public_key, crypto_box_PUBLICKEYBYTES) == 0) + return -1; + + if (conn->dht_public_key_set == 1) { + disconnect_peer_tcp(c, crypt_connection_id); + } + + memcpy(conn->dht_public_key, dht_public_key, crypto_box_PUBLICKEYBYTES); + conn->dht_public_key_set = 1; + conn->dht_public_key_timestamp = timestamp; + + if (conn->status == CRYPTO_CONN_COOKIE_REQUESTING) { + conn->cookie_request_number = random_64b(); + uint8_t cookie_request[COOKIE_REQUEST_LENGTH]; + + if (create_cookie_request(c, cookie_request, conn->dht_public_key, conn->cookie_request_number, + conn->shared_key) != sizeof(cookie_request)) + return -1; + + if (new_temp_packet(c, crypt_connection_id, cookie_request, sizeof(cookie_request)) != 0) + return -1; + }//TODO + + connect_peer_tcp(c, crypt_connection_id); + return 0; +} + +/* Set the direct ip of the crypto connection. + * + * return -1 on failure. + * return 0 on success. + */ +int set_direct_ip_port(Net_Crypto *c, int crypt_connection_id, IP_Port ip_port) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) + return -1; + + if (!ipport_equal(&ip_port, &conn->ip_port)) { + conn->ip_port = ip_port; + conn->direct_lastrecv_time = 0; + return 0; + } + + return -1; +} + +static int tcp_response_callback(void *object, uint8_t connection_id, uint8_t *public_key) +{ + TCP_Client_Connection *TCP_con = object; + Net_Crypto *c = TCP_con->net_crypto_pointer; + + int crypt_connection_id = getcryptconnection_id_dht_pubkey(c, public_key); + + if (crypt_connection_id == -1) + return -1; + + set_tcp_connection_number(TCP_con, connection_id, crypt_connection_id); + + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) + return -1; + + uint32_t location = TCP_con->net_crypto_location; + + if (location >= MAX_TCP_CONNECTIONS) + return -1; + + if (c->tcp_connections[location] != TCP_con) + return -1; + + conn->con_number_tcp[location] = connection_id; + uint32_t i; + + for (i = 0; i < conn->num_tcp_relays; ++i) { + if (memcmp(TCP_con->public_key, conn->tcp_relays[i].client_id, crypto_box_PUBLICKEYBYTES) == 0) { + conn->status_tcp[location] = STATUS_TCP_INVISIBLE; + return 0; + } + } + + conn->status_tcp[location] = STATUS_TCP_OFFLINE; + return 0; +} + +static int tcp_status_callback(void *object, uint32_t number, uint8_t connection_id, uint8_t status) +{ + TCP_Client_Connection *TCP_con = object; + Net_Crypto *c = TCP_con->net_crypto_pointer; + + Crypto_Connection *conn = get_crypto_connection(c, number); + + if (conn == 0) + return -1; + + uint32_t location = TCP_con->net_crypto_location; + + if (location >= MAX_TCP_CONNECTIONS) + return -1; + + if (c->tcp_connections[location] != TCP_con) + return -1; + + if (status == 1) { + conn->status_tcp[location] = STATUS_TCP_OFFLINE; + } else if (status == 2) { + conn->status_tcp[location] = STATUS_TCP_ONLINE; + } + + conn->con_number_tcp[location] = connection_id; + return 0; +} + +static int tcp_data_callback(void *object, uint32_t number, uint8_t connection_id, uint8_t *data, uint16_t length) +{ + + if (length == 0) + return -1; + + TCP_Client_Connection *TCP_con = object; + Net_Crypto *c = TCP_con->net_crypto_pointer; + + if (data[0] == NET_PACKET_COOKIE_REQUEST) { + return tcp_handle_cookie_request(c, TCP_con, connection_id, data, length); + } + + Crypto_Connection *conn = get_crypto_connection(c, number); + + if (conn == 0) + return -1; + + if (handle_packet_connection(c, number, data, length) != 0) + return -1; + + //TODO detect and kill bad TCP connections. + return 0; +} + +static int tcp_oob_callback(void *object, uint8_t *public_key, uint8_t *data, uint16_t length) +{ + if (length == 0 || length > MAX_CRYPTO_PACKET_SIZE) + return -1; + + TCP_Client_Connection *TCP_con = object; + Net_Crypto *c = TCP_con->net_crypto_pointer; + uint32_t location = TCP_con->net_crypto_location; + + if (data[0] == NET_PACKET_COOKIE_REQUEST) { + return tcp_oob_handle_cookie_request(c, TCP_con, public_key, data, length); + } + + int crypt_connection_id = getcryptconnection_id_dht_pubkey(c, public_key); + + if (crypt_connection_id == -1) { + IP_Port source; + source.ip.family = TCP_FAMILY; + source.ip.ip6.uint32[0] = location; + + if (data[0] != NET_PACKET_CRYPTO_HS) { + fprintf(stderr, "tcp snhappen %u\n", data[0]); + return -1; + } + + if (handle_new_connection_handshake(c, source, data, length) != 0) + return -1; + + return 0; + } + + if (handle_packet_connection(c, crypt_connection_id, data, length) != 0) + return -1; + + return 0; +} + +/* Check if tcp connection to public key can be created. + * + * return -1 if it can't. + * return 0 if it can. + */ +static int tcp_connection_check(Net_Crypto *c, uint8_t *public_key) +{ + uint32_t i; + + for (i = 0; i < MAX_TCP_CONNECTIONS; ++i) { + if (c->tcp_connections_new[i] == NULL) + continue; + + if (memcmp(c->tcp_connections_new[i]->public_key, public_key, crypto_box_PUBLICKEYBYTES) == 0) + return -1; + } + + uint32_t num = 0; + + for (i = 0; i < MAX_TCP_CONNECTIONS; ++i) { + if (c->tcp_connections[i] == NULL) + continue; + + if (memcmp(c->tcp_connections[i]->public_key, public_key, crypto_box_PUBLICKEYBYTES) == 0) + return -1; + + ++num; + } + + if (num == MAX_TCP_CONNECTIONS) + return -1; + + return 0; +} + +/* Add a tcp relay, associating it to a crypt_connection_id. + * + * return 0 if it was added. + * return -1 if it wasn't. + */ +int add_tcp_relay_peer(Net_Crypto *c, int crypt_connection_id, IP_Port ip_port, uint8_t *public_key) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) + return -1; + + if (ip_port.ip.family == TCP_INET) { + ip_port.ip.family = AF_INET; + } else if (ip_port.ip.family == TCP_INET6) { + ip_port.ip.family = AF_INET6; + } + + if (ip_port.ip.family != AF_INET && ip_port.ip.family != AF_INET6) + return -1; + + uint32_t i; + + for (i = 0; i < conn->num_tcp_relays; ++i) { + if (memcmp(conn->tcp_relays[i].client_id, public_key, crypto_box_PUBLICKEYBYTES) == 0) { + conn->tcp_relays[i].ip_port = ip_port; + return 0; + } + } + + if (conn->num_tcp_relays == MAX_TCP_RELAYS_PEER) { + uint16_t index = rand() % MAX_TCP_RELAYS_PEER; + conn->tcp_relays[index].ip_port = ip_port; + memcpy(conn->tcp_relays[index].client_id, public_key, crypto_box_PUBLICKEYBYTES); + } else { + conn->tcp_relays[conn->num_tcp_relays].ip_port = ip_port; + memcpy(conn->tcp_relays[conn->num_tcp_relays].client_id, public_key, crypto_box_PUBLICKEYBYTES); + ++conn->num_tcp_relays; + } + + for (i = 0; i < MAX_TCP_CONNECTIONS; ++i) { + if (c->tcp_connections[i] == NULL) + continue; + + if (memcmp(c->tcp_connections[i]->public_key, public_key, crypto_box_PUBLICKEYBYTES) == 0) { + if (conn->status_tcp[i] == STATUS_TCP_OFFLINE) + conn->status_tcp[i] = STATUS_TCP_INVISIBLE; + } + } + + return add_tcp_relay(c, ip_port, public_key); +} + +/* Add a tcp relay to the array. + * + * return 0 if it was added. + * return -1 if it wasn't. + */ +int add_tcp_relay(Net_Crypto *c, IP_Port ip_port, uint8_t *public_key) +{ + if (ip_port.ip.family == TCP_INET) { + ip_port.ip.family = AF_INET; + } else if (ip_port.ip.family == TCP_INET6) { + ip_port.ip.family = AF_INET6; + } - if (length == 0) - return 0; + if (ip_port.ip.family != AF_INET && ip_port.ip.family != AF_INET6) + return -1; - if (temp_data[0] != 3) + if (tcp_connection_check(c, public_key) != 0) return -1; - int len = decrypt_data_fast(c->crypto_connections[crypt_connection_id].shared_key, - c->crypto_connections[crypt_connection_id].recv_nonce, - temp_data + 1, length - 1, data); + uint32_t i; - if (len != -1) { - increment_nonce(c->crypto_connections[crypt_connection_id].recv_nonce); - return len; + for (i = 0; i < MAX_TCP_CONNECTIONS; ++i) { + if (c->tcp_connections_new[i] == NULL) { + c->tcp_connections_new[i] = new_TCP_connection(ip_port, public_key, c->dht->self_public_key, c->dht->self_secret_key); + return 0; + } } return -1; } -/* returns the number of packet slots left in the sendbuffer. - * return 0 if failure. - */ -uint32_t crypto_num_free_sendqueue_slots(Net_Crypto *c, int crypt_connection_id) -{ - if (crypt_connection_id_not_valid(c, crypt_connection_id)) - return 0; - - return num_free_sendqueue_slots(c->lossless_udp, c->crypto_connections[crypt_connection_id].number); -} - -/* return 0 if data could not be put in packet queue. - * return 1 if data was put into the queue. +/* Copy a maximum of num TCP relays we are connected to to tcp_relays. + * NOTE that the family of the copied ip ports will be set to TCP_INET or TCP_INET6. + * + * return number of relays copied to tcp_relays on success. + * return 0 on failure. */ -int write_cryptpacket(Net_Crypto *c, int crypt_connection_id, uint8_t *data, uint32_t length) +unsigned int copy_connected_tcp_relays(Net_Crypto *c, Node_format *tcp_relays, uint16_t num) { - if (crypt_connection_id_not_valid(c, crypt_connection_id)) + if (num == 0) return 0; - if (length - crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES > MAX_DATA_SIZE - 1) - return 0; - - if (c->crypto_connections[crypt_connection_id].status != CRYPTO_CONN_ESTABLISHED) - return 0; + uint32_t i; + uint16_t copied = 0; - uint8_t temp_data[MAX_DATA_SIZE]; - int len = encrypt_data_fast(c->crypto_connections[crypt_connection_id].shared_key, - c->crypto_connections[crypt_connection_id].sent_nonce, - data, length, temp_data + 1); + for (i = 0; i < MAX_TCP_CONNECTIONS; ++i) { + if (c->tcp_connections[i] != NULL) { + memcpy(tcp_relays[copied].client_id, c->tcp_connections[i]->public_key, crypto_box_PUBLICKEYBYTES); + tcp_relays[copied].ip_port = c->tcp_connections[i]->ip_port; - if (len == -1) - return 0; + if (tcp_relays[copied].ip_port.ip.family == AF_INET) { + tcp_relays[copied].ip_port.ip.family = TCP_INET; + } else if (tcp_relays[copied].ip_port.ip.family == AF_INET6) { + tcp_relays[copied].ip_port.ip.family = TCP_INET6; + } - temp_data[0] = 3; + ++copied; - if (write_packet(c->lossless_udp, c->crypto_connections[crypt_connection_id].number, temp_data, len + 1) == 0) - return 0; + if (copied == num) + return copied; + } + } - increment_nonce(c->crypto_connections[crypt_connection_id].sent_nonce); - return 1; + return copied; } -/* Create a request to peer. - * send_public_key and send_secret_key are the pub/secret keys of the sender. - * recv_public_key is public key of reciever. - * packet must be an array of MAX_DATA_SIZE big. - * Data represents the data we send with the request with length being the length of the data. - * request_id is the id of the request (32 = friend request, 254 = ping request). +/* Add a connected tcp connection to the tcp_connections array. * - * return -1 on failure. - * return the length of the created packet on success. + * return 0 if it was added. + * return -1 if it wasn't. */ -int create_request(uint8_t *send_public_key, uint8_t *send_secret_key, uint8_t *packet, uint8_t *recv_public_key, - uint8_t *data, uint32_t length, uint8_t request_id) +static int add_tcp_connected(Net_Crypto *c, TCP_Client_Connection *tcp_con) { - if (MAX_DATA_SIZE < length + 1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1 + crypto_box_MACBYTES) - return -1; + uint32_t i; - uint8_t nonce[crypto_box_NONCEBYTES]; - uint8_t temp[MAX_DATA_SIZE]; - memcpy(temp + 1, data, length); - temp[0] = request_id; - new_nonce(nonce); - int len = encrypt_data(recv_public_key, send_secret_key, nonce, temp, length + 1, - 1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + packet); + for (i = 0; i < MAX_TCP_CONNECTIONS; ++i) { + if (c->tcp_connections[i] == NULL) + break; + } - if (len == -1) + if (i == MAX_TCP_CONNECTIONS) return -1; - packet[0] = NET_PACKET_CRYPTO; - memcpy(packet + 1, recv_public_key, crypto_box_PUBLICKEYBYTES); - memcpy(packet + 1 + crypto_box_PUBLICKEYBYTES, send_public_key, crypto_box_PUBLICKEYBYTES); - memcpy(packet + 1 + crypto_box_PUBLICKEYBYTES * 2, nonce, crypto_box_NONCEBYTES); + uint32_t tcp_num = i; + + for (i = 0; i < c->crypto_connections_length; ++i) { + Crypto_Connection *conn = get_crypto_connection(c, i); + + if (conn == 0) + return -1; + + if (conn->status == CRYPTO_CONN_NO_CONNECTION) + continue; + + if (conn->status == CRYPTO_CONN_TIMED_OUT) + continue; + + if (conn->dht_public_key_set) + if (send_routing_request(tcp_con, conn->dht_public_key) != 1) + return -1; + + } - return len + 1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES; + tcp_con->net_crypto_pointer = c; + tcp_con->net_crypto_location = tcp_num; + routing_response_handler(tcp_con, tcp_response_callback, tcp_con); + routing_status_handler(tcp_con, tcp_status_callback, tcp_con); + routing_data_handler(tcp_con, tcp_data_callback, tcp_con); + oob_data_handler(tcp_con, tcp_oob_callback, tcp_con); + c->tcp_connections[tcp_num] = tcp_con; + return 0; } -/* Puts the senders public key in the request in public_key, the data from the request - * in data if a friend or ping request was sent to us and returns the length of the data. - * packet is the request packet and length is its length. - * - * return -1 if not valid request. - */ -int handle_request(uint8_t *self_public_key, uint8_t *self_secret_key, uint8_t *public_key, uint8_t *data, - uint8_t *request_id, uint8_t *packet, uint16_t length) +static void do_tcp(Net_Crypto *c) { - if (length > crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1 + crypto_box_MACBYTES && - length <= MAX_DATA_SIZE) { - if (memcmp(packet + 1, self_public_key, crypto_box_PUBLICKEYBYTES) == 0) { - memcpy(public_key, packet + 1 + crypto_box_PUBLICKEYBYTES, crypto_box_PUBLICKEYBYTES); - uint8_t nonce[crypto_box_NONCEBYTES]; - uint8_t temp[MAX_DATA_SIZE]; - memcpy(nonce, packet + 1 + crypto_box_PUBLICKEYBYTES * 2, crypto_box_NONCEBYTES); - int len1 = decrypt_data(public_key, self_secret_key, nonce, - packet + 1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES, - length - (crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1), temp); + uint32_t i; - if (len1 == -1 || len1 == 0) - return -1; + for (i = 0; i < MAX_TCP_CONNECTIONS; ++i) { + if (c->tcp_connections_new[i] == NULL) + continue; + + do_TCP_connection(c->tcp_connections_new[i]); - request_id[0] = temp[0]; - --len1; - memcpy(data, temp + 1, len1); - return len1; + if (c->tcp_connections_new[i]->status == TCP_CLIENT_CONFIRMED) { + if (add_tcp_connected(c, c->tcp_connections_new[i]) == 0) { + c->tcp_connections_new[i] = NULL; + } else { + kill_TCP_connection(c->tcp_connections_new[i]); + c->tcp_connections_new[i] = NULL; + } } } - return -1; + for (i = 0; i < MAX_TCP_CONNECTIONS; ++i) { + if (c->tcp_connections[i] == NULL) + continue; + + do_TCP_connection(c->tcp_connections[i]); + } } -void cryptopacket_registerhandler(Net_Crypto *c, uint8_t byte, cryptopacket_handler_callback cb, void *object) +static void clear_disconnected_tcp_peer(Crypto_Connection *conn, uint32_t number) { - c->cryptopackethandlers[byte].function = cb; - c->cryptopackethandlers[byte].object = object; + if (conn->status == CRYPTO_CONN_NO_CONNECTION) + return; + + if (number >= MAX_TCP_CONNECTIONS) + return; + + conn->status_tcp[number] = STATUS_TCP_NULL; + conn->con_number_tcp[number] = 0; } -static int cryptopacket_handle(void *object, IP_Port source, uint8_t *packet, uint32_t length) +static void clear_disconnected_tcp(Net_Crypto *c) { - DHT *dht = object; + uint32_t i, j; - if (packet[0] == NET_PACKET_CRYPTO) { - if (length <= crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1 + crypto_box_MACBYTES || - length > MAX_DATA_SIZE + crypto_box_MACBYTES) - return 1; + for (i = 0; i < MAX_TCP_CONNECTIONS; ++i) { + if (c->tcp_connections_new[i] == NULL) + continue; + + if (c->tcp_connections_new[i]->status != TCP_CLIENT_DISCONNECTED) + continue; + + kill_TCP_connection(c->tcp_connections_new[i]); + c->tcp_connections_new[i] = NULL; + } - if (memcmp(packet + 1, dht->self_public_key, crypto_box_PUBLICKEYBYTES) == 0) { // Check if request is for us. - uint8_t public_key[crypto_box_PUBLICKEYBYTES]; - uint8_t data[MAX_DATA_SIZE]; - uint8_t number; - int len = handle_request(dht->self_public_key, dht->self_secret_key, public_key, data, &number, packet, length); + for (i = 0; i < MAX_TCP_CONNECTIONS; ++i) { + if (c->tcp_connections[i] == NULL) + continue; + + TCP_Client_Connection *tcp_con = c->tcp_connections[i]; - if (len == -1 || len == 0) - return 1; + if (tcp_con->status != TCP_CLIENT_DISCONNECTED) + continue; - if (!dht->c->cryptopackethandlers[number].function) return 1; + c->tcp_connections[i] = NULL; + kill_TCP_connection(tcp_con); - return dht->c->cryptopackethandlers[number].function(dht->c->cryptopackethandlers[number].object, source, public_key, - data, len); + for (j = 0; j < c->crypto_connections_length; ++j) { + Crypto_Connection *conn = get_crypto_connection(c, j); - } else { /* If request is not for us, try routing it. */ - int retval = route_packet(dht, packet + 1, packet, length); + if (conn == 0) + return; - if ((unsigned int)retval == length) - return 0; + clear_disconnected_tcp_peer(conn, i); } } - - return 1; } -/* Send a crypto handshake packet containing an encrypted secret nonce and session public key - * to peer with connection_id and public_key. - * The packet is encrypted with a random nonce which is sent in plain text with the packet. +/* Set function to be called when connection with crypt_connection_id goes connects/disconnects. + * + * The set function should return -1 on failure and 0 on success. + * Note that if this function is set, the connection will clear itself on disconnect. + * Object and id will be passed to this function untouched. + * status is 1 if the connection is going online, 0 if it is going offline. + * + * return -1 on failure. + * return 0 on success. */ -static int send_cryptohandshake(Net_Crypto *c, int connection_id, uint8_t *public_key, uint8_t *secret_nonce, - uint8_t *session_key) +int connection_status_handler(Net_Crypto *c, int crypt_connection_id, int (*connection_status_callback)(void *object, + int id, uint8_t status), void *object, int id) { - uint8_t temp_data[MAX_DATA_SIZE]; - uint8_t temp[crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES]; - uint8_t nonce[crypto_box_NONCEBYTES]; - - new_nonce(nonce); - memcpy(temp, secret_nonce, crypto_box_NONCEBYTES); - memcpy(temp + crypto_box_NONCEBYTES, session_key, crypto_box_PUBLICKEYBYTES); - - int len = encrypt_data(public_key, c->self_secret_key, nonce, temp, crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES, - 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + temp_data); + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); - if (len == -1) - return 0; + if (conn == 0) + return -1; - temp_data[0] = 2; - memcpy(temp_data + 1, c->self_public_key, crypto_box_PUBLICKEYBYTES); - memcpy(temp_data + 1 + crypto_box_PUBLICKEYBYTES, nonce, crypto_box_NONCEBYTES); - return write_packet(c->lossless_udp, connection_id, temp_data, - len + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES); + conn->connection_status_callback = connection_status_callback; + conn->connection_status_callback_object = object; + conn->connection_status_callback_id = id; + return 0; } -/* Extract secret nonce, session public key and public_key from a packet(data) with length length. +/* Set function to be called when connection with crypt_connection_id receives a data packet of length. * - * return 1 if successful. - * return 0 if failure. + * The set function should return -1 on failure and 0 on success. + * Object and id will be passed to this function untouched. + * + * return -1 on failure. + * return 0 on success. */ -static int handle_cryptohandshake(Net_Crypto *c, uint8_t *public_key, uint8_t *secret_nonce, - uint8_t *session_key, uint8_t *data, uint16_t length) +int connection_data_handler(Net_Crypto *c, int crypt_connection_id, int (*connection_data_callback)(void *object, + int id, uint8_t *data, uint16_t length), void *object, int id) { - int pad = (- crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES); - - if (length != 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES - + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + pad) { - return 0; - } - - if (data[0] != 2) - return 0; - - uint8_t temp[crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES]; - - memcpy(public_key, data + 1, crypto_box_PUBLICKEYBYTES); + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); - int len = decrypt_data(public_key, c->self_secret_key, data + 1 + crypto_box_PUBLICKEYBYTES, - data + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, - crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + pad, temp); - - if (len != crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES) - return 0; + if (conn == 0) + return -1; - memcpy(secret_nonce, temp, crypto_box_NONCEBYTES); - memcpy(session_key, temp + crypto_box_NONCEBYTES, crypto_box_PUBLICKEYBYTES); - return 1; + conn->connection_data_callback = connection_data_callback; + conn->connection_data_callback_object = object; + conn->connection_data_callback_id = id; + return 0; } -/* Get crypto connection id from public key of peer. +/* Get the crypto connection id from the ip_port. * - * return -1 if there are no connections like we are looking for. - * return id if it found it. + * return -1 on failure. + * return connection id on success. */ -static int getcryptconnection_id(Net_Crypto *c, uint8_t *public_key) +static int crypto_id_ip_port(Net_Crypto *c, IP_Port ip_port) { uint32_t i; for (i = 0; i < c->crypto_connections_length; ++i) { - if (c->crypto_connections[i].status != CRYPTO_CONN_NO_CONNECTION) - if (memcmp(public_key, c->crypto_connections[i].public_key, crypto_box_PUBLICKEYBYTES) == 0) + if (is_alive(c->crypto_connections[i].status)) + if (ipport_equal(&ip_port, &c->crypto_connections[i].ip_port)) return i; } return -1; } -/* Set the size of the friend list to numfriends. +#define CRYPTO_MIN_PACKET_SIZE (1 + sizeof(uint16_t) + crypto_box_MACBYTES) + +/* Handle raw UDP packets coming directly from the socket. + * + * Handles: + * Cookie response packets. + * Crypto handshake packets. + * Crypto data packets. * - * return -1 if realloc fails. - * return 0 if it succeeds. */ -static int realloc_cryptoconnection(Net_Crypto *c, uint32_t num) +static int udp_handle_packet(void *object, IP_Port source, uint8_t *packet, uint32_t length) { - if (num == 0) { - free(c->crypto_connections); - c->crypto_connections = NULL; + if (length <= CRYPTO_MIN_PACKET_SIZE || length > MAX_CRYPTO_PACKET_SIZE) + return 1; + + Net_Crypto *c = object; + int crypt_connection_id = crypto_id_ip_port(c, source); + + if (crypt_connection_id == -1) { + if (packet[0] != NET_PACKET_CRYPTO_HS) + return 1; + + if (handle_new_connection_handshake(c, source, packet, length) != 0) + return 1; + return 0; } - Crypto_Connection *newcrypto_connections = realloc(c->crypto_connections, num * sizeof(Crypto_Connection)); + if (handle_packet_connection(c, crypt_connection_id, packet, length) != 0) + return 1; - if (newcrypto_connections == NULL) + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) return -1; - c->crypto_connections = newcrypto_connections; + conn->direct_lastrecv_time = current_time_monotonic(); return 0; } -/* Start a secure connection with other peer who has public_key and ip_port. - * - * return -1 if failure. - * return crypt_connection_id of the initialized connection if everything went well. +/* The dT for the average packet recieving rate calculations. + Also used as the */ +#define PACKET_COUNTER_AVERAGE_INTERVAL 200 + +/* Ratio of recv queue size / recv packet rate (in seconds) times + * the number of ms between request packets to send at that ratio */ -int crypto_connect(Net_Crypto *c, uint8_t *public_key, IP_Port ip_port) +#define REQUEST_PACKETS_COMPARE_CONSTANT (0.5 * 100.0) +static void send_crypto_packets(Net_Crypto *c) { uint32_t i; - int id_existing = getcryptconnection_id(c, public_key); - - if (id_existing != -1) { - IP_Port c_ip = connection_ip(c->lossless_udp, c->crypto_connections[id_existing].number); - - if (ipport_equal(&c_ip, &ip_port)) - return -1; - } - - if (realloc_cryptoconnection(c, c->crypto_connections_length + 1) == -1 - || c->crypto_connections == NULL) - return -1; + uint64_t temp_time = current_time_monotonic(); - memset(&(c->crypto_connections[c->crypto_connections_length]), 0, sizeof(Crypto_Connection)); - c->crypto_connections[c->crypto_connections_length].number = ~0; + for (i = 0; i < c->crypto_connections_length; ++i) { + Crypto_Connection *conn = get_crypto_connection(c, i); - for (i = 0; i <= c->crypto_connections_length; ++i) { - if (c->crypto_connections[i].status == CRYPTO_CONN_NO_CONNECTION) { - int id_new = new_connection(c->lossless_udp, ip_port); + if (conn == 0) + return; - if (id_new == -1) - return -1; + if (CRYPTO_SEND_PACKET_INTERVAL + conn->temp_packet_sent_time < temp_time) { + send_temp_packet(c, i); + } - c->crypto_connections[i].number = id_new; - c->crypto_connections[i].status = CRYPTO_CONN_HANDSHAKE_SENT; - random_nonce(c->crypto_connections[i].recv_nonce); - memcpy(c->crypto_connections[i].public_key, public_key, crypto_box_PUBLICKEYBYTES); - crypto_box_keypair(c->crypto_connections[i].sessionpublic_key, c->crypto_connections[i].sessionsecret_key); - c->crypto_connections[i].timeout = unix_time() + CRYPTO_HANDSHAKE_TIMEOUT; + if ((conn->status == CRYPTO_CONN_NOT_CONFIRMED || conn->status == CRYPTO_CONN_ESTABLISHED) + && (CRYPTO_SEND_PACKET_INTERVAL + conn->last_request_packet_sent) < temp_time) { + if (send_request_packet(c, i) == 0) { + conn->last_request_packet_sent = temp_time; + } - if (c->crypto_connections_length == i) - ++c->crypto_connections_length; + } - if (send_cryptohandshake(c, id_new, public_key, c->crypto_connections[i].recv_nonce, - c->crypto_connections[i].sessionpublic_key) == 1) { - increment_nonce(c->crypto_connections[i].recv_nonce); - return i; + if (conn->status == CRYPTO_CONN_ESTABLISHED) { + if (((double)num_packets_array(&conn->recv_array) / (conn->packet_recv_rate + 1.0)) * (double)( + temp_time - conn->last_request_packet_sent) > REQUEST_PACKETS_COMPARE_CONSTANT) { + if (send_request_packet(c, i) == 0) { + conn->last_request_packet_sent = temp_time; + } } - return -1; /* This should never happen. */ - } - } + if ((PACKET_COUNTER_AVERAGE_INTERVAL + conn->packet_counter_set) < temp_time) { + conn->packet_recv_rate = (double)conn->packet_counter / ((double)(temp_time - conn->packet_counter_set) / 1000.0); + conn->packet_counter = 0; + conn->packet_counter_set = temp_time; - return -1; -} + if ((double)num_packets_array(&conn->send_array) < 0.3 * (conn->packet_send_rate)) { + conn->packet_send_rate *= 1.2; + } else if ((double)num_packets_array(&conn->send_array) > 0.4 * (conn->packet_send_rate)) { + conn->packet_send_rate *= 0.8; + } -/* Handle an incoming connection. - * - * return -1 if no crypto inbound connection. - * return incoming connection id (Lossless_UDP one) if there is an incoming crypto connection. - * - * Put the public key of the peer in public_key, the secret_nonce from the handshake into secret_nonce - * and the session public key for the connection in session_key. - * to accept it see: accept_crypto_inbound(...). - * to refuse it just call kill_connection(...) on the connection id. - */ -int crypto_inbound(Net_Crypto *c, uint8_t *public_key, uint8_t *secret_nonce, uint8_t *session_key) -{ - while (1) { - int incoming_con = incoming_connection(c->lossless_udp, 1); + if (conn->packet_send_rate < CRYPTO_PACKET_MIN_RATE || !conn->sending) + conn->packet_send_rate = CRYPTO_PACKET_MIN_RATE; + + if (conn->packet_send_rate > CRYPTO_PACKET_BUFFER_SIZE * 2) + conn->packet_send_rate = CRYPTO_PACKET_BUFFER_SIZE * 2; - if (incoming_con != -1) { - if (is_connected(c->lossless_udp, incoming_con) == LUDP_TIMED_OUT) { - kill_connection(c->lossless_udp, incoming_con); - continue; } - if (id_packet(c->lossless_udp, incoming_con) == 2) { - uint8_t temp_data[MAX_DATA_SIZE]; - uint16_t len = read_packet_silent(c->lossless_udp, incoming_con, temp_data); + if (conn->last_packets_left_set == 0) { + conn->last_packets_left_set = temp_time; + conn->packets_left = conn->packet_send_rate; + } else if (((1000.0 / conn->packet_send_rate) + conn->last_packets_left_set) < temp_time) { + uint32_t num_packets = conn->packet_send_rate * ((double)(temp_time - conn->last_packets_left_set) / 1000.0); - if (handle_cryptohandshake(c, public_key, secret_nonce, session_key, temp_data, len)) { - return incoming_con; + if (conn->packets_left > num_packets * 2 + CRYPTO_MIN_QUEUE_LENGTH) { + conn->packets_left = num_packets * 2 + CRYPTO_MIN_QUEUE_LENGTH; } else { - kill_connection(c->lossless_udp, incoming_con); + conn->packets_left += num_packets; } - } else { - kill_connection(c->lossless_udp, incoming_con); + + conn->last_packets_left_set = temp_time; + } + + int ret = send_requested_packets(c, i, conn->packets_left); + + if (ret != -1) { + conn->packets_left -= ret; + } + + if (conn->sending != 0 && num_packets_array(&conn->send_array) < CRYPTO_MIN_QUEUE_LENGTH) { + --conn->sending; } - } else { - break; } } - - return -1; } -/* Kill a crypto connection. - * - * return 0 if killed successfully. - * return 1 if there was a problem. + +/* returns the number of packet slots left in the sendbuffer. + * return 0 if failure. */ -int crypto_kill(Net_Crypto *c, int crypt_connection_id) +uint32_t crypto_num_free_sendqueue_slots(Net_Crypto *c, int crypt_connection_id) { - if (crypt_connection_id_not_valid(c, crypt_connection_id)) - return 1; + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); - if (c->crypto_connections[crypt_connection_id].status != CRYPTO_CONN_NO_CONNECTION) { - c->crypto_connections[crypt_connection_id].status = CRYPTO_CONN_NO_CONNECTION; - kill_connection(c->lossless_udp, c->crypto_connections[crypt_connection_id].number); - memset(&(c->crypto_connections[crypt_connection_id]), 0 , sizeof(Crypto_Connection)); - c->crypto_connections[crypt_connection_id].number = ~0; - uint32_t i; + if (conn == 0) + return 0; - for (i = c->crypto_connections_length; i != 0; --i) { - if (c->crypto_connections[i - 1].status != CRYPTO_CONN_NO_CONNECTION) - break; - } + return conn->packets_left; +} - if (c->crypto_connections_length != i) { - c->crypto_connections_length = i; - realloc_cryptoconnection(c, c->crypto_connections_length); - } - return 0; - } - return 1; -} -/* Accept an incoming connection using the parameters provided by crypto_inbound. - * - * return -1 if not successful. - * return the crypt_connection_id if successful. +/* return -1 if data could not be put in packet queue. + * return positive packet number if data was put into the queue. */ -int accept_crypto_inbound(Net_Crypto *c, int connection_id, uint8_t *public_key, uint8_t *secret_nonce, - uint8_t *session_key) +int64_t write_cryptpacket(Net_Crypto *c, int crypt_connection_id, uint8_t *data, uint32_t length) { - uint32_t i; + if (length == 0) + return -1; - if (discard_packet(c->lossless_udp, connection_id) == -1) + if (data[0] < CRYPTO_RESERVED_PACKETS) return -1; - /* - * if(getcryptconnection_id(public_key) != -1) - * { - * return -1; - * } - */ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); - if (realloc_cryptoconnection(c, c->crypto_connections_length + 1) == -1 - || c->crypto_connections == NULL) + if (conn == 0) return -1; - memset(&(c->crypto_connections[c->crypto_connections_length]), 0, sizeof(Crypto_Connection)); - c->crypto_connections[c->crypto_connections_length].number = ~0; - - for (i = 0; i <= c->crypto_connections_length; ++i) { - if (c->crypto_connections[i].status == CRYPTO_CONN_NO_CONNECTION) { - c->crypto_connections[i].number = connection_id; - c->crypto_connections[i].status = CRYPTO_CONN_NOT_CONFIRMED; - c->crypto_connections[i].timeout = unix_time() + CRYPTO_HANDSHAKE_TIMEOUT; - random_nonce(c->crypto_connections[i].recv_nonce); - memcpy(c->crypto_connections[i].sent_nonce, secret_nonce, crypto_box_NONCEBYTES); - memcpy(c->crypto_connections[i].peersessionpublic_key, session_key, crypto_box_PUBLICKEYBYTES); - increment_nonce(c->crypto_connections[i].sent_nonce); - memcpy(c->crypto_connections[i].public_key, public_key, crypto_box_PUBLICKEYBYTES); - - crypto_box_keypair(c->crypto_connections[i].sessionpublic_key, c->crypto_connections[i].sessionsecret_key); - - if (c->crypto_connections_length == i) - ++c->crypto_connections_length; - - if (send_cryptohandshake(c, connection_id, public_key, c->crypto_connections[i].recv_nonce, - c->crypto_connections[i].sessionpublic_key) == 1) { - increment_nonce(c->crypto_connections[i].recv_nonce); - uint32_t zero = 0; - encrypt_precompute(c->crypto_connections[i].peersessionpublic_key, - c->crypto_connections[i].sessionsecret_key, - c->crypto_connections[i].shared_key); - c->crypto_connections[i].status = - CRYPTO_CONN_ESTABLISHED; /* Connection status needs to be 3 for write_cryptpacket() to work. */ - write_cryptpacket(c, i, ((uint8_t *)&zero), sizeof(zero)); - c->crypto_connections[i].status = CRYPTO_CONN_NOT_CONFIRMED; /* Set it to its proper value right after. */ - return i; - } + if (conn->status != CRYPTO_CONN_ESTABLISHED) + return -1; - return -1; /* This should never happen. */ - } - } + if (conn->packets_left == 0) + return -1; - return -1; + int64_t ret = send_lossless_packet(c, crypt_connection_id, data, length); + + if (ret == -1) + return -1; + + --conn->packets_left; + conn->sending = CRYPTO_MIN_QUEUE_LENGTH; + return ret; +} + +/* Kill a crypto connection. + * + * return -1 on failure. + * return 0 on success. + */ +int crypto_kill(Net_Crypto *c, int crypt_connection_id) +{ + //TODO + send_kill_packet(c, crypt_connection_id); + disconnect_peer_tcp(c, crypt_connection_id); + return wipe_crypto_connection(c, crypt_connection_id); } -/* return 0 if no connection. - * return 1 we have sent a handshake. - * return 2 if connection is not confirmed yet (we have received a handshake but no empty data packet). - * return 3 if the connection is established. - * return 4 if the connection is timed out and waiting to be killed. +/* return one of CRYPTO_CONN_* values indicating the state of the connection. + * + * sets direct_connected to 1 if connection connects directly to other, 0 if it isn't. */ -int is_cryptoconnected(Net_Crypto *c, int crypt_connection_id) +unsigned int crypto_connection_status(Net_Crypto *c, int crypt_connection_id, uint8_t *direct_connected) { - if ((unsigned int)crypt_connection_id < c->crypto_connections_length) - return c->crypto_connections[crypt_connection_id].status; + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) + return CRYPTO_CONN_NO_CONNECTION; + + *direct_connected = 0; - return CRYPTO_CONN_NO_CONNECTION; + if ((CRYPTO_SEND_PACKET_INTERVAL * MAX_NUM_SENDPACKET_TRIES + conn->direct_lastrecv_time) > current_time_monotonic()) + *direct_connected = 1; + + return conn->status; } void new_keys(Net_Crypto *c) @@ -721,97 +2298,14 @@ void load_keys(Net_Crypto *c, uint8_t *keys) memcpy(c->self_secret_key, keys + crypto_box_PUBLICKEYBYTES, crypto_box_SECRETKEYBYTES); } -/* Handle received packets for not yet established crypto connections. */ -static void receive_crypto(Net_Crypto *c) -{ - uint32_t i; - uint64_t temp_time = unix_time(); - - for (i = 0; i < c->crypto_connections_length; ++i) { - if (c->crypto_connections[i].status == CRYPTO_CONN_NO_CONNECTION) - continue; - - if (c->crypto_connections[i].status == CRYPTO_CONN_HANDSHAKE_SENT) { - uint8_t temp_data[MAX_DATA_SIZE]; - uint8_t secret_nonce[crypto_box_NONCEBYTES]; - uint8_t public_key[crypto_box_PUBLICKEYBYTES]; - uint8_t session_key[crypto_box_PUBLICKEYBYTES]; - uint16_t len; - - if (id_packet(c->lossless_udp, c->crypto_connections[i].number) == 2) { /* Handle handshake packet. */ - len = read_packet(c->lossless_udp, c->crypto_connections[i].number, temp_data); - - if (handle_cryptohandshake(c, public_key, secret_nonce, session_key, temp_data, len)) { - if (memcmp(public_key, c->crypto_connections[i].public_key, crypto_box_PUBLICKEYBYTES) == 0) { - memcpy(c->crypto_connections[i].sent_nonce, secret_nonce, crypto_box_NONCEBYTES); - memcpy(c->crypto_connections[i].peersessionpublic_key, session_key, crypto_box_PUBLICKEYBYTES); - increment_nonce(c->crypto_connections[i].sent_nonce); - uint32_t zero = 0; - encrypt_precompute(c->crypto_connections[i].peersessionpublic_key, - c->crypto_connections[i].sessionsecret_key, - c->crypto_connections[i].shared_key); - c->crypto_connections[i].status = - CRYPTO_CONN_ESTABLISHED; /* Connection status needs to be 3 for write_cryptpacket() to work. */ - write_cryptpacket(c, i, ((uint8_t *)&zero), sizeof(zero)); - c->crypto_connections[i].status = CRYPTO_CONN_NOT_CONFIRMED; /* Set it to its proper value right after. */ - } else { - /* This should not happen, timeout the connection if it does. */ - c->crypto_connections[i].status = CRYPTO_CONN_TIMED_OUT; - } - } else { - /* This should not happen, timeout the connection if it does. */ - c->crypto_connections[i].status = CRYPTO_CONN_TIMED_OUT; - } - } else if (id_packet(c->lossless_udp, - c->crypto_connections[i].number) != (uint8_t)~0) { - /* This should not happen, timeout the connection if it does. */ - c->crypto_connections[i].status = CRYPTO_CONN_TIMED_OUT; - } - } - - if (c->crypto_connections[i].status == CRYPTO_CONN_NOT_CONFIRMED) { - if (id_packet(c->lossless_udp, c->crypto_connections[i].number) == 3) { - uint8_t temp_data[MAX_DATA_SIZE]; - uint8_t data[MAX_DATA_SIZE]; - int length = read_packet(c->lossless_udp, c->crypto_connections[i].number, temp_data); - int len = decrypt_data(c->crypto_connections[i].peersessionpublic_key, - c->crypto_connections[i].sessionsecret_key, - c->crypto_connections[i].recv_nonce, temp_data + 1, length - 1, data); - uint32_t zero = 0; - - if (len == sizeof(uint32_t) && memcmp(((uint8_t *)&zero), data, sizeof(uint32_t)) == 0) { - increment_nonce(c->crypto_connections[i].recv_nonce); - encrypt_precompute(c->crypto_connections[i].peersessionpublic_key, - c->crypto_connections[i].sessionsecret_key, - c->crypto_connections[i].shared_key); - c->crypto_connections[i].status = CRYPTO_CONN_ESTABLISHED; - c->crypto_connections[i].timeout = ~0; - /* Connection is accepted. */ - confirm_connection(c->lossless_udp, c->crypto_connections[i].number); - } else { - /* This should not happen, timeout the connection if it does. */ - c->crypto_connections[i].status = CRYPTO_CONN_TIMED_OUT; - } - } else if (id_packet(c->lossless_udp, c->crypto_connections[i].number) != (uint8_t)~0) { - /* This should not happen, timeout the connection if it does. */ - c->crypto_connections[i].status = CRYPTO_CONN_TIMED_OUT; - } - } - - if (temp_time > c->crypto_connections[i].timeout) { - c->crypto_connections[i].status = CRYPTO_CONN_TIMED_OUT; - } - } -} - /* Run this to (re)initialize net_crypto. * Sets all the global connection variables to their default values. */ -Net_Crypto *new_net_crypto(Networking_Core *net) +Net_Crypto *new_net_crypto(DHT *dht) { unix_time_update(); - if (net == NULL) + if (dht == NULL) return NULL; Net_Crypto *temp = calloc(1, sizeof(Net_Crypto)); @@ -819,31 +2313,55 @@ Net_Crypto *new_net_crypto(Networking_Core *net) if (temp == NULL) return NULL; - temp->lossless_udp = new_lossless_udp(net); - - if (temp->lossless_udp == NULL) { - free(temp); - return NULL; - } + temp->dht = dht; new_keys(temp); - return temp; -} + new_symmetric_key(temp->secret_symmetric_key); -void init_cryptopackets(void *dht) -{ - DHT *s_dht = dht; - networking_registerhandler(s_dht->c->lossless_udp->net, NET_PACKET_CRYPTO, &cryptopacket_handle, s_dht); + networking_registerhandler(dht->net, NET_PACKET_COOKIE_REQUEST, &udp_handle_cookie_request, temp); + networking_registerhandler(dht->net, NET_PACKET_COOKIE_RESPONSE, &udp_handle_packet, temp); + networking_registerhandler(dht->net, NET_PACKET_CRYPTO_HS, &udp_handle_packet, temp); + networking_registerhandler(dht->net, NET_PACKET_CRYPTO_DATA, &udp_handle_packet, temp); + return temp; } static void kill_timedout(Net_Crypto *c) { uint32_t i; + //uint64_t temp_time = current_time_monotonic(); for (i = 0; i < c->crypto_connections_length; ++i) { - if (c->crypto_connections[i].status != CRYPTO_CONN_NO_CONNECTION - && is_connected(c->lossless_udp, c->crypto_connections[i].number) == LUDP_TIMED_OUT) - c->crypto_connections[i].status = CRYPTO_CONN_TIMED_OUT; + Crypto_Connection *conn = get_crypto_connection(c, i); + + if (conn == 0) + return; + + if (conn->status == CRYPTO_CONN_NO_CONNECTION || conn->status == CRYPTO_CONN_TIMED_OUT) + continue; + + if (conn->status == CRYPTO_CONN_COOKIE_REQUESTING || conn->status == CRYPTO_CONN_HANDSHAKE_SENT + || conn->status == CRYPTO_CONN_NOT_CONFIRMED) { + if (conn->temp_packet_num_sent < MAX_NUM_SENDPACKET_TRIES) + continue; + + conn->killed = 1; + + } + + if (conn->killed) { + if (conn->connection_status_callback) { + conn->connection_status_callback(conn->connection_status_callback_object, conn->connection_status_callback_id, 0); + crypto_kill(c, i); + continue; + } + + conn->status = CRYPTO_CONN_TIMED_OUT; + continue; + } + + if (conn->status == CRYPTO_CONN_ESTABLISHED) { + //TODO: add a timeout here? + } } } @@ -851,9 +2369,10 @@ static void kill_timedout(Net_Crypto *c) void do_net_crypto(Net_Crypto *c) { unix_time_update(); - do_lossless_udp(c->lossless_udp); kill_timedout(c); - receive_crypto(c); + do_tcp(c); + clear_disconnected_tcp(c); + send_crypto_packets(c); } void kill_net_crypto(Net_Crypto *c) @@ -864,7 +2383,15 @@ void kill_net_crypto(Net_Crypto *c) crypto_kill(c, i); } - kill_lossless_udp(c->lossless_udp); + for (i = 0; i < MAX_TCP_CONNECTIONS; ++i) { + kill_TCP_connection(c->tcp_connections_new[i]); + kill_TCP_connection(c->tcp_connections[i]); + } + + networking_registerhandler(c->dht->net, NET_PACKET_COOKIE_REQUEST, NULL, NULL); + networking_registerhandler(c->dht->net, NET_PACKET_COOKIE_RESPONSE, NULL, NULL); + networking_registerhandler(c->dht->net, NET_PACKET_CRYPTO_HS, NULL, NULL); + networking_registerhandler(c->dht->net, NET_PACKET_CRYPTO_DATA, NULL, NULL); memset(c, 0, sizeof(Net_Crypto)); free(c); } diff --git a/toxcore/net_crypto.h b/toxcore/net_crypto.h index da776527..25f8c2f7 100644 --- a/toxcore/net_crypto.h +++ b/toxcore/net_crypto.h @@ -24,21 +24,62 @@ #ifndef NET_CRYPTO_H #define NET_CRYPTO_H -#include "Lossless_UDP.h" - -#define CRYPTO_PACKET_FRIEND_REQ 32 /* Friend request crypto packet ID. */ -#define CRYPTO_PACKET_HARDENING 48 /* Hardening crypto packet ID. */ -#define CRYPTO_PACKET_NAT_PING 254 /* NAT ping crypto packet ID. */ -#define CRYPTO_PACKET_GROUP_CHAT_GET_NODES 48 /* Group chat get Nodes packet */ -#define CRYPTO_PACKET_GROUP_CHAT_SEND_NODES 49 /* Group chat send Nodes packet */ -#define CRYPTO_PACKET_GROUP_CHAT_BROADCAST 50 /* Group chat broadcast packet */ -#define CRYPTO_HANDSHAKE_TIMEOUT (CONNECTION_TIMEOUT * 2) +#include "DHT.h" +#include "TCP_client.h" #define CRYPTO_CONN_NO_CONNECTION 0 -#define CRYPTO_CONN_HANDSHAKE_SENT 1 -#define CRYPTO_CONN_NOT_CONFIRMED 2 -#define CRYPTO_CONN_ESTABLISHED 3 -#define CRYPTO_CONN_TIMED_OUT 4 +#define CRYPTO_CONN_COOKIE_REQUESTING 1 //send cookie request packets +#define CRYPTO_CONN_HANDSHAKE_SENT 2 //send handshake packets +#define CRYPTO_CONN_NOT_CONFIRMED 3 //send handshake packets +#define CRYPTO_CONN_ESTABLISHED 4 +#define CRYPTO_CONN_TIMED_OUT 5 + +#define CRYPTO_PACKET_BUFFER_SIZE 16384 /* Must be a power of 2 */ + +/* Minimum packet rate per second. */ +#define CRYPTO_PACKET_MIN_RATE 40.0 + +/* Minimum packet queue max length. */ +#define CRYPTO_MIN_QUEUE_LENGTH 8 + +#define MAX_CRYPTO_PACKET_SIZE 1400 + +#define CRYPTO_DATA_PACKET_MIN_SIZE (1 + sizeof(uint16_t) + (sizeof(uint32_t) + sizeof(uint32_t)) + crypto_box_MACBYTES) + +/* Max size of data in packets TODO*/ +#define MAX_CRYPTO_DATA_SIZE (MAX_CRYPTO_PACKET_SIZE - CRYPTO_DATA_PACKET_MIN_SIZE) + +/* Interval in ms between sending cookie request/handshake packets. */ +#define CRYPTO_SEND_PACKET_INTERVAL 500 +/* The maximum number of times we try to send the cookie request and handshake + before giving up. */ +#define MAX_NUM_SENDPACKET_TRIES 8 + +#define PACKET_ID_PADDING 0 +#define PACKET_ID_REQUEST 1 +#define PACKET_ID_KILL 2 + +#define CRYPTO_RESERVED_PACKETS 16 + +#define MAX_TCP_CONNECTIONS 32 +#define MAX_TCP_RELAYS_PEER 4 + +#define STATUS_TCP_NULL 0 +#define STATUS_TCP_OFFLINE 1 +#define STATUS_TCP_INVISIBLE 2 /* we know the other peer is connected to this relay but he isn't appearing online */ +#define STATUS_TCP_ONLINE 3 + +typedef struct { + uint64_t time; + uint16_t length; + uint8_t data[MAX_CRYPTO_DATA_SIZE]; +} Packet_Data; + +typedef struct { + Packet_Data *buffer[CRYPTO_PACKET_BUFFER_SIZE]; + uint32_t buffer_start; + uint32_t buffer_end; /* packet numbers in array: {buffer_start, buffer_end) */ +} Packets_Array; typedef struct { uint8_t public_key[crypto_box_PUBLICKEYBYTES]; /* The real public key of the peer. */ @@ -48,27 +89,73 @@ typedef struct { uint8_t sessionsecret_key[crypto_box_SECRETKEYBYTES]; /* Our private key for this session. */ uint8_t peersessionpublic_key[crypto_box_PUBLICKEYBYTES]; /* The public key of the peer. */ uint8_t shared_key[crypto_box_BEFORENMBYTES]; /* The precomputed shared key from encrypt_precompute. */ - uint8_t status; /* 0 if no connection, 1 we have sent a handshake, 2 if connection is not confirmed yet - * (we have received a handshake but no empty data packet), 3 if the connection is established. - * 4 if the connection is timed out. + uint8_t status; /* 0 if no connection, 1 we are sending cookie request packets, + * 2 if we are sending handshake packets + * 3 if connection is not confirmed yet (we have received a handshake but no data packets yet), + * 4 if the connection is established. + * 5 if the connection is timed out. */ - uint16_t number; /* Lossless_UDP connection number corresponding to this connection. */ - uint64_t timeout; + uint64_t cookie_request_number; /* number used in the cookie request packets for this connection */ + uint8_t dht_public_key[crypto_box_PUBLICKEYBYTES]; /* The dht public key of the peer */ + uint8_t dht_public_key_set; /* True if the dht public key is set, false if it isn't. */ + uint64_t dht_public_key_timestamp; /* Timestamp of the last time we confirmed the key was correct. */ -} Crypto_Connection; + uint8_t *temp_packet; /* Where the cookie request/handshake packet is stored while it is being sent. */ + uint16_t temp_packet_length; + uint64_t temp_packet_sent_time; /* The time at which the last temp_packet was sent in ms. */ + uint32_t temp_packet_num_sent; + + IP_Port ip_port; /* The ip and port to contact this guy directly.*/ + uint64_t direct_lastrecv_time; /* The Time at which we last received a direct packet in ms. */ + + Packets_Array send_array; + Packets_Array recv_array; + + int (*connection_status_callback)(void *object, int id, uint8_t status); + void *connection_status_callback_object; + int connection_status_callback_id; + + int (*connection_data_callback)(void *object, int id, uint8_t *data, uint16_t length); + void *connection_data_callback_object; + int connection_data_callback_id; + + uint64_t last_request_packet_sent; + + uint32_t packet_counter; + double packet_recv_rate; + uint64_t packet_counter_set; + + double packet_send_rate; + uint32_t packets_left; + uint64_t last_packets_left_set; + + uint8_t sending; /* indicates if data is being sent or not. */ -typedef int (*cryptopacket_handler_callback)(void *object, IP_Port ip_port, uint8_t *source_pubkey, uint8_t *data, - uint32_t len); + uint8_t killed; /* set to 1 to kill the connection. */ + + uint8_t status_tcp[MAX_TCP_CONNECTIONS]; /* set to one of STATUS_TCP_* */ + uint8_t con_number_tcp[MAX_TCP_CONNECTIONS]; + + Node_format tcp_relays[MAX_TCP_RELAYS_PEER]; + uint16_t num_tcp_relays; +} Crypto_Connection; typedef struct { - cryptopacket_handler_callback function; - void *object; -} Cryptopacket_Handles; + IP_Port source; + uint8_t public_key[crypto_box_PUBLICKEYBYTES]; /* The real public key of the peer. */ + uint8_t dht_public_key[crypto_box_PUBLICKEYBYTES]; /* The dht public key of the peer. */ + uint8_t recv_nonce[crypto_box_NONCEBYTES]; /* Nonce of received packets. */ + uint8_t peersessionpublic_key[crypto_box_PUBLICKEYBYTES]; /* The public key of the peer. */ + uint8_t *cookie; + uint8_t cookie_length; +} New_Connection; typedef struct { - Lossless_UDP *lossless_udp; + DHT *dht; Crypto_Connection *crypto_connections; + TCP_Client_Connection *tcp_connections_new[MAX_TCP_CONNECTIONS]; + TCP_Client_Connection *tcp_connections[MAX_TCP_CONNECTIONS]; uint32_t crypto_connections_length; /* Length of connections array. */ @@ -76,154 +163,131 @@ typedef struct { uint8_t self_public_key[crypto_box_PUBLICKEYBYTES]; uint8_t self_secret_key[crypto_box_SECRETKEYBYTES]; - Cryptopacket_Handles cryptopackethandlers[256]; -} Net_Crypto; + /* The secret key used for cookies */ + uint8_t secret_symmetric_key[crypto_box_KEYBYTES]; -#include "DHT.h" + int (*new_connection_callback)(void *object, New_Connection *n_c); + void *new_connection_callback_object; +} Net_Crypto; -/* return zero if the buffer contains only zeros. */ -uint8_t crypto_iszero(uint8_t *buffer, uint32_t blen); -/* Encrypts plain of length length to encrypted of length + 16 using the - * public key(32 bytes) of the receiver and the secret key of the sender and a 24 byte nonce. +/* Set function to be called when someone requests a new connection to us. + * + * The set function should return -1 on failure and 0 on success. * - * return -1 if there was a problem. - * return length of encrypted data if everything was fine. + * n_c is only valid for the duration of the function call. */ -int encrypt_data(uint8_t *public_key, uint8_t *secret_key, uint8_t *nonce, - uint8_t *plain, uint32_t length, uint8_t *encrypted); - +void new_connection_handler(Net_Crypto *c, int (*new_connection_callback)(void *object, New_Connection *n_c), + void *object); -/* Decrypts encrypted of length length to plain of length length - 16 using the - * public key(32 bytes) of the sender, the secret key of the receiver and a 24 byte nonce. +/* Accept a crypto connection. * - * return -1 if there was a problem (decryption failed). - * return length of plain data if everything was fine. + * return -1 on failure. + * return connection id on success. */ -int decrypt_data(uint8_t *public_key, uint8_t *secret_key, uint8_t *nonce, - uint8_t *encrypted, uint32_t length, uint8_t *plain); - -/* Fast encrypt/decrypt operations. Use if this is not a one-time communication. - encrypt_precompute does the shared-key generation once so it does not have - to be preformed on every encrypt/decrypt. */ -void encrypt_precompute(uint8_t *public_key, uint8_t *secret_key, uint8_t *enc_key); +int accept_crypto_connection(Net_Crypto *c, New_Connection *n_c); -/* Fast encrypt. Depends on enc_key from encrypt_precompute. */ -int encrypt_data_fast(uint8_t *enc_key, uint8_t *nonce, - uint8_t *plain, uint32_t length, uint8_t *encrypted); - -/* Fast decrypt. Depends on enc_ley from encrypt_precompute. */ -int decrypt_data_fast(uint8_t *enc_key, uint8_t *nonce, - uint8_t *encrypted, uint32_t length, uint8_t *plain); - -/* Encrypts plain of length length to encrypted of length + 16 using a - * secret key crypto_secretbox_KEYBYTES big and a 24 byte nonce. +/* Create a crypto connection. + * If one to that real public key already exists, return it. * - * return -1 if there was a problem. - * return length of encrypted data if everything was fine. + * return -1 on failure. + * return connection id on success. */ -int encrypt_data_symmetric(uint8_t *secret_key, uint8_t *nonce, uint8_t *plain, uint32_t length, uint8_t *encrypted); +int new_crypto_connection(Net_Crypto *c, uint8_t *real_public_key); -/* Decrypts encrypted of length length to plain of length length - 16 using a - * secret key crypto_secretbox_KEYBYTES big and a 24 byte nonce. +/* Copy friends DHT public key into dht_key. * - * return -1 if there was a problem (decryption failed). - * return length of plain data if everything was fine. + * return 0 on failure (no key copied). + * return timestamp on success (key copied). */ -int decrypt_data_symmetric(uint8_t *secret_key, uint8_t *nonce, uint8_t *encrypted, uint32_t length, uint8_t *plain); - -/* Increment the given nonce by 1. */ -void increment_nonce(uint8_t *nonce); +uint64_t get_connection_dht_key(Net_Crypto *c, int crypt_connection_id, uint8_t *dht_public_key); -/* Fill the given nonce with random bytes. */ -void random_nonce(uint8_t *nonce); +/* Set the DHT public key of the crypto connection. + * timestamp is the time (current_time_monotonic()) at which the key was last confirmed belonging to + * the other peer. + * + * return -1 on failure. + * return 0 on success. + */ +int set_connection_dht_public_key(Net_Crypto *c, int crypt_connection_id, uint8_t *dht_public_key, uint64_t timestamp); -/* Fill a key crypto_secretbox_KEYBYTES big with random bytes */ -void new_symmetric_key(uint8_t *key); +/* Set the direct ip of the crypto connection. + * + * return -1 on failure. + * return 0 on success. + */ +int set_direct_ip_port(Net_Crypto *c, int crypt_connection_id, IP_Port ip_port); -/*Gives a nonce guaranteed to be different from previous ones.*/ -void new_nonce(uint8_t *nonce); +/* Set function to be called when connection with crypt_connection_id goes connects/disconnects. + * + * The set function should return -1 on failure and 0 on success. + * Note that if this function is set, the connection will clear itself on disconnect. + * Object and id will be passed to this function untouched. + * status is 1 if the connection is going online, 0 if it is going offline. + * + * return -1 on failure. + * return 0 on success. + */ +int connection_status_handler(Net_Crypto *c, int crypt_connection_id, int (*connection_status_callback)(void *object, + int id, uint8_t status), void *object, int id); -/* return 0 if there is no received data in the buffer. - * return -1 if the packet was discarded. - * return length of received data if successful. +/* Set function to be called when connection with crypt_connection_id receives a data packet of length. + * + * The set function should return -1 on failure and 0 on success. + * Object and id will be passed to this function untouched. + * + * return -1 on failure. + * return 0 on success. */ -int read_cryptpacket(Net_Crypto *c, int crypt_connection_id, uint8_t *data); +int connection_data_handler(Net_Crypto *c, int crypt_connection_id, int (*connection_data_callback)(void *object, + int id, uint8_t *data, uint16_t length), void *object, int id); + /* returns the number of packet slots left in the sendbuffer. * return 0 if failure. */ uint32_t crypto_num_free_sendqueue_slots(Net_Crypto *c, int crypt_connection_id); -/* return 0 if data could not be put in packet queue. - * return 1 if data was put into the queue. +/* return -1 if data could not be put in packet queue. + * return positive packet number if data was put into the queue. */ -int write_cryptpacket(Net_Crypto *c, int crypt_connection_id, uint8_t *data, uint32_t length); - -/* Create a request to peer. - * send_public_key and send_secret_key are the pub/secret keys of the sender. - * recv_public_key is public key of reciever. - * packet must be an array of MAX_DATA_SIZE big. - * Data represents the data we send with the request with length being the length of the data. - * request_id is the id of the request (32 = friend request, 254 = ping request). +int64_t write_cryptpacket(Net_Crypto *c, int crypt_connection_id, uint8_t *data, uint32_t length); + +/* Add a tcp relay, associating it to a crypt_connection_id. * - * return -1 on failure. - * return the length of the created packet on success. + * return 0 if it was added. + * return -1 if it wasn't. */ -int create_request(uint8_t *send_public_key, uint8_t *send_secret_key, uint8_t *packet, uint8_t *recv_public_key, - uint8_t *data, uint32_t length, uint8_t request_id); +int add_tcp_relay_peer(Net_Crypto *c, int crypt_connection_id, IP_Port ip_port, uint8_t *public_key); -/* puts the senders public key in the request in public_key, the data from the request - in data if a friend or ping request was sent to us and returns the length of the data. - packet is the request packet and length is its length - return -1 if not valid request. */ -int handle_request(uint8_t *self_public_key, uint8_t *self_secret_key, uint8_t *public_key, uint8_t *data, - uint8_t *request_id, uint8_t *packet, uint16_t length); - -/* Function to call when request beginning with byte is received. */ -void cryptopacket_registerhandler(Net_Crypto *c, uint8_t byte, cryptopacket_handler_callback cb, void *object); +/* Add a tcp relay to the array. + * + * return 0 if it was added. + * return -1 if it wasn't. + */ +int add_tcp_relay(Net_Crypto *c, IP_Port ip_port, uint8_t *public_key); -/* Start a secure connection with other peer who has public_key and ip_port. +/* Copy a maximum of num TCP relays we are connected to to tcp_relays. + * NOTE that the family of the copied ip ports will be set to TCP_INET or TCP_INET6. * - * return -1 if failure. - * return crypt_connection_id of the initialized connection if everything went well. + * return number of relays copied to tcp_relays on success. + * return 0 on failure. */ -int crypto_connect(Net_Crypto *c, uint8_t *public_key, IP_Port ip_port); +unsigned int copy_connected_tcp_relays(Net_Crypto *c, Node_format *tcp_relays, uint16_t num); /* Kill a crypto connection. * - * return 0 if killed successfully. - * return 1 if there was a problem. + * return -1 on failure. + * return 0 on success. */ int crypto_kill(Net_Crypto *c, int crypt_connection_id); -/* Handle an incoming connection. - * - * return -1 if no crypto inbound connection. - * return incoming connection id (Lossless_UDP one) if there is an incoming crypto connection. - * - * Put the public key of the peer in public_key, the secret_nonce from the handshake into secret_nonce - * and the session public key for the connection in session_key. - * to accept it see: accept_crypto_inbound(...). - * to refuse it just call kill_connection(...) on the connection id. - */ -int crypto_inbound(Net_Crypto *c, uint8_t *public_key, uint8_t *secret_nonce, uint8_t *session_key); -/* Accept an incoming connection using the parameters provided by crypto_inbound. +/* return one of CRYPTO_CONN_* values indicating the state of the connection. * - * return -1 if not successful. - * return crypt_connection_id if successful. - */ -int accept_crypto_inbound(Net_Crypto *c, int connection_id, uint8_t *public_key, uint8_t *secret_nonce, - uint8_t *session_key); - -/* return 0 if no connection. - * return 1 we have sent a handshake - * return 2 if connexion is not confirmed yet (we have received a handshake but no empty data packet). - * return 3 if the connection is established. - * return 4 if the connection is timed out and waiting to be killed. + * sets direct_connected to 1 if connection connects directly to other, 0 if it isn't. */ -int is_cryptoconnected(Net_Crypto *c, int crypt_connection_id); +unsigned int crypto_connection_status(Net_Crypto *c, int crypt_connection_id, uint8_t *direct_connected); /* Generate our public and private keys. @@ -244,15 +308,13 @@ void load_keys(Net_Crypto *c, uint8_t *keys); /* Create new instance of Net_Crypto. * Sets all the global connection variables to their default values. */ -Net_Crypto *new_net_crypto(Networking_Core *net); +Net_Crypto *new_net_crypto(DHT *dht); /* Main loop. */ void do_net_crypto(Net_Crypto *c); void kill_net_crypto(Net_Crypto *c); -/* Initialize the cryptopacket handling. */ -void init_cryptopackets(void *dht); #endif diff --git a/toxcore/network.c b/toxcore/network.c index 5980abe3..a8ed4294 100644 --- a/toxcore/network.c +++ b/toxcore/network.c @@ -29,13 +29,17 @@ #include "config.h" #endif -#define LOGGING #include "logger.h" #if !defined(_WIN32) && !defined(__WIN32__) && !defined (WIN32) #include #endif +#ifdef __APPLE__ +#include +#include +#endif + #include "network.h" #include "util.h" @@ -153,6 +157,21 @@ int set_socket_nonblock(sock_t sock) #endif } +/* Set socket to not emit SIGPIPE + * + * return 1 on success + * return 0 on failure + */ +int set_socket_nosigpipe(sock_t sock) +{ +#if defined(__MACH__) + int set = 1; + return (setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int)) == 0); +#else + return 1; +#endif +} + /* Set socket to dual (IPv4 + IPv6 socket) * * return 1 on success @@ -160,7 +179,7 @@ int set_socket_nonblock(sock_t sock) */ int set_socket_dualstack(sock_t sock) { - char ipv6only = 0; + int ipv6only = 0; socklen_t optsize = sizeof(ipv6only); int res = getsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6only, &optsize); @@ -171,8 +190,9 @@ int set_socket_dualstack(sock_t sock) return (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6only, sizeof(ipv6only)) == 0); } + /* return current UNIX time in microseconds (us). */ -uint64_t current_time(void) +static uint64_t current_time_actual(void) { uint64_t time; #if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) @@ -192,29 +212,52 @@ uint64_t current_time(void) #endif } -/* return a random number. - */ -uint32_t random_int(void) -{ - uint32_t randnum; - randombytes((uint8_t *)&randnum , sizeof(randnum)); - return randnum; -} -uint64_t random_64b(void) +#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) +static uint64_t last_monotime; +static uint64_t add_monotime; +#endif + +/* return current monotonic time in milliseconds (ms). */ +uint64_t current_time_monotonic(void) { - uint64_t randnum; - randombytes((uint8_t *)&randnum, sizeof(randnum)); - return randnum; + uint64_t time; +#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) + time = (uint64_t)GetTickCount() + add_monotime; + + if (time < last_monotime) { /* Prevent time from ever decreasing because of 32 bit wrap. */ + uint32_t add = ~0; + add_monotime += add; + time += add; + } + + last_monotime = time; +#else + struct timespec monotime; +#if defined(__linux__) + clock_gettime(CLOCK_MONOTONIC_RAW, &monotime); +#elif defined(__APPLE__) + clock_serv_t muhclock; + mach_timespec_t machtime; + + host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &muhclock); + clock_get_time(muhclock, &machtime); + mach_port_deallocate(mach_task_self(), muhclock); + + monotime.tv_sec = machtime.tv_sec; + monotime.tv_nsec = machtime.tv_nsec; +#else + clock_gettime(CLOCK_MONOTONIC, &monotime); +#endif + time = 1000ULL * monotime.tv_sec + (monotime.tv_nsec / 1000000ULL); +#endif + return time; } /* In case no logging */ #ifndef LOGGING - #define loglogdata(__message__, __buffer__, __buflen__, __ip_port__, __res__) - -#else - +#else #define data_0(__buflen__, __buffer__) __buflen__ > 4 ? ntohl(*(uint32_t *)&__buffer__[1]) : 0 #define data_1(__buflen__, __buffer__) __buflen__ > 7 ? ntohl(*(uint32_t *)&__buffer__[5]) : 0 @@ -299,7 +342,7 @@ int sendpacket(Networking_Core *net, IP_Port ip_port, uint8_t *data, uint32_t le if ((res >= 0) && ((uint32_t)res == length)) net->send_fail_eagain = 0; else if ((res < 0) && (errno == EWOULDBLOCK)) - net->send_fail_eagain = current_time(); + net->send_fail_eagain = current_time_monotonic(); return res; } @@ -308,7 +351,6 @@ int sendpacket(Networking_Core *net, IP_Port ip_port, uint8_t *data, uint32_t le * ip and port of sender is put into ip_port. * Packet data is put into data. * Packet length is put into length. - * Dump all empty packets. */ static int receivepacket(sock_t sock, IP_Port *ip_port, uint8_t *data, uint32_t *length) { @@ -322,7 +364,7 @@ static int receivepacket(sock_t sock, IP_Port *ip_port, uint8_t *data, uint32_t *length = 0; int fail_or_len = recvfrom(sock, (char *) data, MAX_UDP_PACKET_SIZE, 0, (struct sockaddr *)&addr, &addrlen); - if (fail_or_len <= 0) { + if (fail_or_len < 0) { LOGGER_SCOPE( if ((fail_or_len < 0) && (errno != EWOULDBLOCK)) LOGGER_ERROR("Unexpected error reading from socket: %u, %s\n", errno, strerror(errno)); ); @@ -438,13 +480,13 @@ int networking_wait_execute(uint8_t *data, long seconds, long microseconds) * that code) */ if (s->send_fail_eagain != 0) { - // current_time(): microseconds - uint64_t now = current_time(); + // current_time(): milliseconds + uint64_t now = current_time_monotonic(); /* s->sendqueue_length: might be used to guess how long we keep checking */ /* for now, threshold is hardcoded to 250ms, too long for a really really * fast link, but too short for a sloooooow link... */ - if (now - s->send_fail_eagain < 250000) { + if (now - s->send_fail_eagain < 250) { writefds_add = 1; } } @@ -508,6 +550,11 @@ int networking_wait_cleanup(Networking_Core *net, uint8_t *data) return 1; } +#ifndef VANILLA_NACL +/* Used for sodium_init() */ +#include +#endif + uint8_t at_startup_ran = 0; int networking_at_startup(void) { @@ -531,9 +578,9 @@ int networking_at_startup(void) return -1; #else - srandom((uint32_t)current_time()); + srandom((uint32_t)current_time_actual()); #endif - srand((uint32_t)current_time()); + srand((uint32_t)current_time_actual()); at_startup_ran = 1; return 0; } @@ -637,7 +684,6 @@ Networking_Core *new_networking(IP ip, uint16_t port) } if (ip.family == AF_INET6) { - #ifdef LOGGING int is_dualstack = #endif /* LOGGING */ @@ -650,7 +696,6 @@ Networking_Core *new_networking(IP ip, uint16_t port) mreq.ipv6mr_multiaddr.s6_addr[ 1] = 0x02; mreq.ipv6mr_multiaddr.s6_addr[15] = 0x01; mreq.ipv6mr_interface = 0; - #ifdef LOGGING int res = #endif /* LOGGING */ @@ -829,6 +874,31 @@ void ipport_copy(IP_Port *target, IP_Port *source) memcpy(target, source, sizeof(IP_Port)); }; +/* packing and unpacking functions */ +void ip_pack(uint8_t *data, IP *source) +{ + data[0] = source->family; + memcpy(data + 1, &source->ip6, SIZE_IP6); +} + +void ip_unpack(IP *target, uint8_t *data) +{ + target->family = data[0]; + memcpy(&target->ip6, data + 1, SIZE_IP6); +} + +void ipport_pack(uint8_t *data, IP_Port *source) +{ + ip_pack(data, &source->ip); + memcpy(data + SIZE_IP, &source->port, SIZE_PORT); +} + +void ipport_unpack(IP_Port *target, uint8_t *data) +{ + ip_unpack(&target->ip, data); + memcpy(&target->port, data + SIZE_IP, SIZE_PORT); +} + /* ip_ntoa * converts ip into a string * uses a static buffer, so mustn't used multiple times in the same output diff --git a/toxcore/network.h b/toxcore/network.h index 42ade800..0eb7bbd0 100644 --- a/toxcore/network.h +++ b/toxcore/network.h @@ -89,7 +89,7 @@ typedef int sock_t; #endif #if defined(__sun__) -#define __EXTENSIONS__ 1 // SunOS! +#define __EXTENSIONS__ 1 // SunOS! #if defined(__SunOS5_6__) || defined(__SunOS5_7__) || defined(__SunOS5_8__) || defined(__SunOS5_9__) || defined(__SunOS5_10__) //Nothing needed #else @@ -97,21 +97,6 @@ typedef int sock_t; #endif #endif -#ifndef VANILLA_NACL -/* We use libsodium by default. */ -#include -#else -#include -#include -#include -#include -#define crypto_box_MACBYTES (crypto_box_ZEROBYTES - crypto_box_BOXZEROBYTES) -#endif - -#ifndef crypto_secretbox_MACBYTES -#define crypto_secretbox_MACBYTES (crypto_secretbox_ZEROBYTES - crypto_secretbox_BOXZEROBYTES) -#endif - #ifndef IPV6_ADD_MEMBERSHIP #ifdef IPV6_JOIN_GROUP #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP @@ -129,6 +114,10 @@ typedef int sock_t; #define NET_PACKET_HANDSHAKE 16 /* Handshake packet ID. */ #define NET_PACKET_SYNC 17 /* SYNC packet ID. */ #define NET_PACKET_DATA 18 /* Data packet ID. */ +#define NET_PACKET_COOKIE_REQUEST 24 /* Cookie request packet */ +#define NET_PACKET_COOKIE_RESPONSE 25 /* Cookie response packet */ +#define NET_PACKET_CRYPTO_HS 26 /* Crypto handshake packet */ +#define NET_PACKET_CRYPTO_DATA 27 /* Crypto data packet */ #define NET_PACKET_CRYPTO 32 /* Encrypted data packet ID. */ #define NET_PACKET_LAN_DISCOVERY 33 /* LAN discovery packet ID. */ #define NET_PACKET_GROUP_CHATS 48 /* Group chats packet ID. */ @@ -161,8 +150,11 @@ typedef int sock_t; #define TOX_PORTRANGE_TO 33545 #define TOX_PORT_DEFAULT TOX_PORTRANGE_FROM - -/* TODO: remove padding bytes next time we need to break compatibility with old versions of core. */ +/* TCP related */ +#define TCP_ONION_FAMILY (AF_INET6 + 1) +#define TCP_INET (AF_INET6 + 2) +#define TCP_INET6 (AF_INET6 + 3) +#define TCP_FAMILY (AF_INET6 + 4) typedef union __attribute__ ((__packed__)) { @@ -186,8 +178,6 @@ IP6; typedef struct __attribute__ ((__packed__)) { uint8_t family; - /* Not used for anything right now. */ - uint8_t padding[3]; union { IP4 ip4; IP6 ip6; @@ -195,23 +185,19 @@ typedef struct __attribute__ ((__packed__)) } IP; -typedef union __attribute__ ((__packed__)) +typedef struct __attribute__ ((__packed__)) __attribute__((gcc_struct)) { - struct { - IP4 ip; - uint16_t port; - /* Not used for anything right now. */ - uint16_t padding; - }; - uint8_t uint8[8]; -} -IP4_Port; - -typedef struct __attribute__ ((__packed__)) IP_Port { IP ip; uint16_t port; - uint16_t padding; -} IP_Port; +} +IP_Port; + + +#define SIZE_IP4 4 +#define SIZE_IP6 16 +#define SIZE_IP (1 + SIZE_IP6) +#define SIZE_PORT 2 +#define SIZE_IPPORT (SIZE_IP + SIZE_PORT) #define TOX_ENABLE_IPV6_DEFAULT 1 @@ -250,6 +236,16 @@ void ip_copy(IP *target, IP *source); /* copies an ip_port structure */ void ipport_copy(IP_Port *target, IP_Port *source); + +/* packs IP into data, writes SIZE_IP bytes to data */ +void ip_pack(uint8_t *data, IP *source); +/* unpacks IP from data, reads SIZE_IP bytes from data */ +void ip_unpack(IP *target, uint8_t *data); +/* packs IP_Port into data, writes SIZE_IPPORT bytes to data */ +void ipport_pack(uint8_t *data, IP_Port *source); +/* unpacks IP_Port from data, reads SIZE_IPPORT bytes to data */ +void ipport_unpack(IP_Port *target, uint8_t *data); + /* * addr_resolve(): * uses getaddrinfo to resolve an address into an IP address @@ -332,6 +328,13 @@ void kill_sock(sock_t sock); */ int set_socket_nonblock(sock_t sock); +/* Set socket to not emit SIGPIPE + * + * return 1 on success + * return 0 on failure + */ +int set_socket_nosigpipe(sock_t sock); + /* Set socket to dual (IPv4 + IPv6 socket) * * return 1 on success @@ -339,13 +342,8 @@ int set_socket_nonblock(sock_t sock); */ int set_socket_dualstack(sock_t sock); -/* return current time in milleseconds since the epoch. */ -uint64_t current_time(void); - -/* return a random number. - */ -uint32_t random_int(void); -uint64_t random_64b(void); +/* return current monotonic time in milliseconds (ms). */ +uint64_t current_time_monotonic(void); /* Basic network functions: */ diff --git a/toxcore/onion.c b/toxcore/onion.c index ccb729f3..479c6209 100644 --- a/toxcore/onion.c +++ b/toxcore/onion.c @@ -26,8 +26,6 @@ #include "onion.h" #include "util.h" -#define MAX_ONION_SIZE MAX_DATA_SIZE - #define RETURN_1 ONION_RETURN_1 #define RETURN_2 ONION_RETURN_2 #define RETURN_3 ONION_RETURN_3 @@ -89,41 +87,43 @@ int create_onion_path(DHT *dht, Onion_Path *new_path, Node_format *nodes) /* Create and send a onion packet. * * Use Onion_Path path to send data of length to dest. + * Maximum length of data is ONION_MAX_DATA_SIZE. * * return -1 on failure. * return 0 on success. */ int send_onion_packet(Networking_Core *net, Onion_Path *path, IP_Port dest, uint8_t *data, uint32_t length) { - if (1 + length + SEND_1 > MAX_ONION_SIZE || length == 0) + if (1 + length + SEND_1 > ONION_MAX_PACKET_SIZE || length == 0) return -1; to_net_family(&dest.ip); - uint8_t step1[sizeof(IP_Port) + length]; + uint8_t step1[SIZE_IPPORT + length]; + - memcpy(step1, &dest, sizeof(IP_Port)); - memcpy(step1 + sizeof(IP_Port), data, length); + ipport_pack(step1, &dest); + memcpy(step1 + SIZE_IPPORT, data, length); uint8_t nonce[crypto_box_NONCEBYTES]; random_nonce(nonce); - uint8_t step2[sizeof(IP_Port) + SEND_BASE + length]; - memcpy(step2, &path->ip_port3, sizeof(IP_Port)); - memcpy(step2 + sizeof(IP_Port), path->public_key3, crypto_box_PUBLICKEYBYTES); + uint8_t step2[SIZE_IPPORT + SEND_BASE + length]; + ipport_pack(step2, &path->ip_port3); + memcpy(step2 + SIZE_IPPORT, path->public_key3, crypto_box_PUBLICKEYBYTES); - int len = encrypt_data_fast(path->shared_key3, nonce, step1, sizeof(step1), - step2 + sizeof(IP_Port) + crypto_box_PUBLICKEYBYTES); + int len = encrypt_data_symmetric(path->shared_key3, nonce, step1, sizeof(step1), + step2 + SIZE_IPPORT + crypto_box_PUBLICKEYBYTES); - if ((uint32_t)len != sizeof(IP_Port) + length + crypto_box_MACBYTES) + if ((uint32_t)len != SIZE_IPPORT + length + crypto_box_MACBYTES) return -1; - uint8_t step3[sizeof(IP_Port) + SEND_BASE * 2 + length]; - memcpy(step3, &path->ip_port2, sizeof(IP_Port)); - memcpy(step3 + sizeof(IP_Port), path->public_key2, crypto_box_PUBLICKEYBYTES); - len = encrypt_data_fast(path->shared_key2, nonce, step2, sizeof(step2), - step3 + sizeof(IP_Port) + crypto_box_PUBLICKEYBYTES); + uint8_t step3[SIZE_IPPORT + SEND_BASE * 2 + length]; + ipport_pack(step3, &path->ip_port2); + memcpy(step3 + SIZE_IPPORT, path->public_key2, crypto_box_PUBLICKEYBYTES); + len = encrypt_data_symmetric(path->shared_key2, nonce, step2, sizeof(step2), + step3 + SIZE_IPPORT + crypto_box_PUBLICKEYBYTES); - if ((uint32_t)len != sizeof(IP_Port) + SEND_BASE + length + crypto_box_MACBYTES) + if ((uint32_t)len != SIZE_IPPORT + SEND_BASE + length + crypto_box_MACBYTES) return -1; uint8_t packet[1 + length + SEND_1]; @@ -131,10 +131,10 @@ int send_onion_packet(Networking_Core *net, Onion_Path *path, IP_Port dest, uint memcpy(packet + 1, nonce, crypto_box_NONCEBYTES); memcpy(packet + 1 + crypto_box_NONCEBYTES, path->public_key1, crypto_box_PUBLICKEYBYTES); - len = encrypt_data_fast(path->shared_key1, nonce, step3, sizeof(step3), - packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES); + len = encrypt_data_symmetric(path->shared_key1, nonce, step3, sizeof(step3), + packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES); - if ((uint32_t)len != sizeof(IP_Port) + SEND_BASE * 2 + length + crypto_box_MACBYTES) + if ((uint32_t)len != SIZE_IPPORT + SEND_BASE * 2 + length + crypto_box_MACBYTES) return -1; if ((uint32_t)sendpacket(net, path->ip_port1, packet, sizeof(packet)) != sizeof(packet)) @@ -142,13 +142,18 @@ int send_onion_packet(Networking_Core *net, Onion_Path *path, IP_Port dest, uint return 0; } + /* Create and send a onion response sent initially to dest with. + * Maximum length of data is ONION_RESPONSE_MAX_DATA_SIZE. * * return -1 on failure. * return 0 on success. */ int send_onion_response(Networking_Core *net, IP_Port dest, uint8_t *data, uint32_t length, uint8_t *ret) { + if (length > ONION_RESPONSE_MAX_DATA_SIZE || length == 0) + return -1; + uint8_t packet[1 + RETURN_3 + length]; packet[0] = NET_PACKET_ONION_RECV_3; memcpy(packet + 1, ret, RETURN_3); @@ -164,7 +169,7 @@ static int handle_send_initial(void *object, IP_Port source, uint8_t *packet, ui { Onion *onion = object; - if (length > MAX_ONION_SIZE) + if (length > ONION_MAX_PACKET_SIZE) return 1; if (length <= 1 + SEND_1) @@ -172,11 +177,11 @@ static int handle_send_initial(void *object, IP_Port source, uint8_t *packet, ui change_symmetric_key(onion); - uint8_t plain[MAX_ONION_SIZE]; + uint8_t plain[ONION_MAX_PACKET_SIZE]; uint8_t shared_key[crypto_box_BEFORENMBYTES]; get_shared_key(&onion->shared_keys_1, shared_key, onion->dht->self_secret_key, packet + 1 + crypto_box_NONCEBYTES); - int len = decrypt_data_fast(shared_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES, - length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES), plain); + int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES, + length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES), plain); if ((uint32_t)len != length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES)) return 1; @@ -187,23 +192,26 @@ static int handle_send_initial(void *object, IP_Port source, uint8_t *packet, ui int onion_send_1(Onion *onion, uint8_t *plain, uint32_t len, IP_Port source, uint8_t *nonce) { IP_Port send_to; - memcpy(&send_to, plain, sizeof(IP_Port)); + ipport_unpack(&send_to, plain); to_host_family(&send_to.ip); - uint8_t data[MAX_ONION_SIZE]; + uint8_t ip_port[SIZE_IPPORT]; + ipport_pack(ip_port, &source); + + uint8_t data[ONION_MAX_PACKET_SIZE]; data[0] = NET_PACKET_ONION_SEND_1; memcpy(data + 1, nonce, crypto_box_NONCEBYTES); - memcpy(data + 1 + crypto_box_NONCEBYTES, plain + sizeof(IP_Port), len - sizeof(IP_Port)); - uint32_t data_len = 1 + crypto_box_NONCEBYTES + (len - sizeof(IP_Port)); + memcpy(data + 1 + crypto_box_NONCEBYTES, plain + SIZE_IPPORT, len - SIZE_IPPORT); + uint32_t data_len = 1 + crypto_box_NONCEBYTES + (len - SIZE_IPPORT); uint8_t *ret_part = data + data_len; new_nonce(ret_part); - len = encrypt_data_symmetric(onion->secret_symmetric_key, ret_part, (uint8_t *)&source, sizeof(IP_Port), - ret_part + crypto_secretbox_NONCEBYTES); + len = encrypt_data_symmetric(onion->secret_symmetric_key, ret_part, ip_port, SIZE_IPPORT, + ret_part + crypto_box_NONCEBYTES); - if (len != sizeof(IP_Port) + crypto_secretbox_MACBYTES) + if (len != SIZE_IPPORT + crypto_box_MACBYTES) return 1; - data_len += crypto_secretbox_NONCEBYTES + len; + data_len += crypto_box_NONCEBYTES + len; if ((uint32_t)sendpacket(onion->net, send_to, data, data_len) != data_len) return 1; @@ -215,7 +223,7 @@ static int handle_send_1(void *object, IP_Port source, uint8_t *packet, uint32_t { Onion *onion = object; - if (length > MAX_ONION_SIZE) + if (length > ONION_MAX_PACKET_SIZE) return 1; if (length <= 1 + SEND_2) @@ -223,36 +231,36 @@ static int handle_send_1(void *object, IP_Port source, uint8_t *packet, uint32_t change_symmetric_key(onion); - uint8_t plain[MAX_ONION_SIZE]; + uint8_t plain[ONION_MAX_PACKET_SIZE]; uint8_t shared_key[crypto_box_BEFORENMBYTES]; get_shared_key(&onion->shared_keys_2, shared_key, onion->dht->self_secret_key, packet + 1 + crypto_box_NONCEBYTES); - int len = decrypt_data_fast(shared_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES, - length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + RETURN_1), plain); + int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES, + length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + RETURN_1), plain); if ((uint32_t)len != length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + RETURN_1 + crypto_box_MACBYTES)) return 1; IP_Port send_to; - memcpy(&send_to, plain, sizeof(IP_Port)); + ipport_unpack(&send_to, plain); to_host_family(&send_to.ip); - uint8_t data[MAX_ONION_SIZE]; + uint8_t data[ONION_MAX_PACKET_SIZE]; data[0] = NET_PACKET_ONION_SEND_2; memcpy(data + 1, packet + 1, crypto_box_NONCEBYTES); - memcpy(data + 1 + crypto_box_NONCEBYTES, plain + sizeof(IP_Port), len - sizeof(IP_Port)); - uint32_t data_len = 1 + crypto_box_NONCEBYTES + (len - sizeof(IP_Port)); + memcpy(data + 1 + crypto_box_NONCEBYTES, plain + SIZE_IPPORT, len - SIZE_IPPORT); + uint32_t data_len = 1 + crypto_box_NONCEBYTES + (len - SIZE_IPPORT); uint8_t *ret_part = data + data_len; new_nonce(ret_part); - uint8_t ret_data[RETURN_1 + sizeof(IP_Port)]; - memcpy(ret_data, &source, sizeof(IP_Port)); - memcpy(ret_data + sizeof(IP_Port), packet + (length - RETURN_1), RETURN_1); + uint8_t ret_data[RETURN_1 + SIZE_IPPORT]; + ipport_pack(ret_data, &source); + memcpy(ret_data + SIZE_IPPORT, packet + (length - RETURN_1), RETURN_1); len = encrypt_data_symmetric(onion->secret_symmetric_key, ret_part, ret_data, sizeof(ret_data), - ret_part + crypto_secretbox_NONCEBYTES); + ret_part + crypto_box_NONCEBYTES); - if (len != RETURN_2 - crypto_secretbox_NONCEBYTES) + if (len != RETURN_2 - crypto_box_NONCEBYTES) return 1; - data_len += crypto_secretbox_NONCEBYTES + len; + data_len += crypto_box_NONCEBYTES + len; if ((uint32_t)sendpacket(onion->net, send_to, data, data_len) != data_len) return 1; @@ -264,7 +272,7 @@ static int handle_send_2(void *object, IP_Port source, uint8_t *packet, uint32_t { Onion *onion = object; - if (length > MAX_ONION_SIZE) + if (length > ONION_MAX_PACKET_SIZE) return 1; if (length <= 1 + SEND_3) @@ -272,31 +280,31 @@ static int handle_send_2(void *object, IP_Port source, uint8_t *packet, uint32_t change_symmetric_key(onion); - uint8_t plain[MAX_ONION_SIZE]; + uint8_t plain[ONION_MAX_PACKET_SIZE]; uint8_t shared_key[crypto_box_BEFORENMBYTES]; get_shared_key(&onion->shared_keys_3, shared_key, onion->dht->self_secret_key, packet + 1 + crypto_box_NONCEBYTES); - int len = decrypt_data_fast(shared_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES, - length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + RETURN_2), plain); + int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES, + length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + RETURN_2), plain); if ((uint32_t)len != length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + RETURN_2 + crypto_box_MACBYTES)) return 1; IP_Port send_to; - memcpy(&send_to, plain, sizeof(IP_Port)); + ipport_unpack(&send_to, plain); to_host_family(&send_to.ip); - uint8_t data[MAX_ONION_SIZE]; - memcpy(data, plain + sizeof(IP_Port), len - sizeof(IP_Port)); - uint32_t data_len = (len - sizeof(IP_Port)); - uint8_t *ret_part = data + (len - sizeof(IP_Port)); + uint8_t data[ONION_MAX_PACKET_SIZE]; + memcpy(data, plain + SIZE_IPPORT, len - SIZE_IPPORT); + uint32_t data_len = (len - SIZE_IPPORT); + uint8_t *ret_part = data + (len - SIZE_IPPORT); new_nonce(ret_part); - uint8_t ret_data[RETURN_2 + sizeof(IP_Port)]; - memcpy(ret_data, &source, sizeof(IP_Port)); - memcpy(ret_data + sizeof(IP_Port), packet + (length - RETURN_2), RETURN_2); + uint8_t ret_data[RETURN_2 + SIZE_IPPORT]; + ipport_pack(ret_data, &source); + memcpy(ret_data + SIZE_IPPORT, packet + (length - RETURN_2), RETURN_2); len = encrypt_data_symmetric(onion->secret_symmetric_key, ret_part, ret_data, sizeof(ret_data), - ret_part + crypto_secretbox_NONCEBYTES); + ret_part + crypto_box_NONCEBYTES); - if (len != RETURN_3 - crypto_secretbox_NONCEBYTES) + if (len != RETURN_3 - crypto_box_NONCEBYTES) return 1; data_len += RETURN_3; @@ -312,7 +320,7 @@ static int handle_recv_3(void *object, IP_Port source, uint8_t *packet, uint32_t { Onion *onion = object; - if (length > MAX_ONION_SIZE) + if (length > ONION_MAX_PACKET_SIZE) return 1; if (length <= 1 + RETURN_3) @@ -320,19 +328,19 @@ static int handle_recv_3(void *object, IP_Port source, uint8_t *packet, uint32_t change_symmetric_key(onion); - uint8_t plain[sizeof(IP_Port) + RETURN_2]; - int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + crypto_secretbox_NONCEBYTES, - sizeof(IP_Port) + RETURN_2 + crypto_secretbox_MACBYTES, plain); + uint8_t plain[SIZE_IPPORT + RETURN_2]; + int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES, + SIZE_IPPORT + RETURN_2 + crypto_box_MACBYTES, plain); if ((uint32_t)len != sizeof(plain)) return 1; IP_Port send_to; - memcpy(&send_to, plain, sizeof(IP_Port)); + ipport_unpack(&send_to, plain); - uint8_t data[MAX_ONION_SIZE]; + uint8_t data[ONION_MAX_PACKET_SIZE]; data[0] = NET_PACKET_ONION_RECV_2; - memcpy(data + 1, plain + sizeof(IP_Port), RETURN_2); + memcpy(data + 1, plain + SIZE_IPPORT, RETURN_2); memcpy(data + 1 + RETURN_2, packet + 1 + RETURN_3, length - (1 + RETURN_3)); uint32_t data_len = 1 + RETURN_2 + (length - (1 + RETURN_3)); @@ -346,7 +354,7 @@ static int handle_recv_2(void *object, IP_Port source, uint8_t *packet, uint32_t { Onion *onion = object; - if (length > MAX_ONION_SIZE) + if (length > ONION_MAX_PACKET_SIZE) return 1; if (length <= 1 + RETURN_2) @@ -354,19 +362,19 @@ static int handle_recv_2(void *object, IP_Port source, uint8_t *packet, uint32_t change_symmetric_key(onion); - uint8_t plain[sizeof(IP_Port) + RETURN_1]; - int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + crypto_secretbox_NONCEBYTES, - sizeof(IP_Port) + RETURN_1 + crypto_secretbox_MACBYTES, plain); + uint8_t plain[SIZE_IPPORT + RETURN_1]; + int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES, + SIZE_IPPORT + RETURN_1 + crypto_box_MACBYTES, plain); if ((uint32_t)len != sizeof(plain)) return 1; IP_Port send_to; - memcpy(&send_to, plain, sizeof(IP_Port)); + ipport_unpack(&send_to, plain); - uint8_t data[MAX_ONION_SIZE]; + uint8_t data[ONION_MAX_PACKET_SIZE]; data[0] = NET_PACKET_ONION_RECV_1; - memcpy(data + 1, plain + sizeof(IP_Port), RETURN_1); + memcpy(data + 1, plain + SIZE_IPPORT, RETURN_1); memcpy(data + 1 + RETURN_1, packet + 1 + RETURN_2, length - (1 + RETURN_2)); uint32_t data_len = 1 + RETURN_1 + (length - (1 + RETURN_2)); @@ -380,7 +388,7 @@ static int handle_recv_1(void *object, IP_Port source, uint8_t *packet, uint32_t { Onion *onion = object; - if (length > MAX_ONION_SIZE) + if (length > ONION_MAX_PACKET_SIZE) return 1; if (length <= 1 + RETURN_1) @@ -388,14 +396,16 @@ static int handle_recv_1(void *object, IP_Port source, uint8_t *packet, uint32_t change_symmetric_key(onion); - IP_Port send_to; - - int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + crypto_secretbox_NONCEBYTES, - sizeof(IP_Port) + crypto_secretbox_MACBYTES, (uint8_t *) &send_to); + uint8_t plain[SIZE_IPPORT]; + int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES, + SIZE_IPPORT + crypto_box_MACBYTES, plain); - if ((uint32_t)len != sizeof(IP_Port)) + if ((uint32_t)len != SIZE_IPPORT) return 1; + IP_Port send_to; + ipport_unpack(&send_to, plain); + uint32_t data_len = length - (1 + RETURN_1); if (onion->recv_1_function && send_to.ip.family != AF_INET && send_to.ip.family != AF_INET6) @@ -424,7 +434,7 @@ Onion *new_onion(DHT *dht) return NULL; onion->dht = dht; - onion->net = dht->c->lossless_udp->net; + onion->net = dht->net; new_symmetric_key(onion->secret_symmetric_key); onion->timestamp = unix_time(); diff --git a/toxcore/onion.h b/toxcore/onion.h index 4e363724..13dc8f52 100644 --- a/toxcore/onion.h +++ b/toxcore/onion.h @@ -28,7 +28,7 @@ typedef struct { DHT *dht; Networking_Core *net; - uint8_t secret_symmetric_key[crypto_secretbox_KEYBYTES]; + uint8_t secret_symmetric_key[crypto_box_KEYBYTES]; uint64_t timestamp; Shared_Keys shared_keys_1; @@ -39,15 +39,20 @@ typedef struct { void *callback_object; } Onion; -#define ONION_RETURN_1 (crypto_secretbox_NONCEBYTES + sizeof(IP_Port) + crypto_secretbox_MACBYTES) -#define ONION_RETURN_2 (crypto_secretbox_NONCEBYTES + sizeof(IP_Port) + crypto_secretbox_MACBYTES + ONION_RETURN_1) -#define ONION_RETURN_3 (crypto_secretbox_NONCEBYTES + sizeof(IP_Port) + crypto_secretbox_MACBYTES + ONION_RETURN_2) +#define ONION_MAX_PACKET_SIZE 1400 -#define ONION_SEND_BASE (crypto_box_PUBLICKEYBYTES + sizeof(IP_Port) + crypto_box_MACBYTES) +#define ONION_RETURN_1 (crypto_box_NONCEBYTES + SIZE_IPPORT + crypto_box_MACBYTES) +#define ONION_RETURN_2 (crypto_box_NONCEBYTES + SIZE_IPPORT + crypto_box_MACBYTES + ONION_RETURN_1) +#define ONION_RETURN_3 (crypto_box_NONCEBYTES + SIZE_IPPORT + crypto_box_MACBYTES + ONION_RETURN_2) + +#define ONION_SEND_BASE (crypto_box_PUBLICKEYBYTES + SIZE_IPPORT + crypto_box_MACBYTES) #define ONION_SEND_3 (crypto_box_NONCEBYTES + ONION_SEND_BASE + ONION_RETURN_2) #define ONION_SEND_2 (crypto_box_NONCEBYTES + ONION_SEND_BASE*2 + ONION_RETURN_1) #define ONION_SEND_1 (crypto_box_NONCEBYTES + ONION_SEND_BASE*3) +#define ONION_MAX_DATA_SIZE (ONION_MAX_PACKET_SIZE - (ONION_SEND_1 + 1)) +#define ONION_RESPONSE_MAX_DATA_SIZE (ONION_MAX_PACKET_SIZE - (1 + ONION_RETURN_3)) + typedef struct { uint8_t shared_key1[crypto_box_BEFORENMBYTES]; uint8_t shared_key2[crypto_box_BEFORENMBYTES]; @@ -76,6 +81,7 @@ int create_onion_path(DHT *dht, Onion_Path *new_path, Node_format *nodes); /* Create and send a onion packet. * * Use Onion_Path path to send data of length to dest. + * Maximum length of data is ONION_MAX_DATA_SIZE. * * return -1 on failure. * return 0 on success. @@ -83,6 +89,7 @@ int create_onion_path(DHT *dht, Onion_Path *new_path, Node_format *nodes); int send_onion_packet(Networking_Core *net, Onion_Path *path, IP_Port dest, uint8_t *data, uint32_t length); /* Create and send a onion response sent initially to dest with. + * Maximum length of data is ONION_RESPONSE_MAX_DATA_SIZE. * * return -1 on failure. * return 0 on success. diff --git a/toxcore/onion_announce.c b/toxcore/onion_announce.c index 331e54d8..e6489a67 100644 --- a/toxcore/onion_announce.c +++ b/toxcore/onion_announce.c @@ -32,7 +32,7 @@ #define ANNOUNCE_REQUEST_SIZE (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES + crypto_box_PUBLICKEYBYTES + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + crypto_box_MACBYTES) #define ANNOUNCE_REQUEST_SIZE_RECV (ANNOUNCE_REQUEST_SIZE + ONION_RETURN_3) -#define DATA_REQUEST_MIN_SIZE (1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES) +#define DATA_REQUEST_MIN_SIZE ONION_DATA_REQUEST_MIN_SIZE #define DATA_REQUEST_MIN_SIZE_RECV (DATA_REQUEST_MIN_SIZE + ONION_RETURN_3) /* Create and send an onion announce request packet. @@ -50,14 +50,14 @@ * return 0 on success. */ int send_announce_request(Networking_Core *net, Onion_Path *path, Node_format dest, uint8_t *public_key, - uint8_t *secret_key, uint8_t *ping_id, uint8_t *client_id, uint8_t *data_public_key, uint8_t *sendback_data) + uint8_t *secret_key, uint8_t *ping_id, uint8_t *client_id, uint8_t *data_public_key, uint64_t sendback_data) { uint8_t plain[ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES + crypto_box_PUBLICKEYBYTES + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH]; memcpy(plain, ping_id, ONION_PING_ID_SIZE); memcpy(plain + ONION_PING_ID_SIZE, client_id, crypto_box_PUBLICKEYBYTES); memcpy(plain + ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES, data_public_key, crypto_box_PUBLICKEYBYTES); - memcpy(plain + ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES + crypto_box_PUBLICKEYBYTES, sendback_data, - ONION_ANNOUNCE_SENDBACK_DATA_LENGTH); + memcpy(plain + ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES + crypto_box_PUBLICKEYBYTES, &sendback_data, + sizeof(sendback_data)); uint8_t packet[ANNOUNCE_REQUEST_SIZE]; packet[0] = NET_PACKET_ANNOUNCE_REQUEST; random_nonce(packet + 1); @@ -90,6 +90,9 @@ int send_announce_request(Networking_Core *net, Onion_Path *path, Node_format de int send_data_request(Networking_Core *net, Onion_Path *path, IP_Port dest, uint8_t *public_key, uint8_t *encrypt_public_key, uint8_t *nonce, uint8_t *data, uint16_t length) { + if ((unsigned int)DATA_REQUEST_MIN_SIZE + length > ONION_MAX_DATA_SIZE) + return -1; + uint8_t packet[DATA_REQUEST_MIN_SIZE + length]; packet[0] = NET_PACKET_ONION_DATA_REQUEST; memcpy(packet + 1, public_key, crypto_box_PUBLICKEYBYTES); @@ -115,11 +118,11 @@ static void generate_ping_id(Onion_Announce *onion_a, uint64_t time, uint8_t *pu uint8_t *ping_id) { time /= PING_ID_TIMEOUT; - uint8_t data[crypto_secretbox_KEYBYTES + sizeof(time) + crypto_box_PUBLICKEYBYTES + sizeof(ret_ip_port)]; - memcpy(data, onion_a->secret_bytes, crypto_secretbox_KEYBYTES); - memcpy(data + crypto_secretbox_KEYBYTES, &time, sizeof(time)); - memcpy(data + crypto_secretbox_KEYBYTES + sizeof(time), public_key, crypto_box_PUBLICKEYBYTES); - memcpy(data + crypto_secretbox_KEYBYTES + sizeof(time) + crypto_box_PUBLICKEYBYTES, &ret_ip_port, sizeof(ret_ip_port)); + uint8_t data[crypto_box_KEYBYTES + sizeof(time) + crypto_box_PUBLICKEYBYTES + sizeof(ret_ip_port)]; + memcpy(data, onion_a->secret_bytes, crypto_box_KEYBYTES); + memcpy(data + crypto_box_KEYBYTES, &time, sizeof(time)); + memcpy(data + crypto_box_KEYBYTES + sizeof(time), public_key, crypto_box_PUBLICKEYBYTES); + memcpy(data + crypto_box_KEYBYTES + sizeof(time) + crypto_box_PUBLICKEYBYTES, &ret_ip_port, sizeof(ret_ip_port)); crypto_hash_sha256(ping_id, data, sizeof(data)); } @@ -221,9 +224,9 @@ static int handle_announce_request(void *object, IP_Port source, uint8_t *packet get_shared_key(&onion_a->shared_keys_recv, shared_key, onion_a->dht->self_secret_key, packet_public_key); uint8_t plain[ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES + crypto_box_PUBLICKEYBYTES + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH]; - int len = decrypt_data_fast(shared_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES, - ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES + crypto_box_PUBLICKEYBYTES + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + - crypto_box_MACBYTES, plain); + int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES, + ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES + crypto_box_PUBLICKEYBYTES + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + + crypto_box_MACBYTES, plain); if ((uint32_t)len != sizeof(plain)) return 1; @@ -247,14 +250,8 @@ static int handle_announce_request(void *object, IP_Port source, uint8_t *packet /*Respond with a announce response packet*/ Node_format nodes_list[MAX_SENT_NODES]; - uint32_t num_nodes = get_close_nodes(onion_a->dht, plain + ONION_PING_ID_SIZE, nodes_list, source.ip.family, - LAN_ip(source.ip) == 0, 1); - - uint32_t i; - - for (i = 0; i < num_nodes; ++i) - to_net_family(&nodes_list[i].ip_port.ip); - + uint32_t num_nodes = get_close_nodes(onion_a->dht, plain + ONION_PING_ID_SIZE, nodes_list, 0, LAN_ip(source.ip) == 0, + 1); uint8_t nonce[crypto_box_NONCEBYTES]; random_nonce(nonce); @@ -274,13 +271,20 @@ static int handle_announce_request(void *object, IP_Port source, uint8_t *packet } } - memcpy(pl + 1 + ONION_PING_ID_SIZE, nodes_list, num_nodes * sizeof(Node_format)); + int nodes_length = 0; + + if (num_nodes != 0) { + nodes_length = pack_nodes(pl + 1 + ONION_PING_ID_SIZE, sizeof(nodes_list), nodes_list, num_nodes); + + if (nodes_length <= 0) + return 1; + } uint8_t data[ONION_ANNOUNCE_RESPONSE_MAX_SIZE]; - len = encrypt_data_fast(shared_key, nonce, pl, 1 + ONION_PING_ID_SIZE + num_nodes * sizeof(Node_format), - data + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + crypto_box_NONCEBYTES); + len = encrypt_data_symmetric(shared_key, nonce, pl, 1 + ONION_PING_ID_SIZE + nodes_length, + data + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + crypto_box_NONCEBYTES); - if ((uint32_t)len != 1 + ONION_PING_ID_SIZE + num_nodes * sizeof(Node_format) + crypto_box_MACBYTES) + if (len != 1 + ONION_PING_ID_SIZE + nodes_length + crypto_box_MACBYTES) return 1; data[0] = NET_PACKET_ANNOUNCE_RESPONSE; @@ -303,7 +307,7 @@ static int handle_data_request(void *object, IP_Port source, uint8_t *packet, ui if (length <= DATA_REQUEST_MIN_SIZE_RECV) return 1; - if (length >= MAX_DATA_SIZE) + if (length > ONION_MAX_PACKET_SIZE) return 1; int index = in_entries(onion_a, packet + 1); diff --git a/toxcore/onion_announce.h b/toxcore/onion_announce.h index b7e08363..ea320998 100644 --- a/toxcore/onion_announce.h +++ b/toxcore/onion_announce.h @@ -29,7 +29,7 @@ #define ONION_ANNOUNCE_TIMEOUT 300 #define ONION_PING_ID_SIZE crypto_hash_sha256_BYTES -#define ONION_ANNOUNCE_SENDBACK_DATA_LENGTH (crypto_secretbox_NONCEBYTES + sizeof(uint32_t) + sizeof(uint64_t) + crypto_box_PUBLICKEYBYTES + sizeof(IP_Port) + crypto_secretbox_MACBYTES) +#define ONION_ANNOUNCE_SENDBACK_DATA_LENGTH (sizeof(uint64_t)) #define ONION_ANNOUNCE_RESPONSE_MIN_SIZE (1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + crypto_box_NONCEBYTES + 1 + ONION_PING_ID_SIZE + crypto_box_MACBYTES) #define ONION_ANNOUNCE_RESPONSE_MAX_SIZE (ONION_ANNOUNCE_RESPONSE_MIN_SIZE + sizeof(Node_format)*MAX_SENT_NODES) @@ -40,6 +40,9 @@ #error announce response packets assume that ONION_PING_ID_SIZE is equal to crypto_box_PUBLICKEYBYTES #endif +#define ONION_DATA_REQUEST_MIN_SIZE (1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES) +#define MAX_DATA_REQUEST_SIZE (ONION_MAX_DATA_SIZE - ONION_DATA_REQUEST_MIN_SIZE) + typedef struct { uint8_t public_key[crypto_box_PUBLICKEYBYTES]; IP_Port ret_ip_port; @@ -52,8 +55,8 @@ typedef struct { DHT *dht; Networking_Core *net; Onion_Announce_Entry entries[ONION_ANNOUNCE_MAX_ENTRIES]; - /* This is crypto_secretbox_KEYBYTES long just so we can use new_symmetric_key() to fill it */ - uint8_t secret_bytes[crypto_secretbox_KEYBYTES]; + /* This is crypto_box_KEYBYTES long just so we can use new_symmetric_key() to fill it */ + uint8_t secret_bytes[crypto_box_KEYBYTES]; Shared_Keys shared_keys_recv; } Onion_Announce; @@ -73,7 +76,7 @@ typedef struct { * return 0 on success. */ int send_announce_request(Networking_Core *net, Onion_Path *path, Node_format dest, uint8_t *public_key, - uint8_t *secret_key, uint8_t *ping_id, uint8_t *client_id, uint8_t *data_public_key, uint8_t *sendback_data); + uint8_t *secret_key, uint8_t *ping_id, uint8_t *client_id, uint8_t *data_public_key, uint64_t sendback_data); /* Create and send an onion data request packet. * @@ -86,6 +89,8 @@ int send_announce_request(Networking_Core *net, Onion_Path *path, Node_format de * * nonce is the nonce to encrypt this packet with * + * The maximum length of data is MAX_DATA_REQUEST_SIZE. + * * return -1 on failure. * return 0 on success. */ diff --git a/toxcore/onion_client.c b/toxcore/onion_client.c index 329b1d13..dfdb1638 100644 --- a/toxcore/onion_client.c +++ b/toxcore/onion_client.c @@ -28,8 +28,37 @@ #include "util.h" #include "LAN_discovery.h" +/* defines for the array size and + timeout for onion announce packets. */ +#define ANNOUNCE_ARRAY_SIZE 256 #define ANNOUNCE_TIMEOUT 10 + +/* + * return -1 if nodes are suitable for creating a new path. + * return path number of already existing similar path if one already exists. + */ +static int is_path_used(Onion_Client_Paths *onion_paths, Node_format *nodes) +{ + uint32_t i; + + for (i = 0; i < NUMBER_ONION_PATHS; ++i) { + if (is_timeout(onion_paths->last_path_success[i], ONION_PATH_TIMEOUT)) { + continue; + } + + if (is_timeout(onion_paths->path_creation_time[i], ONION_PATH_MAX_LIFETIME)) { + continue; + } + + if (ipport_equal(&onion_paths->paths[i].ip_port1, &nodes[0].ip_port)) { + return i; + } + } + + return -1; +} + /* Create a new path or use an old suitable one (if pathnum is valid) * or a rondom one from onion_paths. * @@ -51,11 +80,17 @@ static int random_path(DHT *dht, Onion_Client_Paths *onion_paths, uint32_t pathn if (random_nodes_path(dht, nodes, 3) != 3) return -1; - if (create_onion_path(dht, &onion_paths->paths[pathnum], nodes) == -1) - return -1; + int n = is_path_used(onion_paths, nodes); - onion_paths->last_path_success[pathnum] = unix_time() + ONION_PATH_FIRST_TIMEOUT - ONION_PATH_TIMEOUT; - onion_paths->path_creation_time[pathnum] = unix_time(); + if (n == -1) { + if (create_onion_path(dht, &onion_paths->paths[pathnum], nodes) == -1) + return -1; + + onion_paths->last_path_success[pathnum] = unix_time() + ONION_PATH_FIRST_TIMEOUT - ONION_PATH_TIMEOUT; + onion_paths->path_creation_time[pathnum] = unix_time(); + } else { + pathnum = n; + } } memcpy(path, &onion_paths->paths[pathnum], sizeof(Onion_Path)); @@ -105,20 +140,15 @@ static uint32_t set_path_timeouts(Onion_Client *onion_c, uint32_t num, IP_Port s * return 0 on success * */ -static int new_sendback(Onion_Client *onion_c, uint32_t num, uint8_t *public_key, IP_Port ip_port, uint8_t *sendback) +static int new_sendback(Onion_Client *onion_c, uint32_t num, uint8_t *public_key, IP_Port ip_port, uint64_t *sendback) { - uint8_t plain[sizeof(uint32_t) + sizeof(uint64_t) + crypto_box_PUBLICKEYBYTES + sizeof(IP_Port)]; - uint64_t time = unix_time(); - random_nonce(sendback); - memcpy(plain, &num, sizeof(uint32_t)); - memcpy(plain + sizeof(uint32_t), &time, sizeof(uint64_t)); - memcpy(plain + sizeof(uint32_t) + sizeof(uint64_t), public_key, crypto_box_PUBLICKEYBYTES); - memcpy(plain + sizeof(uint32_t) + sizeof(uint64_t) + crypto_box_PUBLICKEYBYTES, &ip_port, sizeof(IP_Port)); - - int len = encrypt_data_symmetric(onion_c->secret_symmetric_key, sendback, plain, sizeof(plain), - sendback + crypto_secretbox_NONCEBYTES); + uint8_t data[sizeof(uint32_t) + crypto_box_PUBLICKEYBYTES + sizeof(IP_Port)]; + memcpy(data, &num, sizeof(uint32_t)); + memcpy(data + sizeof(uint32_t), public_key, crypto_box_PUBLICKEYBYTES); + memcpy(data + sizeof(uint32_t) + crypto_box_PUBLICKEYBYTES, &ip_port, sizeof(IP_Port)); + *sendback = ping_array_add(&onion_c->announce_ping_array, data, sizeof(data)); - if ((uint32_t)len + crypto_secretbox_NONCEBYTES != ONION_ANNOUNCE_SENDBACK_DATA_LENGTH) + if (*sendback == 0) return -1; return 0; @@ -136,24 +166,17 @@ static int new_sendback(Onion_Client *onion_c, uint32_t num, uint8_t *public_key */ static uint32_t check_sendback(Onion_Client *onion_c, uint8_t *sendback, uint8_t *ret_pubkey, IP_Port *ret_ip_port) { - uint8_t plain[sizeof(uint32_t) + sizeof(uint64_t) + crypto_box_PUBLICKEYBYTES + sizeof(IP_Port)]; - int len = decrypt_data_symmetric(onion_c->secret_symmetric_key, sendback, sendback + crypto_secretbox_NONCEBYTES, - ONION_ANNOUNCE_SENDBACK_DATA_LENGTH - crypto_secretbox_NONCEBYTES, plain); + uint64_t sback; + memcpy(&sback, sendback, sizeof(uint64_t)); + uint8_t data[sizeof(uint32_t) + crypto_box_PUBLICKEYBYTES + sizeof(IP_Port)]; - if ((uint32_t)len != sizeof(plain)) - return ~0; - - uint64_t timestamp; - memcpy(×tamp, plain + sizeof(uint32_t), sizeof(uint64_t)); - uint64_t temp_time = unix_time(); - - if (timestamp + ANNOUNCE_TIMEOUT < temp_time || temp_time < timestamp) + if (ping_array_check(data, sizeof(data), &onion_c->announce_ping_array, sback) != sizeof(data)) return ~0; - memcpy(ret_pubkey, plain + sizeof(uint32_t) + sizeof(uint64_t), crypto_box_PUBLICKEYBYTES); - memcpy(ret_ip_port, plain + sizeof(uint32_t) + sizeof(uint64_t) + crypto_box_PUBLICKEYBYTES, sizeof(IP_Port)); + memcpy(ret_pubkey, data + sizeof(uint32_t), crypto_box_PUBLICKEYBYTES); + memcpy(ret_ip_port, data + sizeof(uint32_t) + crypto_box_PUBLICKEYBYTES, sizeof(IP_Port)); uint32_t num; - memcpy(&num, plain, sizeof(uint32_t)); + memcpy(&num, data, sizeof(uint32_t)); return num; } @@ -163,9 +186,9 @@ static int client_send_announce_request(Onion_Client *onion_c, uint32_t num, IP_ if (num > onion_c->num_friends) return -1; - uint8_t sendback[ONION_ANNOUNCE_SENDBACK_DATA_LENGTH]; + uint64_t sendback; - if (new_sendback(onion_c, num, dest_pubkey, dest, sendback) == -1) + if (new_sendback(onion_c, num, dest_pubkey, dest, &sendback) == -1) return -1; uint8_t zero_ping_id[ONION_PING_ID_SIZE] = {0}; @@ -183,9 +206,9 @@ static int client_send_announce_request(Onion_Client *onion_c, uint32_t num, IP_ if (random_path(onion_c->dht, &onion_c->onion_paths, pathnum, &path) == -1) return -1; - return send_announce_request(onion_c->net, &path, dest_node, onion_c->dht->c->self_public_key, - onion_c->dht->c->self_secret_key, ping_id, - onion_c->dht->c->self_public_key, onion_c->temp_public_key, sendback); + return send_announce_request(onion_c->net, &path, dest_node, onion_c->c->self_public_key, + onion_c->c->self_secret_key, ping_id, + onion_c->c->self_public_key, onion_c->temp_public_key, sendback); } else { if (random_path(onion_c->dht, &onion_c->friends_list[num - 1].onion_paths, pathnum, &path) == -1) return -1; @@ -236,7 +259,7 @@ static int client_add_to_list(Onion_Client *onion_c, uint32_t num, uint8_t *publ if (num == 0) { list_nodes = onion_c->clients_announce_list; - reference_id = onion_c->dht->c->self_public_key; + reference_id = onion_c->c->self_public_key; if (is_stored && memcmp(pingid_or_key, onion_c->temp_public_key, crypto_box_PUBLICKEYBYTES) != 0) { is_stored = 0; @@ -253,16 +276,9 @@ static int client_add_to_list(Onion_Client *onion_c, uint32_t num, uint8_t *publ int index = -1; uint32_t i; - for (i = 0; i < MAX_ONION_CLIENTS; ++i) { - if (is_timeout(list_nodes[i].timestamp, ONION_NODE_TIMEOUT) - || id_closest(reference_id, list_nodes[i].client_id, public_key) == 2) { - index = i; - - if (i != 0) - break; - } else { - break; - } + if (is_timeout(list_nodes[0].timestamp, ONION_NODE_TIMEOUT) + || id_closest(reference_id, list_nodes[0].client_id, public_key) == 2) { + index = 0; } for (i = 0; i < MAX_ONION_CLIENTS; ++i) { @@ -286,7 +302,7 @@ static int client_add_to_list(Onion_Client *onion_c, uint32_t num, uint8_t *publ list_nodes[index].is_stored = is_stored; list_nodes[index].timestamp = unix_time(); - list_nodes[index].last_pinged = unix_time(); + list_nodes[index].last_pinged = 0; list_nodes[index].path_used = set_path_timeouts(onion_c, num, source); return 0; } @@ -318,21 +334,18 @@ static int client_ping_nodes(Onion_Client *onion_c, uint32_t num, Node_format *n Onion_Node *list_nodes = NULL; uint8_t *reference_id = NULL; - uint32_t *ping_nodes_sent_second = NULL; Last_Pinged *last_pinged = NULL; uint8_t *last_pinged_index = NULL; if (num == 0) { list_nodes = onion_c->clients_announce_list; - reference_id = onion_c->dht->c->self_public_key; - ping_nodes_sent_second = &onion_c->ping_nodes_sent_second; + reference_id = onion_c->c->self_public_key; last_pinged = onion_c->last_pinged; last_pinged_index = &onion_c->last_pinged_index; } else { list_nodes = onion_c->friends_list[num - 1].clients_list; reference_id = onion_c->friends_list[num - 1].real_client_id; - ping_nodes_sent_second = &onion_c->friends_list[num - 1].ping_nodes_sent_second; last_pinged = onion_c->friends_list[num - 1].last_pinged; last_pinged_index = &onion_c->friends_list[num - 1].last_pinged_index; } @@ -342,11 +355,6 @@ static int client_ping_nodes(Onion_Client *onion_c, uint32_t num, Node_format *n for (i = 0; i < num_nodes; ++i) { - if (*ping_nodes_sent_second > MAX_PING_NODES_SECOND_PEER) - return 0; - - to_host_family(&nodes[i].ip_port.ip); - if (!lan_ips_accepted) if (LAN_ip(nodes[i].ip_port.ip) == 0) continue; @@ -361,8 +369,7 @@ static int client_ping_nodes(Onion_Client *onion_c, uint32_t num, Node_format *n } if (j == MAX_ONION_CLIENTS && good_to_ping(last_pinged, last_pinged_index, nodes[i].client_id)) { - if (client_send_announce_request(onion_c, num, nodes[i].ip_port, nodes[i].client_id, NULL, ~0) == 0) - ++*ping_nodes_sent_second; + client_send_announce_request(onion_c, num, nodes[i].ip_port, nodes[i].client_id, NULL, ~0); } } } @@ -377,10 +384,7 @@ static int handle_announce_response(void *object, IP_Port source, uint8_t *packe if (length < ONION_ANNOUNCE_RESPONSE_MIN_SIZE || length > ONION_ANNOUNCE_RESPONSE_MAX_SIZE) return 1; - if ((length - ONION_ANNOUNCE_RESPONSE_MIN_SIZE) % sizeof(Node_format) != 0) - return 1; - - uint16_t num_nodes = (length - ONION_ANNOUNCE_RESPONSE_MIN_SIZE) / sizeof(Node_format); + uint16_t len_nodes = length - ONION_ANNOUNCE_RESPONSE_MIN_SIZE; uint8_t public_key[crypto_box_PUBLICKEYBYTES]; IP_Port ip_port; @@ -389,11 +393,11 @@ static int handle_announce_response(void *object, IP_Port source, uint8_t *packe if (num > onion_c->num_friends) return 1; - uint8_t plain[1 + ONION_PING_ID_SIZE + num_nodes * sizeof(Node_format)]; + uint8_t plain[1 + ONION_PING_ID_SIZE + len_nodes]; int len = -1; if (num == 0) { - len = decrypt_data(public_key, onion_c->dht->c->self_secret_key, packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH, + len = decrypt_data(public_key, onion_c->c->self_secret_key, packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH, packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + crypto_box_NONCEBYTES, length - (1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + crypto_box_NONCEBYTES), plain); } else { @@ -409,20 +413,24 @@ static int handle_announce_response(void *object, IP_Port source, uint8_t *packe if ((uint32_t)len != sizeof(plain)) return 1; - if (client_add_to_list(onion_c, num, public_key, ip_port, plain[0], plain + 1, source) == -1) return 1; - Node_format nodes[MAX_SENT_NODES]; - memcpy(nodes, plain + 1 + ONION_PING_ID_SIZE, num_nodes * sizeof(Node_format)); + if (len_nodes != 0) { + Node_format nodes[MAX_SENT_NODES]; + int num_nodes = unpack_nodes(nodes, MAX_SENT_NODES, 0, plain + 1 + ONION_PING_ID_SIZE, len_nodes, 0); - if (client_ping_nodes(onion_c, num, nodes, num_nodes, source) == -1) - return 1; + if (num_nodes <= 0) + return 1; + + if (client_ping_nodes(onion_c, num, nodes, num_nodes, source) == -1) + return 1; + } return 0; } -#define DATA_IN_RESPONSE_MIN_SIZE (crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES) +#define DATA_IN_RESPONSE_MIN_SIZE ONION_DATA_IN_RESPONSE_MIN_SIZE static int handle_data_response(void *object, IP_Port source, uint8_t *packet, uint32_t length) { @@ -431,7 +439,7 @@ static int handle_data_response(void *object, IP_Port source, uint8_t *packet, u if (length <= (ONION_DATA_RESPONSE_MIN_SIZE + DATA_IN_RESPONSE_MIN_SIZE)) return 1; - if (length > MAX_DATA_SIZE) + if (length > MAX_DATA_REQUEST_SIZE) return 1; uint8_t temp_plain[length - ONION_DATA_RESPONSE_MIN_SIZE]; @@ -443,7 +451,7 @@ static int handle_data_response(void *object, IP_Port source, uint8_t *packet, u return 1; uint8_t plain[sizeof(temp_plain) - DATA_IN_RESPONSE_MIN_SIZE]; - len = decrypt_data(temp_plain, onion_c->dht->c->self_secret_key, packet + 1, temp_plain + crypto_box_PUBLICKEYBYTES, + len = decrypt_data(temp_plain, onion_c->c->self_secret_key, packet + 1, temp_plain + crypto_box_PUBLICKEYBYTES, sizeof(temp_plain) - crypto_box_PUBLICKEYBYTES, plain); if ((uint32_t)len != sizeof(plain)) @@ -469,9 +477,6 @@ static int handle_fakeid_announce(void *object, uint8_t *source_pubkey, uint8_t if (length > FAKEID_DATA_MAX_LENGTH) return 1; - if ((length - FAKEID_DATA_MIN_LENGTH) % sizeof(Node_format) != 0) - return 1; - int friend_num = onion_friend_num(onion_c, source_pubkey); if (friend_num == -1) @@ -485,37 +490,42 @@ static int handle_fakeid_announce(void *object, uint8_t *source_pubkey, uint8_t return 1; onion_c->friends_list[friend_num].last_noreplay = no_replay; + onion_set_friend_DHT_pubkey(onion_c, friend_num, data + 1 + sizeof(uint64_t), current_time_monotonic()); + onion_c->friends_list[friend_num].last_seen = unix_time(); - if (memcmp(data + 1 + sizeof(uint64_t), onion_c->friends_list[friend_num].fake_client_id, - crypto_box_PUBLICKEYBYTES) != 0) { - DHT_delfriend(onion_c->dht, onion_c->friends_list[friend_num].fake_client_id); + uint16_t len_nodes = length - FAKEID_DATA_MIN_LENGTH; - onion_c->friends_list[friend_num].last_seen = unix_time(); + if (len_nodes != 0) { + Node_format nodes[MAX_SENT_NODES]; + int num_nodes = unpack_nodes(nodes, MAX_SENT_NODES, 0, data + 1 + sizeof(uint64_t) + crypto_box_PUBLICKEYBYTES, + len_nodes, 1); - if (DHT_addfriend(onion_c->dht, data + 1 + sizeof(uint64_t)) == 1) { + if (num_nodes <= 0) return 1; - } - onion_c->friends_list[friend_num].is_fake_clientid = 1; - memcpy(onion_c->friends_list[friend_num].fake_client_id, data + 1 + sizeof(uint64_t), crypto_box_PUBLICKEYBYTES); - } + int i; - uint16_t num_nodes = (length - FAKEID_DATA_MIN_LENGTH) / sizeof(Node_format); - Node_format nodes[num_nodes]; - memcpy(nodes, data + 1 + sizeof(uint64_t) + crypto_box_PUBLICKEYBYTES, sizeof(nodes)); - uint32_t i; + for (i = 0; i < num_nodes; ++i) { + uint8_t family = nodes[i].ip_port.ip.family; - for (i = 0; i < num_nodes; ++i) { - to_host_family(&nodes[i].ip_port.ip); - DHT_getnodes(onion_c->dht, &nodes[i].ip_port, nodes[i].client_id, onion_c->friends_list[friend_num].fake_client_id); + if (family == AF_INET || family == AF_INET6) { + DHT_getnodes(onion_c->dht, &nodes[i].ip_port, nodes[i].client_id, onion_c->friends_list[friend_num].fake_client_id); + } else if (family == TCP_INET || family == TCP_INET6) { + if (onion_c->friends_list[friend_num].tcp_relay_node_callback) { + void *obj = onion_c->friends_list[friend_num].tcp_relay_node_callback_object; + uint32_t number = onion_c->friends_list[friend_num].tcp_relay_node_callback_number; + onion_c->friends_list[friend_num].tcp_relay_node_callback(obj, number, nodes[i].ip_port, nodes[i].client_id); + } + } + } } return 0; } /* Send data of length length to friendnum. - * This data will be recieved by the friend using the Onion_Data_Handlers callbacks. + * This data will be received by the friend using the Onion_Data_Handlers callbacks. * - * Even if this function succeeds, the friend might not recieve any data. + * Even if this function succeeds, the friend might not receive any data. * * return the number of packets sent on success * return -1 on failure. @@ -525,7 +535,7 @@ int send_onion_data(Onion_Client *onion_c, int friend_num, uint8_t *data, uint32 if ((uint32_t)friend_num >= onion_c->num_friends) return -1; - if (length + DATA_IN_RESPONSE_MIN_SIZE + ONION_DATA_RESPONSE_MIN_SIZE + ONION_SEND_1 > MAX_DATA_SIZE) + if (length + DATA_IN_RESPONSE_MIN_SIZE > MAX_DATA_REQUEST_SIZE) return -1; if (length == 0) @@ -535,8 +545,8 @@ int send_onion_data(Onion_Client *onion_c, int friend_num, uint8_t *data, uint32 random_nonce(nonce); uint8_t packet[DATA_IN_RESPONSE_MIN_SIZE + length]; - memcpy(packet, onion_c->dht->c->self_public_key, crypto_box_PUBLICKEYBYTES); - int len = encrypt_data(onion_c->friends_list[friend_num].real_client_id, onion_c->dht->c->self_secret_key, nonce, data, + memcpy(packet, onion_c->c->self_public_key, crypto_box_PUBLICKEYBYTES); + int len = encrypt_data(onion_c->friends_list[friend_num].real_client_id, onion_c->c->self_secret_key, nonce, data, length, packet + crypto_box_PUBLICKEYBYTES); if ((uint32_t)len + crypto_box_PUBLICKEYBYTES != sizeof(packet)) @@ -578,7 +588,7 @@ int send_onion_data(Onion_Client *onion_c, int friend_num, uint8_t *data, uint32 /* Try to send the fakeid via the DHT instead of onion * - * Even if this function succeeds, the friend might not recieve any data. + * Even if this function succeeds, the friend might not receive any data. * * return the number of packets sent on success * return -1 on failure. @@ -595,15 +605,15 @@ static int send_dht_fakeid(Onion_Client *onion_c, int friend_num, uint8_t *data, new_nonce(nonce); uint8_t temp[DATA_IN_RESPONSE_MIN_SIZE + crypto_box_NONCEBYTES + length]; - memcpy(temp, onion_c->dht->c->self_public_key, crypto_box_PUBLICKEYBYTES); + memcpy(temp, onion_c->c->self_public_key, crypto_box_PUBLICKEYBYTES); memcpy(temp + crypto_box_PUBLICKEYBYTES, nonce, crypto_box_NONCEBYTES); - int len = encrypt_data(onion_c->friends_list[friend_num].real_client_id, onion_c->dht->c->self_secret_key, nonce, data, + int len = encrypt_data(onion_c->friends_list[friend_num].real_client_id, onion_c->c->self_secret_key, nonce, data, length, temp + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES); if ((uint32_t)len + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES != sizeof(temp)) return -1; - uint8_t packet[MAX_DATA_SIZE]; + uint8_t packet[MAX_CRYPTO_REQUEST_SIZE]; len = create_request(onion_c->dht->self_public_key, onion_c->dht->self_secret_key, packet, onion_c->friends_list[friend_num].fake_client_id, temp, sizeof(temp), FAKEID_DATA_ID); @@ -624,14 +634,14 @@ static int handle_dht_fakeid(void *object, IP_Port source, uint8_t *source_pubke return 1; uint8_t plain[FAKEID_DATA_MAX_LENGTH]; - int len = decrypt_data(packet, onion_c->dht->c->self_secret_key, packet + crypto_box_PUBLICKEYBYTES, + int len = decrypt_data(packet, onion_c->c->self_secret_key, packet + crypto_box_PUBLICKEYBYTES, packet + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, length - (crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES), plain); if ((uint32_t)len != length - (DATA_IN_RESPONSE_MIN_SIZE + crypto_box_NONCEBYTES)) return 1; - if (memcpy(source_pubkey, packet, crypto_box_PUBLICKEYBYTES) != 0) + if (memcmp(source_pubkey, plain + 1 + sizeof(uint64_t), crypto_box_PUBLICKEYBYTES) != 0) return 1; return handle_fakeid_announce(onion_c, packet, plain, len); @@ -657,20 +667,26 @@ static int send_fakeid_announce(Onion_Client *onion_c, uint16_t friend_num, uint memcpy(data + 1, &no_replay, sizeof(no_replay)); memcpy(data + 1 + sizeof(uint64_t), onion_c->dht->self_public_key, crypto_box_PUBLICKEYBYTES); Node_format nodes[MAX_SENT_NODES]; - uint16_t num_nodes = closelist_nodes(onion_c->dht, nodes, MAX_SENT_NODES); - uint32_t i; + uint16_t num_relays = copy_connected_tcp_relays(onion_c->c, nodes, (MAX_SENT_NODES / 2)); + uint16_t num_nodes = closelist_nodes(onion_c->dht, &nodes[num_relays], MAX_SENT_NODES - num_relays); + num_nodes += num_relays; + int nodes_len = 0; + + if (num_nodes != 0) { + nodes_len = pack_nodes(data + FAKEID_DATA_MIN_LENGTH, FAKEID_DATA_MAX_LENGTH - FAKEID_DATA_MIN_LENGTH, nodes, + num_nodes); - for (i = 0; i < num_nodes; ++i) - to_net_family(&nodes[i].ip_port.ip); + if (nodes_len <= 0) + return -1; + } - memcpy(data + FAKEID_DATA_MIN_LENGTH, nodes, sizeof(Node_format) * num_nodes); int num1 = -1, num2 = -1; if (onion_dht_both != 1) - num1 = send_onion_data(onion_c, friend_num, data, FAKEID_DATA_MIN_LENGTH + sizeof(Node_format) * num_nodes); + num1 = send_onion_data(onion_c, friend_num, data, FAKEID_DATA_MIN_LENGTH + nodes_len); if (onion_dht_both != 0) - num2 = send_dht_fakeid(onion_c, friend_num, data, FAKEID_DATA_MIN_LENGTH + sizeof(Node_format) * num_nodes); + num2 = send_dht_fakeid(onion_c, friend_num, data, FAKEID_DATA_MIN_LENGTH + nodes_len); if (num1 == -1) return num2; @@ -788,14 +804,34 @@ int onion_delfriend(Onion_Client *onion_c, int friend_num) return friend_num; } -/* Get the ip of friend friendnum and put it in ip_port +/* Set the function for this friend that will be callbacked with object and number + * when that friends gives us one of the TCP relays he is connected to. * - * return -1, -- if client_id does NOT refer to a friend - * return 0, -- if client_id refers to a friend and we failed to find the friend (yet) - * return 1, ip if client_id refers to a friend and we found him + * object and number will be passed as argument to this function. * + * return -1 on failure. + * return 0 on success. */ -int onion_getfriendip(Onion_Client *onion_c, int friend_num, IP_Port *ip_port) +int recv_tcp_relay_handler(Onion_Client *onion_c, int friend_num, int (*tcp_relay_node_callback)(void *object, + uint32_t number, IP_Port ip_port, uint8_t *public_key), void *object, uint32_t number) +{ + if ((uint32_t)friend_num >= onion_c->num_friends) + return -1; + + onion_c->friends_list[friend_num].tcp_relay_node_callback = tcp_relay_node_callback; + onion_c->friends_list[friend_num].tcp_relay_node_callback_object = object; + onion_c->friends_list[friend_num].tcp_relay_node_callback_number = number; + return 0; +} + +/* Set a friends DHT public key. + * timestamp is the time (current_time_monotonic()) at which the key was last confirmed belonging to + * the other peer. + * + * return -1 on failure. + * return 0 on success. + */ +int onion_set_friend_DHT_pubkey(Onion_Client *onion_c, int friend_num, uint8_t *dht_key, uint64_t timestamp) { if ((uint32_t)friend_num >= onion_c->num_friends) return -1; @@ -803,12 +839,67 @@ int onion_getfriendip(Onion_Client *onion_c, int friend_num, IP_Port *ip_port) if (onion_c->friends_list[friend_num].status == 0) return -1; + if (onion_c->friends_list[friend_num].fake_client_id_timestamp >= timestamp) + return -1; + + if (onion_c->friends_list[friend_num].is_fake_clientid) { + if (memcmp(dht_key, onion_c->friends_list[friend_num].fake_client_id, crypto_box_PUBLICKEYBYTES) == 0) { + return -1; + } + + DHT_delfriend(onion_c->dht, onion_c->friends_list[friend_num].fake_client_id); + } + + if (DHT_addfriend(onion_c->dht, dht_key) == 1) { + return -1; + } + + onion_c->friends_list[friend_num].last_seen = unix_time(); + onion_c->friends_list[friend_num].is_fake_clientid = 1; + onion_c->friends_list[friend_num].fake_client_id_timestamp = timestamp; + memcpy(onion_c->friends_list[friend_num].fake_client_id, dht_key, crypto_box_PUBLICKEYBYTES); + + return 0; +} + +/* Copy friends DHT public key into dht_key. + * + * return 0 on failure (no key copied). + * return timestamp on success (key copied). + */ +uint64_t onion_getfriend_DHT_pubkey(Onion_Client *onion_c, int friend_num, uint8_t *dht_key) +{ + if ((uint32_t)friend_num >= onion_c->num_friends) + return 0; + + if (onion_c->friends_list[friend_num].status == 0) + return 0; + if (!onion_c->friends_list[friend_num].is_fake_clientid) + return 0; + + memcpy(dht_key, onion_c->friends_list[friend_num].fake_client_id, crypto_box_PUBLICKEYBYTES); + return onion_c->friends_list[friend_num].fake_client_id_timestamp; +} + +/* Get the ip of friend friendnum and put it in ip_port + * + * return -1, -- if client_id does NOT refer to a friend + * return 0, -- if client_id refers to a friend and we failed to find the friend (yet) + * return 1, ip if client_id refers to a friend and we found him + * + */ +int onion_getfriendip(Onion_Client *onion_c, int friend_num, IP_Port *ip_port) +{ + uint8_t dht_public_key[crypto_box_PUBLICKEYBYTES]; + + if (onion_getfriend_DHT_pubkey(onion_c, friend_num, dht_public_key) == 0) return -1; - return DHT_getfriendip(onion_c->dht, onion_c->friends_list[friend_num].fake_client_id, ip_port); + return DHT_getfriendip(onion_c->dht, dht_public_key, ip_port); } + /* Set if friend is online or not. * NOTE: This function is there and should be used so that we don't send useless packets to the friend if he is online. * @@ -856,6 +947,11 @@ static void do_friend(Onion_Client *onion_c, uint16_t friendnum) ++count; + if (list_nodes[i].last_pinged == 0) { + list_nodes[i].last_pinged = unix_time(); + continue; + } + if (is_timeout(list_nodes[i].last_pinged, ANNOUNCE_FRIEND)) { if (client_send_announce_request(onion_c, friendnum + 1, list_nodes[i].ip_port, list_nodes[i].client_id, 0, ~0) == 0) { list_nodes[i].last_pinged = unix_time(); @@ -924,6 +1020,13 @@ static void do_announce(Onion_Client *onion_c) continue; ++count; + + /* Don't announce ourselves the first time this is run to new peers */ + if (list_nodes[i].last_pinged == 0) { + list_nodes[i].last_pinged = 1; + continue; + } + uint32_t interval = ANNOUNCE_INTERVAL_NOT_ANNOUNCED; if (list_nodes[i].is_stored) { @@ -941,7 +1044,7 @@ static void do_announce(Onion_Client *onion_c) if (count != MAX_ONION_CLIENTS) { if (count < (uint32_t)rand() % MAX_ONION_CLIENTS) { Node_format nodes_list[MAX_SENT_NODES]; - uint32_t num_nodes = get_close_nodes(onion_c->dht, onion_c->dht->c->self_public_key, nodes_list, + uint32_t num_nodes = get_close_nodes(onion_c->dht, onion_c->c->self_public_key, nodes_list, rand() % 2 ? AF_INET : AF_INET6, 1, 0); for (i = 0; i < num_nodes; ++i) { @@ -963,16 +1066,14 @@ void do_onion_client(Onion_Client *onion_c) for (i = 0; i < onion_c->num_friends; ++i) { do_friend(onion_c, i); cleanup_friend(onion_c, i); - onion_c->friends_list[i].ping_nodes_sent_second = 0; } - onion_c->ping_nodes_sent_second = 0; onion_c->last_run = unix_time(); } -Onion_Client *new_onion_client(DHT *dht) +Onion_Client *new_onion_client(Net_Crypto *c) { - if (dht == NULL) + if (c == NULL) return NULL; Onion_Client *onion_c = calloc(1, sizeof(Onion_Client)); @@ -980,14 +1081,20 @@ Onion_Client *new_onion_client(DHT *dht) if (onion_c == NULL) return NULL; - onion_c->dht = dht; - onion_c->net = dht->c->lossless_udp->net; + if (ping_array_init(&onion_c->announce_ping_array, ANNOUNCE_ARRAY_SIZE, ANNOUNCE_TIMEOUT) != 0) { + free(onion_c); + return NULL; + } + + onion_c->dht = c->dht; + onion_c->net = c->dht->net; + onion_c->c = c; new_symmetric_key(onion_c->secret_symmetric_key); crypto_box_keypair(onion_c->temp_public_key, onion_c->temp_secret_key); networking_registerhandler(onion_c->net, NET_PACKET_ANNOUNCE_RESPONSE, &handle_announce_response, onion_c); networking_registerhandler(onion_c->net, NET_PACKET_ONION_DATA_RESPONSE, &handle_data_response, onion_c); oniondata_registerhandler(onion_c, FAKEID_DATA_ID, &handle_fakeid_announce, onion_c); - cryptopacket_registerhandler(onion_c->dht->c, FAKEID_DATA_ID, &handle_dht_fakeid, onion_c); + cryptopacket_registerhandler(onion_c->dht, FAKEID_DATA_ID, &handle_dht_fakeid, onion_c); return onion_c; } @@ -997,11 +1104,12 @@ void kill_onion_client(Onion_Client *onion_c) if (onion_c == NULL) return; + ping_array_free_all(&onion_c->announce_ping_array); realloc_onion_friends(onion_c, 0); networking_registerhandler(onion_c->net, NET_PACKET_ANNOUNCE_RESPONSE, NULL, NULL); networking_registerhandler(onion_c->net, NET_PACKET_ONION_DATA_RESPONSE, NULL, NULL); oniondata_registerhandler(onion_c, FAKEID_DATA_ID, NULL, NULL); - cryptopacket_registerhandler(onion_c->dht->c, FAKEID_DATA_ID, NULL, NULL); + cryptopacket_registerhandler(onion_c->dht, FAKEID_DATA_ID, NULL, NULL); memset(onion_c, 0, sizeof(Onion_Client)); free(onion_c); } diff --git a/toxcore/onion_client.h b/toxcore/onion_client.h index 4045cc0e..9cf6cf3e 100644 --- a/toxcore/onion_client.h +++ b/toxcore/onion_client.h @@ -25,6 +25,8 @@ #define ONION_CLIENT_H #include "onion_announce.h" +#include "net_crypto.h" +#include "ping_array.h" #define MAX_ONION_CLIENTS 8 #define ONION_NODE_PING_INTERVAL 30 @@ -42,11 +44,6 @@ #define ONION_PATH_TIMEOUT 30 #define ONION_PATH_MAX_LIFETIME 600 -/* A cheap way of making it take less bandwidth at startup: - by limiting the number of ping packets we can send per - second per peer. */ -#define MAX_PING_NODES_SECOND_PEER 5 - #define MAX_STORED_PINGED_NODES 9 #define MIN_NODE_PING_TIME 10 @@ -80,6 +77,7 @@ typedef struct { uint8_t is_online; /* Set by the onion_set_friend_status function. */ uint8_t is_fake_clientid; /* 0 if we don't know the fake client id of the other 1 if we do. */ + uint64_t fake_client_id_timestamp; uint8_t fake_client_id[crypto_box_PUBLICKEYBYTES]; uint8_t real_client_id[crypto_box_PUBLICKEYBYTES]; @@ -95,16 +93,20 @@ typedef struct { uint64_t last_seen; Onion_Client_Paths onion_paths; - uint32_t ping_nodes_sent_second; Last_Pinged last_pinged[MAX_STORED_PINGED_NODES]; uint8_t last_pinged_index; + + int (*tcp_relay_node_callback)(void *object, uint32_t number, IP_Port ip_port, uint8_t *public_key); + void *tcp_relay_node_callback_object; + uint32_t tcp_relay_node_callback_number; } Onion_Friend; typedef int (*oniondata_handler_callback)(void *object, uint8_t *source_pubkey, uint8_t *data, uint32_t len); typedef struct { DHT *dht; + Net_Crypto *c; Networking_Core *net; Onion_Friend *friends_list; uint16_t num_friends; @@ -113,15 +115,15 @@ typedef struct { Onion_Client_Paths onion_paths; - uint8_t secret_symmetric_key[crypto_secretbox_KEYBYTES]; + uint8_t secret_symmetric_key[crypto_box_KEYBYTES]; uint64_t last_run; uint8_t temp_public_key[crypto_box_PUBLICKEYBYTES]; uint8_t temp_secret_key[crypto_box_SECRETKEYBYTES]; - uint32_t ping_nodes_sent_second; - Last_Pinged last_pinged[MAX_STORED_PINGED_NODES]; + + Ping_Array announce_ping_array; uint8_t last_pinged_index; struct { oniondata_handler_callback function; @@ -170,11 +172,41 @@ int onion_set_friend_online(Onion_Client *onion_c, int friend_num, uint8_t is_on */ int onion_getfriendip(Onion_Client *onion_c, int friend_num, IP_Port *ip_port); +/* Set the function for this friend that will be callbacked with object and number + * when that friends gives us one of the TCP relays he is connected to. + * + * object and number will be passed as argument to this function. + * + * return -1 on failure. + * return 0 on success. + */ +int recv_tcp_relay_handler(Onion_Client *onion_c, int friend_num, int (*tcp_relay_node_callback)(void *object, + uint32_t number, IP_Port ip_port, uint8_t *public_key), void *object, uint32_t number); + +/* Set a friends DHT public key. + * timestamp is the time (current_time_monotonic()) at which the key was last confirmed belonging to + * the other peer. + * + * return -1 on failure. + * return 0 on success. + */ +int onion_set_friend_DHT_pubkey(Onion_Client *onion_c, int friend_num, uint8_t *dht_key, uint64_t timestamp); + +/* Copy friends DHT public key into dht_key. + * + * return 0 on failure (no key copied). + * return timestamp on success (key copied). + */ +uint64_t onion_getfriend_DHT_pubkey(Onion_Client *onion_c, int friend_num, uint8_t *dht_key); + +#define ONION_DATA_IN_RESPONSE_MIN_SIZE (crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES) +#define ONION_CLIENT_MAX_DATA_SIZE (MAX_DATA_REQUEST_SIZE - ONION_DATA_IN_RESPONSE_MIN_SIZE) /* Send data of length length to friendnum. - * This data will be recieved by the friend using the Onion_Data_Handlers callbacks. + * Maximum length of data is ONION_CLIENT_MAX_DATA_SIZE. + * This data will be received by the friend using the Onion_Data_Handlers callbacks. * - * Even if this function succeeds, the friend might not recieve any data. + * Even if this function succeeds, the friend might not receive any data. * * return the number of packets sent on success * return -1 on failure. @@ -186,7 +218,7 @@ void oniondata_registerhandler(Onion_Client *onion_c, uint8_t byte, oniondata_ha void do_onion_client(Onion_Client *onion_c); -Onion_Client *new_onion_client(DHT *dht); +Onion_Client *new_onion_client(Net_Crypto *c); void kill_onion_client(Onion_Client *onion_c); diff --git a/toxcore/ping.c b/toxcore/ping.c index 649d3fff..c01170ab 100644 --- a/toxcore/ping.c +++ b/toxcore/ping.c @@ -34,118 +34,29 @@ #include "network.h" #include "util.h" +#include "ping_array.h" #define PING_NUM_MAX 512 /* Maximum newly announced nodes to ping per TIME_TO_PING seconds. */ -#define MAX_TO_PING 16 +#define MAX_TO_PING 8 /* Ping newly announced nodes to ping per TIME_TO_PING seconds*/ -#define TIME_TO_PING 5 +#define TIME_TO_PING 8 -typedef struct { - IP_Port ip_port; - uint64_t id; - uint64_t timestamp; - uint8_t shared_key[crypto_box_BEFORENMBYTES]; -} pinged_t; struct PING { DHT *dht; - pinged_t pings[PING_NUM_MAX]; - size_t num_pings; - size_t pos_pings; - + Ping_Array ping_array; Node_format to_ping[MAX_TO_PING]; uint64_t last_to_ping; }; -static int is_ping_timeout(uint64_t time) -{ - return is_timeout(time, PING_TIMEOUT); -} - -static void remove_timeouts(PING *ping) // O(n) -{ - size_t i, id; - size_t new_pos = ping->pos_pings; - size_t new_num = ping->num_pings; - - // Loop through buffer, oldest first. - for (i = 0; i < ping->num_pings; i++) { - id = (ping->pos_pings + i) % PING_NUM_MAX; - - if (is_ping_timeout(ping->pings[id].timestamp)) { - new_pos++; - new_num--; - } - // Break here because list is sorted. - else { - break; - } - } - - ping->num_pings = new_num; - ping->pos_pings = new_pos % PING_NUM_MAX; -} - -static uint64_t add_ping(PING *ping, IP_Port ipp, uint8_t *shared_encryption_key) // O(n) -{ - size_t p; - - remove_timeouts(ping); - - /* Remove oldest ping if full buffer. */ - if (ping->num_pings == PING_NUM_MAX) { - ping->num_pings--; - ping->pos_pings = (ping->pos_pings + 1) % PING_NUM_MAX; - } - - /* Insert new ping at end of list. */ - p = (ping->pos_pings + ping->num_pings) % PING_NUM_MAX; - - ping->pings[p].ip_port = ipp; - ping->pings[p].timestamp = unix_time(); - ping->pings[p].id = random_64b(); - memcpy(ping->pings[p].shared_key, shared_encryption_key, crypto_box_BEFORENMBYTES); - - ping->num_pings++; - return ping->pings[p].id; -} - -/* checks if ip/port or ping_id are already in the list to ping - * if both are set, both must match, otherwise the set must match - * - * returns 0 if neither is set or no match was found - * returns the (index + 1) of the match if one was found - */ -static int is_pinging(PING *ping, IP_Port ipp, uint64_t ping_id) -{ - // O(n) TODO: Replace this with something else. - - /* at least one MUST be set */ - uint8_t ip_valid = ip_isset(&ipp.ip); - - if (!ip_valid && !ping_id) - return 0; - - size_t i; - - remove_timeouts(ping); - - for (i = 0; i < ping->num_pings; i++) { - size_t id = (ping->pos_pings + i) % PING_NUM_MAX; - if (!ping_id || (ping->pings[id].id == ping_id)) - if (!ip_valid || ipport_equal(&ping->pings[id].ip_port, &ipp)) - return id + 1; - } - - return 0; -} - -#define DHT_PING_SIZE (1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + sizeof(uint64_t) + crypto_box_MACBYTES) +#define PING_PLAIN_SIZE (1 + sizeof(uint64_t)) +#define DHT_PING_SIZE (1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + PING_PLAIN_SIZE + crypto_box_MACBYTES) +#define PING_DATA_SIZE (CLIENT_ID_SIZE + sizeof(IP_Port)) int send_ping_request(PING *ping, IP_Port ipp, uint8_t *client_id) { @@ -153,7 +64,7 @@ int send_ping_request(PING *ping, IP_Port ipp, uint8_t *client_id) int rc; uint64_t ping_id; - if (is_pinging(ping, ipp, 0) || id_equal(client_id, ping->dht->self_public_key)) + if (id_equal(client_id, ping->dht->self_public_key)) return 1; uint8_t shared_key[crypto_box_BEFORENMBYTES]; @@ -161,19 +72,29 @@ int send_ping_request(PING *ping, IP_Port ipp, uint8_t *client_id) // generate key to encrypt ping_id with recipient privkey DHT_get_shared_key_sent(ping->dht, shared_key, client_id); // Generate random ping_id. - ping_id = add_ping(ping, ipp, shared_key); + uint8_t data[PING_DATA_SIZE]; + id_copy(data, client_id); + memcpy(data + CLIENT_ID_SIZE, &ipp, sizeof(IP_Port)); + ping_id = ping_array_add(&ping->ping_array, data, sizeof(data)); + + if (ping_id == 0) + return 1; + + uint8_t ping_plain[PING_PLAIN_SIZE]; + ping_plain[0] = NET_PACKET_PING_REQUEST; + memcpy(ping_plain + 1, &ping_id, sizeof(ping_id)); pk[0] = NET_PACKET_PING_REQUEST; id_copy(pk + 1, ping->dht->self_public_key); // Our pubkey new_nonce(pk + 1 + CLIENT_ID_SIZE); // Generate new nonce - rc = encrypt_data_fast(shared_key, - pk + 1 + CLIENT_ID_SIZE, - (uint8_t *) &ping_id, sizeof(ping_id), - pk + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES); + rc = encrypt_data_symmetric(shared_key, + pk + 1 + CLIENT_ID_SIZE, + ping_plain, sizeof(ping_plain), + pk + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES); - if (rc != sizeof(ping_id) + crypto_box_MACBYTES) + if (rc != PING_PLAIN_SIZE + crypto_box_MACBYTES) return 1; return sendpacket(ping->dht->net, ipp, pk, sizeof(pk)); @@ -188,17 +109,21 @@ static int send_ping_response(PING *ping, IP_Port ipp, uint8_t *client_id, uint6 if (id_equal(client_id, ping->dht->self_public_key)) return 1; + uint8_t ping_plain[PING_PLAIN_SIZE]; + ping_plain[0] = NET_PACKET_PING_RESPONSE; + memcpy(ping_plain + 1, &ping_id, sizeof(ping_id)); + pk[0] = NET_PACKET_PING_RESPONSE; id_copy(pk + 1, ping->dht->self_public_key); // Our pubkey new_nonce(pk + 1 + CLIENT_ID_SIZE); // Generate new nonce // Encrypt ping_id using recipient privkey - rc = encrypt_data_fast(shared_encryption_key, - pk + 1 + CLIENT_ID_SIZE, - (uint8_t *) &ping_id, sizeof(ping_id), - pk + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES ); + rc = encrypt_data_symmetric(shared_encryption_key, + pk + 1 + CLIENT_ID_SIZE, + ping_plain, sizeof(ping_plain), + pk + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES ); - if (rc != sizeof(ping_id) + crypto_box_MACBYTES) + if (rc != PING_PLAIN_SIZE + crypto_box_MACBYTES) return 1; return sendpacket(ping->dht->net, ipp, pk, sizeof(pk)); @@ -208,7 +133,6 @@ static int handle_ping_request(void *_dht, IP_Port source, uint8_t *packet, uint { DHT *dht = _dht; int rc; - uint64_t ping_id; if (length != DHT_PING_SIZE) return 1; @@ -220,17 +144,23 @@ static int handle_ping_request(void *_dht, IP_Port source, uint8_t *packet, uint uint8_t shared_key[crypto_box_BEFORENMBYTES]; + uint8_t ping_plain[PING_PLAIN_SIZE]; // Decrypt ping_id DHT_get_shared_key_recv(dht, shared_key, packet + 1); - rc = decrypt_data_fast(shared_key, - packet + 1 + CLIENT_ID_SIZE, - packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, - sizeof(ping_id) + crypto_box_MACBYTES, - (uint8_t *) &ping_id ); + rc = decrypt_data_symmetric(shared_key, + packet + 1 + CLIENT_ID_SIZE, + packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, + PING_PLAIN_SIZE + crypto_box_MACBYTES, + ping_plain ); + + if (rc != sizeof(ping_plain)) + return 1; - if (rc != sizeof(ping_id)) + if (ping_plain[0] != NET_PACKET_PING_REQUEST) return 1; + uint64_t ping_id; + memcpy(&ping_id, ping_plain + 1, sizeof(ping_id)); // Send response send_ping_response(ping, source, packet + 1, ping_id, shared_key); add_to_ping(ping, packet + 1, source); @@ -242,7 +172,6 @@ static int handle_ping_response(void *_dht, IP_Port source, uint8_t *packet, uin { DHT *dht = _dht; int rc; - uint64_t ping_id; if (length != DHT_PING_SIZE) return 1; @@ -252,30 +181,71 @@ static int handle_ping_response(void *_dht, IP_Port source, uint8_t *packet, uin if (id_equal(packet + 1, ping->dht->self_public_key)) return 1; - int ping_index = is_pinging(ping, source, 0); + uint8_t shared_key[crypto_box_BEFORENMBYTES]; - if (!ping_index) - return 1; + // generate key to encrypt ping_id with recipient privkey + DHT_get_shared_key_sent(ping->dht, shared_key, packet + 1); - --ping_index; + uint8_t ping_plain[PING_PLAIN_SIZE]; // Decrypt ping_id - rc = decrypt_data_fast(ping->pings[ping_index].shared_key, - packet + 1 + CLIENT_ID_SIZE, - packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, - sizeof(ping_id) + crypto_box_MACBYTES, - (uint8_t *) &ping_id); + rc = decrypt_data_symmetric(shared_key, + packet + 1 + CLIENT_ID_SIZE, + packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, + PING_PLAIN_SIZE + crypto_box_MACBYTES, + ping_plain); - if (rc != sizeof(ping_id)) + if (rc != sizeof(ping_plain)) return 1; - if (ping->pings[ping_index].id != ping_id) + if (ping_plain[0] != NET_PACKET_PING_RESPONSE) return 1; - addto_lists(dht, source, packet + 1); + uint64_t ping_id; + memcpy(&ping_id, ping_plain + 1, sizeof(ping_id)); + uint8_t data[PING_DATA_SIZE]; + if (ping_array_check(data, sizeof(data), &ping->ping_array, ping_id) != sizeof(data)) + return 1; + + if (!id_equal(packet + 1, data)) + return 1; + + IP_Port ipp; + memcpy(&ipp, data + CLIENT_ID_SIZE, sizeof(IP_Port)); + + if (!ipport_equal(&ipp, &source)) + return 1; + + addto_lists(dht, source, packet + 1); return 0; } +/* Check if client_id with ip_port is in the list. + * + * return 1 if it is. + * return 0 if it isn't. + */ +static int in_list(Client_data *list, uint32_t length, uint8_t *client_id, IP_Port ip_port) +{ + uint32_t i; + + for (i = 0; i < length; ++i) { + if (id_equal(list[i].client_id, client_id)) { + IPPTsPng *ipptp; + + if (ip_port.ip.family == AF_INET) { + ipptp = &list[i].assoc4; + } else { + ipptp = &list[i].assoc6; + } + + if (!is_timeout(ipptp->timestamp, BAD_NODE_TIMEOUT) && ipport_equal(&ipptp->ip_port, &ip_port)) + return 1; + } + } + + return 0; +} /* Add nodes to the to_ping list. * All nodes in this list are pinged every TIME_TO_PING seconds @@ -292,6 +262,9 @@ int add_to_ping(PING *ping, uint8_t *client_id, IP_Port ip_port) if (!ip_isset(&ip_port.ip)) return -1; + if (in_list(ping->dht->close_clientlist, LCLIENT_LIST, client_id, ip_port)) + return -1; + uint32_t i; for (i = 0; i < MAX_TO_PING; ++i) { @@ -300,12 +273,18 @@ int add_to_ping(PING *ping, uint8_t *client_id, IP_Port ip_port) ipport_copy(&ping->to_ping[i].ip_port, &ip_port); return 0; } + + if (memcmp(ping->to_ping[i].client_id, client_id, CLIENT_ID_SIZE) == 0) { + return -1; + } } + uint32_t r = rand(); + for (i = 0; i < MAX_TO_PING; ++i) { - if (id_closest(ping->dht->self_public_key, ping->to_ping[i].client_id, client_id) == 2) { - memcpy(ping->to_ping[i].client_id, client_id, CLIENT_ID_SIZE); - ipport_copy(&ping->to_ping[i].ip_port, &ip_port); + if (id_closest(ping->dht->self_public_key, ping->to_ping[(i + r) % MAX_TO_PING].client_id, client_id) == 2) { + memcpy(ping->to_ping[(i + r) % MAX_TO_PING].client_id, client_id, CLIENT_ID_SIZE); + ipport_copy(&ping->to_ping[(i + r) % MAX_TO_PING].ip_port, &ip_port); return 0; } } @@ -342,6 +321,11 @@ PING *new_ping(DHT *dht) if (ping == NULL) return NULL; + if (ping_array_init(&ping->ping_array, PING_NUM_MAX, PING_TIMEOUT) != 0) { + free(ping); + return NULL; + } + ping->dht = dht; networking_registerhandler(ping->dht->net, NET_PACKET_PING_REQUEST, &handle_ping_request, dht); networking_registerhandler(ping->dht->net, NET_PACKET_PING_RESPONSE, &handle_ping_response, dht); @@ -353,6 +337,7 @@ void kill_ping(PING *ping) { networking_registerhandler(ping->dht->net, NET_PACKET_PING_REQUEST, NULL, NULL); networking_registerhandler(ping->dht->net, NET_PACKET_PING_RESPONSE, NULL, NULL); + ping_array_free_all(&ping->ping_array); free(ping); } diff --git a/toxcore/ping_array.c b/toxcore/ping_array.c new file mode 100644 index 00000000..e6f684ef --- /dev/null +++ b/toxcore/ping_array.c @@ -0,0 +1,162 @@ +/* ping_array.c + * + * Implementation of an efficient array to store that we pinged something. + * + * + * Copyright (C) 2014 Tox project All Rights Reserved. + * + * This file is part of Tox. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ping_array.h" +#include "crypto_core.h" +#include "util.h" + +static void clear_entry(Ping_Array *array, uint32_t index) +{ + free(array->entries[index].data); + array->entries[index].data = NULL; + array->entries[index].length = + array->entries[index].time = + array->entries[index].ping_id = 0; +} + +/* Clear timed out entries. + */ +static void ping_array_clear_timedout(Ping_Array *array) +{ + while (array->last_deleted != array->last_added) { + uint32_t index = array->last_deleted % array->total_size; + + if (!is_timeout(array->entries[index].time, array->timeout)) + break; + + clear_entry(array, index); + ++array->last_deleted; + } +} + +/* Add a data with length to the Ping_Array list and return a ping_id. + * + * return ping_id on success. + * return 0 on failure. + */ +uint64_t ping_array_add(Ping_Array *array, uint8_t *data, uint32_t length) +{ + ping_array_clear_timedout(array); + uint32_t index = array->last_added % array->total_size; + + if (array->entries[index].data != NULL) { + array->last_deleted = array->last_added - array->total_size; + clear_entry(array, index); + } + + array->entries[index].data = malloc(length); + + if (array->entries[index].data == NULL) + return 0; + + memcpy(array->entries[index].data, data, length); + array->entries[index].length = length; + array->entries[index].time = unix_time(); + ++array->last_added; + uint64_t ping_id = random_64b(); + ping_id /= array->total_size; + ping_id *= array->total_size; + ping_id += index; + + if (ping_id == 0) + ping_id += array->total_size; + + array->entries[index].ping_id = ping_id; + return ping_id; +} + + +/* Check if ping_id is valid and not timed out. + * + * On success, copies the data into data of length, + * + * return length of data copied on success. + * return -1 on failure. + */ +int ping_array_check(uint8_t *data, uint32_t length, Ping_Array *array, uint64_t ping_id) +{ + if (ping_id == 0) + return -1; + + uint32_t index = ping_id % array->total_size; + + if (array->entries[index].ping_id != ping_id) + return -1; + + if (is_timeout(array->entries[index].time, array->timeout)) + return -1; + + if (array->entries[index].length > length) + return -1; + + if (array->entries[index].data == NULL) + return -1; + + memcpy(data, array->entries[index].data, array->entries[index].length); + uint32_t len = array->entries[index].length; + clear_entry(array, index); + return len; +} + +/* Initialize a Ping_Array. + * size represents the total size of the array and should be a power of 2. + * timeout represents the maximum timeout in seconds for the entry. + * + * return 0 on success. + * return -1 on failure. + */ +int ping_array_init(Ping_Array *empty_array, uint32_t size, uint32_t timeout) +{ + if (size == 0 || timeout == 0 || empty_array == NULL) + return -1; + + empty_array->entries = calloc(size * sizeof(Ping_Array_Entry), 1); + + if (empty_array->entries == NULL) + return -1; + + empty_array->last_deleted = empty_array->last_added = 0; + empty_array->total_size = size; + empty_array->timeout = timeout; + return 0; +} + +/* Free all the allocated memory in a Ping_Array. + */ +void ping_array_free_all(Ping_Array *array) +{ + while (array->last_deleted != array->last_added) { + uint32_t index = array->last_deleted % array->total_size; + clear_entry(array, index); + ++array->last_deleted; + } + + free(array->entries); + array->entries = NULL; +} + diff --git a/toxcore/ping_array.h b/toxcore/ping_array.h new file mode 100644 index 00000000..c5811b16 --- /dev/null +++ b/toxcore/ping_array.h @@ -0,0 +1,75 @@ +/* ping_array.h + * + * Implementation of an efficient array to store that we pinged something. + * + * Copyright (C) 2013 Tox project All Rights Reserved. + * + * This file is part of Tox. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + * + */ +#ifndef PING_ARRAY_H +#define PING_ARRAY_H + +#include "network.h" + +typedef struct { + void *data; + uint32_t length; + uint64_t time; + uint64_t ping_id; +} Ping_Array_Entry; + + +typedef struct { + Ping_Array_Entry *entries; + + uint32_t last_deleted; /* number representing the next entry to be deleted. */ + uint32_t last_added; /* number representing the last entry to be added. */ + uint32_t total_size; /* The length of entries */ + uint32_t timeout; /* The timeout after which entries are cleared. */ +} Ping_Array; + + +/* Add a data with length to the Ping_Array list and return a ping_id. + * + * return ping_id on success. + * return 0 on failure. + */ +uint64_t ping_array_add(Ping_Array *array, uint8_t *data, uint32_t length); + +/* Check if ping_id is valid and not timed out. + * + * On success, copies the data into data of length, + * + * return length of data copied on success. + * return -1 on failure. + */ +int ping_array_check(uint8_t *data, uint32_t length, Ping_Array *array, uint64_t ping_id); + +/* Initialize a Ping_Array. + * size represents the total size of the array and should be a power of 2. + * timeout represents the maximum timeout in seconds for the entry. + * + * return 0 on success. + * return -1 on failure. + */ +int ping_array_init(Ping_Array *empty_array, uint32_t size, uint32_t timeout); + +/* Free all the allocated memory in a Ping_Array. + */ +void ping_array_free_all(Ping_Array *array); + +#endif diff --git a/toxcore/tox.c b/toxcore/tox.c index 9b99174c..884223ff 100644 --- a/toxcore/tox.c +++ b/toxcore/tox.c @@ -187,7 +187,7 @@ int tox_set_name(Tox *tox, uint8_t *name, uint16_t length) } /* Get your nickname. - * m - The messanger context to use. + * m - The messenger context to use. * name - Pointer to a string for the name. (must be at least MAX_NAME_LENGTH) * * return length of the name. @@ -722,7 +722,7 @@ int tox_file_send_data(Tox *tox, int32_t friendnumber, uint8_t filenumber, uint8 */ int tox_file_data_size(Tox *tox, int32_t friendnumber) { - return MAX_DATA_SIZE - crypto_box_MACBYTES - 3; + return MAX_CRYPTO_DATA_SIZE - 2; } /* Give the number of bytes left to be sent/received. @@ -740,23 +740,38 @@ uint64_t tox_file_data_remaining(Tox *tox, int32_t friendnumber, uint8_t filenum /***************END OF FILE SENDING FUNCTIONS******************/ -/* Use these functions to bootstrap the client. - * Sends a get nodes request to the given node with ip port and public_key. - */ -void tox_bootstrap_from_ip(Tox *tox, tox_IP_Port _ip_port, uint8_t *public_key) +/* TODO: expose this properly. */ +static int tox_add_tcp_relay(Tox *tox, const char *address, uint8_t ipv6enabled, uint16_t port, uint8_t *public_key) { Messenger *m = tox; - IP_Port ip_port; - memcpy(&ip_port, &_ip_port, sizeof(IP_Port)); - DHT_bootstrap(m->dht, ip_port, public_key); + IP_Port ip_port_v64; + IP *ip_extra = NULL; + IP_Port ip_port_v4; + ip_init(&ip_port_v64.ip, ipv6enabled); + + if (ipv6enabled) { + /* setup for getting BOTH: an IPv6 AND an IPv4 address */ + ip_port_v64.ip.family = AF_UNSPEC; + ip_reset(&ip_port_v4.ip); + ip_extra = &ip_port_v4.ip; + } + + if (addr_resolve_or_parse_ip(address, &ip_port_v64.ip, ip_extra)) { + ip_port_v64.port = port; + add_tcp_relay(m->net_crypto, ip_port_v64, public_key); + return 1; + } else { + return 0; + } } int tox_bootstrap_from_address(Tox *tox, const char *address, uint8_t ipv6enabled, uint16_t port, uint8_t *public_key) { Messenger *m = tox; + tox_add_tcp_relay(tox, address, ipv6enabled, port, public_key); return DHT_bootstrap_from_address(m->dht, address, ipv6enabled, port, public_key); -}; +} /* return 0 if we are not connected to the DHT. * return 1 if we are. @@ -842,33 +857,3 @@ int tox_load(Tox *tox, uint8_t *data, uint32_t length) Messenger *m = tox; return messenger_load(m, data, length); } - -/* return the size of data to pass to messenger_save_encrypted(...) - */ -uint32_t tox_size_encrypted(Tox *tox) -{ - Messenger *m = tox; - return messenger_size_encrypted(m); -} - -/* Save the messenger, encrypting the data with key of length key_length - * - * return 0 on success. - * return -1 on failure. - */ -int tox_save_encrypted(Tox *tox, uint8_t *data, uint8_t *key, uint16_t key_length) -{ - Messenger *m = tox; - return messenger_save_encrypted(m, data, key, key_length); -} - -/* Load the messenger from data of size length encrypted with key of key_length. - * - * return 0 on success. - * return -1 on failure. - */ -int tox_load_encrypted(Tox *tox, uint8_t *data, uint32_t length, uint8_t *key, uint16_t key_length) -{ - Messenger *m = tox; - return messenger_load_encrypted(m, data, length, key, key_length); -} diff --git a/toxcore/tox.h b/toxcore/tox.h index d94c0e13..111b2634 100644 --- a/toxcore/tox.h +++ b/toxcore/tox.h @@ -210,7 +210,7 @@ int tox_set_name(Tox *tox, uint8_t *name, uint16_t length); /* * Get your nickname. - * m - The messanger context to use. + * m - The messenger context to use. * name - needs to be a valid memory location with a size of at least MAX_NAME_LENGTH (128) bytes. * * return length of name. @@ -515,11 +515,11 @@ uint32_t tox_get_chatlist(Tox *tox, int *out_list, uint32_t list_size); * tox_file_data_remaining(...) can be used to know how many bytes are left to send/receive. * * If the connection breaks during file sending (The other person goes offline without pausing the sending and then comes back) - * the reciever must send a control packet with receive_send == 0 message_id = TOX_FILECONTROL_RESUME_BROKEN and the data being - * a uint64_t (in host byte order) containing the number of bytes recieved. + * the receiver must send a control packet with receive_send == 0 message_id = TOX_FILECONTROL_RESUME_BROKEN and the data being + * a uint64_t (in host byte order) containing the number of bytes received. * - * If the sender recieves this packet, he must send a control packet with receive_send == 1 and control_type == TOX_FILECONTROL_ACCEPT - * then he must start sending file data from the position (data , uint64_t in host byte order) recieved in the TOX_FILECONTROL_RESUME_BROKEN packet. + * If the sender receives this packet, he must send a control packet with receive_send == 1 and control_type == TOX_FILECONTROL_ACCEPT + * then he must start sending file data from the position (data , uint64_t in host byte order) received in the TOX_FILECONTROL_RESUME_BROKEN packet. * * More to come... */ @@ -601,43 +601,6 @@ uint64_t tox_file_data_remaining(Tox *tox, int32_t friendnumber, uint8_t filenum /***************END OF FILE SENDING FUNCTIONS******************/ -/* WARNING: DEPRECATED, DO NOT USE. */ -typedef union { - uint8_t c[4]; - uint16_t s[2]; - uint32_t i; -} tox_IP4; - -typedef union { - uint8_t uint8[16]; - uint16_t uint16[8]; - uint32_t uint32[4]; - struct in6_addr in6_addr; -} tox_IP6; - -typedef struct { - uint8_t family; - /* Not used for anything right now. */ - uint8_t padding[3]; - union { - tox_IP4 ip4; - tox_IP6 ip6; - }; -} tox_IP; - -/* will replace IP_Port as soon as the complete infrastructure is in place - * removed the unused union and padding also */ -typedef struct { - tox_IP ip; - uint16_t port; -} tox_IP_Port; -/* WARNING: DEPRECATED, DO NOT USE. */ -/* Sends a "get nodes" request to the given node with ip, port and public_key - * to setup connections - */ -void tox_bootstrap_from_ip(Tox *tox, tox_IP_Port ip_port, uint8_t *public_key); - - /* * Use this function to bootstrap the client. */ @@ -739,32 +702,6 @@ void tox_save(Tox *tox, uint8_t *data); */ int tox_load(Tox *tox, uint8_t *data, uint32_t length); -/**/ - -/* return the size of data to pass to messenger_save_encrypted(...) - */ -uint32_t tox_size_encrypted(Tox *tox); - -/* Save the messenger, encrypting the data with key of length key_length - * - * This functions simply calls and then encrypt the output of tox_save(..) - * with crypto_secretbox(...) from NaCl/libsodium with the key - * given to crypto_secretbox(...) being the SHA256 sum of the key - * passed to this function. - * - * return 0 on success. - * return -1 on failure. - */ -int tox_save_encrypted(Tox *tox, uint8_t *data, uint8_t *key, uint16_t key_length); - -/* Load the messenger from data of size length encrypted with key of key_length. - * - * return 0 on success. - * return -1 on failure. - */ -int tox_load_encrypted(Tox *tox, uint8_t *data, uint32_t length, uint8_t *key, uint16_t key_length); - - #ifdef __cplusplus } #endif diff --git a/toxcore/util.c b/toxcore/util.c index edc611ec..7a2db450 100644 --- a/toxcore/util.c +++ b/toxcore/util.c @@ -36,10 +36,14 @@ /* don't call into system billions of times for no reason */ static uint64_t unix_time_value; +static uint64_t unix_base_time_value; void unix_time_update() { - unix_time_value = (uint64_t)time(NULL); + if (unix_base_time_value == 0) + unix_base_time_value = ((uint64_t)time(NULL) - (current_time_monotonic() / 1000ULL)); + + unix_time_value = (current_time_monotonic() / 1000ULL) + unix_base_time_value; } uint64_t unix_time() @@ -49,7 +53,7 @@ uint64_t unix_time() int is_timeout(uint64_t timestamp, uint64_t timeout) { - return timestamp + timeout <= unix_time_value; + return timestamp + timeout <= unix_time(); } @@ -67,22 +71,17 @@ uint32_t id_copy(uint8_t *dest, uint8_t *src) void host_to_net(uint8_t *num, uint16_t numbytes) { - union { - uint32_t i; - uint8_t c[4]; - } a; - a.i = 1; - - if (a.c[0] == 1) { - uint32_t i; - uint8_t buff[numbytes]; - - for (i = 0; i < numbytes; ++i) { - buff[i] = num[numbytes - i - 1]; - } +#ifndef WORDS_BIGENDIAN + uint32_t i; + uint8_t buff[numbytes]; - memcpy(num, buff, numbytes); + for (i = 0; i < numbytes; ++i) { + buff[i] = num[numbytes - i - 1]; } + + memcpy(num, buff, numbytes); +#endif + return; } /* state load/save */ @@ -99,11 +98,11 @@ int load_state(load_state_callback_func load_state_callback, void *outer, uint16_t type; uint32_t length_sub, cookie_type; - uint32_t size32 = sizeof(uint32_t), size_head = size32 * 2; + uint32_t size_head = sizeof(uint32_t) * 2; while (length >= size_head) { - length_sub = *(uint32_t *)data; - cookie_type = *(uint32_t *)(data + size32); + memcpy(&length_sub, data, sizeof(length_sub)); + memcpy(&cookie_type, data + sizeof(length_sub), sizeof(cookie_type)); data += size_head; length -= size_head; -- cgit v1.2.3 From 565e95301f19884b3597404f41c06566cf5f9dc0 Mon Sep 17 00:00:00 2001 From: mannol Date: Sat, 24 May 2014 16:02:01 +0200 Subject: Tests works and some fixes --- auto_tests/Makefile.inc | 28 +++++++------- auto_tests/toxav_basic_test.c | 86 +++++++++++++++++++++++++------------------ auto_tests/toxav_many_test.c | 21 ++++++----- toxav/msi.c | 84 +++++++++++++++++++++++++++++++++--------- toxav/msi.h | 6 +-- toxav/rtp.c | 6 +-- toxav/toxav.c | 5 ++- toxav/toxav.h | 2 +- toxcore/logger.c | 19 ++++------ toxcore/logger.h | 14 +++---- 10 files changed, 164 insertions(+), 107 deletions(-) (limited to 'toxav/msi.h') diff --git a/auto_tests/Makefile.inc b/auto_tests/Makefile.inc index 5e101f60..55a52541 100644 --- a/auto_tests/Makefile.inc +++ b/auto_tests/Makefile.inc @@ -1,9 +1,7 @@ if BUILD_TESTS -TESTS = messenger_autotest crypto_test network_test assoc_test onion_test TCP_test tox_test -#toxav_basic_test toxav_many_test -check_PROGRAMS = messenger_autotest crypto_test network_test assoc_test onion_test TCP_test tox_test -#toxav_basic_test toxav_many_test +TESTS = messenger_autotest crypto_test network_test assoc_test onion_test TCP_test tox_test +check_PROGRAMS = messenger_autotest crypto_test network_test assoc_test onion_test TCP_test tox_test AUTOTEST_CFLAGS = \ $(LIBSODIUM_CFLAGS) \ @@ -20,11 +18,11 @@ AUTOTEST_LDADD = \ $(CHECK_LIBS) -#Tests don't work atm + if BUILD_AV -#TESTS += toxav_basic_test -#check_PROGRAMS += toxav_basic_test -#AUTOTEST_LDADD += libtoxav.la +TESTS += toxav_basic_test toxav_many_test +check_PROGRAMS += toxav_basic_test toxav_many_test +AUTOTEST_LDADD += libtoxav.la endif messenger_autotest_SOURCES = ../auto_tests/messenger_test.c @@ -76,20 +74,20 @@ tox_test_CFLAGS = $(AUTOTEST_CFLAGS) tox_test_LDADD = $(AUTOTEST_LDADD) -#Tests don't work atm + if BUILD_AV -#toxav_basic_test_SOURCES = ../auto_tests/toxav_basic_test.c +toxav_basic_test_SOURCES = ../auto_tests/toxav_basic_test.c -#toxav_basic_test_CFLAGS = $(AUTOTEST_CFLAGS) +toxav_basic_test_CFLAGS = $(AUTOTEST_CFLAGS) -#toxav_basic_test_LDADD = $(AUTOTEST_LDADD) +toxav_basic_test_LDADD = $(AUTOTEST_LDADD) -#toxav_many_test_SOURCES = ../auto_tests/toxav_many_test.c +toxav_many_test_SOURCES = ../auto_tests/toxav_many_test.c -#toxav_many_test_CFLAGS = $(AUTOTEST_CFLAGS) +toxav_many_test_CFLAGS = $(AUTOTEST_CFLAGS) -#toxav_many_test_LDADD = $(AUTOTEST_LDADD) +toxav_many_test_LDADD = $(AUTOTEST_LDADD) endif endif diff --git a/auto_tests/toxav_basic_test.c b/auto_tests/toxav_basic_test.c index c0162582..116a519a 100644 --- a/auto_tests/toxav_basic_test.c +++ b/auto_tests/toxav_basic_test.c @@ -13,6 +13,7 @@ #include "../toxcore/tox.h" #include "../toxcore/logger.h" +#include "../toxcore/crypto_core.h" #include "../toxav/toxav.h" #if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) @@ -159,6 +160,7 @@ case 3: /* Wait for Both to have status ended */\ if (status_control.Alice.status == Ended && status_control.Bob.status == Ended) running = 0; break; } c_sleep(20); } } printf("\n"); START_TEST(test_AV_flows) +// int test_AV_flows() { long long unsigned int cur_time = time(NULL); Tox *bootstrap_node = tox_new(0); @@ -200,11 +202,10 @@ START_TEST(test_AV_flows) muhcaps.video_height = muhcaps.video_width = 128; Status status_control = { - {none, toxav_new(Alice, 1), NULL}, - {none, toxav_new(Bob, 1), NULL}, + {none, toxav_new(Alice, 1), NULL, -1}, + {none, toxav_new(Bob, 1), NULL, -1}, }; - - + ck_assert_msg(status_control.Alice.av || status_control.Bob.av, "Failed to create 2 toxav instances"); @@ -222,9 +223,11 @@ START_TEST(test_AV_flows) toxav_register_callstate_callback(callback_requ_timeout, av_OnRequestTimeout, &status_control); - - int16_t sample_payload[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - uint8_t prepared_payload[1000]; + const int frame_size = (av_DefaultSettings.audio_sample_rate * av_DefaultSettings.audio_frame_duration / 1000); + int16_t sample_payload[frame_size]; + randombytes_salsa20_random_buf(sample_payload, sizeof(int16_t) * frame_size); + + uint8_t prepared_payload[RTP_PAYLOAD_SIZE]; int payload_size; vpx_image_t *sample_image = vpx_img_alloc(NULL, VPX_IMG_FMT_I420, 128, 128, 1); @@ -241,30 +244,34 @@ START_TEST(test_AV_flows) /* * Call with audio only on both sides. Alice calls Bob. */ + + CALL_AND_START_LOOP(TypeAudio, TypeAudio) { /* Both send */ - int payload_size = toxav_prepare_audio_frame(status_control.Alice.av, status_control.Alice.call_index, prepared_payload, 1000, sample_payload, 120); - if (!( payload_size > 0 )) { /* FIXME: this will always fail */ + payload_size = toxav_prepare_audio_frame(status_control.Alice.av, status_control.Alice.call_index, prepared_payload, 1000, sample_payload, frame_size); + if ( payload_size < 0 ) { ck_assert_msg ( 0, "Failed to encode payload" ); } - toxav_send_audio(status_control.Alice.av, status_control.Alice.call_index, prepared_payload, payload_size); + + payload_size = toxav_prepare_audio_frame(status_control.Bob.av, status_control.Bob.call_index, prepared_payload, 1000, sample_payload, frame_size); + if ( payload_size < 0 ) { + ck_assert_msg ( 0, "Failed to encode payload" ); + } toxav_send_audio(status_control.Bob.av, status_control.Bob.call_index, prepared_payload, payload_size); - + /* Both receive */ - int16_t storage[10]; + int16_t storage[frame_size]; int recved; /* Payload from Bob */ - recved = toxav_recv_audio(status_control.Alice.av, status_control.Alice.call_index, 120, storage); + recved = toxav_recv_audio(status_control.Alice.av, status_control.Alice.call_index, frame_size, storage); if ( recved ) { /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Bob is invalid");*/ - memset(storage, 0, 10); } - /* Payload from Alice */ - recved = toxav_recv_audio(status_control.Bob.av, status_control.Bob.call_index, 120, storage); + recved = toxav_recv_audio(status_control.Bob.av, status_control.Bob.call_index, frame_size, storage); if ( recved ) { /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Alice is invalid");*/ @@ -286,28 +293,30 @@ START_TEST(test_AV_flows) * Call with audio on both sides and video on one side. Alice calls Bob. */ CALL_AND_START_LOOP(TypeAudio, TypeVideo) { - /* Both send */ - int payload_size = toxav_prepare_audio_frame(status_control.Alice.av, status_control.Alice.call_index, prepared_payload, 1000, sample_payload, 120); - if (!( payload_size > 0 )) { /* FIXME: this will always fail */ + /* Both send */ + payload_size = toxav_prepare_audio_frame(status_control.Alice.av, status_control.Alice.call_index, prepared_payload, 1000, sample_payload, frame_size); + if ( payload_size < 0 ) { ck_assert_msg ( 0, "Failed to encode payload" ); } - toxav_send_audio(status_control.Alice.av, status_control.Alice.call_index, prepared_payload, payload_size); + payload_size = toxav_prepare_audio_frame(status_control.Bob.av, status_control.Bob.call_index, prepared_payload, 1000, sample_payload, frame_size); + if ( payload_size < 0 ) { + ck_assert_msg ( 0, "Failed to encode payload" ); + } toxav_send_audio(status_control.Bob.av, status_control.Bob.call_index, prepared_payload, payload_size); // toxav_send_video(status_control.Bob.av, status_control.Bob.call_index, sample_image); /* Both receive */ - int16_t storage[10]; + int16_t storage[frame_size]; vpx_image_t *video_storage; int recved; /* Payload from Bob */ - recved = toxav_recv_audio(status_control.Alice.av, status_control.Alice.call_index, 120, storage); + recved = toxav_recv_audio(status_control.Alice.av, status_control.Alice.call_index, frame_size, storage); if ( recved ) { /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Bob is invalid");*/ - memset(storage, 0, 10); } /* Video payload */ @@ -324,7 +333,7 @@ START_TEST(test_AV_flows) /* Payload from Alice */ - recved = toxav_recv_audio(status_control.Bob.av, status_control.Bob.call_index, 120, storage); + recved = toxav_recv_audio(status_control.Bob.av, status_control.Bob.call_index, frame_size, storage); if ( recved ) { /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Alice is invalid");*/ @@ -347,28 +356,32 @@ START_TEST(test_AV_flows) */ CALL_AND_START_LOOP(TypeVideo, TypeVideo) { /* Both send */ - int payload_size = toxav_prepare_audio_frame(status_control.Alice.av, status_control.Alice.call_index, prepared_payload, 1000, sample_payload, 120); - if (!( payload_size > 0 )) { /* FIXME: this will always fail */ + + payload_size = toxav_prepare_audio_frame(status_control.Alice.av, status_control.Alice.call_index, prepared_payload, 1000, sample_payload, frame_size); + if ( payload_size < 0 ) { ck_assert_msg ( 0, "Failed to encode payload" ); } + toxav_send_audio(status_control.Alice.av, status_control.Alice.call_index, prepared_payload, payload_size); - toxav_send_audio(status_control.Alice.av, status_control.Alice.call_index, prepared_payload, payload_size); -// toxav_send_video(status_control.Alice.av, status_control.Alice.call_index, sample_image); - + payload_size = toxav_prepare_audio_frame(status_control.Bob.av, status_control.Bob.call_index, prepared_payload, 1000, sample_payload, frame_size); + if ( payload_size < 0 ) { + ck_assert_msg ( 0, "Failed to encode payload" ); + } toxav_send_audio(status_control.Bob.av, status_control.Bob.call_index, prepared_payload, payload_size); + +// toxav_send_video(status_control.Alice.av, status_control.Alice.call_index, sample_image); // toxav_send_video(status_control.Bob.av, status_control.Bob.call_index, sample_image); /* Both receive */ - int16_t storage[10]; + int16_t storage[frame_size]; vpx_image_t *video_storage; int recved; /* Payload from Bob */ - recved = toxav_recv_audio(status_control.Alice.av, status_control.Alice.call_index, 120, storage); + recved = toxav_recv_audio(status_control.Alice.av, status_control.Alice.call_index, frame_size, storage); if ( recved ) { /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Bob is invalid");*/ - memset(storage, 0, 10); } /* Video payload */ @@ -385,7 +398,7 @@ START_TEST(test_AV_flows) /* Payload from Alice */ - recved = toxav_recv_audio(status_control.Bob.av, status_control.Bob.call_index, 120, storage); + recved = toxav_recv_audio(status_control.Bob.av, status_control.Bob.call_index, frame_size, storage); if ( recved ) { /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Alice is invalid");*/ @@ -437,7 +450,6 @@ START_TEST(test_AV_flows) toxav_call(status_control.Alice.av, &status_control.Alice.call_index, 0, TypeAudio, 10); step++; break; - \ case 1: /* Bob */ if (status_control.Bob.status == Ringing) { @@ -491,7 +503,7 @@ START_TEST(test_AV_flows) break; case 2: /* Wait for Both to have status ended */ - if (status_control.Alice.status == Ended && status_control.Bob.status == Cancel) running = 0; + if (status_control.Bob.status == Cancel) running = 0; break; } @@ -521,7 +533,7 @@ Suite *tox_suite(void) TCase *tc_av_flows = tcase_create("AV_flows"); tcase_add_test(tc_av_flows, test_AV_flows); - tcase_set_timeout(tc_av_flows, 100); /* Timeout on 100 too much? */ + tcase_set_timeout(tc_av_flows, 200); suite_add_tcase(s, tc_av_flows); return s; @@ -539,4 +551,6 @@ int main(int argc, char *argv[]) srunner_free(test_runner); return number_failed; + +// return test_AV_flows(); } diff --git a/auto_tests/toxav_many_test.c b/auto_tests/toxav_many_test.c index b499b439..f9a24012 100644 --- a/auto_tests/toxav_many_test.c +++ b/auto_tests/toxav_many_test.c @@ -13,6 +13,7 @@ #include "../toxcore/tox.h" #include "../toxcore/logger.h" +#include "../toxcore/crypto_core.h" #include "../toxav/toxav.h" #if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) @@ -131,9 +132,11 @@ void* in_thread_call (void* arg) int step = 0,running = 1; int call_idx; + const int frame_size = (av_DefaultSettings.audio_sample_rate * av_DefaultSettings.audio_frame_duration / 1000); + int16_t sample_payload[frame_size]; + randombytes_salsa20_random_buf(sample_payload, sizeof(int16_t) * frame_size); - int16_t sample_payload[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - uint8_t prepared_payload[1000]; + uint8_t prepared_payload[RTP_PAYLOAD_SIZE]; /* NOTE: CALLEE WILL ALWAHYS NEED CALL_IDX == 0 */ @@ -162,37 +165,37 @@ void* in_thread_call (void* arg) toxav_prepare_transmission(this_call->Callee.av, 0, &cast, 1); toxav_prepare_transmission(this_call->Caller.av, call_idx, &cast, 1); - int payload_size = toxav_prepare_audio_frame(this_call->Caller.av, call_idx, prepared_payload, 1000, sample_payload, 120); - if (!( payload_size > 0 )) { + int payload_size = toxav_prepare_audio_frame(this_call->Caller.av, call_idx, prepared_payload, RTP_PAYLOAD_SIZE, sample_payload, frame_size); + if ( payload_size < 0 ) { ck_assert_msg ( 0, "Failed to encode payload" ); } + while (time(NULL) - start < 10) { /* 10 seconds */ /* Both send */ toxav_send_audio(this_call->Caller.av, call_idx, prepared_payload, payload_size); toxav_send_audio(this_call->Callee.av, 0, prepared_payload, payload_size); - call_print(time(NULL) - start, "Blaaah"); /* Both receive */ - int16_t storage[1000]; + int16_t storage[RTP_PAYLOAD_SIZE]; int recved; /* Payload from CALLER */ - recved = toxav_recv_audio(this_call->Callee.av, 0, 120, storage); + recved = toxav_recv_audio(this_call->Callee.av, 0, frame_size, storage); if ( recved ) { /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from CALLER is invalid");*/ } /* Payload from CALLEE */ - recved = toxav_recv_audio(this_call->Caller.av, call_idx, 120, storage); + recved = toxav_recv_audio(this_call->Caller.av, call_idx, frame_size, storage); if ( recved ) { /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from CALLEE is invalid");*/ } - //c_sleep(20); + c_sleep(20); } step++; /* This terminates the loop */ diff --git a/toxav/msi.c b/toxav/msi.c index fd92e784..048b13eb 100755 --- a/toxav/msi.c +++ b/toxav/msi.c @@ -792,8 +792,10 @@ MSICall* find_call ( MSISession* session, uint8_t* call_id ) uint32_t i = 0; for (; i < session->max_calls; i ++ ) - if ( session->calls[i] && memcmp(session->calls[i]->id, call_id, CALL_ID_LEN) == 0 ) + if ( session->calls[i] && memcmp(session->calls[i]->id, call_id, CALL_ID_LEN) == 0 ) { + LOGGER_DEBUG("Found call id: %s", session->calls[i]->id); return session->calls[i]; + } return NULL; } @@ -843,8 +845,9 @@ int has_call_error ( MSISession *session, MSICall* call, MSIMessage *msg ) return handle_error ( session, call, error_no_callid, msg->friend_id ); } else if ( !call ) { - return handle_error ( session, call, error_no_call, msg->friend_id ); - + LOGGER_WARNING("Handling message while no call!"); + return 0; + } else if ( memcmp ( call->id, msg->callid.header_value, CALL_ID_LEN ) != 0 ) { return handle_error ( session, call, error_id_mismatch, msg->friend_id ); @@ -957,7 +960,10 @@ int terminate_call ( MSISession *session, MSICall *call ) LOGGER_WARNING("Tried to terminate non-existing call!"); return -1; } - + + int rc = pthread_mutex_trylock(&session->mutex); /* Lock if not locked */ + + LOGGER_DEBUG("Terminated call id: %d", call->call_idx); /* Check event loop and cancel timed events if there are any * NOTE: This has to be done before possibly * locking the mutex the second time @@ -982,6 +988,9 @@ int terminate_call ( MSISession *session, MSICall *call ) free ( call ); + if ( rc != EBUSY ) /* Unlock if locked by this call */ + pthread_mutex_unlock(&session->mutex); + return 0; } @@ -1159,10 +1168,10 @@ int handle_recv_end ( MSISession *session, MSICall* call, MSIMessage *msg ) /********** Response handlers **********/ int handle_recv_ringing ( MSISession *session, MSICall* call, MSIMessage *msg ) { - LOGGER_DEBUG("Session: %p Handling 'ringing' on call: %s", session, call->id ); - if ( has_call_error ( session, call, msg ) == 0 ) return 0; + + LOGGER_DEBUG("Session: %p Handling 'ringing' on call: %s", session, call->id ); call->ringing_timer_id = event.timer_alloc ( handle_timeout, call, call->ringing_tout_ms ); @@ -1172,10 +1181,11 @@ int handle_recv_ringing ( MSISession *session, MSICall* call, MSIMessage *msg ) } int handle_recv_starting ( MSISession *session, MSICall* call, MSIMessage *msg ) { - LOGGER_DEBUG("Session: %p Handling 'starting' on call: %s", session, call->id ); - if ( has_call_error ( session, call, msg ) == 0 ) return 0; + + LOGGER_DEBUG("Session: %p Handling 'starting' on call: %s", session, call->id ); + if ( !msg->cryptokey.header_value ) { return handle_error ( session, call, error_no_crypto_key, msg->friend_id ); @@ -1213,11 +1223,11 @@ int handle_recv_starting ( MSISession *session, MSICall* call, MSIMessage *msg ) } int handle_recv_ending ( MSISession *session, MSICall* call, MSIMessage *msg ) { - LOGGER_DEBUG("Session: %p Handling 'ending' on call: %s", session, call->id ); - if ( has_call_error ( session, call, msg ) == 0 ) return 0; + LOGGER_DEBUG("Session: %p Handling 'ending' on call: %s", session, call->id ); + /* Stop timer */ event.timer_release ( call->request_timer_id ); @@ -1308,9 +1318,13 @@ void msi_handle_packet ( Messenger *messenger, int source, uint8_t *data, uint16 _msg->friend_id = source; + pthread_mutex_lock(&_session->mutex); + /* Find what call */ MSICall* _call = _msg->callid.header_value ? find_call(_session, _msg->callid.header_value ) : NULL; + + /* Now handle message */ if ( _msg->request.header_value ) { /* Handle request */ @@ -1381,7 +1395,9 @@ void msi_handle_packet ( Messenger *messenger, int source, uint8_t *data, uint16 LOGGER_WARNING("Invalid message: no resp nor requ headers"); } - free_end:free_message ( _msg ); +free_end: + free_message ( _msg ); + pthread_mutex_unlock(&_session->mutex); } @@ -1438,6 +1454,8 @@ MSISession *msi_init_session ( Messenger* messenger, int32_t max_calls ) /* This is called when remote terminates session */ m_callback_connectionstatus_internal_av(messenger, handle_remote_connection_change, _retu); + pthread_mutex_init(&_retu->mutex, NULL); + LOGGER_DEBUG("New msi session: %p max calls: %u", _retu, max_calls); return _retu; } @@ -1456,6 +1474,10 @@ int msi_terminate_session ( MSISession *session ) return -1; } + pthread_mutex_lock(&session->mutex); + m_callback_msi_packet((struct Messenger *) session->messenger_handle, NULL, NULL); + pthread_mutex_unlock(&session->mutex); + int _status = 0; /* If have calls, cancel them */ @@ -1467,7 +1489,8 @@ int msi_terminate_session ( MSISession *session ) msi_cancel ( session, idx, session->calls[idx]->peers [_it], "MSI session terminated!" ); } - m_callback_msi_packet((struct Messenger *) session->messenger_handle, NULL, NULL); + + pthread_mutex_destroy(&session->mutex); LOGGER_DEBUG("Terminated session: %p", session); free ( session ); @@ -1486,12 +1509,17 @@ int msi_terminate_session ( MSISession *session ) */ int msi_invite ( MSISession* session, int32_t* call_index, MSICallType call_type, uint32_t rngsec, uint32_t friend_id ) { + pthread_mutex_lock(&session->mutex); + LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_id); MSIMessage *_msg_invite = msi_new_message ( TYPE_REQUEST, stringify_request ( invite ) ); MSICall* _call = init_call ( session, 1, rngsec ); /* Just one peer for now */ - if ( !_call ) return -1; /* Cannot handle more calls */ + if ( !_call ) { + pthread_mutex_unlock(&session->mutex); + return -1; /* Cannot handle more calls */ + } *call_index = _call->call_idx; @@ -1517,6 +1545,8 @@ int msi_invite ( MSISession* session, int32_t* call_index, MSICallType call_type LOGGER_DEBUG("Invite sent"); + pthread_mutex_unlock(&session->mutex); + return 0; } @@ -1532,15 +1562,18 @@ int msi_invite ( MSISession* session, int32_t* call_index, MSICallType call_type */ int msi_hangup ( MSISession* session, int32_t call_index ) { + pthread_mutex_lock(&session->mutex); LOGGER_DEBUG("Session: %p Hanging up call: %u", session, call_index); if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) { LOGGER_ERROR("Invalid call index!"); + pthread_mutex_unlock(&session->mutex); return -1; } if ( !session->calls[call_index] || session->calls[call_index]->state != call_active ) { LOGGER_ERROR("No call with such index or call is not active!"); + pthread_mutex_unlock(&session->mutex); return -1; } @@ -1557,6 +1590,7 @@ int msi_hangup ( MSISession* session, int32_t call_index ) session->calls[call_index]->request_timer_id = event.timer_alloc ( handle_timeout, session->calls[call_index], m_deftout ); + pthread_mutex_unlock(&session->mutex); return 0; } @@ -1571,10 +1605,12 @@ int msi_hangup ( MSISession* session, int32_t call_index ) */ int msi_answer ( MSISession* session, int32_t call_index, MSICallType call_type ) { + pthread_mutex_lock(&session->mutex); LOGGER_DEBUG("Session: %p Answering call: %u", session, call_index); if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ){ LOGGER_ERROR("Invalid call index!"); + pthread_mutex_unlock(&session->mutex); return -1; } @@ -1605,7 +1641,8 @@ int msi_answer ( MSISession* session, int32_t call_index, MSICallType call_type free_message ( _msg_starting ); session->calls[call_index]->state = call_active; - + + pthread_mutex_unlock(&session->mutex); return 0; } @@ -1620,10 +1657,12 @@ int msi_answer ( MSISession* session, int32_t call_index, MSICallType call_type */ int msi_cancel ( MSISession* session, int32_t call_index, uint32_t peer, const char* reason ) { + pthread_mutex_lock(&session->mutex); LOGGER_DEBUG("Session: %p Canceling call: %u; reason:", session, call_index, reason? reason : "Unknown"); if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ){ LOGGER_ERROR("Invalid call index!"); + pthread_mutex_unlock(&session->mutex); return -1; } @@ -1634,7 +1673,9 @@ int msi_cancel ( MSISession* session, int32_t call_index, uint32_t peer, const c send_message ( session, session->calls[call_index], _msg_cancel, peer ); free_message ( _msg_cancel ); - session->calls[call_index]->request_timer_id = event.timer_alloc ( handle_timeout, session->calls[call_index], m_deftout ); + /*session->calls[call_index]->request_timer_id = event.timer_alloc ( handle_timeout, session->calls[call_index], m_deftout );*/ + terminate_call ( session, session->calls[call_index] ); + pthread_mutex_unlock(&session->mutex); return 0; } @@ -1649,10 +1690,12 @@ int msi_cancel ( MSISession* session, int32_t call_index, uint32_t peer, const c */ int msi_reject ( MSISession* session, int32_t call_index, const uint8_t* reason ) { + pthread_mutex_lock(&session->mutex); LOGGER_DEBUG("Session: %p Rejecting call: %u; reason:", session, call_index, reason? (char*)reason : "Unknown"); if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ){ LOGGER_ERROR("Invalid call index!"); + pthread_mutex_unlock(&session->mutex); return -1; } @@ -1664,7 +1707,8 @@ int msi_reject ( MSISession* session, int32_t call_index, const uint8_t* reason free_message ( _msg_reject ); session->calls[call_index]->request_timer_id = event.timer_alloc ( handle_timeout, session->calls[call_index], m_deftout ); - + + pthread_mutex_unlock(&session->mutex); return 0; } @@ -1678,14 +1722,18 @@ int msi_reject ( MSISession* session, int32_t call_index, const uint8_t* reason */ int msi_stopcall ( MSISession* session, int32_t call_index ) { + pthread_mutex_lock(&session->mutex); LOGGER_DEBUG("Session: %p Stopping call index: %u", session, call_index); - if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) + if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) { + pthread_mutex_unlock(&session->mutex); return -1; + } /* just terminate it */ terminate_call ( session, session->calls[call_index] ); - + + pthread_mutex_unlock(&session->mutex); return 0; } diff --git a/toxav/msi.h b/toxav/msi.h index 54ae8faf..9c748303 100755 --- a/toxav/msi.h +++ b/toxav/msi.h @@ -84,9 +84,7 @@ typedef struct _MSICall { /* Call info structure */ int ringing_timer_id; /* Timer id for ringing timeout */ - pthread_mutex_t mutex; /* It's to be assumed that call will have - * separate thread so add mutex - */ + pthread_mutex_t mutex; /* */ uint32_t *peers; uint16_t peer_count; @@ -113,7 +111,7 @@ typedef struct _MSISession { uint32_t frequ; uint32_t call_timeout; /* Time of the timeout for some action to end; 0 if infinite */ - + pthread_mutex_t mutex; } MSISession; diff --git a/toxav/rtp.c b/toxav/rtp.c index 1a42f99e..f8f5b63b 100755 --- a/toxav/rtp.c +++ b/toxav/rtp.c @@ -588,7 +588,7 @@ int rtp_handle_packet ( void *object, uint8_t *data, uint32_t length ) _session->queue_size++; pthread_mutex_unlock(&_session->mutex); - + return 0; } @@ -778,13 +778,12 @@ int rtp_send_msg ( RTPSession *session, Messenger *messenger, const uint8_t *dat int encrypted_length = encrypt_data_symmetric( /* TODO: msg->length - 2 (fix this properly)*/ (uint8_t *) session->encrypt_key, _calculated, msg->data + 2, msg->length, _send_data + 3 ); - int full_length = encrypted_length + 3; _send_data[1] = msg->data[0]; _send_data[2] = msg->data[1]; - if ( full_length != send_custom_user_packet(messenger, session->dest, _send_data, full_length) ) { + if ( -1 == send_custom_user_packet(messenger, session->dest, _send_data, encrypted_length + 3) ) { LOGGER_WARNING("Failed to send full packet! std error: %s", strerror(errno)); rtp_free_msg ( session, msg ); return -1; @@ -800,6 +799,7 @@ int rtp_send_msg ( RTPSession *session, Messenger *messenger, const uint8_t *dat } rtp_free_msg ( session, msg ); + return 0; } diff --git a/toxav/toxav.c b/toxav/toxav.c index f92964aa..8289c4e9 100755 --- a/toxav/toxav.c +++ b/toxav/toxav.c @@ -96,9 +96,10 @@ ToxAv *toxav_new( Tox* messenger, int32_t max_calls) { ToxAv *av = calloc ( sizeof(ToxAv), 1); - if (av == NULL) + if (av == NULL) { + LOGGER_WARNING("Allocation failed!"); return NULL; - + } av->messenger = (Messenger *)messenger; av->msi_session = msi_init_session(av->messenger, max_calls); diff --git a/toxav/toxav.h b/toxav/toxav.h index 74f2333b..341b38b4 100755 --- a/toxav/toxav.h +++ b/toxav/toxav.h @@ -67,7 +67,7 @@ typedef enum { * @brief Call type identifier. */ typedef enum { - TypeAudio = 70, + TypeAudio = 192, TypeVideo } ToxAvCallType; diff --git a/toxcore/logger.c b/toxcore/logger.c index ff9146d4..933e8d4b 100644 --- a/toxcore/logger.c +++ b/toxcore/logger.c @@ -25,7 +25,6 @@ #include "config.h" #endif /* HAVE_CONFIG_H */ - #include "logger.h" #ifdef LOGGING @@ -96,7 +95,7 @@ int logger_init(const char* file_name, LoggerLevel level) sprintf(final_l, "%s"/*.%u"*/, file_name, logger_get_pid()); if ( logger.log_file ) { - fprintf(stderr, "Error opening logger name: %s with level %d: %s!\n", final_l, level, strerror(errno)); + fprintf(stderr, "Error opening logger name: %s with level %d: file already opened!\n", final_l, level); free (final_l); return -1; } @@ -104,19 +103,15 @@ int logger_init(const char* file_name, LoggerLevel level) logger.log_file = fopen(final_l, "ab"); if ( logger.log_file == NULL ) { - char error[1000]; - if ( strerror_r(errno, error, 1000) == 0 ) - fprintf(stderr, "Error opening logger file: %s; info: %s\n", final_l, error); - else - fprintf(stderr, "Error opening logger file: %s\n", final_l); - + fprintf(stderr, "Error opening logger file: %s; info: %s\n", final_l, strerror(errno)); + free (final_l); return -1; } logger.level = level; - logger.start_time = current_time(); + logger.start_time = current_time_monotonic(); time_t tim = time(NULL); @@ -147,10 +142,10 @@ void logger_write (LoggerLevel level, const char* format, ...) fflush(logger.log_file); } -char* logger_timestr(char* dest) +char* logger_timestr(char* dest, size_t max_size) { - uint64_t diff = (current_time() - logger.start_time) / 1000; /* ms */ - sprintf(dest, "%"PRIu64"", diff); + uint64_t diff = (current_time_monotonic() - logger.start_time); /* ms */ + snprintf(dest, max_size, "%"PRIu64"", diff); return dest; } diff --git a/toxcore/logger.h b/toxcore/logger.h index d8292f31..0b6367c5 100644 --- a/toxcore/logger.h +++ b/toxcore/logger.h @@ -45,7 +45,7 @@ int logger_init(const char* file_name, LoggerLevel level); const char* logger_stringify_level(LoggerLevel level); unsigned logger_get_pid(); void logger_write (LoggerLevel level, const char* format, ...); -char* logger_timestr (char* dest); +char* logger_timestr (char* dest, size_t max_size); #if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) #define _SFILE (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__) @@ -53,16 +53,16 @@ char* logger_timestr (char* dest); #define _SFILE (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) #endif -#define WRITE_FORMAT(__LEVEL__, format) char* the_str = calloc(sizeof(char), strlen(format)+ 500); sprintf(the_str, "\n[%u] [%s] [%s] [%s:%d %s()] %s", \ - logger_get_pid(), logger_stringify_level(__LEVEL__), logger_timestr(__time__), _SFILE, __LINE__, __func__, format) +#define WRITE_FORMAT(__LEVEL__, format) char __time__[20]; char* the_str = calloc(sizeof(char), strlen(format)+ 500); sprintf(the_str, "\n[%u] [%s] [%s] [%s:%d %s()] %s", \ + logger_get_pid(), logger_stringify_level(__LEVEL__), logger_timestr(__time__, 20), _SFILE, __LINE__, __func__, format) /* Use these macros */ #define LOGGER_INIT(name, level) logger_init(name, level); -#define LOGGER_INFO(format, ...) do { char __time__[20]; WRITE_FORMAT(INFO, format); logger_write( INFO, the_str, ##__VA_ARGS__ ); free(the_str); } while (0) -#define LOGGER_DEBUG(format, ...) do { char __time__[20]; WRITE_FORMAT(DEBUG, format); logger_write( DEBUG, the_str, ##__VA_ARGS__ ); free(the_str); } while (0) -#define LOGGER_WARNING(format, ...) do { char __time__[20]; WRITE_FORMAT(WARNING, format); logger_write( WARNING, the_str, ##__VA_ARGS__ ); free(the_str); } while (0) -#define LOGGER_ERROR(format, ...) do { char __time__[20]; WRITE_FORMAT(ERROR, format); logger_write( ERROR, the_str, ##__VA_ARGS__ ); free(the_str); } while (0) +#define LOGGER_INFO(format, ...) do { WRITE_FORMAT(INFO, format); logger_write( INFO, the_str, ##__VA_ARGS__ ); free(the_str); } while (0) +#define LOGGER_DEBUG(format, ...) do { WRITE_FORMAT(DEBUG, format); logger_write( DEBUG, the_str, ##__VA_ARGS__ ); free(the_str); } while (0) +#define LOGGER_WARNING(format, ...) do { WRITE_FORMAT(WARNING, format); logger_write( WARNING, the_str, ##__VA_ARGS__ ); free(the_str); } while (0) +#define LOGGER_ERROR(format, ...) do { WRITE_FORMAT(ERROR, format); logger_write( ERROR, the_str, ##__VA_ARGS__ ); free(the_str); } while (0) /* To do some checks or similar only when logging use this */ #define LOGGER_SCOPE(__SCOPE_DO__) do { __SCOPE_DO__ } while(0) -- cgit v1.2.3