bool possible_inverse (modification m1, modification m2) { if (root (m1) != root (m2)) return false; switch (m1->k) { case MOD_ASSIGN: return m2->k == MOD_ASSIGN; case MOD_INSERT: return m2->k == MOD_REMOVE && argument (m2) == insert_length (m1->t); case MOD_REMOVE: return m2->k == MOD_INSERT && insert_length (m2->t) == argument (m1); case MOD_SPLIT: return m2->k == MOD_JOIN && index (m2) == index (m1); case MOD_JOIN: return m2->k == MOD_SPLIT && index (m2) == index (m1); case MOD_ASSIGN_NODE: return m2->k == MOD_ASSIGN_NODE; case MOD_INSERT_NODE: return m2->k == MOD_REMOVE_NODE && index (m2) == argument (m1); case MOD_REMOVE_NODE: return m2->k == MOD_INSERT_NODE && argument (m2) == index (m1); case MOD_SET_CURSOR: return m1 == m2; default: FAILED ("invalid situation"); return false; } }
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; }
void send_debug_packet_response(nabto_packet_header* header, uint32_t notification) { uint8_t* buf = nabtoCommunicationBuffer; uint8_t* ptr = nabtoCommunicationBuffer; uint8_t* end = nabtoCommunicationBuffer+nabtoCommunicationBufferSize; ptr = insert_header(ptr, header->nsi_cp, header->nsi_sp, U_DEBUG, true, header->seq, 0, NULL); if (ptr == NULL) { NABTO_LOG_ERROR(("Could not insert debug packet header")); return; } ptr = insert_notify_payload(ptr, end, NP_PAYLOAD_NOTIFY_DEBUG_OK); if (ptr == NULL) { NABTO_LOG_ERROR(("Could not insert notify payload")); return; } { uint16_t length = ptr - buf; insert_length(buf, length); send_to_basestation(buf, length, &nmc.context.gsp); } }
void send_connection_statistics(nabto_connect* con, uint8_t event) { size_t length; uint8_t* ptr = insert_header(nabtoCommunicationBuffer, 0, con->spnsi, NP_PACKET_HDR_TYPE_STATS, false, 0, 0, 0); uint8_t* end = nabtoCommunicationBuffer + nabtoCommunicationBufferSize; ptr = insert_stats_payload(ptr, end, event); if (ptr == NULL) { return; } ptr = insert_version_payload(ptr, end); if (ptr == NULL) { return; } #if NABTO_ENABLE_CLIENT_ID ptr = insert_cp_id_payload(ptr, end, con); if (ptr == NULL) { return; } #endif ptr = insert_sp_id_payload(ptr, end); if (ptr == NULL) { return; } ptr = insert_ipx_payload(ptr, end); if (ptr == NULL) { return; } ptr = insert_connect_stats_payload(ptr, end, con); if (ptr == NULL) { return; } if (!con->noRendezvous) { ptr = insert_rendezvous_stats_payload(ptr, end, con); if (ptr == NULL) { return; } } ptr = insert_connection_stats_payload(ptr, end, con); if (ptr == NULL) { return; } length = ptr - nabtoCommunicationBuffer; insert_length(nabtoCommunicationBuffer, length); send_to_basestation(nabtoCommunicationBuffer, length, &nmc.context.gsp); }
modification invert (modification m, tree t) { ASSERT (is_applicable (t, m), "modification not applicable"); path rp= root (m); switch (m->k) { case MOD_ASSIGN: return mod_assign (rp, copy (subtree (t, rp))); case MOD_INSERT: return mod_remove (rp, index (m), insert_length (m->t)); case MOD_REMOVE: { int i= index (m); int n= argument (m); return mod_insert (rp, i, copy (insert_range (subtree (t, rp), i, n))); } case MOD_SPLIT: return mod_join (rp, index (m)); case MOD_JOIN: { int i= index (m); return mod_split (rp, i, insert_length (subtree (t, rp * i))); } case MOD_ASSIGN_NODE: return mod_assign_node (rp, L (subtree (t, rp))); case MOD_INSERT_NODE: return mod_remove_node (rp, argument (m)); case MOD_REMOVE_NODE: { tree u= subtree (t, rp); int i= index (m); return mod_insert_node (rp, i, copy (u (0, i) * u (i+1, N(u)))); } case MOD_SET_CURSOR: return m; default: FAILED ("unexpected situation"); } }
/** * 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 bool swap1 (modification& m1, modification& m2, int i, int d) { modification r1= dup (m2); modification r2= dup (m1); if (m2->p->item >= i) if (m2->p->item != i || !is_nil (root (m2)) || m2->k != MOD_INSERT) r1->p->item -= d; if (is_nil (root (m2))) switch (m2->k) { case MOD_INSERT: { int b2= m2->p->item; int e2= b2 + insert_length (m2->t); if (b2 <= i) r2->p->item += (e2-b2); break; } case MOD_REMOVE: { int b2= m2->p->item; int e2= b2 + m2->p->next->item; if (b2 <= i && i < e2) if (b2 != i || m1->k != MOD_REMOVE) return false; if (b2 < i) r2->p->item -= (e2-b2); break; } case MOD_SPLIT: if (m2->p->item < i) r2->p->item++; break; case MOD_JOIN: if (m2->p->item == i-1) return false; if (m2->p->item < i) r2->p->item--; break; case MOD_INSERT_NODE: { modification aux= m2; m2= modification (m1->k, path (m2->p->item, m1->p), m1->t); m1= aux; return true; } case MOD_REMOVE_NODE: return false; case MOD_SET_CURSOR: return false; } m1= r1; m2= r2; return true; }
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")); } } }
void send_connection_ended_statistics(nabto_connect* con) { size_t length; uint8_t* ptr = insert_header(nabtoCommunicationBuffer, 0, con->spnsi, NP_PACKET_HDR_TYPE_STATS, false, 0, 0, 0); uint8_t* end = nabtoCommunicationBuffer + nabtoCommunicationBufferSize; ptr = insert_stats_payload(ptr, end, NP_PAYLOAD_STATS_TYPE_UNABTO_CONNECTION_ENDED); if (ptr == NULL) { return; } ptr = insert_version_payload(ptr, end); if (ptr == NULL) { return; } #if NABTO_ENABLE_CLIENT_ID ptr = insert_cp_id_payload(ptr, end, con); if (ptr == NULL) { return; } #endif ptr = insert_sp_id_payload(ptr, end); if (ptr == NULL) { return; } ptr = insert_connection_stats_payload(ptr, end, con); if (ptr == NULL) { return; } length = ptr - nabtoCommunicationBuffer; insert_length(nabtoCommunicationBuffer, length); send_to_basestation(nabtoCommunicationBuffer, length, &nmc.context.gsp); }
bool swap (modification& m1, modification& m2) { path rp1= root (m1); path rp2= root (m2); if (is_nil (rp1)) switch (m1->k) { case MOD_ASSIGN: { if (m1 == m2) return true; if (!is_nil (rp2) || m2->k != MOD_INSERT_NODE) return false; modification aux= m2; m2= modification (m1->k, path (m2->p->item, m1->p), m1->t); m1= aux; return true; } case MOD_INSERT: { if (is_nil (m2->p)) return false; int b= m1->p->item; int e= b + insert_length (m1->t); if (m2->p->item >= b && m2->p->item < e) if (!is_nil (root (m2)) || m2->p->item != b || m2->k != MOD_INSERT) if (!is_nil (root (m2)) || m2->k != MOD_INSERT_NODE) return false; return swap1 (m1, m2, b, e-b); } case MOD_REMOVE: { if (is_nil (m2->p)) return false; int i= m1->p->item; int d= m1->p->next->item; return swap1 (m1, m2, i, -d); } case MOD_SPLIT: { if (is_nil (m2->p)) return false; int i= m1->p->item; if (m2->p->item == i || m2->p->item == i+1) if (!is_nil (root (m2)) || m2->p->item != i || m2->k != MOD_INSERT) if (!is_nil (root (m2)) || m2->k != MOD_INSERT_NODE) return false; return swap1 (m1, m2, i, 1); } case MOD_JOIN: { if (is_nil (m2->p)) return false; int i= m1->p->item; if (m2->p->item == i) if (!is_nil (root (m2)) || m2->k != MOD_INSERT) return false; return swap1 (m1, m2, i, -1); } case MOD_ASSIGN_NODE: { if (!is_nil (root (m2))) return swap_basic (m1, m2); if (m1 == m2) return true; if (!is_nil (rp2) || m2->k != MOD_INSERT_NODE) return false; modification aux= m2; m2= modification (m1->k, path (m2->p->item, m1->p), m1->t); m1= aux; return true; } case MOD_INSERT_NODE: { if (is_nil (root (m2))) return false; if (m2->p->item != m1->p->item) return false; modification aux= m1; m1= modification (m2->k, m2->p->next, m2->t); if (m2->k != MOD_INSERT_NODE || !is_nil (root (m1))) m2= aux; else m2= modification (aux->k, path (m1->p->item, aux->p), aux->t); return true; } case MOD_REMOVE_NODE: { modification aux= m1; m1= modification (m2->k, path (m1->p->item, m2->p), m2->t); m2= aux; return true; } case MOD_SET_CURSOR: { if (!is_nil (rp2) || m2->k == MOD_JOIN || m2->k == MOD_SPLIT || m2->k == MOD_ASSIGN_NODE) return swap_basic (m1, m2); return false; } } else if (is_nil (rp2)) switch (m2->k) { case MOD_ASSIGN: return false; case MOD_INSERT: { int b= m2->p->item; int e= b + insert_length (m2->t); return swap2 (m1, m2, b, e-b); } case MOD_REMOVE: { int b= m2->p->item; int e= b + m2->p->next->item; if (m1->p->item >= b && m1->p->item < e) return false; return swap2 (m1, m2, b, b-e); } case MOD_SPLIT: { int i= m2->p->item; if (m1->p->item == i) return false; return swap2 (m1, m2, i, 1); } case MOD_JOIN: { int i= m2->p->item; if (m1->p->item == i || m1->p->item == i+1) return false; return swap2 (m1, m2, i, -1); } case MOD_ASSIGN_NODE: return swap_basic (m1, m2); case MOD_INSERT_NODE: { modification aux= m2; m2= modification (m1->k, path (m2->p->item, m1->p), m1->t); m1= aux; return true; } case MOD_REMOVE_NODE: { if (m1->p->item != m2->p->item) return false; modification aux= m2; m2= modification (m1->k, m1->p->next, m1->t); m1= aux; return true; } case MOD_SET_CURSOR: { if (!is_nil (rp1) || m1->k == MOD_JOIN || m1->k == MOD_SPLIT || m1->k == MOD_ASSIGN_NODE) return swap_basic (m1, m2); return false; } } else if (rp1->item == rp2->item) { path h (rp1->item); modification s1= m1 / h; modification s2= m2 / h; bool r= swap (s1, s2); m1= h * s1; m2= h * s2; return r; } else return swap_basic (m1, m2); FAILED ("unexpected situation"); }
bool swap (modification& m1, modification& m2) { // Assuming that m1;m2 (the patch m1 followed by m2) is well-defined, // determine modifications m1* and m2* such that m2*;m1* is equivalent // to m1;m2. If such modifications exist, then set m1 := m2* and // m2 := m1* and return true. Otherwise, return false path rp1= root (m1); path rp2= root (m2); if (is_nil (rp1)) switch (m1->k) { case MOD_ASSIGN: { if (m1 == m2) return true; if (!is_nil (rp2) || m2->k != MOD_INSERT_NODE) return false; modification aux= m2; m2= modification (m1->k, path (m2->p->item, m1->p), m1->t); m1= aux; return true; } case MOD_INSERT: { if (is_nil (m2->p)) return false; int b= m1->p->item; int e= b + insert_length (m1->t); if (m2->p->item >= b && m2->p->item < e) if (!is_nil (root (m2)) || m2->p->item != b || m2->k != MOD_INSERT) if (!is_nil (root (m2)) || m2->k != MOD_INSERT_NODE) return false; return swap1 (m1, m2, b, e-b); } case MOD_REMOVE: { if (is_nil (m2->p)) return false; int i= m1->p->item; int d= m1->p->next->item; return swap1 (m1, m2, i, -d); } case MOD_SPLIT: { if (is_nil (m2->p)) return false; int i= m1->p->item; if (m2->p->item == i || m2->p->item == i+1) if (!is_nil (root (m2)) || m2->p->item != i || m2->k != MOD_INSERT) if (!is_nil (root (m2)) || m2->k != MOD_INSERT_NODE) return false; return swap1 (m1, m2, i, 1); } case MOD_JOIN: { if (is_nil (m2->p)) return false; int i= m1->p->item; if (m2->p->item == i) if (!is_nil (root (m2)) || m2->k != MOD_INSERT) return false; return swap1 (m1, m2, i, -1); } case MOD_ASSIGN_NODE: { if (!is_nil (root (m2))) return swap_basic (m1, m2); if (m1 == m2) return true; if (!is_nil (rp2) || m2->k != MOD_INSERT_NODE) return false; modification aux= m2; m2= modification (m1->k, path (m2->p->item, m1->p), m1->t); m1= aux; return true; } case MOD_INSERT_NODE: { if (is_nil (root (m2))) return false; if (m2->p->item != m1->p->item) return false; modification aux= m1; m1= modification (m2->k, m2->p->next, m2->t); if (m2->k != MOD_INSERT_NODE || !is_nil (root (m1))) m2= aux; else m2= modification (aux->k, path (m1->p->item, aux->p), aux->t); return true; } case MOD_REMOVE_NODE: { modification aux= m1; m1= modification (m2->k, path (m1->p->item, m2->p), m2->t); m2= aux; return true; } case MOD_SET_CURSOR: { if (!is_nil (rp2) || m2->k == MOD_JOIN || m2->k == MOD_SPLIT || m2->k == MOD_ASSIGN_NODE) return swap_basic (m1, m2); return false; } } else if (is_nil (rp2)) switch (m2->k) { case MOD_ASSIGN: return false; case MOD_INSERT: { int b= m2->p->item; int e= b + insert_length (m2->t); return swap2 (m1, m2, b, e-b); } case MOD_REMOVE: { int b= m2->p->item; int e= b + m2->p->next->item; if (m1->p->item >= b && m1->p->item < e) return false; return swap2 (m1, m2, b, b-e); } case MOD_SPLIT: { int i= m2->p->item; if (m1->p->item == i) return false; return swap2 (m1, m2, i, 1); } case MOD_JOIN: { int i= m2->p->item; if (m1->p->item == i || m1->p->item == i+1) return false; return swap2 (m1, m2, i, -1); } case MOD_ASSIGN_NODE: return swap_basic (m1, m2); case MOD_INSERT_NODE: { modification aux= m2; m2= modification (m1->k, path (m2->p->item, m1->p), m1->t); m1= aux; return true; } case MOD_REMOVE_NODE: { if (m1->p->item != m2->p->item) return false; modification aux= m2; m2= modification (m1->k, m1->p->next, m1->t); m1= aux; return true; } case MOD_SET_CURSOR: { if (!is_nil (rp1) || m1->k == MOD_JOIN || m1->k == MOD_SPLIT || m1->k == MOD_ASSIGN_NODE) return swap_basic (m1, m2); return false; } } else if (rp1->item == rp2->item) { path h (rp1->item); modification s1= m1 / h; modification s2= m2 / h; bool r= swap (s1, s2); m1= h * s1; m2= h * s2; return r; } else return swap_basic (m1, m2); FAILED ("unexpected situation"); }
/* Handle event by polling application - use data from header stored in data */ application_event_result framework_poll_event(struct naf_handle_s *handle, uint8_t *buf, uint16_t size, uint16_t *olen) { unabto_buffer w_buf; unabto_query_response w_b; uint16_t expected_len; uint8_t *ptr; uint32_t query_id; application_event_result res; uint16_t dlen; expected_len = handle->header.hlen + OFS_DATA; if (size <= expected_len) { NABTO_LOG_ERROR(("buffer too small to contain reconstructed header. size=%" PRIu16 " needed=%" PRIu16, size, expected_len)); return AER_REQ_SYSTEM_ERROR; } /* Write packet header and crypto payload header into buf. */ ptr = reconstruct_header(buf, &handle->header); if (!ptr) { //log message already given (header length mismatch) return AER_REQ_SYSTEM_ERROR; } { ptrdiff_t diff = ptr - buf; if (expected_len != (uint16_t)(diff)) { NABTO_LOG_ERROR(("header (with crypto) length mismatch: %" PRIu16 " != %" PRIptrdiff " !!!!!!!!!!!!!!!!!!!", expected_len, diff)); return AER_REQ_SYSTEM_ERROR; } } /* Set up a write buffer to write into buf (after crypto payload header). */ unabto_buffer_init(&w_buf, buf + expected_len, (int)(size - expected_len)); unabto_query_response_init(&w_b, &w_buf); /* Start reading input buffer from start again. */ unabto_query_request_reset(&handle->readBuffer); /* Skip query id. */ if (!unabto_query_read_uint32(&handle->readBuffer, &query_id)) { return AER_REQ_NO_QUERY_ID; } /* Call application */ NABTO_LOG_TRACE(("APPREQ application_poll: client=" PRI_client_id_q, CLIENT_ID_Q_ARGH(*handle))); res = application_poll(&handle->applicationRequest, NULL, &w_b); NABTO_LOG_TRACE(("APPREQ application_poll: result=%i %" PRItext, res, result_s(res))); if (res != AER_REQ_RESPONSE_READY) { return res; } dlen = unabto_crypto_max_data(&handle->connection->cryptoctx, (uint16_t)(size - expected_len)); if (!unabto_encrypt(&handle->connection->cryptoctx, ptr, unabto_query_response_used(&w_b), ptr, dlen, &dlen)) { NABTO_LOG_TRACE((PRInsi" Encryption failure", MAKE_NSI_PRINTABLE(0, handle->header.nsi_sp, 0))); return AER_REQ_SYSTEM_ERROR; } /* Update packet length and flag fields */ dlen += expected_len; insert_length(buf, dlen); if (!unabto_insert_integrity(&handle->connection->cryptoctx, buf, dlen)) { NABTO_LOG_TRACE((PRInsi" Signing failure", MAKE_NSI_PRINTABLE(0, handle->header.nsi_sp, 0))); return AER_REQ_SYSTEM_ERROR; } *olen = dlen; return AER_REQ_RESPONSE_READY; }