Beispiel #1
0
/* Try to send a friendrequest to peer with public_key
   data is the data in the request and length is the length.
   return -1 if failure.
   return  0 if it sent the friend request directly to the friend.
   return the number of peers it was routed through if it did not send it directly.*/
int send_friendrequest(uint8_t * public_key, uint8_t * data, uint32_t length)
{
    uint8_t packet[MAX_DATA_SIZE];
    int len = create_request(packet, public_key, data, length, 32); /* 32 is friend request packet id */

    if (len == -1)
        return -1;

    IP_Port ip_port = DHT_getfriendip(public_key);

    if (ip_port.ip.i == 1)
        return -1;

    if (ip_port.ip.i != 0) {
        if (sendpacket(ip_port, packet, len) != -1)
            return 0;
        return -1;
    }

    int num = route_tofriend(public_key, packet, len);

    if (num == 0)
        return -1;

    return num;
}
Beispiel #2
0
void print_friendlist()
{
    uint32_t i, j, k;
    IP_Port p_ip;
    printf("_________________FRIENDS__________________________________\n");
    for(k = 0; k < num_friends; k++) {
        printf("FRIEND %u\n", k);
        printf("ID: ");
        for(j = 0; j < 32; j++) {
            printf("%c", friends_list[k].client_id[j]);
        }
        p_ip = DHT_getfriendip(friends_list[k].client_id);
        printf("\nIP: %u.%u.%u.%u:%u",p_ip.ip.c[0],p_ip.ip.c[1],p_ip.ip.c[2],p_ip.ip.c[3],ntohs(p_ip.port));

        printf("\nCLIENTS IN LIST:\n\n");
        
        for(i = 0; i < 4; i++) {
            printf("ClientID: ");
            for(j = 0; j < 32; j++) {
                if(friends_list[k].client_list[i].client_id[j] < 16)
                    printf("0");
                printf("%hhX", friends_list[k].client_list[i].client_id[j]);
            }
            p_ip = friends_list[k].client_list[i].ip_port;
            printf("\nIP: %u.%u.%u.%u:%u",p_ip.ip.c[0],p_ip.ip.c[1],p_ip.ip.c[2],p_ip.ip.c[3],ntohs(p_ip.port));
            printf("\nTimestamp: %llu",(long long unsigned int) friends_list[k].client_list[i].timestamp);
            printf("\nLast pinged: %llu\n",(long long unsigned int) friends_list[k].client_list[i].last_pinged);
            p_ip = friends_list[k].client_list[i].ret_ip_port;
            printf("ret IP: %u.%u.%u.%u:%u\n",p_ip.ip.c[0],p_ip.ip.c[1],p_ip.ip.c[2],p_ip.ip.c[3],ntohs(p_ip.port));
            printf("Timestamp: %llu\n", (long long unsigned int)friends_list[k].client_list[i].ret_timestamp);
        }
    }
}
/* Try to send a friend request to peer with public_key.
 * data is the data in the request and length is the length.
 * return -1 if failure.
 * return  0 if it sent the friend request directly to the friend.
 * return the number of peers it was routed through if it did not send it directly.
 */
int send_friendrequest(DHT *dht, uint8_t *public_key, uint32_t nospam_num, uint8_t *data, uint32_t length)
{
    if (length + sizeof(nospam_num) > MAX_DATA_SIZE)
        return -1;

    uint8_t temp[MAX_DATA_SIZE];
    memcpy(temp, &nospam_num, sizeof(nospam_num));
    memcpy(temp + sizeof(nospam_num), data, length);
    uint8_t packet[MAX_DATA_SIZE];
    int len = create_request(dht->c->self_public_key, dht->c->self_secret_key, packet, public_key, temp,
                             length + sizeof(nospam_num),
                             CRYPTO_PACKET_FRIEND_REQ);

    if (len == -1)
        return -1;

    IP_Port ip_port = DHT_getfriendip(dht, public_key);

    if (ip_port.ip.uint32 == 1)
        return -1;

    if (ip_port.ip.uint32 != 0) {
        if (sendpacket(dht->c->lossless_udp->net->sock, ip_port, packet, len) != -1)
            return 0;

        return -1;
    }

    int num = route_tofriend(dht, public_key, packet, len);

    if (num == 0)
        return -1;

    return num;
}
Beispiel #4
0
/* 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(const 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, dht_public_key, ip_port);
}
/* 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)
{
    if ((uint32_t)friend_num >= onion_c->num_friends)
        return -1;

    if (onion_c->friends_list[friend_num].status == 0)
        return -1;

    if (!onion_c->friends_list[friend_num].is_fake_clientid)
        return -1;

    return DHT_getfriendip(onion_c->dht, onion_c->friends_list[friend_num].fake_client_id, ip_port);
}
Beispiel #6
0
/* Add nodes to the to_ping list.
 * All nodes in this list are pinged every TIME_TO_PING seconds
 * and are then removed from the list.
 * If the list is full the nodes farthest from our public_key are replaced.
 * The purpose of this list is to enable quick integration of new nodes into the
 * network while preventing amplification attacks.
 *
 *  return 0 if node was added.
 *  return -1 if node was not added.
 */
