void send_debug_packet_response(nabto_packet_header* header, uint32_t notification) { uint8_t* buf = nabtoCommunicationBuffer; uint8_t* ptr = nabtoCommunicationBuffer; uint8_t* end = nabtoCommunicationBuffer+nabtoCommunicationBufferSize; ptr = insert_header(ptr, header->nsi_cp, header->nsi_sp, U_DEBUG, true, header->seq, 0, NULL); if (ptr == NULL) { NABTO_LOG_ERROR(("Could not insert debug packet header")); return; } ptr = insert_notify_payload(ptr, end, NP_PAYLOAD_NOTIFY_DEBUG_OK); if (ptr == NULL) { NABTO_LOG_ERROR(("Could not insert notify payload")); return; } { uint16_t length = ptr - buf; insert_length(buf, length); send_to_basestation(buf, length, &nmc.context.gsp); } }
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; }
bool unabto_buffer_test(void) { char * raw_test_string = "asjdhc#21?(!?(92814skzjbcasa"; uint8_t data[7 + 2 + strlen(raw_test_string)]; unabto_buffer buf, raw_string_buf; buffer_write_t w_buf; buffer_read_t r_buf; uint32_t t32; uint16_t t16; uint8_t t8; uint8_t raw_string_data[strlen(raw_test_string) + 1]; buffer_init(&raw_string_buf, (uint8_t*)raw_test_string, strlen(raw_test_string)); buffer_init(&buf, data, sizeof(data)); buffer_write_init(&w_buf, &buf); if (! (buffer_write_uint32(&w_buf, 0x12345678) && buffer_write_uint16(&w_buf, 0x1234) && buffer_write_uint8(&w_buf, 0x12) && buffer_write_raw(&w_buf, &raw_string_buf) ) ) { NABTO_LOG_ERROR(("Buffer write test failed")); return false; } buffer_read_init(&r_buf, &buf); memset(raw_string_data, 0, sizeof(raw_string_data) + 1); buffer_init(&raw_string_buf, raw_string_data, sizeof(raw_string_data)); bool t = false; if (! ( buffer_read_uint32(&r_buf, &t32) && t32 == 0x12345678 && buffer_read_uint16(&r_buf, &t16) && t16 == 0x1234 && buffer_read_uint8(&r_buf, &t8) && t8 == 0x12 && (t = buffer_read_raw(&r_buf, &raw_string_buf)) && buffer_get_size(&raw_string_buf) == strlen(raw_test_string) && 0 == strncmp((char*)buffer_get_data(&raw_string_buf), raw_test_string, strlen(raw_test_string)) )) { NABTO_LOG_ERROR(("Failed read test failed")); return false; } if (buffer_read_uint32(&r_buf, &t32) || buffer_read_uint16(&r_buf, &t16) || buffer_read_uint8(&r_buf, &t8) || buffer_read_raw(&w_buf, &raw_string_buf) || buffer_write_uint32(&w_buf, 0x12345678) || buffer_write_uint16(&w_buf, 0x1234) || buffer_write_uint8(&w_buf, 0x12) || buffer_write_raw(&w_buf, &raw_string_buf) ) { NABTO_LOG_ERROR(("Some function should have returned false but returned true")); return false; } return true; }
bool connect_event(message_event* event, nabto_packet_header* hdr) { nabto_endpoint* peer = &event->udpMessage.peer; bool isLocal = (event->udpMessage.socket == nmc.socketLocal); NABTO_LOG_TRACE(("U_CONNECT: Searching for hdr->nsi_cp=%" PRIu32 " (should not be found)", hdr->nsi_cp)); if (nabto_find_connection(hdr->nsi_cp) == NULL) { uint32_t nsi; uint32_t ec = 0; nabto_connect* con = nabto_init_connection(hdr, &nsi, &ec, isLocal); if (con) { size_t olen; NABTO_LOG_TRACE(("Couldn't find connection (good!). Created a new connection (nsi=%" PRIu32 ") con->spnsi=%" PRIu32, nsi, con->spnsi)); olen = mk_gsp_connect_rsp(nabtoCommunicationBuffer, hdr->seq, NOTIFY_CONNECT_OK, con->spnsi, hdr->nsi_cp, hdr->nsi_sp, isLocal); if (olen == 0) { NABTO_LOG_ERROR(("U_CONNECT out of resources in connect event.")); nabto_release_connection(con); // no resources available } else { if (EP_EQUAL(*peer, nmc.context.gsp)) { send_to_basestation(nabtoCommunicationBuffer, olen, peer); } else { nabto_write(event->udpMessage.socket, nabtoCommunicationBuffer, olen, peer->addr, peer->port); } con->state = CS_CONNECTING; if (!con->noRendezvous) { nabto_rendezvous_start(con); } #if NABTO_ENABLE_TCP_FALLBACK if (con->hasTcpFallbackCapabilities) { unabto_tcp_fallback_connect(con); } #endif return true; } } else if (nsi && ec) { // build negative answer size_t olen = mk_gsp_connect_rsp(nabtoCommunicationBuffer, hdr->seq, ec, nsi, hdr->nsi_cp, hdr->nsi_sp, isLocal); NABTO_LOG_TRACE((PRInsi " Deny connection, result: %" PRIu32, MAKE_NSI_PRINTABLE(0, nsi, 0), ec)); nabto_write(event->udpMessage.socket, nabtoCommunicationBuffer, olen, peer->addr, peer->port); return true; } else { NABTO_LOG_ERROR(("U_CONNECT was a malformed connect event.")); } } return false; }
bool hex_test(const char* string, uint8_t* expected, size_t expectedLength) { uint8_t buffer[MAX_BUFFER_LENGTH]; size_t readLength; if (unabto_read_hex(string, strlen(string), buffer, MAX_BUFFER_LENGTH, &readLength)) { if (expectedLength == readLength && memcmp(expected,buffer, expectedLength) == 0) { return true; } else { NABTO_LOG_ERROR(("invalid read hex in string %s at position %" PRIsize, string, readLength)); } } else { NABTO_LOG_ERROR(("read hex for %s failed", string)); } return false; }
void tcp_provider_disconnect(tcp_socket* tcpSocket) { closesocket(*tcpSocket); *tcpSocket = TCP_PROVIDER_INVALID_SOCKET; NABTO_LOG_ERROR(("TCP connection closed.")); }
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 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; } }
bool convert_pattern_to_module_and_severity(const char* pattern, size_t patternLength, uint32_t* module, uint32_t* severity) { const char* dotIndex = strchr(pattern, '.'); const char* patternEnd = pattern+patternLength; const char* moduleStart; const char* moduleEnd; const char* severityStart; const char* severityEnd; if (dotIndex == NULL) { NABTO_LOG_ERROR(("No . in log pattern")); return false; } moduleStart = pattern; moduleEnd = dotIndex; severityStart = dotIndex+1; severityEnd = patternEnd; if (!convert_module(moduleStart, moduleEnd, module)) { return false; } if (!convert_severity(severityStart, severityEnd, severity)) { return false; } return true; }
bool poll_task_event_queue(void) { OS_ERR osErr; OS_MSG_SIZE size; uint32_t event; event = (uint32_t)OSTaskQPend(0, OS_OPT_PEND_NON_BLOCKING, &size, NULL, &osErr); if(osErr == OS_ERR_PEND_WOULD_BLOCK) { return false; } if(osErr != OS_ERR_NONE) { NABTO_LOG_ERROR(("Error in receiver task: %i", osErr)); return false; } NABTO_LOG_TRACE(("Received event: %u", event)); if (event & EVENT_RECV_DATA) { uint8_t index = event & EVENT_MASK; if(sockets[index].isOpen) { OSSemPost(&sockets[index].receiverSemaphore, OS_OPT_POST_NO_SCHED, &osErr); if(osErr != OS_ERR_NONE) { NABTO_LOG_ERROR(("Unable to post on socket receive semaphore!")); } NABTO_LOG_TRACE(("Received packet on socket %u", index)); } else { NABTO_LOG_TRACE(("Data on non-open socket.")); } } else { NABTO_LOG_TRACE(("Dropped unexpected event.")); } return true; }
/** * 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; }
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); } } }
bool tcp_provider_connect(tcp_socket* tcpSocket, text host, uint16_t port) { struct sockaddr_in sa; *tcpSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(*tcpSocket == TCP_PROVIDER_INVALID_SOCKET) { NABTO_LOG_ERROR(("Unable to connect to TCP relay service!")); return false; } { uint32_t hostIp = resolve_host_name(host); if(hostIp == 0) { NABTO_LOG_ERROR(("Unable to resolve host!")); return false; } sa.sin_family = AF_INET; sa.sin_addr.s_addr = htonl(hostIp); sa.sin_port = htons(port); if(connect(*tcpSocket, (struct sockaddr*)&sa, sizeof(sa))) { closesocket(*tcpSocket); *tcpSocket = TCP_PROVIDER_INVALID_SOCKET; NABTO_LOG_ERROR(("Unable to connect to host!")); return false; } } { // If iMode!=0, non-blocking mode is enabled. u_long iMode = 1; ioctlsocket(*tcpSocket, FIONBIO, &iMode); } NABTO_LOG_TRACE(("Connection to TCP relay service established.")); return true; }
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; }
bool negative_hex_test(const char* string) { uint8_t buffer[MAX_BUFFER_LENGTH]; size_t readLength; if (unabto_read_hex(string, strlen(string), buffer, MAX_BUFFER_LENGTH, &readLength)) { NABTO_LOG_ERROR(("didn't expect to be able to read hex from %s", string)); return false; } else { return true; } }
bool handle_debug_packet(message_event* event, nabto_packet_header* header) { uint8_t* buf = nabtoCommunicationBuffer; uint8_t* end = nabtoCommunicationBuffer+nabtoCommunicationBufferSize; struct unabto_payload_crypto crypto; buf += header->hlen; { struct unabto_payload_packet payload; if (!unabto_find_payload(buf, end, NP_PAYLOAD_TYPE_CRYPTO, &payload)) { NABTO_LOG_ERROR(("No crypto payload in debug packet.")); return false; } if (!unabto_payload_read_crypto(&payload, &crypto)) { NABTO_LOG_ERROR(("Crypto packet too short.")); return false; } } { uint16_t verifSize; if (!unabto_verify_integrity(nmc.context.cryptoConnect, crypto.code, nabtoCommunicationBuffer, header->len, &verifSize)) { NABTO_LOG_DEBUG(("U_DEBUG Integrity verification failed")); return false; } } { struct unabto_payload_packet payload; if (!unabto_find_payload(buf, end, NP_PAYLOAD_TYPE_SYSLOG_CONFIG, &payload)) { NABTO_LOG_ERROR(("No syslog config packet which is the only one understand at the moment.")); return false; } if (!handle_syslog_config(&payload)) { return false; } } return true; }
ssize_t nabto_read(nabto_socket_t socket, uint8_t* buffer, size_t length, uint32_t* address, uint16_t* port) { OS_ERR osErr; uint8_t* receiveBuffer; uint16_t receiveBufferLength; RAK_SOCKET_ADDR socketInfo; if(socket > NUMBER_OF_SOCKETS) { NABTO_LOG_FATAL(("Read on invalid socket!")); return 0; } if(sockets[socket].isOpen == false) { NABTO_LOG_ERROR(("Read on closed socket!")); return 0; } while(poll_task_event_queue()); OSSemPend(&sockets[socket].receiverSemaphore, 0, OS_OPT_PEND_NON_BLOCKING, NULL, &osErr); if(osErr != OS_ERR_NONE) { return 0; } NABTO_LOG_TRACE(("nabto_read=%u receiving...", socket)); if (RAK_RecvData(socket, &receiveBuffer, &receiveBufferLength) != RAK_OK) { return 0; } if(receiveBufferLength > length) { NABTO_LOG_TRACE(("nabto_read=%u oversize frame", socket)); RAK_RecvFree(buffer); return 0; } memcpy(buffer, receiveBuffer, receiveBufferLength); RAK_RecvFree(receiveBuffer); RAK_GetSocketInfo(socket, &socketInfo); *address = socketInfo.dest_addr; *port = socketInfo.dest_port; NABTO_LOG_TRACE(("Received UDP packet from " PRI_IP ":%u length=%u", PRI_IP_FORMAT(*address), *port, receiveBufferLength)); return receiveBufferLength; }
/** * utility function for either sending +ok\n or -error message\n in * case of either success or failure. see spec in * https://www.rfc-editor.org/rfc/rfc1078.txt instead of CRLF only LF * is used. */ bool tunnel_send_init_message(tunnel* tunnel, const char* msg) { unabto_stream_hint hint; size_t written; size_t writeLength = strlen(msg); written = unabto_stream_write(tunnel->stream, (uint8_t*)msg, writeLength, &hint); if (written != writeLength) { NABTO_LOG_ERROR(("we should at a minimum be able to send this simple message, we will probably just goive up...")); return false; } return true; }
bool handle_syslog_config(struct unabto_payload_packet* payload) { #if NABTO_ENABLE_DEBUG_SYSLOG_CONFIG uint8_t flags; uint8_t facility; uint16_t port; uint32_t ip; uint32_t expire; uint8_t* pattern; uint16_t patternLength; bool enabled; const uint8_t* ptr; if (payload->length < (NP_PAYLOAD_SYSLOG_CONFIG_SIZE_WO_STRINGS + 2)) { NABTO_LOG_ERROR(("Syslog config packet too short")); return false; } ptr = payload->dataBegin; READ_FORWARD_U8(flags, ptr); READ_FORWARD_U8(facility, ptr); READ_FORWARD_U16(port, ptr); READ_FORWARD_U32(ip, ptr); READ_FORWARD_U32(expire, ptr); READ_FORWARD_U16(patternLength, ptr); pattern = (uint8_t*)ptr; if (payload->length < (NP_PAYLOAD_SYSLOG_CONFIG_SIZE_WO_STRINGS + 2 + patternLength)) { NABTO_LOG_ERROR(("syslog packet log settings string too long")); return false; } enabled = flags & NP_PAYLOAD_SYSLOG_FLAG_ENABLE; return unabto_debug_syslog_config(enabled, facility, ip, port, expire, pattern, patternLength); #else return false; #endif }
void unabto_tunnel_read_command(tunnel* tunnel, tunnel_event_source event_source) { const uint8_t* buf; unabto_stream_hint hint; size_t readen; if (tunnel->state != TS_READ_COMMAND) { return; } readen = unabto_stream_read(tunnel->stream, &buf, &hint); if (hint != UNABTO_STREAM_HINT_OK) { tunnel->state = TS_CLOSING; } else { if (readen > 0) { size_t i; for (i = 0; i < readen; i++) { if (buf[i] == '\n') { tunnel->state = TS_PARSE_COMMAND; } else { tunnel->staticMemory->command[tunnel->commandLength] = buf[i]; tunnel->commandLength++; } if (tunnel->commandLength > MAX_COMMAND_LENGTH) { NABTO_LOG_ERROR(("Tunnel command too long")); tunnel->state = TS_CLOSING; } } unabto_stream_ack(tunnel->stream, buf, i, &hint); if (hint != UNABTO_STREAM_HINT_OK) { NABTO_LOG_ERROR(("Failed to ack on stream.")); tunnel->state = TS_CLOSING; } } } }
static void unabto_tcp_fallback_close_socket(unabto_tcp_fallback_connection* fbConn) { if (fbConn->socket == INVALID_SOCKET) { NABTO_LOG_ERROR(("trying to close invalid socket")); } else { #if NABTO_ENABLE_EPOLL { struct epoll_event ev; memset(&ev, 0, sizeof(struct epoll_event)); epoll_ctl(unabto_epoll_fd, EPOLL_CTL_DEL, fbConn->socket, &ev); } #endif closesocket(fbConn->socket); fbConn->socket = INVALID_SOCKET; } }
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; }
/* Reconstruct nabto header with crypto payload header. */ uint8_t* reconstruct_header(uint8_t* buf, const nabto_packet_header * hdr) { uint8_t* ptr; // insert copy of request header (Length will be inserted later) ptr = buf; /* Write fixed part of packet header */ WRITE_U32(ptr, hdr->nsi_cp); ptr += 4; WRITE_U32(ptr, hdr->nsi_sp); ptr += 4; WRITE_U8(ptr, hdr->type); ptr += 1; WRITE_U8(ptr, hdr->version); ptr += 1; WRITE_U8(ptr, hdr->rsvd); ptr += 1; WRITE_U8(ptr, hdr->flags | NP_PACKET_HDR_FLAG_RESPONSE); ptr += 1; WRITE_U16(ptr, hdr->seq); ptr += 2; /*WRITE_U16(ptr, len);*/ ptr += 2; /* Length to be packed later */ /* Write NSI.co to packet header (optional) */ if (hdr->flags & NP_PACKET_HDR_FLAG_NSI_CO) { memcpy(ptr, (const void*) hdr->nsi_co, 8); ptr += 8; } /* Write tag to packet header (optional) */ if (hdr->flags & NP_PACKET_HDR_FLAG_TAG) { WRITE_U16(ptr, hdr->tag); ptr += 2; } { ptrdiff_t diff = ptr - buf; if (hdr->hlen != (uint16_t)(diff)) { NABTO_LOG_ERROR(("header length mismatch: %" PRIu16 " != %" PRIptrdiff " !!!!!!!!!!!!!!!!!!!", hdr->hlen, diff)); return NULL; } } // insert crypto header (len and code will be inserted later) WRITE_U8(ptr, NP_PAYLOAD_TYPE_CRYPTO); ptr += 1; WRITE_U8(ptr, NP_PAYLOAD_HDR_FLAG_NONE); /*ptr += 1; WRITE_U16(ptr, len); ptr += 2; WRITE_U16(ptr, code); ptr += 2;*/ /* len and code is patched by unabto_encrypt() */ ptr += 5; return ptr; /* return end of packet (so far) */ }
bool modbus_rtu_master_transfer_message(modbus_message* message) { modbus* bus; if(message->bus >= MODBUS_NUMBER_OF_BUSSES) // invalid bus { NABTO_LOG_TRACE(("Attempted to enqueue a message on an invalid bus (query=%u)!", (int)message)); return false; } bus = &busses[message->bus]; if((message->frameSize + 2) > MODBUS_MAXIMUM_FRAME_SIZE) // not enough space to add CRC { NABTO_LOG_TRACE(("Attempted to enqueue an oversize message (bus=%u, query=%u)!", (int)bus->identifier, (int)message)); return false; } // add CRC message->frameSize += 2; modbus_rtu_crc_update_crc_field(message->frame, message->frameSize); if(list_append(&bus->messageQueue, message)) // add to the end of the transfer queue { message->state = MODBUS_MESSAGE_STATE_QUEUED; NABTO_LOG_TRACE(("Query has been queued (bus=%u, query=%u, length=%u).", bus->identifier, (int)message, (int)message->frameSize)); // eager tick when queue was empty if(list_count(&bus->messageQueue) == 1) { NABTO_LOG_TRACE(("Performing eager tick as message queue was empty (bus=%u).", bus->identifier)); modbus_rtu_master_tick(); } return true; } else { NABTO_LOG_ERROR(("Unable to enqueued query (bus=%u, query=%u, length=%u)!", bus->identifier, (int)message, (int)message->frameSize)); return false; } }
ssize_t nabto_write(nabto_socket_t socket, const uint8_t* buffer, size_t length, uint32_t address, uint16_t port) { int32_t result; if(length > SEND_BUFFER_SIZE) { return 0; } memcpy(sendBuffer, buffer, length); result = RAK_SendData(socket, sendBuffer, length, address, port); if(result != RAK_OK) { NABTO_LOG_ERROR(("RAK_SendData failed: %i", result)); return 0; } NABTO_LOG_TRACE(("Sent UDP packet to " PRI_IP ":%u length=%u", PRI_IP_FORMAT(address), port, length)); return length; }
bool nabto_connect_event(message_event* event, nabto_packet_header* hdr) { /** * We can get here if we got either a connect request or * if the connect request is a rendezvous event. * * If the first payload is an endpoint it's a rendezvous event. * If the request is a request for a new connection the first payload will be an IPX payload. */ uint8_t type = 0; nabto_rd_payload(nabtoCommunicationBuffer+hdr->hlen, nabtoCommunicationBuffer + hdr->len, &type); if (type == NP_PAYLOAD_TYPE_EP) { return rendezvous_event(event, hdr); } if (type == NP_PAYLOAD_TYPE_IPX) { return connect_event(event, hdr); } NABTO_LOG_ERROR(("U_CONNECT was neither a rendezvous nor a connect event.")); return false; }
static void send_rendezvous_socket(nabto_socket_t socket, nabto_connect* con, uint16_t seq, nabto_endpoint* dest, nabto_endpoint *myAddress) { uint8_t* ptr; uint8_t* buf = nabtoCommunicationBuffer; ptr = insert_header(buf, 0, con->spnsi, U_CONNECT, false, seq, 0, 0); ptr = insert_payload(ptr, NP_PAYLOAD_TYPE_EP, 0, 6); WRITE_U32(ptr, dest->addr); ptr += 4; WRITE_U16(ptr, dest->port); ptr += 2; if (seq > 0) { if (!myAddress) { NABTO_LOG_ERROR(("Send rendezvous called with an invalid address")); return; } else { ptr = insert_payload(ptr, NP_PAYLOAD_TYPE_EP, 0, 6); WRITE_U32(ptr, myAddress->addr); ptr += 4; WRITE_U16(ptr, myAddress->port); ptr += 2; } } { size_t len = ptr - buf; insert_length(buf, len); if (seq) { NABTO_LOG_DEBUG((PRInsi " RENDEZVOUS Send to " PRIep ": seq=%" PRIu16 " " PRIep, MAKE_NSI_PRINTABLE(0, con->spnsi, 0), MAKE_EP_PRINTABLE(*dest), seq, MAKE_EP_PRINTABLE(*myAddress))); } else { NABTO_LOG_DEBUG((PRInsi " RENDEZVOUS Send to " PRIep ": seq=0", MAKE_NSI_PRINTABLE(0, con->spnsi, 0), MAKE_EP_PRINTABLE(*dest))); } if (dest->addr != 0 && dest->port != 0) { nabto_write(socket, buf, len, dest->addr, dest->port); } else { NABTO_LOG_TRACE(("invalid rendezvous packet thrown away")); } } }
bool verify_connection_encryption(nabto_connect* con) { // Local connections can use whatever crypto they like. if (con->isLocal) { return true; } // If we don't want encryption it's ok. if (!nmc.nabtoMainSetup.secureData) { return true; } // If secure data is chosen and the connection isn't local. // The encryption for the new connection should match the crypto suite // set in the setup. if (nmc.nabtoMainSetup.secureData && !con->isLocal) { if (con->cryptoctx.code == nmc.nabtoMainSetup.cryptoSuite) { return true; } } NABTO_LOG_ERROR(("The connection's encryption capabilities doesn't match the expected capabilities")); return false; }
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; } } } }
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; }