Ejemplo n.º 1
0
void close_tcp_socket(nabto_connect* con) {
    unabto_tcp_fallback_connection* fbConn = &fbConns[nabto_connection_index(con)];
    unabto_tcp_fallback_close_socket(fbConn);

    con->tcpFallbackConnectionState = UTFS_CLOSED;
    unabto_tcp_fallback_socket_closed(con);
}
void unabto_tcp_fallback_handle_write(nabto_connect* con) {
	ssize_t status;
    int dataToSend;
    unabto_tcp_fallback_connection* fbConn = &fbConns[nabto_connection_index(con)];
    UNABTO_ASSERT(fbConn->sendBufferSent <= fbConn->sendBufferLength); 
    dataToSend = fbConn->sendBufferLength - fbConn->sendBufferSent;
    
    status = send(fbConn->socket, fbConn->sendBuffer + fbConn->sendBufferSent, dataToSend, MSG_NOSIGNAL);
    if (status > 0) {
        fbConn->sendBufferSent += status;
    } else if (status < 0) {
        int err = errno;
        if ((err == EAGAIN) || err == EWOULDBLOCK) {
        } else {
            NABTO_LOG_ERROR((PRI_tcp_fb "Send of tcp packet failed", TCP_FB_ARGS(con)));
            close_tcp_socket(con);
            return; 
        }
    }

    if (fbConn->sendBufferSent > fbConn->sendBufferLength) {
        NABTO_LOG_FATAL(("fbConn->sendBufferSent(%" PRIsize ") > fbConn->sendBufferLength(%" PRIsize "), that should not be possible", fbConn->sendBufferSent, fbConn->sendBufferLength));
    }
    
    if (fbConn->sendBufferSent == fbConn->sendBufferLength) {
        fbConn->sendBufferLength = 0;
    }
}
void close_tcp_socket(nabto_connect* con) {
    unabto_tcp_fallback_connection* fbConn = &fbConns[nabto_connection_index(con)];
    closesocket(fbConn->socket);
    fbConn->socket = INVALID_SOCKET;
    con->tcpFallbackConnectionState = UTFS_CLOSED;
    unabto_tcp_fallback_socket_closed(con);
}
bool unabto_tcp_fallback_init(nabto_connect* con) {
    unabto_tcp_fallback_connection* fbConn = &fbConns[nabto_connection_index(con)];
    memset(fbConn, 0, sizeof(unabto_tcp_fallback_connection));
    fbConn->sendBufferLength = 0;
    fbConn->socket = INVALID_SOCKET;
    return true;
}
/**
 * This is called by unabto when the resource is released. All
 * resources must have been released when returning.
 */
