Exemple #1
0
bool build_and_send_rst_packet(nabto_connect* con, uint16_t tag, struct nabto_win_info* win)
{
    struct nabto_win_info rst;
    uint16_t winLength;
    uint16_t encodeLength;
    uint8_t*       ptr;
    uint8_t*       buf   = nabtoCommunicationBuffer;
    memset(&rst, 0, sizeof( struct nabto_win_info));
    
    nabto_stream_make_rst_response_window(win, &rst);
    winLength = nabto_stream_window_payload_length(&rst);

    ptr = insert_data_header(buf, con->spnsi, con->nsico, tag);
    ptr = insert_payload(ptr, NP_PAYLOAD_TYPE_WINDOW, 0, winLength);

    if (nabto_stream_encode_window(&rst, ptr, &encodeLength)) {
        ptr += encodeLength;
    } else {
        return false;
    }

    ptr = insert_payload(ptr, NP_PAYLOAD_TYPE_CRYPTO, 0, 0);
    
    return send_and_encrypt_packet_con(con, 0, 0, ptr);
}
bool build_and_send_packet(struct nabto_stream_s* stream, uint8_t type, uint32_t seq, const uint8_t* winInfoData, size_t winInfoSize, uint8_t* data, uint16_t size, struct nabto_stream_sack_data* sackData)
{
    enum { l_win = NP_PAYLOAD_WINDOW_SYN_BYTELENGTH - NP_PAYLOAD_WINDOW_BYTELENGTH };
    uint8_t*       ptr;
    nabto_connect* con           = stream->connection;
    uint8_t*       buf           = nabtoCommunicationBuffer;
    struct nabto_stream_tcb* tcb = &stream->u.tcb;
    uint32_t       ackToSend     = unabto_stream_ack_number_to_send(tcb);
    uint16_t       recvWinSize   = unabto_stream_advertised_window_size(tcb);

    if (con == NULL) {
        return false;
    }
    
    nabtoSetFutureStamp(&tcb->ackStamp, 2*tcb->cfg.timeoutMsec);

    ptr = insert_data_header(buf, con->spnsi, con->nsico, stream->streamTag);
    ptr = insert_payload(ptr, NP_PAYLOAD_TYPE_WINDOW, 0, l_win + winInfoSize + (type == NP_PAYLOAD_WINDOW_FLAG_ACK ? 2 : 0));
    WRITE_FORWARD_U8 (ptr, type);
    WRITE_FORWARD_U8 (ptr, NP_STREAM_VERSION);
    WRITE_FORWARD_U16(ptr, stream->idCP);
    WRITE_FORWARD_U16(ptr, stream->idSP);
    WRITE_FORWARD_U32(ptr, seq);
    WRITE_FORWARD_U32(ptr, ackToSend);
    if (type == NP_PAYLOAD_WINDOW_FLAG_ACK) {
        WRITE_FORWARD_U16(ptr, recvWinSize);
    }

    if (winInfoSize) {
        memcpy(ptr, (const void*) winInfoData, winInfoSize); ptr += winInfoSize;
    }
    
    if (sackData && sackData->nPairs > 0) {
        uint8_t i;
        ptr = insert_payload(ptr, NP_PAYLOAD_TYPE_SACK, 0, 8 * sackData->nPairs);
        for (i = 0; i < sackData->nPairs; i++) {
            WRITE_FORWARD_U32(ptr, sackData->pairs[i].start);
            WRITE_FORWARD_U32(ptr, sackData->pairs[i].end);
        }
    }


    ptr = insert_payload(ptr, NP_PAYLOAD_TYPE_CRYPTO, 0, 0);

    if (send_and_encrypt_packet_con(con, data, size, ptr)) {
        tcb->ackSent = ackToSend;
        tcb->lastSentAdvertisedWindow = recvWinSize;
        stream->stats.sentPackets++;
        return true;
    } else {
        return false;
    }
}
uint8_t* insert_connection_stats_payload(uint8_t* ptr, uint8_t* end, nabto_connect* con) {
    nabto_stamp_t now;
    uint32_t connectionAge;

    UNABTO_ASSERT(ptr <= end);
    if (end-ptr < NP_PAYLOAD_CONNECTION_STATS_BYTELENGTH) {
        return NULL;
    }

    ptr = insert_payload(ptr, NP_PAYLOAD_TYPE_CONNECTION_STATS, 0, 21);
    
    WRITE_FORWARD_U8(ptr, NP_PAYLOAD_CONNECTION_STATS_VERSION);
    
    now = nabtoGetStamp();
    connectionAge = nabtoStampDiff2ms(nabtoStampDiff(&now, &con->stats.connectionStart));

    WRITE_FORWARD_U32(ptr, connectionAge);

    WRITE_FORWARD_U32(ptr, con->stats.packetsReceived);
    WRITE_FORWARD_U32(ptr, con->stats.packetsSent);
    WRITE_FORWARD_U32(ptr, con->stats.bytesReceived);
    WRITE_FORWARD_U32(ptr, con->stats.bytesSent);

    return ptr;
}
bool build_handshake_packet(nabto_connect* con, uint8_t* buffer, size_t bufferLength, size_t* packetLength) {
    uint8_t* packetPtr;
    
    /*
     * type,   1 bytes
     * flags,  1 bytes
     * nsi cp, 4 bytes
     * nsi sp, 4 bytes
     * nsi co, 4 bytes
     * id, 20 bytes
     */
    size_t nonceLength = 38;
    uint8_t nonce[38];
    uint8_t* noncePtr = nonce;
    
    packetPtr = insert_header(buffer, con->cpnsi, con->spnsi, NP_PACKET_HDR_TYPE_GW_CONN_U, false, 0, 0, con->consi);

    //NOTE: These type and flags must match the connection attributes set
    //in the unabto_tcp_fallback_connect_thread when a connection is
    //established.
    WRITE_U8(noncePtr, NP_GW_CONN_U_TYPE_TCP); noncePtr+=1;
    WRITE_U8(noncePtr, NP_GW_CONN_U_FLAG_RELIABLE); noncePtr+=1;
    WRITE_U32(noncePtr, con->cpnsi); noncePtr+=4;
    WRITE_U32(noncePtr, con->spnsi); noncePtr+=4;
    memcpy(noncePtr, con->consi, 8); noncePtr+=8;
    memcpy(noncePtr, con->gatewayId, 20);

    packetPtr = insert_payload(packetPtr, NP_PAYLOAD_TYPE_NONCE, nonce, nonceLength);
    
    *packetLength = packetPtr - buffer;

    insert_length(buffer, *packetLength);
    return true;
}
/**
 * Build U_CONNECT response to GSP
 * @param buf                the destination buffer
 * @param seq                the sequence number
 * @param notif              the result notification
 * @param nsi                the nsi value of the connection
 * @param cpnsi              the nsi of the clientpeer to put into the packet.
 * @param spnsi              the nsi of the serverpeer to put into the packet.
 * @param isLocalConnectRsp  true if a capabilities packet 
 * @return                   the size of the response
 */
