// -------------------------------------------------------------------------- // NetTCP6Connect: // // Return values: // 0: success // -1: Failed to resolve srvname. // -2: Socket error / Failed to connect (TCP only). // sint32_t NetTCP6Connect( pal_socket_t *p_sock, char *Host, uint16_t Port ) { pal_socket_t sockfd; struct sockaddr_in6 serv_addr; struct in6_addr addr; if( NULL == NetText2Addr6(Host, &addr) ) { return -1; } memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin6_family = AF_INET6; serv_addr.sin6_port = htons(Port); serv_addr.sin6_addr = addr; /* * Open a TCP socket (an Internet 6 stream socket). */ if( (sockfd = pal_socket(AF_INET6, SOCK_STREAM, 0)) < 0 ) { return -2; } /* * Connect to the server. */ if( pal_connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0 ) { pal_closesocket( sockfd ); return -2; } *p_sock = sockfd; return 0; }
// -------------------------------------------------------------------------- // NetUDPConnect: // // Return values: // 0: success // -1: Failed to resolve srvname. // -2: Socket error / Failed to connect (TCP only). // sint32_t NetUDPConnect(pal_socket_t *p_sock, char *Host, uint16_t Port) { pal_socket_t sockfd; struct sockaddr_in serv_addr; struct in_addr addr; if( NetText2Addr(Host, &addr) == NULL ) { return -1; } memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(Port); serv_addr.sin_addr.s_addr = addr.s_addr; /* * Open a UDP socket. */ if( (sockfd = pal_socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) { return -2; } /* * Connect to the server. */ if( pal_connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0 ) { pal_closesocket( sockfd ); return -2; } *p_sock = sockfd; return 0; }
void M2MConnectionHandlerPimpl::dns_handler() { palStatus_t status; palSocketLength_t _socket_address_len; tr_debug("M2MConnectionHandlerPimpl::dns_handler - _socket_state = %d", _socket_state); switch (_socket_state) { case ESocketStateConnectBeingCalled: case ESocketStateCloseBeingCalled: // Ignore these events break; case ESocketStateDisconnected: // Initialize the socket to stable state close_socket(); status = pal_getAddressInfo(_server_address.c_str(), &_socket_address, &_socket_address_len); if (PAL_SUCCESS != status) { tr_error("addrInfo, err: %d", (int)status); _observer.socket_error(M2MConnectionHandler::DNS_RESOLVING_ERROR); return; } status = pal_setSockAddrPort(&_socket_address, _server_port); if (PAL_SUCCESS != status) { tr_error("setSockAddrPort err: %d", (int)status); } else { tr_debug("address family: %d", (int)_socket_address.addressType); } if (_socket_address.addressType == PAL_AF_INET) { status = pal_getSockAddrIPV4Addr(&_socket_address,_ipV4Addr); if (PAL_SUCCESS != status) { tr_error("sockAddr4, err: %d", (int)status); _observer.socket_error(M2MConnectionHandler::DNS_RESOLVING_ERROR); return; } tr_debug("IPv4 Address %s", tr_array(_ipV4Addr, 4)); _address._address = (void*)_ipV4Addr; _address._length = PAL_IPV4_ADDRESS_SIZE; _address._port = _server_port; } else if (_socket_address.addressType == PAL_AF_INET6) { status = pal_getSockAddrIPV6Addr(&_socket_address,_ipV6Addr); if (PAL_SUCCESS != status) { tr_error("sockAddr6, err: %d", (int)status); _observer.socket_error(M2MConnectionHandler::DNS_RESOLVING_ERROR); return; } tr_debug("IPv6 Address %s", tr_array(_ipV6Addr,sizeof(_ipV6Addr))); _address._address = (void*)_ipV6Addr; _address._length = PAL_IPV6_ADDRESS_SIZE; _address._port = _server_port; } else { tr_error("socket config error, stack: %d", (int)_socket_address.addressType); _observer.socket_error(M2MConnectionHandler::SOCKET_ABORT); return; } if(!init_socket()) { tr_error("socket init error"); // The init_socket() calls the socket_error() -callback directly, so it must not be // done here too. return; } if(is_tcp_connection()) { #ifdef PAL_NET_TCP_AND_TLS_SUPPORT tr_debug("resolve_server_address - Using TCP"); // At least on mbed-os the pal_connect() will perform callbacks even during it // is called, which we will ignore when this state is set. _socket_state = ESocketStateConnectBeingCalled; status = pal_connect(_socket, &_socket_address, sizeof(_socket_address)); if (status == PAL_ERR_SOCKET_IN_PROGRES) { // In this case the connect is done asynchronously, and the pal_socketMiniSelect() // will be used to detect the end of connect. // XXX: the mbed-os version of PAL has a bug (IOTPAL-228) open that the select // does not necessarily work correctly. So, should we actually handle // the PAL_ERR_SOCKET_IN_PROGRESS as a error here if code is compiled for mbed-os? tr_debug("pal_connect(): %d, async connect started", (int)status); // we need to wait for the event _socket_state = ESocketStateConnecting; break; } else if (status == PAL_SUCCESS) { tr_info("pal_connect(): success"); _running = true; _socket_state = ESocketStateConnected; } else { tr_error("pal_connect(): failed: %d", (int)status); close_socket(); _observer.socket_error(M2MConnectionHandler::SOCKET_ABORT); return; } #else tr_error("dns_handler() - TCP not configured" #endif //PAL_NET_TCP_AND_TLS_SUPPORT } else { tr_debug("resolve_server_address - Using UDP"); _socket_state = ESocketStateConnected; _running = true; } // fall through is a normal flow in case the UDP was used or pal_connect() happened to return immediately with PAL_SUCCESS case ESocketStateConnected: if (_security) { if (_security->resource_value_int(M2MSecurity::SecurityMode) == M2MSecurity::Certificate || _security->resource_value_int(M2MSecurity::SecurityMode) == M2MSecurity::Psk) { if( _security_impl != NULL ){ _security_impl->reset(); if (_security_impl->init(_security) == 0) { _is_handshaking = true; tr_debug("resolve_server_address - connect DTLS"); if(_security_impl->start_connecting_non_blocking(_base) < 0 ){ tr_debug("dns_handler - handshake failed"); _is_handshaking = false; close_socket(); _observer.socket_error(M2MConnectionHandler::SSL_CONNECTION_ERROR); return; } } else { tr_error("resolve_server_address - init failed"); close_socket(); _observer.socket_error(M2MConnectionHandler::SSL_CONNECTION_ERROR, false); return; } } else { tr_error("dns_handler - sec is null"); close_socket(); _observer.socket_error(M2MConnectionHandler::SSL_CONNECTION_ERROR, false); return; } } } if(!_is_handshaking) { enable_keepalive(); _observer.address_ready(_address, _server_type, _address._port); } break; // This case is a continuation of a nonblocking connect() and is skipped // completely on UDP. case ESocketStateConnecting: // there is only one socket which we are interested uint8_t socketStatus[1]; pal_timeVal_t zeroTime = {0, 0}; uint32_t socketsSet = 0; status = pal_socketMiniSelect(&_socket, 1, &zeroTime, socketStatus, &socketsSet); if (status != PAL_SUCCESS) { // XXX: how could this fail? What to do? tr_error("dns_handler() - read select fail, err: %d", (int)status); close_socket(); // this will also set the socket state to disconnect // XXX: should we inform the observer here too? return; } if (socketsSet > 0) { if (PAL_NET_SELECT_IS_TX(socketStatus, 0)) { // Socket is connected, signal the dns_handler() again to run rest of the steps tr_debug("dns_handler() - connect+select succeeded"); _socket_state = ESocketStateConnected; send_dns_event(); } else if (PAL_NET_SELECT_IS_ERR(socketStatus, 0)) { tr_error("dns_handler() - connect+select failed"); close_socket(); // this will also set the socket state to disconnect // XXX: should we inform the observer here too? } else { tr_debug("dns_handler() - connect+select not ready yet, continue waiting"); } } break; }