int add_to_ping(PING *ping, const uint8_t *public_key, IP_Port ip_port)
{
    if (!ip_isset(&ip_port.ip)) {
        return -1;
    }

    if (!node_addable_to_close_list(ping->dht, public_key, ip_port)) {
        return -1;
    }

    if (in_list(ping->dht->close_clientlist, LCLIENT_LIST, public_key, ip_port)) {
        return -1;
    }

    IP_Port temp;

    if (DHT_getfriendip(ping->dht, public_key, &temp) == 0) {
        send_ping_request(ping, ip_port, public_key);
        return -1;
    }

    unsigned int i;

    for (i = 0; i < MAX_TO_PING; ++i) {
        if (!ip_isset(&ping->to_ping[i].ip_port.ip)) {
            memcpy(ping->to_ping[i].public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE);
            ipport_copy(&ping->to_ping[i].ip_port, &ip_port);
            return 0;
        }

        if (public_key_cmp(ping->to_ping[i].public_key, public_key) == 0) {
            return -1;
        }
    }

    if (add_to_list(ping->to_ping, MAX_TO_PING, public_key, ip_port, ping->dht->self_public_key)) {
        return 0;
    }

    return -1;
}
int main(int argc, char *argv[])
{
    if (argc < 4) {
        printf("usage %s ip port filename(of file to send)\n", argv[0]);
        exit(0);
    }
    new_keys();
    printf("OUR ID: ");
    uint32_t i;
    for(i = 0; i < 32; i++) {
        if(self_public_key[i] < 16)
            printf("0");
        printf("%hhX",self_public_key[i]);
    }
    printf("\n");
    
    memcpy(self_client_id, self_public_key, 32);
    
    char temp_id[128];
    printf("Enter the client_id of the friend to connect to (32 bytes HEX format):\n");
    scanf("%s", temp_id);
    
    uint8_t friend_id[32];
    memcpy(friend_id, hex_string_to_bin(temp_id), 32);
    
    /* memcpy(self_client_id, "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", 32); */
    

    DHT_addfriend(friend_id);
    IP_Port friend_ip;
    int connection = -1;
    int inconnection = -1;
    
    uint8_t acceptedfriend_public_key[crypto_box_PUBLICKEYBYTES];
    int friendrequest = -1;
    uint8_t request_data[512];
    
    /* initialize networking
     * bind to ip 0.0.0.0:PORT */
    IP ip;
    ip.i = 0;
    init_networking(ip, PORT);
    initNetCrypto();
    
    perror("Initialization");
    IP_Port bootstrap_ip_port;
    bootstrap_ip_port.port = htons(atoi(argv[2]));
    bootstrap_ip_port.ip.i = inet_addr(argv[1]);
    DHT_bootstrap(bootstrap_ip_port);
    
    IP_Port ip_port;
    uint8_t data[MAX_UDP_PACKET_SIZE];
    uint32_t length;
    
    uint8_t buffer1[128];
    int read1 = 0;
    uint8_t buffer2[128];
    int read2 = 0;
    FILE *file1 = fopen(argv[3], "rb");
    if ( file1==NULL ){printf("Error opening file.\n");return 1;}
    FILE *file2 = fopen("received.txt", "wb");
    if ( file2==NULL ){return 1;}
    read1 = fread(buffer1, 1, 128, file1);
    
    while(1) {
        while(receivepacket(&ip_port, data, &length) != -1) {
            if(rand() % 3 != 1) { /* simulate packet loss */
                if(DHT_handlepacket(data, length, ip_port) && LosslessUDP_handlepacket(data, length, ip_port)) {
                    /* if packet is not recognized */
                    printf("Received unhandled packet with length: %u\n", length);
                } else {
                    printf("Received handled packet with length: %u\n", length);
                }
            }
        }
        friend_ip = DHT_getfriendip(friend_id);
        if(friend_ip.ip.i != 0) {
            if(connection == -1 && friendrequest == -1) {
                printf("Sending friend request to peer:");
                printip(friend_ip);
                friendrequest = send_friendrequest(friend_id, friend_ip,(uint8_t *) "Hello World", 12);
                /* connection = crypto_connect((uint8_t *)friend_id, friend_ip); */
                /* connection = new_connection(friend_ip); */
            }
            if(check_friendrequest(friendrequest) == 1) {
                printf("Started connecting to friend:");
                connection = crypto_connect(friend_id, friend_ip);
            }
        }
        if(inconnection == -1) {
            uint8_t secret_nonce[crypto_box_NONCEBYTES];
            uint8_t public_key[crypto_box_PUBLICKEYBYTES];
            uint8_t session_key[crypto_box_PUBLICKEYBYTES];
            inconnection = crypto_inbound(public_key, secret_nonce, session_key);
            inconnection = accept_crypto_inbound(inconnection, acceptedfriend_public_key, secret_nonce, session_key);
            /* inconnection = incoming_connection(); */
            if(inconnection != -1) {
                printf("Someone connected to us:\n");
               /* printip(connection_ip(inconnection)); */
            }
        }
        if(handle_friendrequest(acceptedfriend_public_key, request_data) > 1) {
            printf("RECIEVED FRIEND REQUEST: %s\n", request_data);
        }

        /* if someone connected to us write what he sends to a file
         * also send him our file. */
        if(inconnection != -1) {
            if(write_cryptpacket(inconnection, buffer1, read1)) {
                printf("Wrote data1.\n");
                read1 = fread(buffer1, 1, 128, file1);
            }
            read2 = read_cryptpacket(inconnection, buffer2);
            if(read2 != 0) {
                printf("Received data1.\n");
                if(!fwrite(buffer2, read2, 1, file2)) {
                        printf("file write error1\n");
                }
                if(read2 < 128) {
                    printf("Closed file1 %u\n", read2);
                    fclose(file2);
                }
            }
            /* if buffer is empty and the connection timed out. */
            else if(is_cryptoconnected(inconnection) == 4) {
                crypto_kill(inconnection);
            }
        }
        /* if we are connected to a friend send him data from the file.
         * also put what he sends us in a file. */
        if(is_cryptoconnected(connection) >= 3)  {
            if(write_cryptpacket(0, buffer1, read1)) {
                printf("Wrote data2.\n");
                read1 = fread(buffer1, 1, 128, file1);
            }
            read2 = read_cryptpacket(0, buffer2);
            if(read2 != 0) {
                printf("Received data2.\n");
                if(!fwrite(buffer2, read2, 1, file2)) {
                        printf("file write error2\n");
                }
                if(read2 < 128) {
                    printf("Closed file2 %u\n", read2);
                    fclose(file2);
                }
            }
            /* if buffer is empty and the connection timed out. */
            else if(is_cryptoconnected(connection) == 4) {
                crypto_kill(connection);
            }
        }
        doDHT();
        doLossless_UDP();
        doNetCrypto();
        /*print_clientlist();
         *print_friendlist();
         *c_sleep(300); */
        c_sleep(1);
    }
    
    shutdown_networking();
    return 0;   
}
//TODO: make this function not suck.
static void doFriends(void)
{
    /* TODO: add incoming connections and some other stuff. */
    uint32_t i;
    int len;
    uint8_t temp[MAX_DATA_SIZE];
    for (i = 0; i < numfriends; ++i) {
        if (friendlist[i].status == FRIEND_ADDED) {
            int fr = send_friendrequest(friendlist[i].client_id, friendlist[i].info, friendlist[i].info_size);
            if (fr == 0) /* TODO: This needs to be fixed so that it sends the friend requests a couple of times in case of packet loss */
                set_friend_status(i, FRIEND_REQUESTED);
            else if (fr > 0)
                set_friend_status(i, FRIEND_REQUESTED);
        }
        if (friendlist[i].status == FRIEND_REQUESTED || friendlist[i].status == FRIEND_CONFIRMED) { /* friend is not online */
            if (friendlist[i].status == FRIEND_REQUESTED) {
                if (friendlist[i].friend_request_id + 10 < unix_time()) { /*I know this is hackish but it should work.*/
                    send_friendrequest(friendlist[i].client_id, friendlist[i].info, friendlist[i].info_size);
                    friendlist[i].friend_request_id = unix_time();
                }
            }
            IP_Port friendip = DHT_getfriendip(friendlist[i].client_id);
            switch (is_cryptoconnected(friendlist[i].crypt_connection_id)) {
            case 0:
                if (friendip.ip.i > 1)
                    friendlist[i].crypt_connection_id = crypto_connect(friendlist[i].client_id, friendip);
                break;
            case 3: /*  Connection is established */
                set_friend_status(i, FRIEND_ONLINE);
                friendlist[i].name_sent = 0;
                friendlist[i].userstatus_sent = 0;
                friendlist[i].statusmessage_sent = 0;
                break;
            case 4:
                crypto_kill(friendlist[i].crypt_connection_id);
                friendlist[i].crypt_connection_id = -1;
                break;
            default:
                break;
            }
        }
        while (friendlist[i].status == FRIEND_ONLINE) { /* friend is online */
            if (friendlist[i].name_sent == 0) {
                if (m_sendname(i, self_name, self_name_length))
                    friendlist[i].name_sent = 1;
            }
            if (friendlist[i].statusmessage_sent == 0) {
                if (send_statusmessage(i, self_statusmessage, self_statusmessage_length))
                    friendlist[i].statusmessage_sent = 1;
            }
            if (friendlist[i].userstatus_sent == 0) {
                if (send_userstatus(i, self_userstatus))
                    friendlist[i].userstatus_sent = 1;
            }
            len = read_cryptpacket(friendlist[i].crypt_connection_id, temp);
            uint8_t packet_id = temp[0];
            uint8_t* data = temp + 1;
            int data_length = len - 1;
            if (len > 0) {
                switch (packet_id) {
                case PACKET_ID_NICKNAME: {
                    if (data_length >= MAX_NAME_LENGTH || data_length == 0)
                        break;
                    if(friend_namechange_isset)
                        friend_namechange(i, data, data_length);
                    memcpy(friendlist[i].name, data, data_length);
                    friendlist[i].name[data_length - 1] = 0; /* make sure the NULL terminator is present. */
                    break;
                }
                case PACKET_ID_STATUSMESSAGE: {
                    if (data_length == 0)
                        break;
                    uint8_t *status = calloc(MIN(data_length, MAX_STATUSMESSAGE_LENGTH), 1);
                    memcpy(status, data, MIN(data_length, MAX_STATUSMESSAGE_LENGTH));
                    if (friend_statusmessagechange_isset)
                        friend_statusmessagechange(i, status, MIN(data_length, MAX_STATUSMESSAGE_LENGTH));
                    set_friend_statusmessage(i, status, MIN(data_length, MAX_STATUSMESSAGE_LENGTH));
                    free(status);
                    break;
                }
                case PACKET_ID_USERSTATUS: {
                    if (data_length != 1)
                        break;
                    USERSTATUS status = data[0];
                    if (friend_userstatuschange_isset)
                        friend_userstatuschange(i, status);
                    set_friend_userstatus(i, status);
                    break;
                }
                case PACKET_ID_MESSAGE: {
                    uint8_t *message_id = data;
                    uint8_t message_id_length = 4;
                    uint8_t *message = data + message_id_length;
                    uint16_t message_length = data_length - message_id_length;
                    if (friendlist[i].receives_read_receipts) {
                        write_cryptpacket_id(i, PACKET_ID_RECEIPT, message_id, message_id_length);
                    }
                    if (friend_message_isset)
                        (*friend_message)(i, message, message_length);
                    break;
                }
                case PACKET_ID_ACTION: {
                    if (friend_action_isset)
                        (*friend_action)(i, data, data_length);
                    break;
                }
                case PACKET_ID_RECEIPT: {
                    uint32_t msgid;
                    if (data_length < sizeof(msgid))
                        break;
                    memcpy(&msgid, data, sizeof(msgid));
                    msgid = ntohl(msgid);
                    if (read_receipt_isset)
                        (*read_receipt)(i, msgid);
                    break;
                }
                }
            } else {
                if (is_cryptoconnected(friendlist[i].crypt_connection_id) == 4) { /* if the connection timed out, kill it */
                    crypto_kill(friendlist[i].crypt_connection_id);
                    friendlist[i].crypt_connection_id = -1;
                    set_friend_status(i, FRIEND_CONFIRMED);
                }
                break;
            }
        }
    }
}
Beispiel #9
0
//TODO: make this function not suck.
static void doFriends()
{
    /* TODO: add incoming connections and some other stuff. */
    uint32_t i;
    int len;
    uint8_t temp[MAX_DATA_SIZE];
    for (i = 0; i < numfriends; ++i) {
        if (friendlist[i].status == 1) {
            int fr = send_friendrequest(friendlist[i].client_id, friendlist[i].info, friendlist[i].info_size);
            if (fr == 0) /* TODO: This needs to be fixed so that it sends the friend requests a couple of times in case of packet loss */
                friendlist[i].status = 2;
            else if (fr > 0)
                friendlist[i].status = 2;
        }
        if (friendlist[i].status == 2 || friendlist[i].status == 3) { /* friend is not online */
            if (friendlist[i].status == 2) {
                if (friendlist[i].friend_request_id + 10 < unix_time()) { /*I know this is hackish but it should work.*/
                    send_friendrequest(friendlist[i].client_id, friendlist[i].info, friendlist[i].info_size);
                    friendlist[i].friend_request_id = unix_time();
                }
            }
            IP_Port friendip = DHT_getfriendip(friendlist[i].client_id);
            switch (is_cryptoconnected(friendlist[i].crypt_connection_id)) {
            case 0:
                if (friendip.ip.i > 1)
                    friendlist[i].crypt_connection_id = crypto_connect(friendlist[i].client_id, friendip);
                break;
            case 3: /*  Connection is established */
                friendlist[i].status = 4;
                break;
            case 4:
                crypto_kill(friendlist[i].crypt_connection_id);
                friendlist[i].crypt_connection_id = -1;
                break;
            default:
                break;
            }
        }
        while (friendlist[i].status == 4) { /* friend is online */
            if (friendlist[i].name_sent == 0) {
                if (m_sendname(i, self_name, self_name_length))
                    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) {
                switch (temp[0]) {
                case PACKET_ID_NICKNAME: {
                    if (len >= MAX_NAME_LENGTH + 1 || len == 1)
                        break;
                    if(friend_namechange_isset)
                        friend_namechange(i, temp + 1, len - 1);
                    memcpy(friendlist[i].name, temp + 1, len - 1);
                    friendlist[i].name[len - 2] = 0; /* make sure the NULL terminator is present. */
                    break;
                }
                case PACKET_ID_USERSTATUS: {
                    uint8_t *status = calloc(MIN(len - 1, MAX_USERSTATUS_LENGTH), 1);
                    memcpy(status, temp + 1, MIN(len - 1, MAX_USERSTATUS_LENGTH));
                    if (friend_statuschange_isset)
                        friend_statuschange(i, status, MIN(len - 1, MAX_USERSTATUS_LENGTH));
                    set_friend_userstatus(i, status, MIN(len - 1, MAX_USERSTATUS_LENGTH));
                    free(status);
                    break;
                }
                case PACKET_ID_MESSAGE: {
                    if (friend_message_isset)
                        (*friend_message)(i, temp + 1, len - 1);
                    break;
                }
                }
            } else {
                if (is_cryptoconnected(friendlist[i].crypt_connection_id) == 4) { /* if the connection timed out, kill it */
                    crypto_kill(friendlist[i].crypt_connection_id);
                    friendlist[i].crypt_connection_id = -1;
                    friendlist[i].status = 3;
                }
                break;
            }
        }
    }
}
Beispiel #10
0
//TODO: make this function not suck.
void doFriends(Messenger *m)
{
    /* TODO: add incoming connections and some other stuff. */
    uint32_t i;
    int len;
    uint8_t temp[MAX_DATA_SIZE];
    uint64_t temp_time = unix_time();

    for (i = 0; i < m->numfriends; ++i) {
        if (m->friendlist[i].status == FRIEND_ADDED) {
            int fr = send_friendrequest(m->friendlist[i].client_id, m->friendlist[i].friendrequest_nospam, m->friendlist[i].info,
                                        m->friendlist[i].info_size);

            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.*/
                if (m->friendlist[i].friendrequest_lastsent + m->friendlist[i].friendrequest_timeout < temp_time) {
                    set_friend_status(m, i, FRIEND_ADDED);
                    /* Double the default timeout everytime if friendrequest is assumed to have been
                       sent unsuccessfully. */
                    m->friendlist[i].friendrequest_timeout *= 2;
                }
            }

            IP_Port friendip = DHT_getfriendip(m->friendlist[i].client_id);

            switch (is_cryptoconnected(m->friendlist[i].crypt_connection_id)) {
                case 0:
                    if (friendip.ip.i > 1)
                        m->friendlist[i].crypt_connection_id = crypto_connect(m->friendlist[i].client_id, friendip);

                    break;

                case 3: /*  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;

                case 4:
                    crypto_kill(m->friendlist[i].crypt_connection_id);
                    m->friendlist[i].crypt_connection_id = -1;
                    break;

                default:
                    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;
            }

            if (m->friendlist[i].statusmessage_sent == 0) {
                if (send_statusmessage(m, i, m->statusmessage, m->statusmessage_length))
                    m->friendlist[i].statusmessage_sent = 1;
            }

            if (m->friendlist[i].userstatus_sent == 0) {
                if (send_userstatus(m, i, m->userstatus))
                    m->friendlist[i].userstatus_sent = 1;
            }

            if (m->friendlist[i].ping_lastsent + FRIEND_PING_INTERVAL < temp_time) {
                send_ping(m, i);
            }

            len = read_cryptpacket(m->friendlist[i].crypt_connection_id, temp);
            uint8_t packet_id = temp[0];
            uint8_t *data = temp + 1;
            int data_length = len - 1;

            if (len > 0) {
                switch (packet_id) {
                    case PACKET_ID_PING: {
                        m->friendlist[i].ping_lastrecv = temp_time;
                        break;
                    }

                    case PACKET_ID_NICKNAME: {
                        if (data_length >= MAX_NAME_LENGTH || data_length == 0)
                            break;

                        if (m->friend_namechange)
                            m->friend_namechange(m, i, data, data_length, m->friend_namechange_userdata);

                        memcpy(m->friendlist[i].name, data, data_length);
                        m->friendlist[i].name[data_length - 1] = 0; /* make sure the NULL terminator is present. */
                        break;
                    }

                    case PACKET_ID_STATUSMESSAGE: {
                        if (data_length == 0)
                            break;

                        uint8_t *status = calloc(MIN(data_length, MAX_STATUSMESSAGE_LENGTH), 1);
                        memcpy(status, data, MIN(data_length, MAX_STATUSMESSAGE_LENGTH));

                        if (m->friend_statusmessagechange)
                            m->friend_statusmessagechange(m, i, status, MIN(data_length, MAX_STATUSMESSAGE_LENGTH),
                                                          m->friend_statuschange_userdata);

                        set_friend_statusmessage(m, i, status, MIN(data_length, MAX_STATUSMESSAGE_LENGTH));
                        free(status);
                        break;
                    }

                    case PACKET_ID_USERSTATUS: {
                        if (data_length != 1)
                            break;

                        USERSTATUS status = data[0];

                        if (m->friend_userstatuschange)
                            m->friend_userstatuschange(m, i, status, m->friend_userstatuschange_userdata);

                        set_friend_userstatus(m, i, status);
                        break;
                    }

                    case PACKET_ID_MESSAGE: {
                        uint8_t *message_id = data;
                        uint8_t message_id_length = 4;
                        uint8_t *message = data + message_id_length;
                        uint16_t message_length = data_length - message_id_length;

                        if (m->friendlist[i].receives_read_receipts) {
                            write_cryptpacket_id(m, i, PACKET_ID_RECEIPT, message_id, message_id_length);
                        }

                        if (m->friend_message)
                            (*m->friend_message)(m, i, message, message_length, m->friend_message_userdata);

                        break;
                    }

                    case PACKET_ID_ACTION: {
                        if (m->friend_action)
                            (*m->friend_action)(m, i, data, data_length, m->friend_action_userdata);

                        break;
                    }

                    case PACKET_ID_RECEIPT: {
                        uint32_t msgid;

                        if (data_length < sizeof(msgid))
                            break;

                        memcpy(&msgid, data, sizeof(msgid));
                        msgid = ntohl(msgid);

                        if (m->read_receipt)
                            (*m->read_receipt)(m, i, msgid, m->read_receipt_userdata);

                        break;
                    }
                }
            } else {
                if (is_cryptoconnected(m->friendlist[i].crypt_connection_id) == 4) { /* if the connection timed out, kill it */
                    crypto_kill(m->friendlist[i].crypt_connection_id);
                    m->friendlist[i].crypt_connection_id = -1;
                    set_friend_status(m, i, FRIEND_CONFIRMED);
                }

                break;
            }

            if (m->friendlist[i].ping_lastrecv + FRIEND_CONNECTION_TIMEOUT < temp_time) {
                /* if we stopped recieving ping packets kill it */
                crypto_kill(m->friendlist[i].crypt_connection_id);
                m->friendlist[i].crypt_connection_id = -1;
                set_friend_status(m, i, FRIEND_CONFIRMED);
            }
        }
    }
}