bool unabto_tcp_fallback_close(nabto_connect* con) {
    unabto_tcp_fallback_connection* fbConn = &fbConns[nabto_connection_index(con)];

    if (con->tcpFallbackConnectionState != UTFS_CLOSED) {
        close_tcp_socket(con);
    }
    return true;
}
Ejemplo n.º 6
0
bool unabto_tcp_fallback_init(nabto_connect* con) {
    unabto_tcp_fallback_connection* fbConn = &fbConns[nabto_connection_index(con)];
    memset(fbConn, 0, sizeof(unabto_tcp_fallback_connection));
    fbConn->sendBufferLength = 0;
    fbConn->socket = INVALID_SOCKET;
#if NABTO_ENABLE_EPOLL
    con->epollEventType = UNABTO_EPOLL_TYPE_TCP_FALLBACK;
#endif
    return true;
}
Ejemplo n.º 7
0
void unabto_tcp_fallback_read_ready(nabto_connect* con) { 
    if (con->state != CS_IDLE) {
        unabto_tcp_fallback_state st = con->tcpFallbackConnectionState;
        unabto_tcp_fallback_connection* fbConn = &fbConns[nabto_connection_index(con)];
        if (st > UTFS_IDLE && st < UTFS_CLOSED && fbConn->socket != INVALID_SOCKET) {
            // this calls reads until something blocks.
            unabto_tcp_fallback_read_packets(con);
        }
    }
}
void unabto_tcp_fallback_select_add_to_read_fd_set(fd_set* readFds, int* maxReadFd) {
    int i;
    for (i = 0; i < NABTO_CONNECTIONS_SIZE; i++) {
        nabto_connect* con = &connections[i];

        if (con->state != CS_IDLE) {
            unabto_tcp_fallback_state st = con->tcpFallbackConnectionState;
            unabto_tcp_fallback_connection* fbConn = &fbConns[nabto_connection_index(con)];
            if (st > UTFS_CONNECTING && st < UTFS_CLOSED && fbConn->socket != INVALID_SOCKET) {
                FD_SET(fbConn->socket, readFds);
                *maxReadFd = MAX(*maxReadFd ,fbConn->socket);
            }
        }
    }
}
void unabto_tcp_fallback_select_read_sockets(fd_set* readFds) {
    int i;
    for (i = 0; i < NABTO_CONNECTIONS_SIZE; i++) {
        nabto_connect* con = &connections[i];

        if (con->state != CS_IDLE) {
            unabto_tcp_fallback_state st = con->tcpFallbackConnectionState;
            unabto_tcp_fallback_connection* fbConn = &fbConns[nabto_connection_index(con)];
            if (st > UTFS_IDLE && st < UTFS_CLOSED && fbConn->socket != INVALID_SOCKET) {
                if (FD_ISSET(fbConn->socket, readFds)) {
                    unabto_tcp_fallback_read_packet(con);
                }
            }
        }
    }
}
void unabto_tcp_fallback_select_add_to_write_fd_set(fd_set* writeFds, int* maxWriteFd) {
    int i;
    for (i = 0; i < NABTO_CONNECTIONS_SIZE; i++) {
        nabto_connect* con = &connections[i];

        if (con->state != CS_IDLE) {
            unabto_tcp_fallback_state st = con->tcpFallbackConnectionState;
            unabto_tcp_fallback_connection* fbConn = &fbConns[nabto_connection_index(con)];
            if (st > UTFS_IDLE && st < UTFS_CLOSED) {
                if ((st == UTFS_CONNECTING || fbConn->sendBufferLength > 0) && fbConn->socket != INVALID_SOCKET) {
                    FD_SET(fbConn->socket, writeFds);
                    *maxWriteFd = MAX(*maxWriteFd ,fbConn->socket);
                }
            }
        }
    }
}
Ejemplo n.º 11
0
bool unabto_tcp_fallback_handle_write(nabto_connect* con) {
    ssize_t status;
    int dataToSend;
    bool canMaybeSendMoreData = false;
    unabto_tcp_fallback_connection* fbConn = &fbConns[nabto_connection_index(con)];
    UNABTO_ASSERT(fbConn->sendBufferSent <= fbConn->sendBufferLength); 
    dataToSend = fbConn->sendBufferLength - fbConn->sendBufferSent;

    if (dataToSend == 0) {
        return false;
    }
    
    NABTO_LOG_TRACE(("data to send %i, sendBufferLength %i, sendBufferSent %i", dataToSend, fbConn->sendBufferLength, fbConn->sendBufferSent));
    
    status = send(fbConn->socket, fbConn->sendBuffer + fbConn->sendBufferSent, dataToSend, MSG_NOSIGNAL);
    NABTO_LOG_TRACE(("tcp send status: %i", status));
    if (status > 0) {
        fbConn->sendBufferSent += status;
        canMaybeSendMoreData = true;
    } else if (status < 0) {
        int err = errno;
        if ((err == EAGAIN) || err == EWOULDBLOCK) {
            canMaybeSendMoreData = false;
        } else {
            NABTO_LOG_ERROR((PRI_tcp_fb "Send of tcp packet failed", TCP_FB_ARGS(con)));
            close_tcp_socket(con);
            canMaybeSendMoreData = false;
            return canMaybeSendMoreData; 
        }
    }

    if (fbConn->sendBufferSent > fbConn->sendBufferLength) {
        NABTO_LOG_FATAL(("fbConn->sendBufferSent(%" PRIsize ") > fbConn->sendBufferLength(%" PRIsize "), that should not be possible", fbConn->sendBufferSent, fbConn->sendBufferLength));
    }
    
    if (fbConn->sendBufferSent == fbConn->sendBufferLength) {
        fbConn->sendBufferLength = 0;
        fbConn->sendBufferSent = 0;
        canMaybeSendMoreData = false;
    }

    NABTO_LOG_TRACE(("state after send, sendBufferLength %i, sendBufferSent %i", fbConn->sendBufferLength, fbConn->sendBufferSent));
    
    return canMaybeSendMoreData;
}
Ejemplo n.º 12
0
void unabto_tcp_fallback_write_ready(nabto_connect* con) {
    if (con->state != CS_IDLE) {
        unabto_tcp_fallback_state st = con->tcpFallbackConnectionState;
        unabto_tcp_fallback_connection* fbConn = &fbConns[nabto_connection_index(con)];
        if (st > UTFS_IDLE && st < UTFS_CLOSED && fbConn->socket != INVALID_SOCKET) {
            
            if (st == UTFS_CONNECTING) {
                unabto_tcp_fallback_handle_connect(con);
            }
            if (st >= UTFS_CONNECTED) {
                bool status;
                do {
                    status = unabto_tcp_fallback_handle_write(con);
                } while (status);
            } 
        }
    }
}
unabto_tcp_fallback_error unabto_tcp_fallback_write(nabto_connect* con, uint8_t* buffer, size_t bufferLength) {

    unabto_tcp_fallback_connection* fbConn = &fbConns[nabto_connection_index(con)];
    unabto_tcp_fallback_error status = UTFE_OK;

    if (fbConn->sendBufferLength == 0) {
        memcpy(fbConn->sendBuffer, buffer, bufferLength);
        fbConn->sendBufferLength = bufferLength;
        fbConn->sendBufferSent = 0;
        unabto_tcp_fallback_handle_write(con);
        status = UTFE_OK;
        NABTO_LOG_TRACE((PRI_tcp_fb "Succesful queue of tcp fallback packet.", TCP_FB_ARGS(con)));
    } else {
        NABTO_LOG_TRACE((PRI_tcp_fb "Could not enqueue tcp fallback packet.", TCP_FB_ARGS(con)));
        status = UTFE_QUEUE_FULL;
    }

    return status;
}
Ejemplo n.º 14
0
void unabto_tcp_fallback_select_write_sockets(fd_set* writeFds) {
    int i;
    for (i = 0; i < NABTO_MEMORY_CONNECTIONS_SIZE; i++) {
        nabto_connect* con = &connections[i];

        if (con->state != CS_IDLE) {
            unabto_tcp_fallback_state st = con->tcpFallbackConnectionState;
            unabto_tcp_fallback_connection* fbConn = &fbConns[nabto_connection_index(con)];
            if (st > UTFS_IDLE && st < UTFS_CLOSED && fbConn->socket != INVALID_SOCKET) {
                if (FD_ISSET(fbConn->socket, writeFds)) {
                    if (st == UTFS_CONNECTING) {
                        unabto_tcp_fallback_handle_connect(con);
                    } else if (st >= UTFS_CONNECTED) {
                        unabto_tcp_fallback_handle_write(con);
                    }
                } 
            }
        }
    }
}
void unabto_tcp_fallback_handle_connect(nabto_connect* con) {
#ifndef WIN32
    
    int err;
    optlen len;
    unabto_tcp_fallback_connection* fbConn = &fbConns[nabto_connection_index(con)];
    len = sizeof(err);
    if (getsockopt(fbConn->socket, SOL_SOCKET, SO_ERROR, &err, &len) != 0) {
        closesocket(fbConn->socket);
        fbConn->socket = INVALID_SOCKET;
        con->tcpFallbackConnectionState = UTFS_CLOSED;
    } else {
        if (err == 0) {
            con->tcpFallbackConnectionState = UTFS_CONNECTED;
        } else {
            closesocket(fbConn->socket);
            fbConn->socket = INVALID_SOCKET;
            con->tcpFallbackConnectionState = UTFS_CLOSED;
        }
    }
#endif
}
Ejemplo n.º 16
0
bool unabto_tcp_fallback_handle_connect(nabto_connect* con) {
#ifndef WIN32
    
    int err;
    optlen len;
    unabto_tcp_fallback_connection* fbConn = &fbConns[nabto_connection_index(con)];
    len = sizeof(err);
    if (getsockopt(fbConn->socket, SOL_SOCKET, SO_ERROR, &err, &len) != 0) {
        unabto_tcp_fallback_close_socket(fbConn);
        con->tcpFallbackConnectionState = UTFS_CLOSED;
        return true;
    } else {
        if (err == 0) {
            con->tcpFallbackConnectionState = UTFS_CONNECTED;
            return true;
        } else {
            unabto_tcp_fallback_close_socket(fbConn);
            con->tcpFallbackConnectionState = UTFS_CLOSED;
            return true;
        }
    }
#endif
    return false;
}
void nabto_release_connection(nabto_connect* con)
{
    if (con->state != CS_IDLE) {
        NABTO_LOG_INFO((PRInsi " Release connection (record %i)", MAKE_NSI_PRINTABLE(0, con->spnsi, 0), nabto_connection_index(con)));
        if (con->state != CS_CLOSE_REQUESTED) {
            con->state = CS_CLOSE_REQUESTED;
#if NABTO_ENABLE_STREAM
            nabto_stream_connection_released(con);
#endif
        }

        if (con->socket != NABTO_INVALID_SOCKET) {
            if (con->socket != nmc.socketGSP &&
                con->socket != nmc.socketLocal) 
            {
                nabto_close_socket(&con->socket);
            }
        }

        // in case the rendezvous state is still active.
        nabto_rendezvous_end(con);
        
#if NABTO_ENABLE_TCP_FALLBACK
        unabto_tcp_fallback_close(con);
#endif
        con->state = CS_IDLE;
        nabto_crypto_release(&con->cryptoctx);

    } else {
        NABTO_LOG_TRACE(("nabto_release_connection called on non used connection"));
    }
}
bool unabto_tcp_fallback_connect(nabto_connect* con) {
    unabto_tcp_fallback_connection* fbConn = &fbConns[nabto_connection_index(con)];
    int status;
    int flags;

    fbConn->socket = socket(AF_INET, SOCK_STREAM, 0);
    if (fbConn->socket < 0) {
        NABTO_LOG_ERROR((PRI_tcp_fb "Could not create socket for tcp fallback.", TCP_FB_ARGS(con)));
        return false;
    }

    flags = 1;
    if (setsockopt(fbConn->socket, IPPROTO_TCP, TCP_NODELAY, (char *) &flags, sizeof(int)) != 0) {
        NABTO_LOG_ERROR(("Could not set socket option TCP_NODELAY"));
    }




#ifndef WIN32
    flags = fcntl(fbConn->socket, F_GETFL, 0);
    if (flags < 0) {
        NABTO_LOG_ERROR((PRI_tcp_fb "fcntl fail", TCP_FB_ARGS(con))); 
        closesocket(fbConn->socket);
        fbConn->socket = INVALID_SOCKET;
        con->tcpFallbackConnectionState = UTFS_CLOSED;
        return false;
    }
    if (fcntl(fbConn->socket, F_SETFL, flags | O_NONBLOCK) < 0) {
        NABTO_LOG_ERROR((PRI_tcp_fb "fcntl fail", TCP_FB_ARGS(con)));        
        closesocket(fbConn->socket);
        fbConn->socket = INVALID_SOCKET;
        con->tcpFallbackConnectionState = UTFS_CLOSED;
        return false;
    }

    flags = 1;
    if(setsockopt(fbConn->socket, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof(flags)) < 0) {
        NABTO_LOG_ERROR(("could not enable KEEPALIVE"));
    }
#ifndef __MACH__
    flags = 9;
    if(setsockopt(fbConn->socket, SOL_TCP, TCP_KEEPCNT, &flags, sizeof(flags)) < 0) {
        NABTO_LOG_ERROR(("could not set TCP_KEEPCNT"));
    }

    flags = 60;
    if(setsockopt(fbConn->socket, SOL_TCP, TCP_KEEPIDLE, &flags, sizeof(flags)) < 0) {
        NABTO_LOG_ERROR(("could not set TCP_KEEPIDLE"));
    }
    
    flags = 60;
    if(setsockopt(fbConn->socket, SOL_TCP, TCP_KEEPINTVL, &flags, sizeof(flags)) < 0) {
        NABTO_LOG_ERROR(("could not set TCP KEEPINTVL"));
    }
#else
    flags = 60;
    if(setsockopt(fbConn->socket, IPPROTO_TCP, TCP_KEEPALIVE, &flags, sizeof(flags)) < 0) {
        NABTO_LOG_ERROR(("could not set TCP_KEEPCNT"));
    }
#endif
    
#endif

    memset(&fbConn->fbHost,0,sizeof(struct sockaddr_in));
    fbConn->fbHost.sin_family = AF_INET;
    fbConn->fbHost.sin_addr.s_addr = htonl(con->fallbackHost.addr);
    fbConn->fbHost.sin_port = htons(con->fallbackHost.port);
    
    NABTO_LOG_INFO((PRI_tcp_fb "Ep. " PRIep, TCP_FB_ARGS(con), MAKE_EP_PRINTABLE(con->fallbackHost)));


    status = connect(fbConn->socket, (struct sockaddr*)&fbConn->fbHost, sizeof(struct sockaddr_in));
   
    if (status == 0) {
        con->tcpFallbackConnectionState = UTFS_CONNECTED;
    } else {
        int err = errno;
        // err is two on windows.
        if (err == EINPROGRESS) {
            con->tcpFallbackConnectionState = UTFS_CONNECTING;
        } else {
            NABTO_LOG_ERROR((PRI_tcp_fb "Could not connect to fallback tcp endpoint. %s", TCP_FB_ARGS(con), strerror(errno)));
            closesocket(fbConn->socket);
            fbConn->socket = INVALID_SOCKET;
            con->tcpFallbackConnectionState = UTFS_CLOSED;    
            return false;
        }
    }

#ifdef WIN32
    flags = 1;
    if (ioctlsocket(fbConn->socket, FIONBIO, &flags) != 0) {
        NABTO_LOG_ERROR((PRI_tcp_fb "ioctlsocket fail", TCP_FB_ARGS(con)));        
        closesocket(fbConn->socket);
        fbConn->socket = INVALID_SOCKET;
        con->tcpFallbackConnectionState = UTFS_CLOSED;
        return false;
    }
#endif

    return true;
}
void unabto_tcp_fallback_read_packet(nabto_connect* con) {
    unabto_tcp_fallback_connection* fbConn = &fbConns[nabto_connection_index(con)];
    while(true) {
        if (fbConn->recvBufferLength < 16) {
            int status = recv(fbConn->socket, fbConn->recvBuffer + fbConn->recvBufferLength, 16-fbConn->recvBufferLength, 0);
            int err = errno;
            if (status < 0) {
                if ((err == EAGAIN) || err == EWOULDBLOCK) {
                    return;
                } else {
                    NABTO_LOG_ERROR((PRI_tcp_fb "unabto_tcp_fallback_read_single_packet failed", TCP_FB_ARGS(con)));
                    unabto_tcp_fallback_close(con);
                    return;
                }
            } else if (status == 0) {
                NABTO_LOG_INFO((PRI_tcp_fb "TCP fallback connection closed by peer", TCP_FB_ARGS(con)));
                unabto_tcp_fallback_close(con);
                return;
            } else {
                fbConn->recvBufferLength+=status;
            }
        }

        if (fbConn->recvBufferLength >= 16) {
            uint16_t packetLength;
            int status;
            int err;
            READ_U16(packetLength, fbConn->recvBuffer+14);
            
            status = recv(fbConn->socket, fbConn->recvBuffer + fbConn->recvBufferLength, packetLength - fbConn->recvBufferLength, 0);
            err = errno;
            if (status < 0) {
                if ((err == EAGAIN) || err == EWOULDBLOCK) {
                    return;
                } else {
                    NABTO_LOG_ERROR((PRI_tcp_fb "Tcp read failed", TCP_FB_ARGS(con)));
                    unabto_tcp_fallback_close(con);
                    return;
                }
            } else if (status == 0) {
                NABTO_LOG_INFO((PRI_tcp_fb "TCP fallback connection closed by peer", TCP_FB_ARGS(con)));
                unabto_tcp_fallback_close(con);
                return;
            } else {
                fbConn->recvBufferLength += status;
            }
            
            if (fbConn->recvBufferLength == packetLength) {
                message_event event;
                event.type = MT_TCP_FALLBACK;
                
                memcpy(nabtoCommunicationBuffer, fbConn->recvBuffer, fbConn->recvBufferLength);
                
                NABTO_LOG_TRACE((PRI_tcp_fb "Received fallback packet length %" PRIsize, TCP_FB_ARGS(con), fbConn->recvBufferLength));
                
                nabto_message_event(&event, fbConn->recvBufferLength);
                NABTO_LOG_TRACE((PRI_tcp_fb "fallback packet done\n==================================================", TCP_FB_ARGS(con)));
                
                fbConn->recvBufferLength = 0;
            }
        }
    }
}
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;
}