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