bool nabto_fallback_connect_u_event(uint16_t packetLength, nabto_packet_header* hdr) {
    nabto_connect* con;
    uint8_t* startOfPayloads;
    uint8_t* endOfPayloads;
    uint8_t* noncePayloadStart;
    uint16_t noncePayloadLength;
    uint8_t type;
    uint8_t flags;
    uint8_t* ptr;
    bool isReliable;
    bool hasKeepAlive;

    con = nabto_find_connection(hdr->nsi_sp);
    if (con == 0) {
        NABTO_LOG_TRACE((PRInsi " No connection found.", MAKE_NSI_PRINTABLE(hdr->nsi_cp, hdr->nsi_sp, 0)));
        return false;
    }

    startOfPayloads = nabtoCommunicationBuffer + hdr->hlen;
    endOfPayloads = nabtoCommunicationBuffer + packetLength;

    if (!find_payload(startOfPayloads, endOfPayloads, NP_PAYLOAD_TYPE_NONCE, &noncePayloadStart, &noncePayloadLength)) {
        NABTO_LOG_ERROR((PRI_tcp_fb "No nonce payload in GW_CONN_U packet.", TCP_FB_ARGS(con)));
        return false;
    }

    if (noncePayloadLength < 2) {
        NABTO_LOG_ERROR((PRI_tcp_fb "The payload received is too small to contain both flags and type.", TCP_FB_ARGS(con)));
        return false;
    }

    ptr = noncePayloadStart + NP_PAYLOAD_HDR_BYTELENGTH;

    READ_U8(type, ptr);  ptr++;
    READ_U8(flags, ptr); ptr++;

    isReliable   = (flags & NP_GW_CONN_U_FLAG_RELIABLE) != 0;
    hasKeepAlive = (flags & NP_GW_CONN_U_FLAG_KEEP_ALIVE) != 0;

    con->tcpFallbackConnectionState = UTFS_READY_FOR_DATA;

    // If the connection is still resolving upgrade it to a fallback connection.
    if (isReliable) {
        con->fbConAttr |= CON_ATTR_NO_RETRANSMIT;
        NABTO_LOG_DEBUG((PRI_tcp_fb "connection needs no retransmition", TCP_FB_ARGS(con)));
    }

    if (!hasKeepAlive) {
        con->fbConAttr |= CON_ATTR_NO_KEEP_ALIVE;
        NABTO_LOG_DEBUG((PRI_tcp_fb "connection needs no keep alive", TCP_FB_ARGS(con)));
    } else {
        NABTO_LOG_DEBUG((PRI_tcp_fb "connection needs keep alive", TCP_FB_ARGS(con)));
    }
    
    return true;
}
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;
    }
}
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;
}
bool unabto_tcp_fallback_event(nabto_connect* con) {
    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;
}
Beispiel #5
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;
}
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;
            }
        }
    }
}