From b190dc6fbed142231d7c36d9d4195ec0946442d4 Mon Sep 17 00:00:00 2001 From: Sebastian Stal Date: Thu, 18 Jul 2013 10:56:50 -0700 Subject: [PATCH 1/2] Add custom user statuses to core, updated nTox to support nicknames and user statuses. --- core/Messenger.c | 147 +++++++++++++++++++++++++++++++----- core/Messenger.h | 35 ++++++++- docs/Messenger_Protocol.txt | 6 +- testing/nTox.c | 51 ++++++++++++- 4 files changed, 209 insertions(+), 30 deletions(-) diff --git a/core/Messenger.c b/core/Messenger.c index 85b2ac5a..a14be9d0 100644 --- a/core/Messenger.c +++ b/core/Messenger.c @@ -1,7 +1,7 @@ /* Messenger.c -* +* * An implementation of a simple text chat only messenger on the tox network core. -* +* Copyright (C) 2013 Tox project All Rights Reserved. @@ -23,8 +23,7 @@ */ #include "Messenger.h" - -#define MAX_NAME_LENGTH 128 +#define MIN(a,b) (((a)<(b))?(a):(b)) typedef struct { @@ -35,6 +34,9 @@ typedef struct uint8_t info[MAX_DATA_SIZE]; //the data that is sent during the friend requests we do uint8_t name[MAX_NAME_LENGTH]; uint8_t name_sent;//0 if we didn't send our name to this friend 1 if we have. + uint8_t *userstatus; + uint16_t userstatus_length; + uint8_t userstatus_sent; uint16_t info_size; //length of the info }Friend; @@ -43,6 +45,8 @@ typedef struct uint8_t self_public_key[crypto_box_PUBLICKEYBYTES]; static uint8_t self_name[MAX_NAME_LENGTH]; +static uint8_t *self_userstatus; +static uint16_t self_userstatus_len; #define MAX_NUM_FRIENDS 256 @@ -102,7 +106,7 @@ int getclient_id(int friend_id, uint8_t * client_id) //return -1 if failure. int m_addfriend(uint8_t * client_id, uint8_t * data, uint16_t length) { - if(length == 0 || length >= + if(length == 0 || length >= (MAX_DATA_SIZE - crypto_box_PUBLICKEYBYTES - crypto_box_NONCEBYTES - crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES)) { return -1; @@ -125,7 +129,8 @@ int m_addfriend(uint8_t * client_id, uint8_t * data, uint16_t length) friendlist[i].crypt_connection_id = -1; friendlist[i].friend_request_id = -1; memcpy(friendlist[i].client_id, client_id, CLIENT_ID_SIZE); - + friendlist[i].userstatus = calloc(1, 1); + friendlist[i].userstatus_length = 1; memcpy(friendlist[i].info, data, length); friendlist[i].info_size = length; @@ -152,6 +157,8 @@ int m_addfriend_norequest(uint8_t * client_id) friendlist[i].crypt_connection_id = -1; friendlist[i].friend_request_id = -1; memcpy(friendlist[i].client_id, client_id, CLIENT_ID_SIZE); + friendlist[i].userstatus = calloc(1, 1); + friendlist[i].userstatus_length = 1; numfriends++; return i; } @@ -171,6 +178,7 @@ int m_delfriend(int friendnumber) DHT_delfriend(friendlist[friendnumber].client_id); crypto_kill(friendlist[friendnumber].crypt_connection_id); + free(friendlist[friendnumber].userstatus); memset(&friendlist[friendnumber], 0, sizeof(Friend)); uint32_t i; for(i = numfriends; i != 0; i--) @@ -212,7 +220,7 @@ int m_sendmessage(int friendnumber, uint8_t * message, uint32_t length) if(length >= MAX_DATA_SIZE || friendlist[friendnumber].status != 4) //this does not mean the maximum message length is MAX_DATA_SIZE - 1, it is actually 17 bytes less. { - return 0; + return 0; } uint8_t temp[MAX_DATA_SIZE]; temp[0] = 64; @@ -278,6 +286,72 @@ int getname(int friendnumber, uint8_t * name) return 0; } +int m_set_userstatus(uint8_t *status, uint16_t length) +{ + if(length > MAX_USERSTATUS_LENGTH) + { + return -1; + } + uint8_t *newstatus = calloc(length, 1); + memcpy(newstatus, status, length); + free(self_userstatus); + self_userstatus = newstatus; + self_userstatus_len = length; + + uint32_t i; + for(i = 0; i < numfriends; i++) + { + friendlist[i].userstatus_sent = 0; + } + return 0; +} + +// return the size of friendnumber's user status +// guaranteed to be at most MAX_USERSTATUS_LENGTH +int m_get_userstatus_size(int friendnumber) +{ + if(friendnumber >= numfriends || friendnumber < 0) + { + return -1; + } + return friendlist[friendnumber].userstatus_length; +} + +// copy the user status of friendnumber into buf, truncating if needed to maxlen +// bytes, use m_get_userstatus_size to find out how much you need to allocate +int m_copy_userstatus(int friendnumber, uint8_t * buf, uint32_t maxlen) +{ + if(friendnumber >= numfriends || friendnumber < 0) + { + return -1; + } + memset(buf, 0, 1); + memcpy(buf, friendlist[friendnumber].userstatus, MIN(maxlen, MAX_USERSTATUS_LENGTH) - 1); + return 0; +} + +static int send_userstatus(int friendnumber, uint8_t * status, uint16_t length) +{ + uint8_t *thepacket = malloc(length + 1); + memcpy(thepacket + 1, status, length); + thepacket[0] = 70; + return write_cryptpacket(friendlist[friendnumber].crypt_connection_id, thepacket, length + 1); +} + +static int set_friend_userstatus(int friendnumber, uint8_t * status, uint16_t length) +{ + if(friendnumber >= numfriends || friendnumber < 0) + { + return -1; + } + uint8_t *newstatus = calloc(length, 1); + memcpy(newstatus, status, length); + free(friendlist[friendnumber].userstatus); + friendlist[friendnumber].userstatus = newstatus; + friendlist[friendnumber].userstatus_length = length; + return 0; +} + static void (*friend_request)(uint8_t *, uint8_t *, uint16_t); //set the function that will be executed when a friend request is received. @@ -296,11 +370,24 @@ void m_callback_friendmessage(void (*function)(int, uint8_t *, uint16_t)) } +static void (*friend_namechange)(int, uint8_t *, uint16_t); +void m_callback_namechange(void (*function)(int, uint8_t *, uint16_t)) +{ + friend_namechange = function; +} + +static void (*friend_statuschange)(int, uint8_t *, uint16_t); +void m_callback_userstatus(void (*function)(int, uint8_t *, uint16_t)) +{ + friend_statuschange = function; +} + #define PORT 33445 //run this at startup void initMessenger() { new_keys(); + m_set_userstatus((uint8_t*)"Online", sizeof("Online")); initNetCrypto(); IP ip; ip.i = 0; @@ -321,7 +408,7 @@ static void doFriends() //printf("\n%u %u %u\n", friendip.ip.i, request, friendlist[i].friend_request_id); if(friendip.ip.i > 1 && request == -1) { - friendlist[i].friend_request_id = send_friendrequest(friendlist[i].client_id, + friendlist[i].friend_request_id = send_friendrequest(friendlist[i].client_id, friendip, friendlist[i].info, friendlist[i].info_size); friendlist[i].status = 2; } @@ -356,19 +443,37 @@ static void doFriends() friendlist[i].name_sent = 1; } } + if(friendlist[i].userstatus_sent == 0) + { + if(send_userstatus(i, self_userstatus, self_userstatus_len)) + { + friendlist[i].userstatus_sent = 1; + } + } len = read_cryptpacket(friendlist[i].crypt_connection_id, temp); if(len > 0) { - if(temp[0] == 48 && len == MAX_NAME_LENGTH + 1)//Username - { - memcpy(friendlist[i].name, temp + 1, MAX_NAME_LENGTH); - friendlist[i].name[MAX_NAME_LENGTH - 1] = 0;//make sure the NULL terminator is present. - } - else - if(temp[0] == 64)//Chat message - { - (*friend_message)(i, temp + 1, len - 1); - } + switch(temp[0]) { + case 48: { + if (len != MAX_NAME_LENGTH + 1) break; + friend_namechange(i, temp + 1, MAX_NAME_LENGTH); // todo: use the actual length + memcpy(friendlist[i].name, temp + 1, MAX_NAME_LENGTH); + friendlist[i].name[MAX_NAME_LENGTH - 1] = 0;//make sure the NULL terminator is present. + break; + } + case 64: { + (*friend_message)(i, temp + 1, len - 1); + break; + } + case 70: { + uint8_t *status = calloc(MIN(len - 1, MAX_USERSTATUS_LENGTH), 1); + memcpy(status, temp + 1, MIN(len - 1, MAX_USERSTATUS_LENGTH)); + friend_statuschange(i, status, MIN(len - 1, MAX_USERSTATUS_LENGTH)); + set_friend_userstatus(i, status, MIN(len - 1, MAX_USERSTATUS_LENGTH)); + free(status); + break; + } + } } else { @@ -410,7 +515,7 @@ static void doInbound() if(friend_id != -1) { crypto_kill(friendlist[friend_id].crypt_connection_id); - friendlist[friend_id].crypt_connection_id = + friendlist[friend_id].crypt_connection_id = accept_crypto_inbound(inconnection, public_key, secret_nonce, session_key); friendlist[friend_id].status = 3; @@ -520,7 +625,9 @@ int Messenger_load(uint8_t * data, uint32_t length) uint32_t i; for(i = 0; i < num; i++) { - setfriendname(m_addfriend_norequest(temp[i].client_id), temp[i].name); + int fnum = m_addfriend_norequest(temp[i].client_id); + setfriendname(fnum, temp[i].name); + set_friend_userstatus(fnum, temp[i].userstatus, temp[i].userstatus_length); } free(temp); return 0; diff --git a/core/Messenger.h b/core/Messenger.h index 0b8aa7aa..c89d0f52 100644 --- a/core/Messenger.h +++ b/core/Messenger.h @@ -1,7 +1,7 @@ /* Messenger.h -* +* * An implementation of a simple text chat only messenger on the tox network core. -* +* * NOTE: All the text in the messages must be encoded using UTF-8 Copyright (C) 2013 Tox project All Rights Reserved. @@ -24,12 +24,16 @@ */ -#ifndef MESSENGER_H -#define MESSENGER_H +#ifndef MESSENGER_H +#define MESSENGER_H #include "net_crypto.h" #include "DHT.h" +#define MAX_NAME_LENGTH 128 +#define MAX_USERSTATUS_LENGTH 128 +// don't assume MAX_USERSTATUS_LENGTH will stay at 128, it may be increased +// to an absurdly large number later //add a friend //set the data that will be sent along with friend request @@ -85,6 +89,20 @@ int setname(uint8_t * name, uint16_t length); //return -1 if failure int getname(int friendnumber, uint8_t * name); +// set our user status +// you are responsible for freeing status after +// returns 0 on success, -1 on failure +int m_set_userstatus(uint8_t *status, uint16_t length); + +// return the length of friendnumber's user status, +// including null +// pass it into malloc +int m_get_userstatus_size(int friendnumber); + +// copy friendnumber's userstatus into buf, truncating if size is over maxlen +// get the size you need to allocate from m_get_userstatus_size +int m_copy_userstatus(int friendnumber, uint8_t * buf, uint32_t maxlen); + //set the function that will be executed when a friend request is received. //function format is function(uint8_t * public_key, uint8_t * data, uint16_t length) void m_callback_friendrequest(void (*function)(uint8_t *, uint8_t *, uint16_t)); @@ -94,6 +112,15 @@ void m_callback_friendrequest(void (*function)(uint8_t *, uint8_t *, uint16_t)); //function format is: function(int friendnumber, uint8_t * message, uint32_t length) void m_callback_friendmessage(void (*function)(int, uint8_t *, uint16_t)); +// set the callback for name changes +// function(int friendnumber, uint8_t *newname, uint16_t length) +// you are not responsible for freeing newname +void m_callback_namechange(void (*function)(int, uint8_t *, uint16_t)); + +// set the callback for user status changes +// function(int friendnumber, uint8_t *newstatus, uint16_t length) +// you are not responsible for freeing newstatus +void m_callback_userstatus(void (*function)(int, uint8_t *, uint16_t)); //run this at startup void initMessenger(); diff --git a/docs/Messenger_Protocol.txt b/docs/Messenger_Protocol.txt index 377a6016..78f756ae 100644 --- a/docs/Messenger_Protocol.txt +++ b/docs/Messenger_Protocol.txt @@ -2,8 +2,8 @@ Protocol for messages, data, etc.. Streaming audio/video will not use this protocol as they can absorb some data loss. -The protocol itself will run on top of the encryption which means it should be -impossible for someone to know what type of data is being transmitted.(Well they +The protocol itself will run on top of the encryption which means it should be +impossible for someone to know what type of data is being transmitted.(Well they could just analyze how much data is being transmitted for a pretty good guess) Because it runs on the encryption which itself runs on our Lossless UDP protocol @@ -29,4 +29,4 @@ ids 0 to 16 are reserved. 64 Chat message 6? File transmission. - +70 Status change diff --git a/testing/nTox.c b/testing/nTox.c index d3f6e6a8..ac82d021 100644 --- a/testing/nTox.c +++ b/testing/nTox.c @@ -72,6 +72,30 @@ void line_eval(char lines[HISTORY][STRING_LENGTH], char *line) } int num = atoi(numstring); m_sendmessage(num, (uint8_t*) message, sizeof(message)); + } else if (line[1] == 'n') { + uint8_t name[MAX_NAME_LENGTH]; + int i = 0; + for (i=3; i %s", friendnumber, name, string); + free(name); + new_lines(msg); +} +void print_nickchange(int friendnumber, uint8_t *string, uint16_t length) { + char *name = malloc(MAX_NAME_LENGTH); + getname(friendnumber, (uint8_t*)name); char msg[100+length]; - sprintf(msg, "Message [%d]: %s", friendnumber, string); + sprintf(msg, "[%d] %s is now known as %s.", friendnumber, name, string); + free(name); + new_lines(msg); +} +void print_statuschange(int friendnumber, uint8_t *string, uint16_t length) { + char *name = malloc(MAX_NAME_LENGTH); + getname(friendnumber, (uint8_t*)name); + char msg[100+length+strlen(name)+1]; + sprintf(msg, "[%d] %s's status changed to %s.", friendnumber, name, string); + free(name); new_lines(msg); } int main(int argc, char *argv[]) @@ -173,6 +216,8 @@ int main(int argc, char *argv[]) initMessenger(); m_callback_friendrequest(print_request); m_callback_friendmessage(print_message); + m_callback_namechange(print_nickchange); + m_callback_userstatus(print_statuschange); char idstring0[200]; char idstring1[32][5]; char idstring2[32][5]; From eb262207434443f7a5e4485c6c87c9999bffcd53 Mon Sep 17 00:00:00 2001 From: Sebastian Stal Date: Thu, 18 Jul 2013 11:13:29 -0700 Subject: [PATCH 2/2] Fix a leak. --- core/Messenger.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/Messenger.c b/core/Messenger.c index a14be9d0..8e22f448 100644 --- a/core/Messenger.c +++ b/core/Messenger.c @@ -325,7 +325,7 @@ int m_copy_userstatus(int friendnumber, uint8_t * buf, uint32_t maxlen) { return -1; } - memset(buf, 0, 1); + memset(buf, 0, maxlen); memcpy(buf, friendlist[friendnumber].userstatus, MIN(maxlen, MAX_USERSTATUS_LENGTH) - 1); return 0; } @@ -335,7 +335,9 @@ static int send_userstatus(int friendnumber, uint8_t * status, uint16_t length) uint8_t *thepacket = malloc(length + 1); memcpy(thepacket + 1, status, length); thepacket[0] = 70; - return write_cryptpacket(friendlist[friendnumber].crypt_connection_id, thepacket, length + 1); + int written = write_cryptpacket(friendlist[friendnumber].crypt_connection_id, thepacket, length + 1); + free(thepacket); + return written; } static int set_friend_userstatus(int friendnumber, uint8_t * status, uint16_t length)