Пример #1
0
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);
        }
    }
} 
Пример #3
0
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;
}
Пример #6
0
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);
}
Пример #10
0
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;
}
Пример #11
0
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;
}
Пример #12
0
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"));
    }
}
Пример #14
0
/**
 *  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;
}
Пример #15
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;
}
Пример #16
0
static void unabto_connection_set_future_stamp(nabto_stamp_t* stamp, uint16_t future)
{
    connection_timeout_cache_cached = false;
    nabtoSetFutureStamp(stamp, future);
}
Пример #17
0
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;
}