void unabto_stream_init_data_structure(struct nabto_stream_s* stream) { struct nabto_stream_tcb* tcb = &stream->u.tcb; memset(stream, 0, sizeof(struct nabto_stream_s)); nabtoSetFutureStamp(&tcb->timeoutStamp, 0); nabtoSetFutureStamp(&tcb->dataTimeoutStamp, 0); nabtoSetFutureStamp(&tcb->dataExpireStamp, 0); nabtoSetFutureStamp(&tcb->ackStamp, 0); }
void rendezvous_time_event(nabto_connect* con) { nabto_rendezvous_connect_state* rcs = &con->rendezvousConnectState; if (rcs->state == RS_CONNECTING) { if (nabtoIsStampPassed(&rcs->timestamp)) { send_rendezvous_to_all(con); } #if NABTO_ENABLE_EXTENDED_RENDEZVOUS_MULTIPLE_SOCKETS if (rcs->openManySockets && nabtoIsStampPassed(&rcs->openManySocketsStamp)) { if (rcs->socketsOpened < NABTO_EXTENDED_RENDEZVOUS_MAX_SOCKETS) { nabto_socket_t* candidate = &rcs->sockets[rcs->socketsOpened]; uint16_t localport = 0; if(nabto_init_socket(0,&localport, candidate)) { rcs->socketsOpened++; send_rendezvous_socket(*candidate, con, 0, &con->cp.globalEndpoint, 0); } else { NABTO_LOG_ERROR(("Could not open socket.")); } nabtoSetFutureStamp(&con->rendezvousConnectState.openManySocketsStamp, 20); } else { rcs->openManySockets = false; } } #endif if (rcs->openManyPorts && nabtoIsStampPassed(&rcs->openManyPortsStamp)) { int i; for (i = 0; i < 10; i++) { nabto_endpoint newEp; uint16_t newPort; nabto_random((uint8_t*)&newPort, sizeof(uint16_t)); newEp.addr = con->cp.globalEndpoint.addr; newEp.port = 1024+(newPort%64500); send_rendezvous(con, 0, &newEp, 0); rcs->portsOpened++; } nabtoSetFutureStamp(&rcs->openManyPortsStamp, 50); } if(nabtoIsStampPassed(&rcs->timeout)) { #if NABTO_ENABLE_EXTENDED_RENDEZVOUS_MULTIPLE_SOCKETS NABTO_LOG_INFO(("Rendezvous timeout. Sockets opened %i", rcs->socketsOpened)); #endif nabto_rendezvous_stop(con); } } }
void handle_stream_packet(nabto_connect* con, nabto_packet_header* hdr, uint8_t* start, uint16_t dlen, uint8_t* payloadsStart, uint8_t* payloadsEnd, void* userData) { // read the window and sack payloads struct unabto_payload_packet window; uint8_t* sackStart = 0; uint16_t sackLength = 0; NABTO_NOT_USED(userData); if(!unabto_find_payload(payloadsStart, payloadsEnd, NP_PAYLOAD_TYPE_WINDOW, &window)) { NABTO_LOG_ERROR(("Stream %i, Packet has no WINDOW payload!", hdr->tag)); return; } { struct unabto_payload_packet sack; if (unabto_find_payload(payloadsStart, payloadsEnd, NP_PAYLOAD_TYPE_SACK, &sack)) { sackStart = (uint8_t*)sack.dataBegin; sackLength = sack.dataLength; } } NABTO_LOG_DEBUG(("(.%i.) STREAM EVENT, dlen: %i", hdr->nsi_sp, dlen)); nabtoSetFutureStamp(&con->stamp, con->timeOut); nabto_stream_event(con, hdr, (uint8_t*)(window.dataBegin - SIZE_PAYLOAD_HEADER), start, dlen, sackStart, sackLength); }
void etimer_reset (struct etimer *et) { nabto_stamp_t t; t = et->timer.start; /* FIXME - we don't have any functions to retrieve the remaining time to epoch */ nabtoSetFutureStamp(&et->timer.start, et->timer.interval); }
bool conclude_connection(nabto_connect* con, nabto_endpoint* peer, uint32_t interval) { NABTO_LOG_TRACE(("conclude connection, %i", interval)); if (con->rendezvousConnectState.state != RS_DONE) { con->timeOut = 7*interval/2; nabtoSetFutureStamp(&con->stamp, con->timeOut); // Give extra time in the connect phase. } nabto_rendezvous_stop(con); return true; }
static void retransmit_current_message(modbus* bus) { modbus_message* message; list_peek_first(&bus->messageQueue, (void**)&message); if(--message->remainingTransmissionAttempts > 0) // retransmit message or drop it? { uint32_t compensatedReponseTimeout; if(message->deferredRetransmissions) { if(list_count(&bus->messageQueue) > 1) // should a deferred retransmission be attempted and does it make any sense to defer (only makes sense if more than one packet is in the queue) { if(list_append(&bus->messageQueue, message)) // add to end of queue { list_remove(&bus->messageQueue, message); // remove current/first instance of message in transfer queue message->state = MODBUS_MESSAGE_STATE_QUEUED; bus->state = BUS_STATE_IDLE; NABTO_LOG_TRACE(("Deferring retransmission of query (bus=%u, query=%u).", bus->identifier, (int)message)); return; } bus->state = BUS_STATE_IDLE; NABTO_LOG_TRACE(("Unable to defer query - retransmitting immediately (bus=%u, query=%u)!", bus->identifier, (int)message)); } else { NABTO_LOG_TRACE(("Query allowed deferrence but transfer queue is empty (bus=%u, query=%u).", bus->identifier, (int)message)); } } // retransmit immediately (also used as fallback if deferred retransmission fails) compensatedReponseTimeout = (uint32_t)message->maximumResponsetime + calculate_transmission_time(message->frameSize); uart_flush_receiver(bus->uartChannel); uart_write_buffer(bus->uartChannel, message->frame, message->frameSize); nabtoSetFutureStamp(&bus->responseTimeout, compensatedReponseTimeout); // time to wait for start of response: transmission time of outgoing frame + maximum response time bus->responseSize = 0; bus->responseOverrun = false; NABTO_LOG_TRACE(("Retransmitting query (bus=%u, remaining attempts=%u).", bus->identifier, (int)message->remainingTransmissionAttempts)); } else { // mark message as failed message->state = MODBUS_MESSAGE_STATE_FAILED; // move message from transfer queue to completed list list_remove(&bus->messageQueue, message); list_append(&completedList, message); bus->state = BUS_STATE_IDLE; NABTO_LOG_TRACE(("Dropped query due too many retransmissions (bus=%u, message=%u).", bus->identifier, (int)message)); } }
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; } }
bool unabto_log_system_enable_syslog(uint32_t module, uint32_t severity, uint32_t syslogHost, uint16_t syslogPort, uint32_t syslogExpire) { syslog_host = syslogHost; syslog_port = syslogPort; syslog_expire = syslogExpire; if (syslog_expire > 0) { nabtoSetFutureStamp(&syslog_expire_stamp, (syslog_expire*1000)); } syslog_module |= module; syslog_severity |= severity; syslog_enabled = true; return true; }
void nabto_rendezvous_start(nabto_connect* con) { nabto_rendezvous_connect_state* rcs = &con->rendezvousConnectState; rcs->state = RS_CONNECTING; nabtoSetFutureStamp(&rcs->timeout, 5000); nabtoSetFutureStamp(&rcs->timestamp, 0); #if NABTO_ENABLE_EXTENDED_RENDEZVOUS_MULTIPLE_SOCKETS if (nmc.context.natType == NP_PAYLOAD_IPX_NAT_SYMMETRIC) { con->rendezvousConnectState.openManySockets = true; nabtoSetFutureStamp(&con->rendezvousConnectState.openManySocketsStamp, 20); } #endif if (con->clientNatType == NP_PAYLOAD_IPX_NAT_SYMMETRIC) { con->rendezvousConnectState.openManyPorts = true; nabtoSetFutureStamp(&con->rendezvousConnectState.openManyPortsStamp, 0); } send_rendezvous_to_all(con); }
int aes_timing_test(void) { nabto_stamp_t future; int i = 0; bool r = true; nabtoSetFutureStamp(&future, 1000); while (!nabtoIsStampPassed(&future)) { r &= aes_test(); i++; } if (!r) { NABTO_LOG_TRACE(("failure in aes timing test")); } return i; }
bool platform_initialize() { uint32_t lastIp; nabto_stamp_t timeout; // Configure TCP/IP stack stuff AppConfig.Flags.bIsDHCPEnabled = true; AppConfig.Flags.bInConfigMode = true; AppConfig.MyIPAddr.Val = MY_DEFAULT_IP_ADDR_BYTE1 | MY_DEFAULT_IP_ADDR_BYTE2 << 8ul | MY_DEFAULT_IP_ADDR_BYTE3 << 16ul | MY_DEFAULT_IP_ADDR_BYTE4 << 24ul; AppConfig.DefaultIPAddr.Val = AppConfig.MyIPAddr.Val; AppConfig.MyMask.Val = MY_DEFAULT_MASK_BYTE1 | MY_DEFAULT_MASK_BYTE2 << 8ul | MY_DEFAULT_MASK_BYTE3 << 16ul | MY_DEFAULT_MASK_BYTE4 << 24ul; AppConfig.DefaultMask.Val = AppConfig.MyMask.Val; AppConfig.MyGateway.Val = MY_DEFAULT_GATE_BYTE1 | MY_DEFAULT_GATE_BYTE2 << 8ul | MY_DEFAULT_GATE_BYTE3 << 16ul | MY_DEFAULT_GATE_BYTE4 << 24ul; AppConfig.PrimaryDNSServer.Val = MY_DEFAULT_PRIMARY_DNS_BYTE1 | MY_DEFAULT_PRIMARY_DNS_BYTE2 << 8ul | MY_DEFAULT_PRIMARY_DNS_BYTE3 << 16ul | MY_DEFAULT_PRIMARY_DNS_BYTE4 << 24ul; AppConfig.SecondaryDNSServer.Val = MY_DEFAULT_SECONDARY_DNS_BYTE1 | MY_DEFAULT_SECONDARY_DNS_BYTE2 << 8ul | MY_DEFAULT_SECONDARY_DNS_BYTE3 << 16ul | MY_DEFAULT_SECONDARY_DNS_BYTE4 << 24ul; TickInit(); StackInit(); unabto_microchip_arp_reset(); // Wait for dhcp. lastIp = AppConfig.MyIPAddr.Val; #if ENABLE_DHCP_BUG_WORKAROUND == 1 nabtoSetFutureStamp(&timeout, 5000); #endif NABTO_LOG_DEBUG(("Acquiring IP from DHCP server...")); while (lastIp == AppConfig.MyIPAddr.Val) { StackTask(); #if ENABLE_DHCP_BUG_WORKAROUND == 1 if (nabtoIsStampPassed(&timeout)) { Reset(); } #endif } READ_U32(lastIp, &AppConfig.MyIPAddr.Val); NABTO_LOG_DEBUG(("Got IP from DHCP server: "PRIip, MAKE_IP_PRINTABLE(lastIp))); return true; }
int integrity_verify_timing(void) { nabto_stamp_t future; bool a; int i = 0; nabtoSetFutureStamp(&future, 1000); while(!nabtoIsStampPassed(&future)) { truncated_hmac_sha256_verify_integrity_test(&a); i++; } return i; }
void nabto_release_connection_req(nabto_connect* con) { NABTO_LOG_DEBUG((PRInsi " Release connection req", MAKE_NSI_PRINTABLE(0, con->spnsi, 0))); if (con->state != CS_CLOSE_REQUESTED) { uint32_t timeout = con->timeOut; if (timeout > MAX_TIMEOUT) { timeout = MAX_TIMEOUT; } con->state = CS_CLOSE_REQUESTED; nabtoSetFutureStamp(&con->stamp, timeout); #if NABTO_ENABLE_STREAM nabto_stream_connection_closed(con); #endif con->sendConnectionEndedStatistics = true; } else { NABTO_LOG_TRACE(("nabto_release_connection_req on closed connection")); } }
/** * main using gopt to check command line arguments * -h for help */ int main(int argc, char* argv[]) { // Set nabto to default values nabto_main_setup* nms = unabto_init_context(); // Overwrite default values with command line args if (!check_args(argc, argv, nms)) { return 1; } NABTO_LOG_INFO(("Identity: '%s'", nms->id)); NABTO_LOG_INFO(("Program Release %i.%i", RELEASE_MAJOR, RELEASE_MINOR)); NABTO_LOG_INFO(("Buffer size: %i", nms->bufsize)); // Initialize nabto if (!unabto_init()) { NABTO_LOG_FATAL(("Failed at nabto_main_init")); } nabto_stamp_t attachExpireStamp; // 20 seconds nabtoSetFutureStamp(&attachExpireStamp, 1000*20); // The main loop gives nabto a tick from time to time. // Everything else is taken care of behind the scenes. while (true) { unabto_tick(); nabto_yield(10); if (nabtoIsStampPassed(&attachExpireStamp)) { NABTO_LOG_ERROR(("Attach took too long.")); exit(4); } if (unabto_is_connected_to_gsp()) { NABTO_LOG_INFO(("Successfully attached to the gsp, now exiting.")); exit(0); } } NABTO_LOG_ERROR(("we should not end here")); exit(5); unabto_close(); return 0; }
bool unabto_tcp_fallback_time_event(nabto_connect* con) { if (con->tcpFallbackConnectionState == UTFS_CONNECTING) { nabtoSetFutureStamp(&con->tcpFallbackConnectionStamp, NABTO_TCP_FALLBACK_HANDSHAKE_DELAY); } else if (con->tcpFallbackConnectionState == UTFS_CONNECTED) { uint8_t handshakePacket[1500]; size_t handshakePacketLength; if (!build_handshake_packet(con, handshakePacket, 1500, &handshakePacketLength)) { NABTO_LOG_ERROR((PRI_tcp_fb "Could not create handshake packet.", TCP_FB_ARGS(con))); unabto_tcp_fallback_close(con); return false; } if (unabto_tcp_fallback_write(con, handshakePacket, handshakePacketLength) != UTFE_OK) { NABTO_LOG_ERROR((PRI_tcp_fb "Could not send handshake packet.", TCP_FB_ARGS(con))); return false; } con->tcpFallbackConnectionState = UTFS_HANDSHAKE_SENT; return true; } return false; }
static void unabto_connection_set_future_stamp(nabto_stamp_t* stamp, uint16_t future) { connection_timeout_cache_cached = false; nabtoSetFutureStamp(stamp, future); }
void modbus_rtu_master_tick(void) { modbus* bus; // tick all busses for(bus = busses; bus < (busses + MODBUS_NUMBER_OF_BUSSES); bus++) { modbus_state oldState; oldState = bus->state; switch(bus->state) { case BUS_STATE_IDLE: { modbus_message* message; if(list_peek_first(&bus->messageQueue, (void**)&message)) // is there a message waiting to be sent { if(message->state == MODBUS_MESSAGE_STATE_DISCARDED) // has message been discared by the application while waiting in the queue? { list_remove(&bus->messageQueue, message); modbus_rtu_master_release_message(message); NABTO_LOG_TRACE(("Completing discard request (bus=%u, query=%u).", bus->identifier, (int)message)); } else // start transferring the message { uint32_t compensatedReponseTime = message->maximumResponsetime + calculate_transmission_time(message->frameSize); NABTO_LOG_TRACE(("Sending query (bus=%u, timeout=%u, compensated timeout=%u).", bus->identifier, (int)message->maximumResponsetime, (int)compensatedReponseTime)); uart_flush_receiver(bus->uartChannel); uart_write_buffer(bus->uartChannel, message->frame, message->frameSize); message->state = MODBUS_MESSAGE_STATE_TRANSFERRING; nabtoSetFutureStamp(&bus->responseTimeout, compensatedReponseTime); // time to wait for start of response: transmission time of outgoing frame + maximum response time bus->responseSize = 0; bus->responseOverrun = false; bus->state = BUS_STATE_BUSY; NABTO_LOG_TRACE(("Query sent (bus=%u, timeout=%u, compensated timeout=%u).", bus->identifier, (int)message->maximumResponsetime, (int)compensatedReponseTime)); NABTO_LOG_BUFFER(NABTO_LOG_SEVERITY_LEVEL_TRACE, ("Query (length=%u): (shown with CRC)", (int)message->frameSize), message->frame, message->frameSize); } } } break; case BUS_STATE_BUSY: { uint16_t length; length = uart_can_read(bus->uartChannel); if(length > 0) // has data been received? { if(bus->responseOverrun == false) // ignore all data after an overrun has occurred { if((bus->responseSize + length) <= MODBUS_MAXIMUM_FRAME_SIZE) // is there room for the data? { // add data to response buffer uart_read_buffer(bus->uartChannel, bus->response + bus->responseSize, length); bus->responseSize += length; } else // response buffer overrun { uart_flush_receiver(bus->uartChannel); // discard data bus->responseOverrun = true; // mark response as over size NABTO_LOG_TRACE(("Receiving oversize response (bus=%u, oversize length=%u)!", bus->identifier, (int)((bus->responseSize + length) - MODBUS_MAXIMUM_FRAME_SIZE))); } } else { uart_flush_receiver(bus->uartChannel); // discard data NABTO_LOG_TRACE(("Dumping overrun data (bus=%u, length=%u)!", bus->identifier, (int)length)); } nabtoSetFutureStamp(&bus->frameCommitTimeout, FRAME_SILENT_DURATION); // reset packet commit timer } else if(bus->responseSize > 0) // has the response begun { if(nabtoIsStampPassed(&bus->frameCommitTimeout)) // has the frame ended { modbus_message* message; list_peek_first(&bus->messageQueue, (void**)&message); if(message->state == MODBUS_MESSAGE_STATE_DISCARDED) // has the message been discarded { list_remove(&bus->messageQueue, message); modbus_rtu_master_release_message(message); // perform actual release of discarded message bus->state = BUS_STATE_IDLE; NABTO_LOG_TRACE(("Received response for dumped query (bus=%u, query=%u, response length=%u).", bus->identifier, (int)message, (int)bus->responseSize)); } else { if(modbus_rtu_crc_verify_crc_field(bus->response, bus->responseSize)) // does reponse pass CRC check? { NABTO_LOG_BUFFER(NABTO_LOG_SEVERITY_LEVEL_TRACE, ("Received response (bus=%u, length=%u): (shown with CRC)", bus->identifier, (int)bus->responseSize), bus->response, bus->responseSize); // replace the query in the message with the response (removing CRC) memcpy(message->frame, bus->response, bus->responseSize - 2); message->frameSize = bus->responseSize - 2; message->state = MODBUS_MESSAGE_STATE_COMPLETED; // mark message as completed // move message from transfer queue to completed list list_remove(&bus->messageQueue, message); list_append(&completedList, message); bus->state = BUS_STATE_IDLE; NABTO_LOG_TRACE(("Received response for query (bus=%u, query=%u).", bus->identifier, (int)message)); } else { NABTO_LOG_TRACE(("Received bad response for query (bus=%u, query=%u)!", bus->identifier, (int)message)); retransmit_current_message(bus); } } } } else if(nabtoIsStampPassed(&bus->responseTimeout)) // the response has not begun within the time limit { modbus_message* message; list_peek_first(&bus->messageQueue, (void**)&message); NABTO_LOG_TRACE(("No response received (bus=%u, message=%u)!", bus->identifier, (int)message)); if(message->state == MODBUS_MESSAGE_STATE_DISCARDED) // has the application discarded the message? { list_remove(&bus->messageQueue, message); modbus_rtu_master_release_message(message); // perform actual release of discarded message bus->state = BUS_STATE_IDLE; NABTO_LOG_TRACE(("Completing discard request (bus=%u, query=%u).", bus->identifier, (int)message)); } else // no - just continue and retransmit the message { retransmit_current_message(bus); } } } break; } if(oldState != bus->state) { NABTO_LOG_TRACE(("State change in bus %u: %s -> %s", bus->identifier, modbusStateNames[oldState], modbusStateNames[bus->state])); } } }
void etimer_restart (struct etimer *et) { nabto_stamp_t t; t = et->timer.start; nabtoSetFutureStamp(&et->timer.start, et->timer.interval); }
intptr_t tick_thread_func(void* args) { nabto_stamp_t ne; nabto_stamp_t shortTime; bool received = false; unabto_mutex_lock(&lock); unabto_next_event(&ne); unabto_mutex_unlock(&lock); nabtoSetFutureStamp(&shortTime, 10); while (running) { //struct epoll_event events[1]; int timeout; nabto_stamp_t now; // updating next event is an expensive operation so only do it if // the earlier update is expired. if (nabtoIsStampPassed(&ne) || (received && nabtoIsStampPassed(&shortTime))) { unabto_mutex_lock(&lock); unabto_time_event(); unabto_next_event(&ne); unabto_mutex_unlock(&lock); nabtoSetFutureStamp(&shortTime, 10); received = false; } // the problem is that the timing is changed when packets is received. now = nabtoGetStamp(); timeout = nabtoStampDiff2ms(nabtoStampDiff(&ne, &now)); if (timeout < 0) { NABTO_LOG_DEBUG(("connection timestamp is in the past. setting timeout to 1ms, timeout=%i, this could be a problem.", timeout)); timeout = 1; } else if (timeout == 0) { timeout = 1; } if (received) { if (timeout > 10) { timeout = 10; } } else { if (timeout > 100) { timeout = 100; } } nabto_socket_t readySockets[16]; uint16_t nReady = nabto_read_events(readySockets, 16, timeout); uint16_t i; for (i = 0; i < nReady; i++) { unabto_mutex_lock(&lock); unabto_read_socket(readySockets[i]); unabto_mutex_unlock(&lock); received = true; } if (nReady == 0) { unabto_mutex_lock(&lock); unabto_time_event(); unabto_mutex_unlock(&lock); } } return 0; }
void send_rendezvous_to_all(nabto_connect* con) { send_rendezvous(con, 0, &con->cp.privateEndpoint, 0); send_rendezvous(con, 0, &con->cp.globalEndpoint, 0); nabtoSetFutureStamp(&con->rendezvousConnectState.timestamp, 1000); }
nabto_connect* nabto_init_connection(nabto_packet_header* hdr, uint32_t* nsi, uint32_t* ec, bool isLocal) { uint8_t type; uint8_t flags; /* NP_PAYLOAD_IPX_FLAG_* */ nabto_connect* con; const uint8_t* end = nabtoCommunicationBuffer + hdr->len; uint8_t* ptr = nabtoCommunicationBuffer + hdr->hlen; uint16_t res; uint16_t ipxPayloadLength; ipxPayloadLength = nabto_rd_payload(ptr, end, &type); ptr += SIZE_PAYLOAD_HEADER; *nsi = 0; *ec = 0; if ((ipxPayloadLength != IPX_PAYLOAD_LENGTH_WITHOUT_NSI) && (ipxPayloadLength != IPX_PAYLOAD_LENGTH_WITH_NSI) && (ipxPayloadLength != IPX_PAYLOAD_LENGTH_FULL_NSI)) { NABTO_LOG_TRACE(("Illegal payload size in U_CONNECT request from GSP: %" PRIu16 " %" PRIu8, ipxPayloadLength, type)); return 0; } if (type != NP_PAYLOAD_TYPE_IPX) { NABTO_LOG_TRACE(("Illegal payload type in U_CONNECT request from GSP: %" PRIu16 " %" PRIu8, ipxPayloadLength, type)); return 0; } if (ipxPayloadLength == IPX_PAYLOAD_LENGTH_WITH_NSI || ipxPayloadLength == IPX_PAYLOAD_LENGTH_FULL_NSI) { READ_U32(*nsi, ptr + 13); NABTO_LOG_TRACE(("IPX payload with NSI (SPNSI=%" PRIu32 ")", *nsi)); } else { *nsi = fresh_nsi(); NABTO_LOG_TRACE(("IPX payload without NSI (fresh NSI=%" PRIu32 ")", *nsi)); } if (*nsi == 0) { NABTO_LOG_ERROR(("Trying to create connection with spnsi == 0")); return 0; } if (nabto_find_connection(*nsi)) { NABTO_LOG_DEBUG((PRInsi " A connection already exists this is probably a retransmission", MAKE_NSI_PRINTABLE(0, *nsi, 0))); *ec = NOTIFY_CONNECT_OK; return 0; } con = nabto_init_connection_real(*nsi); if (con == 0) { if (nabto_find_connection(*nsi)) { NABTO_LOG_DEBUG((PRInsi " U_CONNECT: A connection resource is already pending new connection", MAKE_NSI_PRINTABLE(0, *nsi, 0))); } else { NABTO_LOG_INFO((PRInsi " U_CONNECT: No connection resources free for new connection", MAKE_NSI_PRINTABLE(0, *nsi, 0))); #if NABTO_ENABLE_DEVICE_BUSY_AS_FATAL NABTO_LOG_FATAL((PRInsi " U_CONNECT: No free connections configured to be considered fatal", MAKE_NSI_PRINTABLE(0, *nsi, 0))); #endif } *ec = NOTIFY_ERROR_BUSY_MICRO; return 0; } NABTO_LOG_DEBUG((PRInsi " U_CONNECT: Connecting using record %i", MAKE_NSI_PRINTABLE(0, *nsi, 0), nabto_connection_index(con))); READ_U32(con->cp.privateEndpoint.addr, ptr + 0); READ_U16(con->cp.privateEndpoint.port, ptr + 4); READ_U32(con->cp.globalEndpoint.addr, ptr + 6); READ_U16(con->cp.globalEndpoint.port, ptr + 10); READ_U8(flags, ptr + 12); /* the final word (4 bytes) has been read already (nsi) */ con->noRendezvous = (flags & NP_PAYLOAD_IPX_FLAG_NO_RENDEZVOUS) ? 1 : 0; con->cpEqual = EP_EQUAL(con->cp.privateEndpoint, con->cp.globalEndpoint); con->cpAsync = (flags & NP_PAYLOAD_IPX_FLAG_CP_ASYNC) ? 1 : 0; con->clientNatType = (flags & NP_PAYLOAD_IPX_NAT_MASK); con->isLocal = isLocal; NABTO_LOG_INFO((PRInsi " U_CONNECT: cp.private: " PRIep " cp.global: " PRIep ", noRdv=%" PRIu8 ", cpeq=%" PRIu8 ", asy=%" PRIu8 ", NATType: %" PRIu8 , MAKE_NSI_PRINTABLE(0, *nsi, 0), MAKE_EP_PRINTABLE(con->cp.privateEndpoint), MAKE_EP_PRINTABLE(con->cp.globalEndpoint), con->noRendezvous, con->cpEqual, con->cpAsync, con->clientNatType)); #if NABTO_ENABLE_TCP_FALLBACK if (ipxPayloadLength == IPX_PAYLOAD_LENGTH_FULL_NSI) { memcpy(con->consi, ptr+17, 8); con->nsico = con->consi; READ_U32(con->cpnsi, ptr+25); } #endif ptr += ipxPayloadLength; //IPX_PAYLOAD_LENGTH_WITHOUT_NSI or IPX_PAYLOAD_LENGTH_WITH_NSI con->clientId[0] = 0; res = nabto_rd_payload(ptr, end, &type); if (type == NP_PAYLOAD_TYPE_CP_ID) { uint8_t idType; ptr += SIZE_PAYLOAD_HEADER; if (res > 0) { READ_U8(idType, ptr); ++ptr; --res; if (idType == 1) { // 1 == EMAIL size_t sz = res; if (sz >= sizeof(con->clientId)) { if (sizeof(con->clientId) > 1) { NABTO_LOG_WARN(("Client ID truncated")); } sz = sizeof(con->clientId) - 1; } if (sz) { memcpy(con->clientId, (const void*) ptr, sz); } con->clientId[sz] = 0; } } NABTO_LOG_TRACE(("Connection opened from '%s' (to %s)", con->clientId, nmc.nabtoMainSetup.id)); ptr += res; } #if NABTO_ENABLE_CONNECTION_ESTABLISHMENT_ACL_CHECK if (!allow_client_access(con)) { *ec = NOTIFY_ERROR_CP_ACCESS; goto init_error; } #endif #if NABTO_ENABLE_TCP_FALLBACK { uint8_t* gatewayPtr = ptr; res = nabto_rd_payload(ptr, end, &type); if (type == NP_PAYLOAD_TYPE_GW && ipxPayloadLength == IPX_PAYLOAD_LENGTH_FULL_NSI) { uint8_t* gatewayEndPtr; size_t idLength; NABTO_LOG_TRACE(("The connect contains a gateway payload.")); ptr += res + SIZE_PAYLOAD_HEADER; gatewayPtr += SIZE_PAYLOAD_HEADER; gatewayEndPtr = ptr; READ_U32(con->fallbackHost.addr, gatewayPtr); gatewayPtr+=4; READ_U16(con->fallbackHost.port, gatewayPtr); gatewayPtr+=2; // skip the nsi gatewayPtr+=4; idLength = gatewayEndPtr-gatewayPtr; if (idLength != 20) { NABTO_LOG_FATAL(("The id length should be 20 bytes. bytes=%" PRIsize, idLength)); // todo } memcpy(con->gatewayId, gatewayPtr, 20); con->hasTcpFallbackCapabilities = true; } } #endif #if NABTO_ENABLE_UCRYPTO if (nmc.context.nonceSize == NONCE_SIZE) { uint8_t* decryptedDataStart; uint16_t decryptedDataLength; if (!unabto_connection_verify_and_decrypt_connect_packet(hdr, &decryptedDataStart, &decryptedDataLength)) { NABTO_LOG_TRACE(("Failed to read crypto payload in U_CONNECT")); } else { unabto_crypto_reinit_d(&con->cryptoctx, nmc.nabtoMainSetup.cryptoSuite, decryptedDataStart, decryptedDataLength); } } else #endif { NABTO_LOG_TRACE(("######## U_CONNECT without crypto payload")); unabto_crypto_reinit_d(&con->cryptoctx, CRYPT_W_NULL_DATA, 0, 0); } con->timeOut = CONNECTION_TIMEOUT; nabtoSetFutureStamp(&con->stamp, 20000); /* give much extra time during initialisation */ if (!verify_connection_encryption(con)) { goto init_crypto_error; } if (con->cpEqual) { NABTO_LOG_DEBUG((PRInsi " U_CONNECT: addr:" PRIep " rendezvous:%" PRIu8, MAKE_NSI_PRINTABLE(0, *nsi, 0), MAKE_EP_PRINTABLE(con->cp.privateEndpoint), !con->noRendezvous)); } else { NABTO_LOG_DEBUG((PRInsi " U_CONNECT: private:" PRIep ", global:" PRIep " rendezvous:%" PRIu8, MAKE_NSI_PRINTABLE(0, *nsi, 0), MAKE_EP_PRINTABLE(con->cp.privateEndpoint), MAKE_EP_PRINTABLE(con->cp.globalEndpoint), !con->noRendezvous)); } NABTO_LOG_INFO(("Connection opened from '%s' (to %s). Encryption code %i", con->clientId, nmc.nabtoMainSetup.id, con->cryptoctx.code)); return con; init_crypto_error: *ec = NOTIFY_ERROR_ENCR_MISMATCH; #if NABTO_ENABLE_CONNECTION_ESTABLISHMENT_ACL_CHECK init_error: nabto_release_connection(con); #endif return 0; }