static size_t mk_gsp_connect_rsp(uint8_t* buf, uint16_t seq, uint32_t notif, uint32_t nsi, uint32_t cpnsi, uint32_t spnsi, bool isLocalConnectRsp)
{
    uint8_t* ptr = insert_header(buf, cpnsi, spnsi, U_CONNECT, true, seq, 0, 0);
    ptr = insert_payload(ptr, NP_PAYLOAD_TYPE_NOTIFY, 0, 8);
    WRITE_U32(ptr, notif); ptr += 4;
    WRITE_U32(ptr, nsi);   ptr += 4;
    
    if (isLocalConnectRsp) {
        ptr = insert_capabilities(ptr, 1 /*unenc*/);
    }

    insert_length(buf, ptr - buf);
    return ptr - buf;
}
static void send_rendezvous_socket(nabto_socket_t socket, nabto_connect* con, uint16_t seq, nabto_endpoint* dest, nabto_endpoint *myAddress)
{
    uint8_t* ptr;
    uint8_t* buf = nabtoCommunicationBuffer;

    ptr = insert_header(buf, 0, con->spnsi, U_CONNECT, false, seq, 0, 0);
    ptr = insert_payload(ptr, NP_PAYLOAD_TYPE_EP, 0, 6);
    WRITE_U32(ptr, dest->addr); ptr += 4;
    WRITE_U16(ptr, dest->port); ptr += 2;
    if (seq > 0) {
        if (!myAddress) {
            NABTO_LOG_ERROR(("Send rendezvous called with an invalid address"));
            return;
        } else {
            ptr = insert_payload(ptr, NP_PAYLOAD_TYPE_EP, 0, 6);
            WRITE_U32(ptr, myAddress->addr); ptr += 4;
            WRITE_U16(ptr, myAddress->port); ptr += 2;
        }
    }
    {
        size_t len = ptr - buf;

        insert_length(buf, len);

        if (seq) {
            NABTO_LOG_DEBUG((PRInsi " RENDEZVOUS Send to " PRIep ": seq=%" PRIu16 "  " PRIep, MAKE_NSI_PRINTABLE(0, con->spnsi, 0), MAKE_EP_PRINTABLE(*dest), seq, MAKE_EP_PRINTABLE(*myAddress)));
        } else {
            NABTO_LOG_DEBUG((PRInsi " RENDEZVOUS Send to " PRIep ": seq=0", MAKE_NSI_PRINTABLE(0, con->spnsi, 0), MAKE_EP_PRINTABLE(*dest)));
        }
        if (dest->addr != 0 && dest->port != 0) {
            nabto_write(socket, buf, len, dest->addr, dest->port);
        } else {
            NABTO_LOG_TRACE(("invalid rendezvous packet thrown away"));
        }
    }
}
uint8_t* insert_rendezvous_stats_payload(uint8_t* ptr, uint8_t* end, nabto_connect* con) {
    UNABTO_ASSERT(ptr <= end);
    if (end-ptr < NP_PAYLOAD_RENDEZVOUS_STATS_BYTELENGTH) {
        return NULL;
    }
    ptr = insert_payload(ptr, NP_PAYLOAD_TYPE_RENDEZVOUS_STATS, 0, 7);
    
    WRITE_FORWARD_U8(ptr, NP_PAYLOAD_RENDEZVOUS_STATS_VERSION);
    WRITE_FORWARD_U8(ptr, con->clientNatType);
    WRITE_FORWARD_U8(ptr, nmc.context.natType);
    WRITE_FORWARD_U16(ptr, con->rendezvousConnectState.portsOpened);
    WRITE_FORWARD_U16(ptr, con->rendezvousConnectState.socketsOpened);

    return ptr;
}
uint8_t* insert_cp_id_payload(uint8_t* ptr, uint8_t* end, nabto_connect* con) {
    size_t cpIdLength = strlen(con->clientId);

    UNABTO_ASSERT(ptr <= end);
    if ((size_t)(end - ptr) < NP_PAYLOAD_CP_ID_BYTELENGTH + cpIdLength) {
        return NULL;
    }

    ptr = insert_payload(ptr, NP_PAYLOAD_TYPE_CP_ID, 0, 1+cpIdLength);

    WRITE_FORWARD_U8(ptr, NP_PAYLOAD_CP_ID_TYPE_MAIL);
    memcpy(ptr, (const void*) con->clientId, cpIdLength);
    
    ptr += cpIdLength;

    return ptr;
}
uint8_t* insert_connect_stats_payload(uint8_t* ptr, uint8_t* end, nabto_connect* con) {
    uint8_t connectionType;

    UNABTO_ASSERT(ptr <= end);
    if (end-ptr < NP_PAYLOAD_CONNECT_STATS_BYTELENGTH) {
        return NULL;
    }

    ptr = insert_payload(ptr, NP_PAYLOAD_TYPE_CONNECT_STATS, 0, 2);

    switch (get_connection_type(con)) {
    case NCT_LOCAL:              connectionType = NP_PAYLOAD_CONNECT_STATS_CONNECTION_TYPE_LOCAL; break;
    case NCT_CONNECTING:         connectionType = NP_PAYLOAD_CONNECT_STATS_CONNECTION_TYPE_CONNECTING; break;
    case NCT_REMOTE_RELAY:       connectionType = NP_PAYLOAD_CONNECT_STATS_CONNECTION_TYPE_UDP_RELAY; break;
    case NCT_REMOTE_RELAY_MICRO: connectionType = NP_PAYLOAD_CONNECT_STATS_CONNECTION_TYPE_TCP_RELAY; break;
    case NCT_REMOTE_P2P:         connectionType = NP_PAYLOAD_CONNECT_STATS_CONNECTION_TYPE_P2P; break;
    }

    WRITE_FORWARD_U8(ptr, NP_PAYLOAD_CONNECT_STATS_VERSION);
    WRITE_FORWARD_U8(ptr, connectionType);

    return ptr;
}