/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2000-2019 Ericsson Telecom AB // // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v2.0 // which accompanies this distribution, and is available at // https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html /////////////////////////////////////////////////////////////////////////////// // // File: IPL4asp_PT.cc // Reference: // DTLS references: http://www.net-snmp.org/wiki/index.php/DTLS_Implementation_Notes // http://sctp.fh-muenster.de & http://sctp.fh-muenster.de/DTLS.pdf #include #include #include #include #include #include #include #include #include #include #include #include #include #include "IPL4asp_PT.hh" #include "IPL4asp_PortType.hh" #include "Socket_API_Definitions.hh" #include #define IPL4_SCTP_WHOLE_MESSAGE_RECEIVED 0 #define IPL4_SCTP_EOF_RECEIVED 1 #define IPL4_SCTP_ERROR_RECEIVED 2 #define IPL4_SCTP_PARTIAL_RECEIVE 3 #define IPL4_SCTP_SENDER_DRY_EVENT 4 #define IPL4_IPV4_ANY_ADDR "0.0.0.0" #define IPL4_IPV6_ANY_ADDR "::" #ifndef IP_MTU #define IP_MTU 14 #endif //SSL #ifdef IPL4_USE_SSL #define AS_SSL_CHUNCK_SIZE 16384 // character buffer length to store temporary SSL informations, 256 is usually enough #define SSL_CHARBUF_LENGTH 256 // number of bytes to read from the random devices #define SSL_PRNG_LENGTH 1024 #ifndef OPENSSL_NO_SCTP #if defined(BIO_CTRL_DGRAM_SCTP_GET_RCVINFO) && defined(BIO_CTRL_DGRAM_SCTP_SET_SNDINFO) #define OPENSSL_SCTP_SUPPORT #endif #endif // is DTLS_mehod available? #ifndef SSL_OP_NO_DTLSv1_2 #define DTLS_client_method DTLSv1_client_method #define DTLS_server_method DTLSv1_server_method #endif static int current_conn_id=-1; #if OPENSSL_VERSION_NUMBER >= 0x1000200fL static int ipl4_tls_alpn_cb (SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg){ IPL4asp__PortType::IPL4asp__PT_PROVIDER* tp=(IPL4asp__PortType::IPL4asp__PT_PROVIDER*)arg; if(!tp->isConnIdValid(current_conn_id)){ return SSL_TLSEXT_ERR_NOACK; } if(!tp->sockList[current_conn_id].alpn){ return SSL_TLSEXT_ERR_NOACK; } if (SSL_select_next_proto ((unsigned char **)out, outlen, (const unsigned char*)(*tp->sockList[current_conn_id].alpn), tp->sockList[current_conn_id].alpn->lengthof(), in, inlen) != OPENSSL_NPN_NEGOTIATED) { return SSL_TLSEXT_ERR_NOACK; } return SSL_TLSEXT_ERR_OK; } #endif #endif #ifdef USE_IPL4_EIN_SCTP #include //const IPL4asp__Types::OptionList empty_IPL4asp__Types::OptionList(NULL_VALUE); #endif using namespace IPL4asp__Types; namespace IPL4asp__PortType { #ifdef USE_SCTP /* is any of the bytes from offset .. u8_size in 'u8' non-zero? return offset or u8_size if all zero */ static unsigned int byte_nonzero(const uint8_t *u8, unsigned int offset, unsigned int u8_size) { unsigned int j; for (j = offset; j < u8_size; j++) { if (u8[j] != 0) break; } return j; } static unsigned int sctp_sockopt_event_subscribe_size = 0; static int determine_sctp_sockopt_event_subscribe_size(void) { uint8_t buf[256]; socklen_t buf_len = sizeof(buf); int sd, rc; /* only do this once */ if (sctp_sockopt_event_subscribe_size != 0) return 0; sd = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP); if (sd < 0) return sd; rc = getsockopt(sd, IPPROTO_SCTP, SCTP_EVENTS, buf, &buf_len); close(sd); if (rc < 0) return rc; sctp_sockopt_event_subscribe_size = buf_len; TTCN_warning("sizes of 'struct sctp_event_subscribe': compile-time %zu, kernel: %u", sizeof(struct sctp_event_subscribe), sctp_sockopt_event_subscribe_size); return 0; } /* Attempt to work around Linux kernel ABI breakage * * The Linux kernel ABI for the SCTP_EVENTS socket option has been broken repeatedly. * - until commit 35ea82d611da59f8bea44a37996b3b11bb1d3fd7 ( kernel < 4.11), the size is 10 bytes * - in 4.11 it is 11 bytes * - in 4.12 .. 5.4 it is 13 bytes * - in kernels >= 5.5 it is 14 bytes * * This wouldn't be a problem if the kernel didn't have a "stupid" assumption that the structure * size passed by userspace will match 1:1 the length of the structure at kernel compile time. In * an ideal world, it would just use the known first bytes and assume the remainder is all zero. * But as it doesn't do that, let's try to work around this */ static int sctp_setsockopt_events_linux_workaround(int fd, const struct sctp_event_subscribe *event) { const unsigned int compiletime_size = sizeof(*event); unsigned int rc; if (determine_sctp_sockopt_event_subscribe_size() < 0) { TTCN_warning("Cannot determine SCTP_EVENTS socket option size"); return -1; } if (compiletime_size == sctp_sockopt_event_subscribe_size) { /* no kernel workaround needed */ return setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, event, compiletime_size); } else if (compiletime_size < sctp_sockopt_event_subscribe_size) { /* we are using an older userspace with a more modern kernel and hence need * to pad the data */ uint8_t buf[sctp_sockopt_event_subscribe_size]; memcpy(buf, event, compiletime_size); memset(buf + sizeof(*event), 0, sctp_sockopt_event_subscribe_size - compiletime_size); return setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, buf, sctp_sockopt_event_subscribe_size); } else /* if (compiletime_size > sctp_sockopt_event_subscribe_size) */ { /* we are using a newer userspace with an older kernel and hence need to truncate * the data - but only if the caller didn't try to enable any of the events of the * truncated portion */ rc = byte_nonzero((const uint8_t *)event, sctp_sockopt_event_subscribe_size, compiletime_size); if (rc != compiletime_size) { TTCN_warning("Kernel only supports sctp_event_subscribe of %u bytes, " "but caller tried to enable more modern event at offset %u", sctp_sockopt_event_subscribe_size, rc); return -1; } return setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, event, sctp_sockopt_event_subscribe_size); } } #endif int pskIdentityIdx; int pskKeyIdx; #define SET_OS_ERROR_CODE (result.os__error__code()() = errno) #define RETURN_ERROR(code) { \ result.errorCode()() = PortError::code; \ if (result.os__error__code().ispresent()) \ result.os__error__text()() = strerror((int)result.os__error__code()()); \ ASP__Event event; \ event.result() = result; \ if (portRef.globalConnOpts.extendedPortEvents == GlobalConnOpts::YES) \ portRef.incoming_message(event); \ return result; \ } #define RETURN_EXTENDED_ERROR(code) { \ result.errorCode()() = PortError::code; \ if (result.os__error__code().ispresent()) \ result.os__error__text()() = strerror((int)result.os__error__code()()); \ ASP__Event event; \ event.extended__result() = result; \ if (portRef.globalConnOpts.extendedPortEvents == GlobalConnOpts::YES) \ portRef.incoming_message(event); \ } #define RETURN_ERROR_STACK(code) { \ result.errorCode()() = PortError::code; \ if (result.os__error__code().ispresent()) \ result.os__error__text()() = strerror((int)result.os__error__code()()); \ ASP__Event event; \ event.result() = result; \ if (globalConnOpts.extendedPortEvents == GlobalConnOpts::YES) \ incoming_message(event); \ return result; \ } #define RETURN_SOCKET_OPTION() { \ if (length == -1) { \ IPL4_DEBUG("IPL4asp__PT_PROVIDER::getOption: error, getsockopt returned -1"); \ return -1; \ } else { \ IPL4_DEBUG("IPL4asp__PT_PROVIDER::getOption: value obtained: %i", optval); \ return optval; \ }\ } #define IPL4_PORTREF_DEBUG(p,...) if(p.debugAllowed) {p.debug(__VA_ARGS__);} #define IPL4_DEBUG(...) if(debugAllowed) {debug(__VA_ARGS__);} #ifdef LKSCTP_MULTIHOMING_ENABLED int my_sctp_connectx(int sd, struct sockaddr * addrs, int addrcnt){ #ifdef SCTP_SOCKOPT_CONNECTX_OLD return sctp_connectx(sd, addrs, addrcnt,NULL); #else return sctp_connectx(sd, addrs, addrcnt); #endif } #endif inline void IPL4asp__PT_PROVIDER::testIfInitialized() const { if (!mapped) { TTCN_error("IPL4 Test Port not mapped"); } } INTEGER simpleGetMsgLen(const OCTETSTRING& stream, ro__integer& /*args*/) { return stream.lengthof(); } // simpleGetMsgLen IPL4__IPAddressType GetSocketAddressType(int socket) { struct sockaddr addr; socklen_t addrlen = sizeof(addr); if (getsockname(socket,(struct sockaddr *)&addr, &addrlen) == -1) { return IPL4__IPAddressType::ErrorReadingAddress; } return addr.sa_family == AF_INET ? IPL4__IPAddressType::IPv4 : IPL4__IPAddressType::IPv6; } int SetLocalSockAddr(const char* debug_str, IPL4asp__PT_PROVIDER& portRef, int def_addr_family, const char *locName, int locPort, SockAddr& sockAddr, socklen_t& sockAddrLen){ int hp=0; bool locName_empty=(strlen(locName)==0); const char* def_loc_host; if(strlen(portRef.defaultLocHost)==0){ if(def_addr_family==AF_INET6){ def_loc_host= IPL4_IPV6_ANY_ADDR; } else { def_loc_host= IPL4_IPV4_ANY_ADDR; } } else { def_loc_host=portRef.defaultLocHost; } IPL4_PORTREF_DEBUG(portRef, "SetLocalSockAddr: locName: %s loc_port %d def_loc_host %s, add_family %s", locName, locPort,def_loc_host, def_addr_family==AF_INET6?"AF_INET6":"AF_INET"); if (locPort != -1 && !locName_empty) hp = SetSockAddr(locName, locPort, sockAddr, sockAddrLen); else if (locPort == -1 && locName_empty) { // use default host and port IPL4_PORTREF_DEBUG(portRef, "%s: use defaults: %s:%d", debug_str, def_loc_host, portRef.defaultLocPort); hp = SetSockAddr(def_loc_host, portRef.defaultLocPort, sockAddr, sockAddrLen); } else if (locPort == -1) { // use default port IPL4_PORTREF_DEBUG(portRef, "%s: use default port: %s:%d", debug_str, locName, portRef.defaultLocPort); hp = SetSockAddr(locName, portRef.defaultLocPort, sockAddr, sockAddrLen); } else { // use default host IPL4_PORTREF_DEBUG(portRef, "%s: use default host: %s:%d", debug_str, def_loc_host, locPort); hp = SetSockAddr(def_loc_host, locPort, sockAddr, sockAddrLen); } return hp; } int SetSockAddr(const char *name, int port, SockAddr& sa, socklen_t& saLen) { //int err = 0; int addrtype = -1; struct sockaddr_in saddr; #ifdef USE_IPV6 struct sockaddr_in6 saddr6; #endif if(inet_pton(AF_INET, name, &(saddr.sin_addr))) { memset(&sa.v4, 0, sizeof(sa.v4)); saLen = sizeof(sa.v4); sa.v4.sin_family = AF_INET; sa.v4.sin_port = htons(port); memcpy(&sa.v4.sin_addr, &(saddr.sin_addr), sizeof(saddr.sin_addr)); addrtype = AF_INET; } #ifdef USE_IPV6 else if(inet_pton(AF_INET6, name, &(saddr6.sin6_addr))) { memset(&sa.v6, 0, sizeof(sa.v6)); saLen = sizeof(sa.v6); sa.v6.sin6_family = AF_INET6; sa.v6.sin6_port = htons(port); memcpy(&sa.v6.sin6_addr, &(saddr6.sin6_addr), sizeof(saddr6.sin6_addr)); addrtype = AF_INET6; } #endif else { struct addrinfo myaddr, *res; memset(&myaddr,0,sizeof(myaddr)); myaddr.ai_flags = AI_ADDRCONFIG|AI_PASSIVE; myaddr.ai_socktype = SOCK_STREAM; myaddr.ai_protocol = 0; // if ((err = getaddrinfo(name, NULL, &myaddr, &res)) != 0) { if (getaddrinfo(name, NULL, &myaddr, &res) != 0) { //printf("SetSockAddr: getaddrinfo error: %i, %s", err, gai_strerror(err)); return -1; } if (res->ai_addr->sa_family == AF_INET) { // IPv4 struct sockaddr_in *saddr = (struct sockaddr_in *) res->ai_addr; memset(&sa.v4, 0, sizeof(sa.v4)); saLen = sizeof(sa.v4); sa.v4.sin_family = AF_INET; sa.v4.sin_port = htons(port); memcpy(&sa.v4.sin_addr, &(saddr->sin_addr), sizeof(saddr->sin_addr)); addrtype = AF_INET; } #ifdef USE_IPV6 else if (res->ai_addr->sa_family == AF_INET6){ // IPv6 struct sockaddr_in6 *saddr = (struct sockaddr_in6 *) res->ai_addr; memset(&sa.v6, 0, sizeof(sa.v6)); saLen = sizeof(sa.v6); memcpy(&sa.v6,saddr,saLen); sa.v6.sin6_port = htons(port); addrtype = AF_INET6; } #endif else { //printf("sa_family not handled!"); } freeaddrinfo(res); } return addrtype; } bool SetNameAndPort(SockAddr *sa, socklen_t saLen, HostName& name, PortNumber& port) { sa_family_t af; if (saLen == sizeof(sockaddr_in)) { // IPv4 void *src; int vport; af = AF_INET; src = &sa->v4.sin_addr.s_addr; vport = sa->v4.sin_port; char dst[INET_ADDRSTRLEN]; if (inet_ntop(af, src, dst, INET_ADDRSTRLEN) == NULL) { name = "?"; port = -1; return false; } else name = CHARSTRING(dst); port = ntohs(vport); return true; } #ifdef USE_IPV6 else { // IPv6 void *src; int vport; af = AF_INET6; src = &sa->v6.sin6_addr.s6_addr; vport = sa->v6.sin6_port; char dst[INET6_ADDRSTRLEN]; if (inet_ntop(af, src, dst, INET6_ADDRSTRLEN) == NULL) { name = "?"; port = -1; return false; } else name = CHARSTRING(dst); port = ntohs(vport); return true; } #endif name = "?"; port = -1; return false; } // SetNameAndPort #ifdef IPL4_USE_SSL // cookie variables unsigned char ssl_cookie_secret[IPL4_COOKIE_SECRET_LENGTH]; int ssl_cookie_initialized; // do not initialize the cookie twice #endif IPL4asp__PT_PROVIDER::IPL4asp__PT_PROVIDER(const char *par_port_name) : PORT(par_port_name) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::IPL4asp__PT_PROVIDER: enter"); debugAllowed = false; alreadyComplainedAboutMsgLen = false; mapped = false; sockListSize = SOCK_LIST_SIZE_MIN; defaultLocHost = memptystr(); defaultLocPort = 9999; defaultRemHost = NULL; defaultRemPort = -1; default_mode = 0; default_proto = 0; connId_release_confirmed = false; backlog = SOMAXCONN; defaultGetMsgLen = simpleGetMsgLen; defaultGetMsgLen_forConnClosedEvent = simpleGetMsgLen; // by default we pass up to TTCN the remaining buffer content on connClosed defaultMsgLenArgs = new ro__integer(NULL_VALUE); defaultMsgLenArgs_forConnClosedEvent = new ro__integer(NULL_VALUE); pureNonBlocking = false; poll_timeout = -1; max_num_of_poll =-1; lonely_conn_id = -1; lazy_conn_id_level = 0; sctp_PMTU_size = 0; broadcast = false; ssl_cert_per_conn = false; send_extended_result = false; #ifdef USE_SCTP (void) memset(&initmsg, 0, sizeof(struct sctp_initmsg)); initmsg.sinit_num_ostreams = 64; initmsg.sinit_max_instreams = 64; initmsg.sinit_max_attempts = 0; initmsg.sinit_max_init_timeo = 0; (void) memset(&events, 0, sizeof (events)); events.sctp_data_io_event = TRUE; events.sctp_association_event = TRUE; events.sctp_address_event = TRUE; events.sctp_send_failure_event = TRUE; events.sctp_peer_error_event = TRUE; events.sctp_shutdown_event = TRUE; events.sctp_partial_delivery_event = TRUE; #ifdef SCTP_SENDER_DRY_EVENT events.sctp_sender_dry_event = FALSE; #endif #ifdef LKSCTP_1_0_7 events.sctp_adaptation_layer_event = TRUE; #elif defined LKSCTP_1_0_9 events.sctp_adaptation_layer_event = TRUE; events.sctp_authentication_event = FALSE; #else events.sctp_adaption_layer_event = TRUE; #endif #endif #ifdef USE_IPL4_EIN_SCTP native_stack = TRUE; sctpInstanceId=0; userInstanceId=0; userInstanceIdSpecified=false; sctpInstanceIdSpecified=false; userId=USER01_ID; cpManagerIPA=""; #endif //SSL #ifdef IPL4_USE_SSL ssl_initialized=false; ssl_key_file=NULL; ssl_certificate_file=NULL; ssl_trustedCAlist_file=NULL; ssl_cipher_list=NULL; ssl_verify_certificate=false; ssl_use_session_resumption=true; ssl_session=NULL; ssl_password=NULL; ssl_ctx = NULL; ssl_reconnect_attempts = 5; ssl_reconnect_delay = 10000; //in milisec, so by default 0.01sec memset(ssl_cookie_secret, 0, IPL4_COOKIE_SECRET_LENGTH); ssl_cookie_initialized = 0; psk_identity=NULL; psk_identity_hint=NULL; psk_key=NULL; #endif } // IPL4asp__PT_PROVIDER::IPL4asp__PT_PROVIDER IPL4asp__PT_PROVIDER::~IPL4asp__PT_PROVIDER() { IPL4_DEBUG("IPL4asp__PT_PROVIDER::~IPL4asp__PT_PROVIDER: enter"); delete defaultMsgLenArgs; delete defaultMsgLenArgs_forConnClosedEvent; Free(defaultLocHost); Free(defaultRemHost); // now SSL context can be removed #ifdef IPL4_USE_SSL if (ssl_ctx!=NULL) { SSL_CTX_free(ssl_ctx); } if (ssl_dtls_server_ctx!=NULL) { SSL_CTX_free(ssl_dtls_server_ctx); } if (ssl_dtls_client_ctx!=NULL) { SSL_CTX_free(ssl_dtls_client_ctx); } delete [] ssl_key_file; delete [] ssl_certificate_file; delete [] ssl_trustedCAlist_file; delete [] ssl_cipher_list; delete [] ssl_password; delete [] psk_identity; delete [] psk_identity_hint; delete [] psk_key; #endif } // IPL4asp__PT_PROVIDER::~IPL4asp__PT_PROVIDER void IPL4asp__PT_PROVIDER::debug(const char *fmt, ...) { // DO NOT CALL DIRECTLY, use macro IPL4_PORTREF_DEBUG or IPL4_DEBUG // if (debugAllowed) { TTCN_Logger::begin_event(TTCN_DEBUG); TTCN_Logger::log_event("%s: ", get_name()); va_list args; va_start(args, fmt); TTCN_Logger::log_event_va_list(fmt, args); va_end(args); TTCN_Logger::end_event(); // } } // IPL4asp__PT_PROVIDER::debug void IPL4asp__PT_PROVIDER::set_parameter(const char *parameter_name, const char *parameter_value) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::set_parameter: enter (name: %s, value: %s)", parameter_name, parameter_value); if (!strcmp(parameter_name, "debug")) { if (!strcasecmp(parameter_value,"YES")) { debugAllowed = true; ipDiscConfig.debugAllowed = true; } IPL4_DEBUG("IPL4asp__PT_PROVIDER::set_parameter: enter (name: %s, value: %s)", parameter_name, parameter_value); } else if (!strcmp(parameter_name, "max_num_of_poll")) { max_num_of_poll = atoi(parameter_value); } else if (!strcmp(parameter_name, "poll_timeout")) { poll_timeout = atoi(parameter_value); } else if (!strcmp(parameter_name, "defaultListeningPort")) { defaultLocPort = atoi(parameter_value); } else if (!strcmp(parameter_name, "defaultListeningHost")) { if(defaultLocHost){ Free(defaultLocHost); } defaultLocHost = mcopystr(parameter_value); } else if (!strcasecmp(parameter_name, "map_behavior")) { if(!strcasecmp(parameter_value, "connect")){ default_mode = 1; } else if(!strcasecmp(parameter_value, "listen")) { default_mode = 2; } else { default_mode = 0; } } else if (!strcasecmp(parameter_name, "connId_release_mode")) { if(!strcasecmp(parameter_value, "confirmed")){ connId_release_confirmed = true; } else { connId_release_confirmed = false; } } else if (!strcasecmp(parameter_name, "map_protocol")) { if(!strcasecmp(parameter_value, "tcp")){ default_proto = 0; } else if(!strcasecmp(parameter_value, "tls")) { default_proto = 1; } else if(!strcasecmp(parameter_value, "sctp")) { default_proto = 2; } else if(!strcasecmp(parameter_value, "udp")) { default_proto = 3; } } else if (!strcasecmp(parameter_name, "RemotePort")) { defaultRemPort = atoi(parameter_value); } else if (!strcasecmp(parameter_name, "RemoteHost")) { if(defaultRemHost){ Free(defaultRemHost); } defaultRemHost = mcopystr(parameter_value); } else if (!strcmp(parameter_name, "backlog")) { backlog = atoi(parameter_value); if (backlog <= 0) { backlog = SOMAXCONN; TTCN_warning("IPL4asp__PT_PROVIDER::set_parameter: invalid " "backlog value set to %d", backlog); } } else if (!strcmp(parameter_name, "sockListSizeInit")) { sockListSize = atoi(parameter_value); if (sockListSize < SOCK_LIST_SIZE_MIN) { sockListSize = SOCK_LIST_SIZE_MIN; TTCN_warning("IPL4asp__PT_PROVIDER::set_parameter: invalid " "sockListSizeInit value set to %d", sockListSize); } } else if (!strcmp(parameter_name, "pureNonBlocking")) { if (!strcasecmp(parameter_value,"YES")) pureNonBlocking = true; } else if (!strcmp(parameter_name, "useExtendedResult")) { if (!strcasecmp(parameter_value,"YES")) send_extended_result = true; } else if (!strcmp(parameter_name, "lazy_conn_id_handling")) { if (!strcasecmp(parameter_value,"YES")){ lazy_conn_id_level = 1; } else { lazy_conn_id_level = 0; } } else if (!strcasecmp(parameter_name, "sctp_path_mtu_size")) { sctp_PMTU_size = atoi(parameter_value); } else if (!strcmp(parameter_name, "ipAddressDiscoveryType")) { if (!strcasecmp(parameter_value,"DHCP_OR_ARP")) ipDiscConfig.type = IPDiscConfig::DHCP_OR_ARP; else if (!strcasecmp(parameter_value,"DHCP")) ipDiscConfig.type = IPDiscConfig::DHCP; else if (!strcasecmp(parameter_value,"ARP")) ipDiscConfig.type = IPDiscConfig::ARP; } else if (!strcmp(parameter_name, "freebind")){ if (!strcasecmp(parameter_value,"YES")) globalConnOpts.freebind = GlobalConnOpts::YES; else if (!strcasecmp(parameter_value,"NO")) globalConnOpts.freebind = GlobalConnOpts::NO; } else if (!strcmp(parameter_name, "interfaceName")) { ipDiscConfig.expIfName = parameter_value; } else if (!strcmp(parameter_name, "interfaceIpAddress")) { ipDiscConfig.expIfIpAddress = parameter_value; } else if (!strcmp(parameter_name, "excludedInterfaceIpAddress")) { ipDiscConfig.exclIfIpAddress = parameter_value; } else if (!strcmp(parameter_name, "ethernetAddressStart")) { ipDiscConfig.ethernetAddress = parameter_value; } else if (!strcmp(parameter_name, "leaseTime")) { ipDiscConfig.leaseTime = atoi ( parameter_value ); } else if (!strcmp(parameter_name, "leaseFile")) { ipDiscConfig.leaseFile = parameter_value; } else if (!strcmp(parameter_name, "numberOfIpAddressesToFind")){ ipDiscConfig.nOfAddresses = atoi ( parameter_value ); } else if (!strcmp(parameter_name, "dhcpMsgRetransmitCount")){ ipDiscConfig.dhcpMsgRetransmitCount = atoi ( parameter_value ); } else if (!strcmp(parameter_name, "dhcpMsgRetransmitPeriodInms")){ ipDiscConfig.dhcpMsgRetransmitPeriodInms = atoi ( parameter_value ); } else if (!strcmp(parameter_name, "dhcpMaxParallelRequestCount")){ ipDiscConfig.dhcpMaxParallelRequestCount = atoi ( parameter_value ); } else if (!strcmp(parameter_name, "dhcpTimeout")){ ipDiscConfig.dhcpTimeout = atoi ( parameter_value ); } else if (!strcmp(parameter_name, "arpMsgRetransmitCount")){ ipDiscConfig.arpMsgRetransmitCount = atoi ( parameter_value ); } else if (!strcmp(parameter_name, "arpMsgRetransmitPeriodInms")){ ipDiscConfig.arpMsgRetransmitPeriodInms = atoi ( parameter_value ); } else if (!strcmp(parameter_name, "arpMaxParallelRequestCount")){ ipDiscConfig.arpMaxParallelRequestCount = atoi ( parameter_value ); } else if (!strcmp(parameter_name, "tcpReuseAddress")){ if (!strcasecmp(parameter_value,"YES")) globalConnOpts.tcpReuseAddr = GlobalConnOpts::YES; else if (!strcasecmp(parameter_value,"NO")) globalConnOpts.tcpReuseAddr = GlobalConnOpts::NO; }else if (!strcmp(parameter_name, "sslReuseAddress")){ if (!strcasecmp(parameter_value,"YES")) globalConnOpts.tcpReuseAddr = GlobalConnOpts::YES; else if (!strcasecmp(parameter_value,"NO")) globalConnOpts.tcpReuseAddr = GlobalConnOpts::NO; } else if (!strcmp(parameter_name, "udpReuseAddress")){ if (!strcasecmp(parameter_value,"YES")) globalConnOpts.udpReuseAddr = GlobalConnOpts::YES; else if (!strcasecmp(parameter_value,"NO")) globalConnOpts.udpReuseAddr = GlobalConnOpts::NO; } else if (!strcmp(parameter_name, "sctpReuseAddress")){ if (!strcasecmp(parameter_value,"YES")) globalConnOpts.sctpReuseAddr = GlobalConnOpts::YES; else if (!strcasecmp(parameter_value,"NO")) globalConnOpts.sctpReuseAddr = GlobalConnOpts::NO; } else if (!strcmp(parameter_name, "tcpKeepAlive")){ if (!strcasecmp(parameter_value,"YES")) globalConnOpts.tcpKeepAlive = GlobalConnOpts::YES; else if (!strcasecmp(parameter_value,"NO")) globalConnOpts.tcpKeepAlive = GlobalConnOpts::NO; } else if (!strcmp(parameter_name, "tcpKeepCount")){ globalConnOpts.tcpKeepCnt = atoi ( parameter_value ); } else if (!strcmp(parameter_name, "tcpKeepIdle")){ globalConnOpts.tcpKeepIdle = atoi ( parameter_value ); } else if (!strcmp(parameter_name, "tcpKeepInterval")){ globalConnOpts.tcpKeepIntvl = atoi ( parameter_value ); } else if (!strcmp(parameter_name, "sslKeepAlive")){ if (!strcasecmp(parameter_value,"YES")) globalConnOpts.tcpKeepAlive = GlobalConnOpts::YES; else if (!strcasecmp(parameter_value,"NO")) globalConnOpts.tcpKeepAlive = GlobalConnOpts::NO; } else if (!strcmp(parameter_name, "sslKeepCount")){ globalConnOpts.tcpKeepCnt = atoi ( parameter_value ); } else if (!strcmp(parameter_name, "sslKeepIdle")){ globalConnOpts.tcpKeepIdle = atoi ( parameter_value ); } else if (!strcmp(parameter_name, "sslKeepInterval")){ globalConnOpts.tcpKeepIntvl = atoi ( parameter_value ); } else if (!strcmp(parameter_name, "extendedPortEvents")){ if (!strcasecmp(parameter_value,"YES")) globalConnOpts.extendedPortEvents = GlobalConnOpts::YES; else if (!strcasecmp(parameter_value,"NO")) globalConnOpts.extendedPortEvents = GlobalConnOpts::NO; } else if (!strcmp(parameter_name, "sinit_num_ostreams")){ //sctp specific params starts here globalConnOpts.sinit_num_ostreams = atoi ( parameter_value ); } else if (!strcmp(parameter_name, "sinit_max_instreams")){ globalConnOpts.sinit_max_instreams = atoi ( parameter_value ); } else if (!strcmp(parameter_name, "sinit_max_attempts")){ globalConnOpts.sinit_max_attempts = atoi ( parameter_value ); } else if (!strcmp(parameter_name, "sinit_max_init_timeo")){ globalConnOpts.sinit_max_init_timeo = atoi ( parameter_value ); } else if (!strcmp(parameter_name, "sctp_data_io_event")){ if (!strcasecmp(parameter_value,"YES")) globalConnOpts.sctp_data_io_event = GlobalConnOpts::YES; else if (!strcasecmp(parameter_value,"NO")) globalConnOpts.sctp_data_io_event = GlobalConnOpts::NO; } else if (!strcmp(parameter_name, "sctp_association_event")){ if (!strcasecmp(parameter_value,"YES")) globalConnOpts.sctp_association_event = GlobalConnOpts::YES; else if (!strcasecmp(parameter_value,"NO")) globalConnOpts.sctp_association_event = GlobalConnOpts::NO; } else if (!strcmp(parameter_name, "sctp_address_event")){ if (!strcasecmp(parameter_value,"YES")) globalConnOpts.sctp_address_event = GlobalConnOpts::YES; else if (!strcasecmp(parameter_value,"NO")) globalConnOpts.sctp_address_event = GlobalConnOpts::NO; } else if (!strcmp(parameter_name, "sctp_send_failure_event")){ if (!strcasecmp(parameter_value,"YES")) globalConnOpts.sctp_send_failure_event = GlobalConnOpts::YES; else if (!strcasecmp(parameter_value,"NO")) globalConnOpts.sctp_send_failure_event = GlobalConnOpts::NO; } else if (!strcmp(parameter_name, "sctp_peer_error_event")){ if (!strcasecmp(parameter_value,"YES")) globalConnOpts.sctp_peer_error_event = GlobalConnOpts::YES; else if (!strcasecmp(parameter_value,"NO")) globalConnOpts.sctp_peer_error_event = GlobalConnOpts::NO; } else if (!strcmp(parameter_name, "sctp_shutdown_event")){ if (!strcasecmp(parameter_value,"YES")) globalConnOpts.sctp_shutdown_event = GlobalConnOpts::YES; else if (!strcasecmp(parameter_value,"NO")) globalConnOpts.sctp_shutdown_event = GlobalConnOpts::NO; } else if (!strcmp(parameter_name, "sctp_partial_delivery_event")){ if (!strcasecmp(parameter_value,"YES")) globalConnOpts.sctp_partial_delivery_event = GlobalConnOpts::YES; else if (!strcasecmp(parameter_value,"NO")) globalConnOpts.sctp_partial_delivery_event = GlobalConnOpts::NO; } else if (!strcmp(parameter_name, "sctp_adaptation_layer_event")){ if (!strcasecmp(parameter_value,"YES")) globalConnOpts.sctp_adaptation_layer_event = GlobalConnOpts::YES; else if (!strcasecmp(parameter_value,"NO")) globalConnOpts.sctp_adaptation_layer_event = GlobalConnOpts::NO; } else if (!strcmp(parameter_name, "sctp_authentication_event")){ if (!strcasecmp(parameter_value,"YES")) globalConnOpts.sctp_authentication_event = GlobalConnOpts::YES; else if (!strcasecmp(parameter_value,"NO")) globalConnOpts.sctp_authentication_event = GlobalConnOpts::NO; } #ifdef SCTP_SENDER_DRY_EVENT else if (!strcmp(parameter_name, "sctp_sender_dry_event")){ if (!strcasecmp(parameter_value,"YES")) globalConnOpts.sctp_sender_dry_event = GlobalConnOpts::YES; else if (!strcasecmp(parameter_value,"NO")) globalConnOpts.sctp_sender_dry_event = GlobalConnOpts::NO; } #endif else if (!strcmp(parameter_name, "sctp_connection_method")){ if (!strcasecmp(parameter_value,"METHOD_0")) globalConnOpts.connection_method = GlobalConnOpts::METHOD_ZERO; else if (!strcasecmp(parameter_value,"METHOD_1")) globalConnOpts.connection_method = GlobalConnOpts::METHOD_ONE; else if (!strcasecmp(parameter_value,"METHOD_2")) globalConnOpts.connection_method = GlobalConnOpts::METHOD_TWO; } else if (!strcmp(parameter_name, "sctp_stack")){ if (!strcasecmp(parameter_value,"kernel")) native_stack=TRUE; else if (!strcasecmp(parameter_value,"EIN")) native_stack=FALSE; } else if(!strcmp(parameter_name,"broadcast")){ if (!strcasecmp(parameter_value,"enabled")) broadcast = true; else if (!strcasecmp(parameter_value,"disabled")) broadcast = false; else { broadcast = false; TTCN_warning("IPL4asp__PT::set_parameter(): Unsupported Test Port parameter value: %s", parameter_value); } } else if (!strcmp(parameter_name, "SSLv2")){ if (!strcasecmp(parameter_value,"YES")) globalConnOpts.ssl_supp.SSLv2 = GlobalConnOpts::YES; else if (!strcasecmp(parameter_value,"NO")) globalConnOpts.ssl_supp.SSLv2 = GlobalConnOpts::NO; } else if (!strcmp(parameter_name, "SSLv3")){ if (!strcasecmp(parameter_value,"YES")) globalConnOpts.ssl_supp.SSLv3 = GlobalConnOpts::YES; else if (!strcasecmp(parameter_value,"NO")) globalConnOpts.ssl_supp.SSLv3 = GlobalConnOpts::NO; } else if (!strcmp(parameter_name, "TLSv1")){ if (!strcasecmp(parameter_value,"YES")) globalConnOpts.ssl_supp.TLSv1 = GlobalConnOpts::YES; else if (!strcasecmp(parameter_value,"NO")) globalConnOpts.ssl_supp.TLSv1 = GlobalConnOpts::NO; } else if (!strcmp(parameter_name, "TLSv1_1")){ if (!strcasecmp(parameter_value,"YES")) globalConnOpts.ssl_supp.TLSv1_1 = GlobalConnOpts::YES; else if (!strcasecmp(parameter_value,"NO")) globalConnOpts.ssl_supp.TLSv1_1 = GlobalConnOpts::NO; } else if (!strcmp(parameter_name, "TLSv1_2")){ if (!strcasecmp(parameter_value,"YES")) globalConnOpts.ssl_supp.TLSv1_2 = GlobalConnOpts::YES; else if (!strcasecmp(parameter_value,"NO")) globalConnOpts.ssl_supp.TLSv1_2 = GlobalConnOpts::NO; } else if (!strcmp(parameter_name, "DTLSv1")){ if (!strcasecmp(parameter_value,"YES")) globalConnOpts.ssl_supp.DTLSv1 = GlobalConnOpts::YES; else if (!strcasecmp(parameter_value,"NO")) globalConnOpts.ssl_supp.DTLSv1 = GlobalConnOpts::NO; } else if (!strcmp(parameter_name, "DTLSv1_2")){ if (!strcasecmp(parameter_value,"YES")) globalConnOpts.ssl_supp.DTLSv1_2 = GlobalConnOpts::YES; else if (!strcasecmp(parameter_value,"NO")) globalConnOpts.ssl_supp.DTLSv1_2 = GlobalConnOpts::NO; } else if (!strcmp(parameter_name, "TLS_CERT_PER_CONN")){ if (!strcasecmp(parameter_value,"YES")) ssl_cert_per_conn= true; else ssl_cert_per_conn= false; } #ifdef USE_IPL4_EIN_SCTP else if(!strcasecmp("cpManagerIPA", parameter_name)) { cpManagerIPA = parameter_value; } else if (!strcmp(parameter_name, "USERID")){ if(!SS7Common::handle_parameter(parameter_name, parameter_value, &userId)) { TTCN_error("IPL4asp__PT::set_parameter(): Invalid user ID."); } } else if(strcasecmp("userInstanceId", parameter_name) == 0) { int uinst = atoi(parameter_value); if(uinst < 0 || uinst > 255) { log_warning("Wrong userInstanceId parameter value: %s, Must be an integer between 0 and 255 ", parameter_value); } else { userInstanceId = uinst; userInstanceIdSpecified = true; if(!sctpInstanceIdSpecified) sctpInstanceId = userInstanceId; } } else if(strcasecmp("sctpInstanceId", parameter_name) == 0) { int tinst = atoi(parameter_value); if(tinst < 0 || tinst > 255) { log_warning("Wrong sctpInstanceId parameter value: %s, Must be an integer between 0 and 255 ", parameter_value); } else { sctpInstanceId = tinst; sctpInstanceIdSpecified = true; } } #endif //SSL params #ifdef IPL4_USE_SSL else if(strcmp(parameter_name, ssl_use_session_resumption_name()) == 0) { if(strcasecmp(parameter_value, "yes") == 0) ssl_use_session_resumption = true; else if(strcasecmp(parameter_value, "no") == 0) ssl_use_session_resumption = false; else log_warning("Parameter value '%s' not recognized for parameter '%s'", parameter_value, ssl_use_session_resumption_name()); } else if(strcmp(parameter_name, ssl_private_key_file_name()) == 0) { delete [] ssl_key_file; ssl_key_file=new char[strlen(parameter_value)+1]; strcpy(ssl_key_file, parameter_value); } else if(strcmp(parameter_name, ssl_trustedCAlist_file_name()) == 0) { delete [] ssl_trustedCAlist_file; ssl_trustedCAlist_file=new char[strlen(parameter_value)+1]; strcpy(ssl_trustedCAlist_file, parameter_value); } else if(strcmp(parameter_name, ssl_certificate_file_name()) == 0) { delete [] ssl_certificate_file; ssl_certificate_file=new char[strlen(parameter_value)+1]; strcpy(ssl_certificate_file, parameter_value); } else if(strcmp(parameter_name, ssl_cipher_list_name()) == 0) { delete [] ssl_cipher_list; ssl_cipher_list=new char[strlen(parameter_value)+1]; strcpy(ssl_cipher_list, parameter_value); } else if(strcmp(parameter_name, ssl_password_name()) == 0) { ssl_password=new char[strlen(parameter_value)+1]; strcpy(ssl_password, parameter_value); } else if(strcmp(parameter_name, ssl_verifycertificate_name()) == 0) { if(strcasecmp(parameter_value, "yes") == 0) ssl_verify_certificate = true; else if(strcasecmp(parameter_value, "no") == 0) ssl_verify_certificate = false; else log_warning("Parameter value '%s' not recognized for parameter '%s'", parameter_value, ssl_verifycertificate_name()); } else if (!strcmp(parameter_name, "ssl_reconnect_attempts")){ ssl_reconnect_attempts = atoi ( parameter_value ); } else if (!strcmp(parameter_name, "ssl_reconnect_delay")){ ssl_reconnect_delay = atoi ( parameter_value ); } else if(strcmp(parameter_name,psk_identity_name()) == 0) { psk_identity=new char[strlen(parameter_value)+1]; strcpy(psk_identity, parameter_value); } else if(strcmp(parameter_name,psk_identity_hint_name()) == 0) { psk_identity_hint=new char[strlen(parameter_value)+1]; strcpy(psk_identity_hint, parameter_value); } else if(strcmp(parameter_name, psk_key_name()) == 0) { psk_key=new char[strlen(parameter_value)+1]; strcpy(psk_key, parameter_value); } #endif else if (!strcasecmp(parameter_name, "noDelay")) { if (!strcasecmp(parameter_value,"YES")) { globalConnOpts.tcp_nodelay = GlobalConnOpts::YES; globalConnOpts.sctp_nodelay = GlobalConnOpts::YES; } } else if (!strcmp(parameter_name, "dscp")){ int idscp = atoi(parameter_value); if(idscp < 0 || idscp > 56) { log_warning("Wrong dscp parameter value: %s, Must be an integer between 0 and 56 ", parameter_value); } else { globalConnOpts.dscp = idscp; } } // else if ( next param ) ... } // IPL4asp__PT_PROVIDER::set_parameter void IPL4asp__PT_PROVIDER::Handle_Fd_Event_Writable(int fd) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Writable: fd: %i", fd); std::map::iterator it = fd2IndexMap.find(fd); if (pureNonBlocking) { if (it != fd2IndexMap.end()) { //Add SSL layer #ifdef IPL4_USE_SSL IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Writable: client? %s sslState: %i", sockList[it->second].ssl_tls_type == CLIENT ? "yes" : "no", sockList[it->second].sslState); if(sockList[it->second].ssl_tls_type != NONE && sockList[it->second].type != IPL4asp_SCTP) { switch(sockList[it->second].sslState){ case STATE_WAIT_FOR_RECEIVE_CALLBACK: sockList[it->second].sslState = STATE_NORMAL; Handler_Remove_Fd_Write(fd); IPL4_DEBUG("DONT WRITE ON %i", fd); return; case STATE_CONNECTING: case STATE_HANDSHAKING: { switch(perform_ssl_handshake(it->second)) { case FAIL: IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Writable: SSL mapping failed for client socket: %d", sockList[it->second].sock); sendError(PortError::ERROR__SOCKET, it->second); if (ConnDel(it->second) == -1) IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Writable: unable to close socket"); return; case WANT_READ: IPL4_DEBUG("DONT WRITE ON %i", fd); Handler_Remove_Fd_Write(fd); return; case WANT_WRITE: return; case SUCCESS: //if success, then the handshake is over, we are done break; default: IPL4_DEBUG( "IPL4asp__PT_PROVIDER::Handle_Fd_Event_Writable: perform_ssl_handshake return value is not handled!"); } sockList[it->second].sslState = STATE_NORMAL; IPL4_DEBUG("DONT WRITE ON %i", fd); Handler_Remove_Fd_Write(fd); if(sockList[it->second].server) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Writable: Client connection Accepted."); reportConnOpened(it->second); } else { sendError(PortError::ERROR__AVAILABLE, it->second); } IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Writable: Leave."); return; } default: IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Writable: Unhandled SSL State %d . Client: %d", sockList[it->second].sslState, it->second); Handler_Remove_Fd_Write(fd); IPL4_DEBUG("DONT WRITE ON %i", fd); IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Writable: Leave."); return; } } else if(sockList[it->second].ssl_tls_type != NONE && sockList[it->second].type == IPL4asp_SCTP) { Handler_Remove_Fd_Write(fd); IPL4_DEBUG("DONT WRITE ON %i", fd); return; } #endif Handler_Remove_Fd_Write(fd); IPL4_DEBUG("DONT WRITE ON %i", fd); sendError(PortError::ERROR__AVAILABLE, it->second); } else IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Writable: Error: fd not found"); } else IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Writable: Error: pureNonBlocking is FALSE"); IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Writable: Leave."); } void IPL4asp__PT_PROVIDER::Handle_Fd_Event_Error(int fd) { // The error events are handled as readable event. Handle_Fd_Event_Readable(fd); } void IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable(int fd) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: enter, fd: %i", fd); #ifdef USE_IPL4_EIN_SCTP if(!native_stack && (fd == pipe_to_TTCN_thread_fds[0] || fd == pipe_to_TTCN_thread_log_fds[0])){ handle_message_from_ein(fd); return; } #endif std::map::iterator it = fd2IndexMap.find(fd); if (it == fd2IndexMap.end()) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: Error: fd not found"); return; } int connId = it->second; IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: connId: %d READABLE sock: %i, type: %i, sslState: %i", connId, sockList[connId].sock, sockList[connId].type, sockList[connId].sslState); ASP__RecvFrom asp; asp.connId() = connId; asp.userData() = sockList[connId].userData; asp.remName() = *(sockList[connId].remoteaddr); asp.remPort() = *(sockList[connId].remoteport); asp.locName() = *(sockList[connId].localaddr); asp.locPort() = *(sockList[connId].localport); asp.proto().tcp() = TcpTuple(null_type()); // Identify local socket SockAddr sa; socklen_t saLen = sizeof(SockAddr); // Handle active socket int len = -3; unsigned char buf[RECV_MAX_LEN]; #ifdef IPL4_USE_SSL int ssl_err_msg = 0; #endif if((sockList[connId].ssl_tls_type != NONE) and ((sockList[connId].sslState == STATE_CONNECTING) || (sockList[connId].sslState == STATE_HANDSHAKING))) { // 1st branch: handle SSL/TLS handshake if(sockList[connId].type == IPL4asp_UDP) { asp.proto().dtls().udp() = UdpTuple(null_type()); } else { asp.proto().ssl() = SslTuple(null_type()); } #ifdef IPL4_USE_SSL if(sockList[connId].server) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: incoming SSL connection..."); if (ssl_verify_certificate && ((sockList[connId].ssl_trustedCAlist_file==NULL && ssl_cert_per_conn) || (ssl_trustedCAlist_file==NULL && !ssl_cert_per_conn))) { IPL4_DEBUG("%s is not defined in the configuration file although %s=yes", ssl_trustedCAlist_file_name(), ssl_verifycertificate_name()); sendError(PortError::ERROR__SOCKET, connId); } if(sockList[connId].type == IPL4asp_UDP) { #ifdef SRTP_AES128_CM_SHA1_80 // DTLS listen & accept the incoming connection SockAddr sa_client; int ret = DTLSv1_listen(sockList[connId].sslObj, #if OPENSSL_VERSION_NUMBER >= 0x10100000L (BIO_ADDR*) #endif &sa_client); IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: DTLSv1_listen exited with ret.value %d", ret); if(ret <= 0) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: not enough data for DTLSv1_listen..."); ssl_getresult(ret); return; } // if UDP/DTLS server, then create a new socket for the incoming connection // get the listening socket parameters if(!getsockname(sockList[connId].sock, (struct sockaddr *)&sa, &saLen)) { int client_fd = socket(((struct sockaddr *)&sa)->sa_family, SOCK_DGRAM, 0); int reuse = 1; setsockopt(client_fd, SOL_SOCKET, SO_REUSEADDR, (const void*) &reuse, (socklen_t) sizeof(reuse)); if (fcntl(client_fd, F_SETFL, O_NONBLOCK) == -1) { TTCN_warning("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: fcntl O_NONBLOCK on socket %d failed: %s", client_fd, strerror(errno)); close(client_fd); sendError(PortError::ERROR__SOCKET, fd, errno); return; } if(bind(client_fd, (struct sockaddr *)&sa, saLen) < 0) { TTCN_warning("Binding to the incoming DTLS connection's local server socket failed!"); close(client_fd); sendError(PortError::ERROR__SOCKET, fd, errno); return; } if(connect(client_fd, (struct sockaddr *) (struct sockaddr *)&sa_client, saLen) < 0) { TTCN_warning("Connecting from the incoming DTLS connection's local server socket failed!"); close(client_fd); sendError(PortError::ERROR__SOCKET, fd, errno); return; } int clientConnId = ConnAdd(IPL4asp_UDP, client_fd, SERVER,NULL,connId); // client's bio is the read bio of the server sockList[clientConnId].bio = SSL_get_rbio(sockList[connId].sslObj); BIO_set_fd(sockList[clientConnId].bio, client_fd, BIO_NOCLOSE); BIO_ctrl(sockList[clientConnId].bio, BIO_CTRL_DGRAM_SET_CONNECTED, 0, &sa_client); // set the server's SSL obj into the new client sockList[clientConnId].sslObj = sockList[connId].sslObj; // if(sockList[connId].dtlsSrtpProfiles) { // Done by the ConnAdd // // set the server's dtls srtp profiles into the accepted client // // we could use strdup, but let's stick to Malloc if we want TITAN memory debug // int len = strlen(sockList[connId].dtlsSrtpProfiles); // sockList[clientConnId].dtlsSrtpProfiles = (char*)Malloc(len + 1); // memcpy(sockList[clientConnId].dtlsSrtpProfiles, sockList[connId].dtlsSrtpProfiles, len); // IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: dtlsSrtpProfiles %s is set for the accepted client connId: %d", sockList[clientConnId].dtlsSrtpProfiles, clientConnId); // } // this connection will be client + SSL SERVER sockList[clientConnId].server = false; sockList[clientConnId].ssl_tls_type = SERVER; if (!SetNameAndPort(&sa_client, saLen, *(sockList[clientConnId].remoteaddr), *(sockList[clientConnId].remoteport))) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: SetNameAndPort failed"); sendError(PortError::ERROR__HOSTNAME, clientConnId); } // now restart the TLS on the server connId Socket__API__Definitions::Result result(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE); starttls(connId, true, result); // continue the handshake with the client connId connId = clientConnId; set_dscp_option(sockList[connId].sock); IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: client connection accepted on fd:%d/connId:%d; continuing with the handshake...", client_fd, clientConnId); } else { TTCN_warning("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: could not get current socket parameters"); return; } #else TTCN_error("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: DTLS is not supported by the current OpenSSL API. libopenssl >=1.0.1 is required!"); #endif } } switch(perform_ssl_handshake(connId)) { case SUCCESS: //if success continue sockList[it->second].sslState = STATE_NORMAL; break; case FAIL: IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: SSL mapping failed for client socket: %d", connId); sendError(PortError::ERROR__SOCKET, it->second); sendConnClosed(connId, asp.remName(), asp.remPort(), asp.locName(), asp.locPort(), asp.proto(), asp.userData()); if (ConnDel(connId) == -1) IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: unable to close socket"); return; case WANT_READ: case WANT_WRITE: return; default: IPL4_DEBUG( "IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: perform_ssl_handshake return value is not handled!"); } if(sockList[connId].ssl_tls_type == SERVER) { IPL4_DEBUG( "IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: our server accepted an incoming %s connection.", sockList[connId].type == IPL4asp_UDP ? "DTLS" : "SSL"); reportConnOpened(connId); if((sockList[connId].type == IPL4asp_SCTP) || (sockList[connId].type == IPL4asp_SCTP_LISTEN)) sockList[connId].sctpHandshakeCompletedBeforeDtls = true; } else { IPL4_DEBUG( "IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: our client established a %s connection.", sockList[connId].type == IPL4asp_UDP ? "DTLS" : "SSL"); sendError(PortError::ERROR__AVAILABLE, connId); if((sockList[connId].type == IPL4asp_SCTP) || (sockList[connId].type == IPL4asp_SCTP_LISTEN)) sockList[connId].sctpHandshakeCompletedBeforeDtls = true; } #endif //IPL4_USE_SSL } else if((sockList[connId].type == IPL4asp_TCP_LISTEN) || (sockList[connId].type == IPL4asp_SCTP_LISTEN)) { // 2nd branch: handle TCP/SCTP server accept IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: incoming connection requested"); int sock = accept(sockList[connId].sock, (struct sockaddr *)&sa, &saLen); if (sock == -1) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: tcp accept error: %s", strerror(errno)); sendError(PortError::ERROR__SOCKET, connId, errno); return; } else { if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: fcntl O_NONBLOCK on socket %d failed: %s", sock, strerror(errno)); close(sock); sendError(PortError::ERROR__SOCKET, sock, errno); return; } } int k; if(sockList[connId].type == IPL4asp_SCTP_LISTEN) { #ifdef USE_SCTP k = ConnAdd(IPL4asp_SCTP, sock, sockList[connId].ssl_tls_type, NULL ,connId); #else sendError(PortError::ERROR__UNSUPPORTED__PROTOCOL, sockList[connId].sock); return; #endif } else { // TCP_LISTEN k = ConnAdd(IPL4asp_TCP, sock, sockList[connId].ssl_tls_type == SERVER ? CLIENT : NONE, NULL, connId); } if ( k == -1) { sendError(PortError::ERROR__INSUFFICIENT__MEMORY, connId); return; } #ifdef IPL4_USE_SSL if((sockList[connId].ssl_tls_type == SERVER) && (sockList[connId].type == IPL4asp_TCP_LISTEN)) { Socket__API__Definitions::Result result(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE); starttls(k, true, result); } #endif // if we are not doing SSL, then report the connection opened // if SSL is also triggered, we will report the connOpened at the end of the handshake if(sockList[connId].ssl_tls_type == NONE) { reportConnOpened(k); } } else { // 3rd branch: normal data receiving switch (sockList[connId].type) { case IPL4asp_UDP: { IPL4_DEBUG( "IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: udp message received"); // normal UDP receiving first if((sockList[connId].ssl_tls_type == NONE) || // if DTLS+SRTP, then no demultiplex yet, just pass the incoming packet as UDP to the testcase ((sockList[connId].dtlsSrtpProfiles != NULL) && (sockList[connId].sslState == STATE_NORMAL))) { asp.proto().udp() = UdpTuple(null_type()); len = recvfrom(sockList[connId].sock, buf, RECV_MAX_LEN, 0, (struct sockaddr *)&sa, &saLen); if ((len >= 0) && !SetNameAndPort(&sa, saLen, asp.remName(), asp.remPort())) sendError(PortError::ERROR__HOSTNAME, connId); } #ifdef IPL4_USE_SSL // nice DTLS is coming else { asp.proto().dtls().udp() = UdpTuple(null_type()); len = receive_ssl_message_on_fd(connId, &ssl_err_msg); } #endif if (len == -1) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: udp recvfrom error: %s", strerror(errno)); sendError(PortError::ERROR__SOCKET, connId, errno); break; } else if((len == -2) and (sockList[connId].ssl_tls_type != NONE)) { // if SSL is reporting block for sending switch (sockList[connId].sslState) { case STATE_BLOCK_FOR_SENDING: IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: state is STATE_BLOCK_FOR_SENDING, don't close connection."); Handler_Remove_Fd_Read(connId); sockList[connId].sslState = STATE_DONT_CLOSE; IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: setting socket state to STATE_DONT_CLOSE"); break; case STATE_DONT_CLOSE: IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: state is STATE_DONT_CLOSE, don't close connection."); break; default: break; } } else if((len == 0 #ifdef IPL4_USE_SSL || ssl_err_msg == SSL_ERROR_ZERO_RETURN #endif ) and (sockList[connId].ssl_tls_type != NONE)) { reportRemainingData_beforeConnClosed(connId, asp.remName(), asp.remPort(), asp.locName(), asp.locPort(), asp.proto(), asp.userData()); sendConnClosed(connId, asp.remName(), asp.remPort(), asp.locName(), asp.locPort(), asp.proto(), asp.userData()); if (ConnDel(connId) == -1) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: ConnDel failed"); } } if(len > 0) { if(sockList[connId].ssl_tls_type == NONE) { asp.msg() = OCTETSTRING(len, buf); incoming_message(asp); } else { // throw warning if connId is SRTP & the incoming packet is DTLS if(sockList[connId].dtlsSrtpProfiles != NULL) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: first byte is %d.", (*buf)); if((*buf > 19) && (*buf < 64)) { // this is the DTLS range according to http://tools.ietf.org/html/rfc5764#section-5.1.2 // TODO FIXME: here we shall find a way how to decrypt the buffer (incoming DTLS) with the sockList[connId].ssl TTCN_warning("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: DTLS received on connId: %d, but demultiplexing is not implemented! Throwing the packet away...", connId); break; } else { // ordinary UDP (DTLS+SRTP or DTLS + STUN) asp.msg() = OCTETSTRING(len, buf); } } else { // no fragmentation in UDP, DTLS neither. no need to call the getMsgLen asp.msg() = OCTETSTRING(len, sockList[connId].buf[0]->get_data()); sockList[connId].buf[0]->set_pos((size_t)len); sockList[connId].buf[0]->cut(); } incoming_message(asp); } } break; } case IPL4asp_TCP_LISTEN: {break;} // IPL4asp_TCP_LISTEN case IPL4asp_TCP: { memset(&sa, 0, saLen); if(sockList[connId].ssl_tls_type == NONE) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: TCP recvfrom enter:"); asp.proto().tcp() = TcpTuple(null_type()); len = recv(sockList[connId].sock, buf, RECV_MAX_LEN, 0); } #ifdef IPL4_USE_SSL else { IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: SSL recvfrom enter:"); asp.proto().ssl() = SslTuple(null_type()); if (!isConnIdValid(connId)) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::receive_message_on_fd: invalid connId: %connId", connId); break; } len = receive_ssl_message_on_fd(connId, &ssl_err_msg); } #endif if (len > 0) { // in normal case, this is where we put the incoming data in the buffer // in SSL case, the receive_ssl_message_on_fd() already placed it there if(sockList[connId].ssl_tls_type == NONE) { (*sockList[connId].buf)->put_s(len, buf); } bool msgFound = false; do { if (sockList[connId].getMsgLen != simpleGetMsgLen) { if (sockList[connId].msgLen == -1){ OCTETSTRING oct; (*sockList[connId].buf)->get_string(oct); sockList[connId].msgLen = sockList[connId].getMsgLen.invoke(oct,*sockList[connId].msgLenArgs); } } else { sockList[connId].msgLen = (*sockList[connId].buf)->get_len(); if(!alreadyComplainedAboutMsgLen && (sockList[connId].type == IPL4asp_TCP)) { TTCN_warning("There is no GetMsgLen function registered for connId: %d. The messages will not be dissected on this connection! This warning is logged only once per testport.", connId); alreadyComplainedAboutMsgLen = true; } } if(sockList[connId].msgLen == 0) { // The GetMsgLen function should not return 0. // If it returns 0, then we log what we can, and stop the component. OCTETSTRING oct; (*sockList[connId].buf)->get_string(oct); TTCN_Logger::begin_event(TTCN_ERROR); TTCN_Logger::log_event("%s: MsgLen calculation function returned 0 on connection %s:%u <-> %s:%u. Received data: ", get_name(), (const char*)*sockList[connId].localaddr, (unsigned int)sockList[connId].localport->get_long_long_val(), (const char*)*sockList[connId].remoteaddr, (unsigned int)sockList[connId].remoteport->get_long_long_val()); oct.log(); TTCN_Logger::end_event(); errno = EDEADLK; TTCN_error("MsgLen returned 0"); } else if (sockList[connId].msgLen == -2){ // The GetMsgLen function returned -2 means // it is impossible to determine the length of the message -> report & close OCTETSTRING oct; (*sockList[connId].buf)->get_string(oct); TTCN_Logger::begin_event(TTCN_WARNING); TTCN_Logger::log_event("%s: MsgLen calculation function reported length calculation error on connection %s:%u <-> %s:%u. Received data: ", get_name(), (const char*)*sockList[connId].localaddr, (unsigned int)sockList[connId].localport->get_long_long_val(), (const char*)*sockList[connId].remoteaddr, (unsigned int)sockList[connId].remoteport->get_long_long_val()); oct.log(); TTCN_Logger::end_event(); errno = EDEADLK; sendError(PortError::ERROR__LENGTH, connId, errno); // close the connection len = 0; // leave the loop and close the connection in the code below break; } else { msgFound = (sockList[connId].msgLen != -1) && (sockList[connId].msgLen <= (int)sockList[connId].buf[0]->get_len()); if (msgFound) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: message length: (%d/%d bytes)\n", sockList[connId].msgLen, (int)sockList[connId].buf[0]->get_len()); asp.msg() = OCTETSTRING(sockList[connId].msgLen, sockList[connId].buf[0]->get_data()); sockList[connId].buf[0]->set_pos((size_t)sockList[connId].msgLen); sockList[connId].buf[0]->cut(); if(lazy_conn_id_level && sockListCnt==1 && lonely_conn_id!=-1){ asp.connId()=-1; } incoming_message(asp); sockList[connId].msgLen = -1; } } } while (msgFound && sockList[connId].buf[0]->get_len() != 0); if (sockList[connId].buf[0]->get_len() != 0) IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: incomplete message (%d bytes)\n", (int)sockList[connId].buf[0]->get_len()); } // NOTE: after this if, we will also enter the connClosed part with len == 0 or len == -1 // and automatically perform connection closing in case of socket error if (len == -1) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: %s recvfrom error: %s", sockList[connId].ssl_tls_type == NONE ? "tcp" : "ssl", strerror(errno)); sendError(PortError::ERROR__SOCKET, connId, errno); } /* else if (len == -2) => means that reading would block in SSL case. in this case I stop receiving message on the file descriptor, do nothing */ if ((len == 0) || (len == -1) #ifdef IPL4_USE_SSL || (ssl_err_msg == SSL_ERROR_ZERO_RETURN) #endif ) { // peer disconnected IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: " "peer closed connection %d, fd: %d", connId, sockList[connId].sock); bool dontCloseConn = false; if(sockList[connId].ssl_tls_type == NONE) { closingPeer = sa; closingPeerLen = saLen; if (connId == dontCloseConnectionId) { //close(sockList[connId].sock); IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: closing connection %d" " postponed due to nonblocking send operation", connId); dontCloseConn = true; break; } } #ifdef IPL4_USE_SSL else { // SSL case switch (sockList[connId].sslState) { case STATE_BLOCK_FOR_SENDING: IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: state is STATE_BLOCK_FOR_SENDING, don't close connection."); Handler_Remove_Fd_Read(connId); sockList[connId].sslState = STATE_DONT_CLOSE; IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: setting socket state to STATE_DONT_CLOSE"); dontCloseConn = true; break; case STATE_DONT_CLOSE: IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: state is STATE_DONT_CLOSE, don't close connection."); dontCloseConn = true; break; default: closingPeer = sa; closingPeerLen = saLen; if (connId == dontCloseConnectionId) { //close(sockList[connId].sock); IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: closing connection %d" " postponed due to nonblocking send operation", connId); dontCloseConn = true; } } // switch (client_data->reading_state) } #endif reportRemainingData_beforeConnClosed(connId, asp.remName(), asp.remPort(), asp.locName(), asp.locPort(), asp.proto(), asp.userData()); sendConnClosed(connId, asp.remName(), asp.remPort(), asp.locName(), asp.locPort(), asp.proto(), asp.userData()); if(!dontCloseConn) { if (ConnDel(connId) == -1) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: ConnDel failed"); } } closingPeerLen = 0; } break; } // IPL4asp_TCP case IPL4asp_SCTP_LISTEN: {break;} // IPL4asp_SCTP_LISTEN case IPL4asp_SCTP: { #ifdef USE_SCTP ASP__Event event; IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: sctp message received"); memset(&sa, 0, saLen); IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: sctp peername and sockname obtained"); int sock = sockList[connId].sock; ssize_t n = 0; size_t buflen = RECV_MAX_LEN; struct msghdr msg[1]; struct iovec iov[1]; struct cmsghdr *cmsg; struct sctp_sndrcvinfo *sri; char cbuf[sizeof (*cmsg) + sizeof (*sri)]; size_t cmsglen = sizeof (*cmsg) + sizeof (*sri); struct sockaddr_storage peer_addr; socklen_t peer_addr_len=sizeof(struct sockaddr_storage); /* Initialize the message header for receiving */ memset(msg, 0, sizeof (*msg)); memset(&peer_addr, 0, peer_addr_len); msg->msg_name=(void *)&peer_addr; msg->msg_namelen=peer_addr_len; msg->msg_control = cbuf; msg->msg_controllen = sizeof (*cmsg) + sizeof (*sri); msg->msg_flags = 0; memset(cbuf, 0, sizeof (*cmsg) + sizeof (*sri)); cmsg = (struct cmsghdr *)cbuf; sri = (struct sctp_sndrcvinfo *)(cmsg + 1); iov->iov_base = buf; iov->iov_len = RECV_MAX_LEN; msg->msg_iov = iov; msg->msg_iovlen = 1; #ifdef OPENSSL_SCTP_SUPPORT bool sctpNotification = false; #endif int getmsg_retv=getmsg(sock, connId, msg, buf, &buflen, &n, cmsglen); switch(getmsg_retv){ case IPL4_SCTP_WHOLE_MESSAGE_RECEIVED: { if(msg->msg_namelen){ char remaddr[46]; // INET6_ADDRSTRLEN memset(remaddr,0,46); if(peer_addr.ss_family==AF_INET){ struct sockaddr_in* remipv4addr=(struct sockaddr_in*)&peer_addr; if(inet_ntop(AF_INET,&(remipv4addr->sin_addr),remaddr,46)){ asp.remName()=remaddr; } } #ifdef USE_IPV6 else if(peer_addr.ss_family==AF_INET6){ struct sockaddr_in6* remipv6addr=(struct sockaddr_in6*)&peer_addr; if(inet_ntop(AF_INET6,&(remipv6addr->sin6_addr),remaddr,46)){ asp.remName()=remaddr; } } #endif } (*sockList[connId].buf)->put_s(n, buf); const unsigned char* atm=(*sockList[connId].buf)->get_data(); if (msg->msg_flags & MSG_NOTIFICATION) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: Notification received"); handle_event(sock, connId, atm); #ifdef IPL4_USE_SSL #ifdef OPENSSL_SCTP_SUPPORT sctpNotification = true; #endif union sctp_notification *snp; snp = (sctp_notification *)buf; if(snp->sn_header.sn_type == SCTP_ASSOC_CHANGE) { struct sctp_assoc_change *sac; sac = &snp->sn_assoc_change; if (sac->sac_state == SCTP_COMM_UP and sockList[connId].ssl_tls_type == SERVER and sockList[connId].sslState == STATE_NORMAL) { // now restart the TLS on the server connId Socket__API__Definitions::Result result(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE); starttls(connId, true, result); } } #ifdef SCTP_SENDER_DRY_EVENT // SCTP_SENDER_DRY_EVENT notifies that the SCTP stack has no more user data to send or retransmit (rfc6458). // This means that dtls DATA might be also received. #ifdef OPENSSL_SCTP_SUPPORT if(snp->sn_header.sn_type == SCTP_SENDER_DRY_EVENT) sctpNotification = false; #endif #endif if(snp->sn_header.sn_type == SCTP_SHUTDOWN_EVENT) { // Somehow the recvmsg with MSG_PEEK flag in getmsg returns values > 0 even in case of the SCTP Shutdown event // The connection close should be then triggered at this point IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: Socket is closed."); if (connId == dontCloseConnectionId) { closingPeer = sa; closingPeerLen = saLen; //close(sockList[connId].sock); IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: closing connection %d" " postponed due to nonblocking send operation", connId); return; } if(sockList[connId].ssl_tls_type == NONE || !sockList[connId].sctpHandshakeCompletedBeforeDtls){ asp.proto().sctp()=SctpTuple(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE); } else { // if the SCTP_SHUTDOWN_EVENT is received when DTLS is also used, the conn. closed will be evaluated at this point. // Thus, the DTLS-SCTP should be reported as protocol. asp.proto().dtls().sctp() = SctpTuple(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE); } sendConnClosed(connId, asp.remName(), asp.remPort(), asp.locName(), asp.locPort(), asp.proto(), asp.userData()); if (ConnDel(connId) == -1) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: ConnDel failed"); } closingPeerLen = 0; } #endif } else if(sockList[connId].ssl_tls_type == NONE || !sockList[connId].sctpHandshakeCompletedBeforeDtls) { IPL4_DEBUG("PL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: Incoming data (%ld bytes): stream = %hu, ssn = %hu, flags = %hx, ppid = %u \n", n, sri->sinfo_stream,(unsigned int)sri->sinfo_ssn, sri->sinfo_flags, sri->sinfo_ppid); INTEGER i_ppid; if (ntohl(sri->sinfo_ppid) <= (unsigned long)INT_MAX) i_ppid = ntohl(sri->sinfo_ppid); else { char sbuf[16]; sprintf(sbuf, "%u", ntohl(sri->sinfo_ppid)); i_ppid = INTEGER(sbuf); } asp.proto().sctp() = SctpTuple(sri->sinfo_stream, i_ppid, OMIT_VALUE, OMIT_VALUE); (*sockList[connId].buf)->get_string(asp.msg()); if(lazy_conn_id_level && sockListCnt==1 && lonely_conn_id!=-1){ asp.connId()=-1; } incoming_message(asp); } if(sockList[connId].buf) (*sockList[connId].buf)->clear(); } break; case IPL4_SCTP_PARTIAL_RECEIVE: IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: partial receive: %ld bytes", n); (*sockList[connId].buf)->put_s(n, buf); break; case IPL4_SCTP_ERROR_RECEIVED: IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: SCTP error, Socket is closed."); case IPL4_SCTP_EOF_RECEIVED: IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: Socket is closed."); if (connId == dontCloseConnectionId) { closingPeer = sa; closingPeerLen = saLen; //close(sockList[connId].sock); IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: closing connection %d" " postponed due to nonblocking send operation", connId); return; } if(sockList[connId].ssl_tls_type == NONE || !sockList[connId].sctpHandshakeCompletedBeforeDtls){ asp.proto().sctp()=SctpTuple(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE); } else { // if the SCTP_SHUTDOWN_EVENT is received when DTLS is also used, the conn. closed will be evaluated at this point. // Thus, the DTLS-SCTP should be reported as protocol. asp.proto().dtls().sctp() = SctpTuple(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE); } sendConnClosed(connId, asp.remName(), asp.remPort(), asp.locName(), asp.locPort(), asp.proto(), asp.userData()); #ifdef OPENSSL_SCTP_SUPPORT sctpNotification = true; #endif if (ConnDel(connId) == -1) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: ConnDel failed"); } closingPeerLen = 0; break; default: break; } #ifdef IPL4_USE_SSL #ifdef OPENSSL_SCTP_SUPPORT if(sockList[connId].sctpHandshakeCompletedBeforeDtls && !sctpNotification) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: dtls/sctp message received"); ssize_t n = 0; struct bio_dgram_sctp_rcvinfo rinfo; int getmsg_retv=getmsg(sockList[connId].sock, connId, &n, &ssl_err_msg); switch(getmsg_retv){ case IPL4_SCTP_WHOLE_MESSAGE_RECEIVED: { // asp.remName()=remaddr; ?????? INTEGER i_ppid; memset(&rinfo, 0, sizeof(struct bio_dgram_sctp_rcvinfo)); BIO_ctrl(sockList[connId].bio, BIO_CTRL_DGRAM_SCTP_GET_RCVINFO, sizeof(struct bio_dgram_sctp_rcvinfo), &rinfo); IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: Incoming data ssl (%ld bytes): stream = %hu, ssn = %hu, flags = %hx, ppid = %u \n", n, rinfo.rcv_sid,(unsigned int)rinfo.rcv_ssn, rinfo.rcv_flags, rinfo.rcv_ppid); if (ntohl(rinfo.rcv_ppid) <= (unsigned long)INT_MAX) i_ppid = ntohl(rinfo.rcv_ppid); else { char sbuf[16]; sprintf(sbuf, "%u", ntohl(rinfo.rcv_ppid)); i_ppid = INTEGER(sbuf); } asp.proto().dtls().sctp() = SctpTuple(rinfo.rcv_sid, i_ppid, OMIT_VALUE, OMIT_VALUE); len = (*sockList[connId].buf)->get_len() - n; sockList[connId].buf[0]->set_pos((size_t)len); sockList[connId].buf[0]->cut(); asp.msg() = OCTETSTRING(n, sockList[connId].buf[0]->get_data()); if(lazy_conn_id_level && sockListCnt==1 && lonely_conn_id!=-1){ asp.connId()=-1; } incoming_message(asp); if(sockList[connId].buf) (*sockList[connId].buf)->clear(); if(ssl_err_msg == SSL_ERROR_ZERO_RETURN) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: SSL_ERROR_ZERO_RETURN received."); asp.proto().dtls().sctp() = SctpTuple(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE); event.connClosed() = ConnectionClosedEvent(connId,asp.remName(), asp.remPort(), asp.locName(), asp.locPort(), asp.proto(), asp.userData()); incoming_message(event); if (ConnDel(connId) == -1) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: ConnDel failed"); } closingPeerLen = 0; } } break; case IPL4_SCTP_PARTIAL_RECEIVE: IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: partial receive: %ld bytes", n); break; case IPL4_SCTP_ERROR_RECEIVED: IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: DTLS/SCTP error, Socket is closed."); case IPL4_SCTP_EOF_RECEIVED: IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: Socket is closed."); if (connId == dontCloseConnectionId) { closingPeer = sa; closingPeerLen = saLen; //close(sockList[connId].sock); IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: closing connection %d" " postponed due to nonblocking send operation", connId); return; } asp.proto().dtls().sctp() = SctpTuple(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE); event.connClosed() = ConnectionClosedEvent(connId,asp.remName(), asp.remPort(), asp.locName(), asp.locPort(), asp.proto(), asp.userData()); incoming_message(event); if (ConnDel(connId) == -1) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: ConnDel failed"); } closingPeerLen = 0; break; case IPL4_SCTP_SENDER_DRY_EVENT: IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: SCTP_SENDER_DRY_EVENT did not contain any DTLS data"); break; default: break; } } #endif #endif #else sendError(PortError::ERROR__UNSUPPORTED__PROTOCOL, sockList[connId].sock); #endif break; } // IPL4asp_SCTP default: sendError(PortError::ERROR__UNSUPPORTED__PROTOCOL, sockList[connId].sock); break; } // switch } IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: leave"); } // IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable void IPL4asp__PT_PROVIDER::reportConnOpened(const int client_id) { ASP__Event event; event.connOpened().remName() = *(sockList[client_id].remoteaddr); event.connOpened().remPort() = *(sockList[client_id].remoteport); event.connOpened().locName() = *(sockList[client_id].localaddr); event.connOpened().locPort() = *(sockList[client_id].localport); if(sockList[client_id].type == IPL4asp_UDP) { if(sockList[client_id].ssl_tls_type != NONE) { event.connOpened().proto().dtls().udp() = UdpTuple(null_type()); } else { IPL4_DEBUG( "IPL4asp__PT_PROVIDER::reportConnOpened: unhandled UDP case!"); } } else if((sockList[client_id].type == IPL4asp_TCP) || (sockList[client_id].type == IPL4asp_TCP_LISTEN)) { if(sockList[client_id].ssl_tls_type != NONE) { event.connOpened().proto().ssl() = SslTuple(null_type()); } else { event.connOpened().proto().tcp() = TcpTuple(null_type()); } } else if((sockList[client_id].type == IPL4asp_SCTP) || (sockList[client_id].type == IPL4asp_SCTP_LISTEN)) { if(sockList[client_id].ssl_tls_type != NONE) { event.connOpened().proto().dtls().sctp() = SctpTuple(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE); } else { event.connOpened().proto().sctp() = SctpTuple(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE); } } else { IPL4_DEBUG( "IPL4asp__PT_PROVIDER::reportConnOpened: unhandled protocol!"); } set_dscp_option(sockList[client_id].sock); event.connOpened().connId() = client_id; event.connOpened().userData() = sockList[client_id].userData; incoming_message(event); } #ifdef USE_SCTP int IPL4asp__PT_PROVIDER::getmsg(int fd, int connId, struct msghdr *msg, void */*buf*/, size_t */*buflen*/, ssize_t *nrp, size_t /*cmsglen*/) { if(!sockList[connId].sctpHandshakeCompletedBeforeDtls) { *nrp = recvmsg(fd, msg, 0); } else { // In case of DTLS/SCTP the socket will be accessed by the SSL_read as well. // With MSG_PEEK the data is copied into the buffer but is not removed from the input queue // so that SSL_read can access the data as well. *nrp = recvmsg(fd, msg, MSG_PEEK); } //IPL4_DEBUG("IPL4asp__PT_PROVIDER::getmsg: nr: %ld",*nrp); if (*nrp < 0) { /* EOF or error */ IPL4_DEBUG("IPL4asp__PT_PROVIDER::getmsg: error: %d, %s",errno,strerror(errno)); return IPL4_SCTP_ERROR_RECEIVED; } else if (*nrp==0){ IPL4_DEBUG("IPL4asp__PT_PROVIDER::getmsg: connection closed"); return IPL4_SCTP_EOF_RECEIVED; } /* Whole message is received, return it. */ if (msg->msg_flags & MSG_EOR) { return IPL4_SCTP_WHOLE_MESSAGE_RECEIVED; } #else int IPL4asp__PT_PROVIDER::getmsg(int /*fd*/, int /*connId*/, struct msghdr */*msg*/, void */*buf*/, size_t */*buflen*/, ssize_t */*nrp*/, size_t /*cmsglen*/) { #endif return IPL4_SCTP_PARTIAL_RECEIVE; } int IPL4asp__PT_PROVIDER::getmsg(int fd, int connId, ssize_t *nrp, int *ssl_err_msg) { #ifdef USE_SCTP #ifdef IPL4_USE_SSL *nrp = receive_ssl_message_on_fd(connId, ssl_err_msg);; if (*nrp == 0) { switch (sockList[connId].sslState) { case STATE_BLOCK_FOR_SENDING: IPL4_DEBUG("IPL4asp__PT_PROVIDER::getmsg: ssl state is STATE_BLOCK_FOR_SENDING, don't close connection."); Handler_Remove_Fd_Read(connId); sockList[connId].sslState = STATE_DONT_CLOSE; IPL4_DEBUG("IPL4asp__PT_PROVIDER::getmsg: setting socket ssl state to STATE_DONT_CLOSE"); break; case STATE_DONT_CLOSE: IPL4_DEBUG("IPL4asp__PT_PROVIDER::getmsg: ssl state is STATE_DONT_CLOSE, don't close connection."); break; default: break; } return IPL4_SCTP_EOF_RECEIVED; } else if(*nrp > 0) { return IPL4_SCTP_WHOLE_MESSAGE_RECEIVED; } else if(*nrp < 0 && *ssl_err_msg != SSL_ERROR_WANT_READ){ return IPL4_SCTP_ERROR_RECEIVED; } else if(*nrp < 0 && *ssl_err_msg == SSL_ERROR_WANT_READ){ return IPL4_SCTP_SENDER_DRY_EVENT; } #endif #endif return IPL4_SCTP_PARTIAL_RECEIVE; } void IPL4asp__PT_PROVIDER::handle_event(int /*fd*/, int connId, const void *buf) { #ifdef USE_SCTP ASP__Event event; union sctp_notification *snp; snp = (sctp_notification *)buf; switch (snp->sn_header.sn_type) { case SCTP_ASSOC_CHANGE: IPL4_DEBUG("IPL4asp__PT_PROVIDER::handle_event: incoming SCTP_ASSOC_CHANGE event."); struct sctp_assoc_change *sac; sac = &snp->sn_assoc_change; if (events.sctp_association_event) { event.sctpEvent().sctpAssocChange().clientId() = connId; event.sctpEvent().sctpAssocChange().proto().sctp() = SctpTuple(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE); switch(sac->sac_state){ case SCTP_COMM_UP: event.sctpEvent().sctpAssocChange().sac__state() = IPL4asp__Types::SAC__STATE::SCTP__COMM__UP; break; case SCTP_COMM_LOST: event.sctpEvent().sctpAssocChange().sac__state() = IPL4asp__Types::SAC__STATE::SCTP__COMM__LOST; break; case SCTP_RESTART: event.sctpEvent().sctpAssocChange().sac__state() = IPL4asp__Types::SAC__STATE::SCTP__RESTART; break; case SCTP_SHUTDOWN_COMP: event.sctpEvent().sctpAssocChange().sac__state() = IPL4asp__Types::SAC__STATE::SCTP__SHUTDOWN__COMP; break; case SCTP_CANT_STR_ASSOC: event.sctpEvent().sctpAssocChange().sac__state() = IPL4asp__Types::SAC__STATE::SCTP__CANT__STR__ASSOC; break; default: event.sctpEvent().sctpAssocChange().sac__state() = IPL4asp__Types::SAC__STATE::SCTP__UNKNOWN__SAC__STATE; TTCN_warning("IPL4asp__PT_PROVIDER::handle_event: Unexpected sac_state value received %d", sac->sac_state); break; } incoming_message(event); if(sac->sac_state == SCTP_COMM_LOST) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::handle_event: SCTP_ASSOC_CHANGE event SCTP_COMM_LOST, closing Sock."); ProtoTuple proto_close; proto_close.sctp()=SctpTuple(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE); sendConnClosed(connId, *(sockList[connId].remoteaddr), *(sockList[connId].remoteport), *(sockList[connId].localaddr), *(sockList[connId].localport), proto_close, sockList[connId].userData); if (ConnDel(connId) == -1) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::handle_event: ConnDel failed"); } closingPeerLen = 0; } } break; case SCTP_PEER_ADDR_CHANGE: IPL4_DEBUG("IPL4asp__PT_PROVIDER::handle_event: incoming SCTP_PEER_ADDR_CHANGE event."); struct sctp_paddr_change *spc; spc = &snp->sn_paddr_change; if (events.sctp_address_event) { event.sctpEvent().sctpPeerAddrChange().clientId() = connId; switch(spc->spc_state) { case SCTP_ADDR_AVAILABLE: event.sctpEvent().sctpPeerAddrChange().spc__state() = IPL4asp__Types::SPC__STATE::SCTP__ADDR__AVAILABLE; break; case SCTP_ADDR_UNREACHABLE: event.sctpEvent().sctpPeerAddrChange().spc__state() = IPL4asp__Types::SPC__STATE::SCTP__ADDR__UNREACHABLE; break; case SCTP_ADDR_REMOVED: event.sctpEvent().sctpPeerAddrChange().spc__state() = IPL4asp__Types::SPC__STATE::SCTP__ADDR__REMOVED; break; case SCTP_ADDR_ADDED: event.sctpEvent().sctpPeerAddrChange().spc__state() = IPL4asp__Types::SPC__STATE::SCTP__ADDR__ADDED; break; case SCTP_ADDR_MADE_PRIM: event.sctpEvent().sctpPeerAddrChange().spc__state() = IPL4asp__Types::SPC__STATE::SCTP__ADDR__MADE__PRIM; break; #if defined(LKSCTP_1_0_7) || defined(LKSCTP_1_0_9) case SCTP_ADDR_CONFIRMED: event.sctpEvent().sctpPeerAddrChange().spc__state() = IPL4asp__Types::SPC__STATE::SCTP__ADDR__CONFIRMED; break; #endif default: event.sctpEvent().sctpPeerAddrChange().spc__state() = IPL4asp__Types::SPC__STATE::SCTP__UNKNOWN__SPC__STATE; TTCN_warning("IPL4asp__PT_PROVIDER::handle_event: Unexpected spc_state value received %d", spc->spc_state); break; } incoming_message(event); } break; case SCTP_REMOTE_ERROR: IPL4_DEBUG("IPL4asp__PT_PROVIDER::handle_event: incoming SCTP_REMOTE_ERROR event."); // struct sctp_remote_error *sre; // sre = &snp->sn_remote_error; if (events.sctp_peer_error_event) { event.sctpEvent().sctpRemoteError().clientId() = connId; incoming_message(event); } break; case SCTP_SEND_FAILED: IPL4_DEBUG("IPL4asp__PT_PROVIDER::handle_event: incoming SCTP_SEND_FAILED event."); // struct sctp_send_failed *ssf; // ssf = &snp->sn_send_failed; if (events.sctp_send_failure_event) { event.sctpEvent().sctpSendFailed().clientId() = connId; incoming_message(event); } break; case SCTP_SHUTDOWN_EVENT: IPL4_DEBUG("IPL4asp__PT_PROVIDER::handle_event: incoming SCTP_SHUTDOWN_EVENT event."); // struct sctp_shutdown_event *sse; // sse = &snp->sn_shutdown_event; if (events.sctp_shutdown_event) { event.sctpEvent().sctpShutDownEvent().clientId() = connId; incoming_message(event); } break; #if defined(LKSCTP_1_0_7) || defined(LKSCTP_1_0_9) case SCTP_ADAPTATION_INDICATION: IPL4_DEBUG("IPL4asp__PT_PROVIDER::handle_event: incoming SCTP_ADAPTATION_INDICATION event."); // struct sctp_adaptation_event *sai; // sai = &snp->sn_adaptation_event; if (events.sctp_adaptation_layer_event) { event.sctpEvent().sctpAdaptationIndication().clientId() = connId; incoming_message(event); } break; #else case SCTP_ADAPTION_INDICATION: IPL4_DEBUG("IPL4asp__PT_PROVIDER::handle_event: incoming SCTP_ADAPTION_INDICATION event."); // struct sctp_adaption_event *sai; // sai = &snp->sn_adaption_event; if (events.sctp_adaption_layer_event) { event.sctpEvent().sctpAdaptationIndication().clientId() = connId; incoming_message(event); } break; #endif case SCTP_PARTIAL_DELIVERY_EVENT: IPL4_DEBUG("IPL4asp__PT_PROVIDER::handle_event: incoming SCTP_PARTIAL_DELIVERY_EVENT event."); // struct sctp_pdapi_event *pdapi; // pdapi = &snp->sn_pdapi_event; if (events.sctp_partial_delivery_event) { event.sctpEvent().sctpPartialDeliveryEvent().clientId() = connId; incoming_message(event); } break; #ifdef SCTP_SENDER_DRY_EVENT case SCTP_SENDER_DRY_EVENT: IPL4_DEBUG("IPL4asp__PT_PROVIDER::handle_event: incoming SCTP_SENDER_DRY_EVENT event."); if (events.sctp_sender_dry_event) { event.sctpEvent().sctpSenderDryEvent().clientId() = connId; incoming_message(event); } break; #endif default: IPL4_DEBUG("IPL4asp__PT_PROVIDER::handle_event: Unknown notification type!"); break; } #endif } void IPL4asp__PT_PROVIDER::user_map(const char *system_port) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::user_map(%s): enter",system_port); sockList = NULL; sockListCnt = 0; firstFreeSock = -1; lastFreeSock = -1; dontCloseConnectionId = -1; closingPeerLen = 0; lonely_conn_id = -1; #ifdef USE_IPL4_EIN_SCTP if(!native_stack) do_bind(); #endif mapped = true; switch(default_mode){ case 1: // connect if(lazy_conn_id_level!=1){ TTCN_error("IPL4asp__PT_PROVIDER::user_map(%s): Autoconnect: The lazy_conn_id_level should be \"Yes\" ",system_port); } if(defaultRemHost==NULL){ TTCN_error("IPL4asp__PT_PROVIDER::user_map(%s): Autoconnect: The remote host should be specified.",system_port); } if(defaultRemPort==-1){ TTCN_error("IPL4asp__PT_PROVIDER::user_map(%s): Autoconnect: The remote port should be specified.",system_port); } { ProtoTuple pt; pt.unspecified() = NULL_VALUE; switch(default_proto){ case 1: // TLS pt.ssl() = NULL_VALUE; break; case 2: // SCTP pt.sctp() = SctpTuple(OMIT_VALUE,OMIT_VALUE,OMIT_VALUE,OMIT_VALUE); break; case 3: // UDP pt.udp() = NULL_VALUE; break; default: // TCP pt.tcp() = NULL_VALUE; break; } OptionList op= NULL_VALUE; Result res= f__IPL4__PROVIDER__connect(*this,defaultRemHost,defaultRemPort,defaultLocHost,defaultLocPort,-1,pt,op); if(res.errorCode().ispresent()){ TTCN_error("IPL4asp__PT_PROVIDER::user_map(%s): Autoconnect: Can not connect: %d %s ",system_port,res.os__error__code().ispresent()?(int)res.os__error__code()():-1,res.os__error__text().ispresent()?(const char*)res.os__error__text()():""); } } break; case 2: // listen if(lazy_conn_id_level!=0){ TTCN_error("IPL4asp__PT_PROVIDER::user_map(%s): Autolisten: The lazy_conn_id_level should be \"No\" ",system_port); } { ProtoTuple pt; pt.unspecified() = NULL_VALUE; switch(default_proto){ case 1: // TLS pt.ssl() = NULL_VALUE; break; case 2: // SCTP pt.sctp() = SctpTuple(OMIT_VALUE,OMIT_VALUE,OMIT_VALUE,OMIT_VALUE); break; case 3: // UDP pt.udp() = NULL_VALUE; break; default: // TCP pt.tcp() = NULL_VALUE; break; } OptionList op= NULL_VALUE; Result res= f__IPL4__PROVIDER__listen(*this,defaultLocHost,defaultLocPort,pt,op); if(res.errorCode().ispresent()){ TTCN_error("IPL4asp__PT_PROVIDER::user_map(%s): Autolisten: Can not listen: %d %s ",system_port,res.os__error__code().ispresent()?(int)res.os__error__code()():-1,res.os__error__text().ispresent()?(const char*)res.os__error__text()():""); } } break; default: // do nothing break; } } // IPL4asp__PT_PROVIDER::user_map void IPL4asp__PT_PROVIDER::user_unmap(const char *system_port) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::user_unmap(%s): enter",system_port); mapped = false; if (sockListCnt > 0) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::user_unmap: There are %i open connections", sockListCnt); } if (sockList != 0) { for (unsigned int i = 1; i < sockListSize; ++i) { #ifdef USE_IPL4_EIN_SCTP if(!native_stack && sockList[i].sock != SockDesc::SOCK_NONEX && (sockList[i].type==IPL4asp_SCTP_LISTEN || sockList[i].type==IPL4asp_SCTP)){ sockList[i].next_action=SockDesc::ACTION_DELETE; if(sockList[i].type == IPL4asp_SCTP){ EINSS7_00SctpShutdownReq(sockList[i].sock); } else { if(sockList[i].ref_count==0){ EINSS7_00SctpDestroyReq(sockList[i].endpoint_id); ConnDelEin(i,true); } } } else #endif if (sockList[i].sock > 0) ConnDel(i,true); } } sockListCnt = 0; firstFreeSock = -1; lastFreeSock = -1; #ifdef USE_IPL4_EIN_SCTP if(!native_stack) do_unbind(); #endif Free(sockList); sockList = 0; if(globalConnOpts.dtlsSrtpProfiles) { Free(globalConnOpts.dtlsSrtpProfiles); globalConnOpts.dtlsSrtpProfiles = NULL; } lonely_conn_id = -1; Uninstall_Handler(); } // IPL4asp__PT_PROVIDER::user_unmap void IPL4asp__PT_PROVIDER::user_start() { IPL4_DEBUG("IPL4asp__PT_PROVIDER::user_start: enter"); } // IPL4asp__PT_PROVIDER::user_start void IPL4asp__PT_PROVIDER::user_stop() { IPL4_DEBUG("IPL4asp__PT_PROVIDER::user_stop: enter"); } // IPL4asp__PT_PROVIDER::user_stop bool IPL4asp__PT_PROVIDER::getAndCheckSockType(int connId, ProtoTuple::union_selection_type proto, SockType &type) { if (!isConnIdValid(connId)) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::getAndCheckSockType: invalid connId: %i", connId); return false; } type = sockList[connId].type; IPL4_DEBUG("IPL4asp__PT_PROVIDER::getAndCheckSockType: sock type is: %i", type); if (proto != ProtoTuple::UNBOUND_VALUE && proto != ProtoTuple::ALT_unspecified) { /* Proto is specified. It is used for checking only. */ if(((type == IPL4asp_UDP) && (proto != ProtoTuple::ALT_udp) && (proto != ProtoTuple::ALT_dtls)) || (((type == IPL4asp_TCP_LISTEN) || (type == IPL4asp_TCP)) && ((proto != ProtoTuple::ALT_tcp) && (proto != ProtoTuple::ALT_ssl))) || (((type == IPL4asp_SCTP_LISTEN) || (type == IPL4asp_SCTP)) && (proto != ProtoTuple::ALT_sctp))) { return false; } } return true; } void IPL4asp__PT_PROVIDER::outgoing_send(const ASP__Send& asp) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::outgoing_send: ASP Send: enter"); testIfInitialized(); Socket__API__Definitions::Result result(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE); outgoing_send_core(asp, result); if(result.errorCode().ispresent()){ ASP__Event event; if(send_extended_result){ event.extended__result().errorCode() =result.errorCode(); event.extended__result().connId() =result.connId(); event.extended__result().os__error__code() =result.os__error__code(); event.extended__result().os__error__text() =result.os__error__text(); event.extended__result().msg() = asp.msg(); } else { event.result()=result; } incoming_message(event); } } // IPL4asp__PT_PROVIDER::outgoing_send int IPL4asp__PT_PROVIDER::outgoing_send_core(const ASP__Send& asp, Socket__API__Definitions::Result& result) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::outgoing_send_core: ASP Send: enter"); testIfInitialized(); SockType type; int local_conn_id=asp.connId(); if(lazy_conn_id_level && asp.connId()==-1){ local_conn_id=lonely_conn_id; } ProtoTuple::union_selection_type proto = ProtoTuple::ALT_unspecified; if (asp.proto().ispresent()) proto = asp.proto()().get_selection(); if (getAndCheckSockType(local_conn_id, proto, type)) { if (asp.proto().ispresent()) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::outgoing_send_core: ASP Send: calling sendNonBlocking with proto"); return sendNonBlocking(local_conn_id, (sockaddr *)NULL, (socklen_t)0, type, asp.msg(), result, asp.proto()); } else { IPL4_DEBUG("IPL4asp__PT_PROVIDER::outgoing_send_core: ASP Send: calling sendNonBlocking without proto"); return sendNonBlocking(local_conn_id, (sockaddr *)NULL, (socklen_t)0, type, asp.msg(), result); } } else { IPL4_DEBUG("IPL4asp__PT_PROVIDER::outgoing_send_core: ASP Send: INVALID INPUT PARAMETER"); setResult(result, PortError::ERROR__INVALID__INPUT__PARAMETER, asp.connId()); } return -1; } // IPL4asp__PT_PROVIDER::outgoing_send_core void IPL4asp__PT_PROVIDER::outgoing_send(const ASP__SendTo& asp) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::outgoing_send: ASP Send: enter"); testIfInitialized(); Socket__API__Definitions::Result result(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE); outgoing_send_core(asp, result); if(result.errorCode().ispresent()){ ASP__Event event; if(send_extended_result){ event.extended__result().errorCode() =result.errorCode(); event.extended__result().connId() =result.connId(); event.extended__result().os__error__code() =result.os__error__code(); event.extended__result().os__error__text() =result.os__error__text(); event.extended__result().msg() = asp.msg(); } else { event.result()=result; } incoming_message(event); } } int IPL4asp__PT_PROVIDER::outgoing_send_core(const ASP__SendTo& asp, Socket__API__Definitions::Result& result) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::outgoing_send_core: ASP SendTo: enter"); testIfInitialized(); SockType type; int local_conn_id=asp.connId(); if(lazy_conn_id_level && local_conn_id==-1){ local_conn_id=lonely_conn_id; } ProtoTuple::union_selection_type proto = ProtoTuple::ALT_unspecified; if (asp.proto().ispresent()) proto = asp.proto()().get_selection(); if (getAndCheckSockType(local_conn_id, proto, type)) { if (asp.remPort() < 0 || asp.remPort() > 65535){ setResult(result, PortError::ERROR__INVALID__INPUT__PARAMETER, asp.connId()); return -1; } SockAddr to; socklen_t toLen; switch (type) { case IPL4asp_UDP: case IPL4asp_TCP_LISTEN: case IPL4asp_TCP: //#ifdef IPL4_USE_SSL // case IPL4asp_SSL_LISTEN: // case IPL4asp_SSL: //#endif if (SetSockAddr(asp.remName(), asp.remPort(), to, toLen) == -1) { setResult(result,PortError::ERROR__HOSTNAME, asp.connId()); return -1; } break; #ifdef USE_SCTP case IPL4asp_SCTP_LISTEN: case IPL4asp_SCTP: if (SetSockAddr(asp.remName(), asp.remPort(), to, toLen) == -1) { setResult(result,PortError::ERROR__HOSTNAME, asp.connId()); return -1; } break; #endif default: setResult(result,PortError::ERROR__UNSUPPORTED__PROTOCOL, asp.connId()); return -1; } if (asp.proto().ispresent()) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::outgoing_send_core: ASP SendTo: calling sendNonBlocking with proto"); return sendNonBlocking(local_conn_id, (sockaddr *)&to, toLen, type, asp.msg(), result, asp.proto()); } else { return sendNonBlocking(local_conn_id, (sockaddr *)&to, toLen, type, asp.msg(), result); } } else { setResult(result, PortError::ERROR__INVALID__INPUT__PARAMETER, asp.connId()); } return -1; } // IPL4asp__PT_PROVIDER::outgoing_send_core int IPL4asp__PT_PROVIDER::sendNonBlocking(const ConnectionId& connId, sockaddr *sa, socklen_t saLen, SockType type, const OCTETSTRING& msg, Socket__API__Definitions::Result& result, const Socket__API__Definitions::ProtoTuple& protoTuple) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::sendNonBlocking: enter: connId: %d", (int)connId); int sock = sockList[(int)connId].sock; IPL4_DEBUG("IPL4asp__PT_PROVIDER::sendNonBlocking: fd: %d", sock); if (sock < 0) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::sendNonBlocking: Connection %s", (sock == SockDesc::SOCK_CLOSED) ? "closed" : "does not exist"); setResult(result,PortError::ERROR__SOCKET, (int)connId); return -1; } int rem = msg.lengthof(); int sent_octets=0; const unsigned char *ptr = (const unsigned char *)msg; #ifdef IPL4_USE_SSL IPL4_DEBUG("IPL4asp__PT_PROVIDER::sendNonBlocking: ssl_tls_type: %d", sockList[(int)connId].ssl_tls_type); if((sockList[(int)connId].ssl_tls_type != NONE) && (protoTuple.get_selection() != ProtoTuple::ALT_udp)) { // if (ssl_current_client!=NULL) log_warning("Warning: race condition while setting current client object pointer"); // ssl_current_client=(IPL4asp__PT_PROVIDER *)this; IPL4_DEBUG("IPL4asp__PT_PROVIDER::sendNonBlocking: sslState: %d", sockList[(int)connId].sslState); if (sockList[(int)connId].sslState!=STATE_NORMAL) { // The socket is not writeable, so we subscribe to the event that notifies us when it becomes writable again // and we pass up a TEMPORARILY_UNAVAILABLE ASP to inform the user. // TODO: This functionality can be improved by buffering the message that we couldn't send thus the user doesn't have to // buffer it himself. It would be more efficient to buffer it here anyway (it would mean less ASP traffic) Handler_Add_Fd_Write(sock); IPL4_DEBUG("DO WRITE ON %i", sock); setResult(result,PortError::ERROR__TEMPORARILY__UNAVAILABLE, (int)connId, EAGAIN); IPL4_DEBUG("IPL4asp__PT_PROVIDER::sendNonBlocking: leave (TEMPORARILY UNAVAILABLE) " "connId: %i, fd: %i", (int)connId, sock); // ssl_current_client=NULL; return 0; } if(!getSslObj((int)connId, ssl_current_ssl)) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::sendNonBlocking: current SSL invalid for client: %d", (int)connId); IPL4_DEBUG("IPL4asp__PT_PROVIDER::sendNonBlocking: Connection %s", (sock == SockDesc::SOCK_CLOSED) ? "closed" : "does not exist"); setResult(result,PortError::ERROR__SOCKET, (int)connId); // ssl_current_client=NULL; return -1; } if (ssl_current_ssl==NULL) { IPL4_DEBUG("PL4asp__PT_PROVIDER::sendNonBlocking:No SSL data available for client %d",(int)connId); setResult(result,PortError::ERROR__SOCKET, (int)connId); // ssl_current_client=NULL; return -1; } } #endif while (rem != 0) { int ret=-1; switch (type) { case IPL4asp_UDP: case IPL4asp_TCP_LISTEN: case IPL4asp_TCP: if((sockList[(int)connId].ssl_tls_type == NONE) || (protoTuple.get_selection() == ProtoTuple::ALT_udp)) { // if UDP is requested over the DTLS, then send UDP unencrypted IPL4_DEBUG("IPL4asp__PT_PROVIDER::sendNonBlocking, sending unencrypted..."); if (sa != NULL) ret = sendto(sock, ptr, rem, 0, sa, saLen); else ret = ::send(sock, ptr, rem, 0); } else { #ifdef IPL4_USE_SSL write_ssl_message_on_fd(&ret, &rem, connId, ptr); #endif } // else branch break; case IPL4asp_SCTP_LISTEN: case IPL4asp_SCTP: #ifdef USE_IPL4_EIN_SCTP if(!native_stack){ ULONG_T streamID=0; ULONG_T payloadProtId=0; if (protoTuple.get_selection()==ProtoTuple::ALT_sctp) { if(protoTuple.sctp().sinfo__stream().ispresent()) { streamID = (int)(protoTuple.sctp().sinfo__stream()()); } if(protoTuple.sctp().sinfo__ppid().ispresent()) { payloadProtId=protoTuple.sctp().sinfo__ppid()().get_long_long_val(); } } USHORT_T einretval=EINSS7_00SctpSendReq(sock,payloadProtId,rem,(unsigned char*)ptr,streamID,0,NULL,false); if(RETURN_OK != einretval){ setResult(result,PortError::ERROR__SOCKET, (int)connId, einretval); return -1; } else { return rem; } } #endif #ifdef USE_SCTP if(sockList[connId].ssl_tls_type == NONE || !sockList[connId].sctpHandshakeCompletedBeforeDtls) { struct cmsghdr *cmsg; struct sctp_sndrcvinfo *sri; char cbuf[sizeof (*cmsg) + sizeof (*sri)]; struct msghdr msg; struct iovec iov; iov.iov_len = rem; memset(&msg, 0, sizeof (msg)); iov.iov_base = (char *)ptr; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = cbuf; msg.msg_controllen = sizeof (*cmsg) + sizeof (*sri); memset(cbuf, 0, sizeof (*cmsg) + sizeof (*sri)); cmsg = (struct cmsghdr *)cbuf; sri = (struct sctp_sndrcvinfo *)(cmsg + 1); cmsg->cmsg_len = sizeof (*cmsg) + sizeof (*sri); cmsg->cmsg_level = IPPROTO_SCTP; cmsg->cmsg_type = SCTP_SNDRCV; sri->sinfo_stream = 0; sri->sinfo_ppid = 0; if (protoTuple.get_selection()==ProtoTuple::ALT_sctp) { if(protoTuple.sctp().sinfo__stream().ispresent()) { sri->sinfo_stream = (int)(protoTuple.sctp().sinfo__stream()()); } if(protoTuple.sctp().sinfo__ppid().ispresent()) { unsigned int ui; INTEGER in = protoTuple.sctp().sinfo__ppid()(); if (in.is_native() && in > 0) ui = (unsigned int)(int)in; else { ui = (unsigned int)in.get_long_long_val(); } sri->sinfo_ppid = htonl(ui); } } IPL4_DEBUG("IPL4asp__PT_PROVIDER::sendNonBlocking: sctp sinfo: %d, ppid: %d", sri->sinfo_stream,sri->sinfo_ppid); ret = ::sendmsg(sock, &msg, 0); break; } #ifdef IPL4_USE_SSL #ifdef OPENSSL_SCTP_SUPPORT else { struct bio_dgram_sctp_sndinfo sinfo; memset(&sinfo, 0, sizeof(struct bio_dgram_sctp_sndinfo)); if (protoTuple.get_selection()==ProtoTuple::ALT_sctp) { if(protoTuple.sctp().sinfo__stream().ispresent()) { sinfo.snd_sid = (int)(protoTuple.sctp().sinfo__stream()()); } if(protoTuple.sctp().sinfo__ppid().ispresent()) { unsigned int ui; INTEGER in = protoTuple.sctp().sinfo__ppid()(); if (in.is_native() && in > 0) ui = (unsigned int)(int)in; else ui = (unsigned int)in.get_long_long_val(); sinfo.snd_ppid = htonl(ui); } } BIO_ctrl(sockList[connId].bio, BIO_CTRL_DGRAM_SCTP_SET_SNDINFO, sizeof(struct bio_dgram_sctp_sndinfo), &sinfo); IPL4_DEBUG("IPL4asp__PT_PROVIDER::sendNonBlocking: dtls over sctp sinfo: %d, ppid: %d", sinfo.snd_sid,sinfo.snd_ppid); write_ssl_message_on_fd(&ret, &rem, connId, ptr); break; } #endif #endif #endif default: setResult(result,PortError::ERROR__UNSUPPORTED__PROTOCOL, (int)connId); return -1; } #ifdef IPL4_USE_SSL //In case of ssl it is used if the client id does not exist //if so, cannot do anything, send an error report and return; if(ret == -2) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::sendNonBlocking: Connection %s", (sock == SockDesc::SOCK_CLOSED) ? "closed" : "does not exist"); setResult(result,PortError::ERROR__SOCKET, (int)connId); // ssl_current_client=NULL; return -1; } #endif if (ret != -1) { rem -= ret; ptr += ret; sent_octets += ret; continue; // try sending the remaning octets } IPL4_DEBUG("IPL4asp__PT_PROVIDER::sendNonBlocking: error %s", strerror(errno)); switch (errno) { // error handling case EINTR: // interrupted signal: try again break; case EPIPE: { //client closed connection IPL4_DEBUG("IPL4asp__PT_PROVIDER::sendNonBlocking: " "client closed connection, send event ASP and remove socket"); int ii = connId; ASP__Event event; event.connClosed().connId() = connId; event.connClosed().remName() = *(sockList[ii].remoteaddr); event.connClosed().remPort() = *(sockList[ii].remoteport); event.connClosed().locName() = *(sockList[ii].localaddr); event.connClosed().locPort() = *(sockList[ii].localport); event.connClosed().proto().tcp() = TcpTuple(null_type()); event.connClosed().userData() = 0; int l_ud=-1; getUserData((int)connId, l_ud); event.connClosed().userData() = l_ud; switch (type) { case IPL4asp_UDP: // no such operation in UDP break; case IPL4asp_TCP_LISTEN: case IPL4asp_TCP: if(sockList[ii].ssl_tls_type == NONE) { event.connClosed().proto().tcp() = TcpTuple(null_type()); } else { event.connClosed().proto().ssl() = SslTuple(null_type()); } break; case IPL4asp_SCTP_LISTEN: case IPL4asp_SCTP: event.connClosed().proto().sctp() = SctpTuple(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE); default: setResult(result,PortError::ERROR__UNSUPPORTED__PROTOCOL, (int)connId); break; } IPL4_DEBUG("IPL4asp__PT_PROVIDER::sendNonBlocking"); /* if (getsockname(sock, (struct sockaddr *)&sa, &saLen) == -1) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::sendNonBlocking: getsockname error: %s", strerror(errno)); setResult(result,PortError::ERROR__HOSTNAME, (int)connId, errno); } else if (!SetNameAndPort((SockAddr *)&sa, saLen, event.connClosed().locName(), event.connClosed().locPort())) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::sendNonBlocking: SetNameAndPort failed"); setResult(result,PortError::ERROR__HOSTNAME, (int)connId); }*/ reportRemainingData_beforeConnClosed(connId, event.connClosed().remName(), event.connClosed().remPort(), event.connClosed().locName(), event.connClosed().locPort(), event.connClosed().proto(), event.connClosed().userData()); incoming_message(event); if (ConnDel((int)connId) == -1) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::sendNonBlocking: ConnDel failed"); setResult(result,PortError::ERROR__SOCKET, (int)connId); } /* if (!SetNameAndPort(&closingPeer, closingPeerLen, event.connClosed().remName(), event.connClosed().remPort())) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::sendNonBlocking: SetNameAndPort failed"); setResult(result,PortError::ERROR__HOSTNAME, (int)connId); }*/ return -1; } case EAGAIN: // same as case EWOULDBLOCK: if (pureNonBlocking) { // The socket is not writeable, so we subscribe to the event that notifies us when it becomes writable again // and we pass up a TEMPORARILY_UNAVAILABLE ASP to inform the user. // TODO: This functionality can be improved by buffering the message that we couldn't send thus the user doesn't have to // buffer it himself. It would be more efficient to buffer it here anyway (it would mean less ASP traffic) Handler_Add_Fd_Write(sock); IPL4_DEBUG("DO WRITE ON %i", sock); setResult(result,PortError::ERROR__TEMPORARILY__UNAVAILABLE, (int)connId, EAGAIN); IPL4_DEBUG("IPL4asp__PT_PROVIDER::sendNonBlocking: leave (TEMPORARILY UNAVAILABLE) " "connId: %i, fd: %i", (int)connId, sock); return sent_octets; } // If we don't use purenonBlocking mode, we let TITAN work (and block) until the message can be sent: dontCloseConnectionId = (int)connId; closingPeerLen = 0; IPL4_DEBUG("IPL4asp__PT_PROVIDER::sendNonBlocking: waits in TTCN_Snapshot::block_for_sending"); TTCN_Snapshot::block_for_sending((int)sock); IPL4_DEBUG("IPL4asp__PT_PROVIDER::sendNonBlocking: TITAN returned" " to send on connection %d, socket %d", (int)connId, sock); if (closingPeerLen > 0) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::sendNonBlocking: " "postponed close of connection %d", (int)connId); ASP__Event event; event.connClosed().connId() = connId; int ii = connId; event.connClosed().remName() = *(sockList[ii].remoteaddr); event.connClosed().remPort() = *(sockList[ii].remoteport); event.connClosed().locName() = *(sockList[ii].localaddr); event.connClosed().locPort() = *(sockList[ii].localport); event.connClosed().proto().tcp() = TcpTuple(null_type()); event.connClosed().userData() = 0; int l_ud=-1; getUserData((int)connId, l_ud); event.connClosed().userData() = l_ud; switch (type) { case IPL4asp_UDP: // no such operation in UDP break; case IPL4asp_TCP_LISTEN: case IPL4asp_TCP: if(sockList[ii].ssl_tls_type == NONE) { event.connClosed().proto().tcp() = TcpTuple(null_type()); } else { event.connClosed().proto().ssl() = SslTuple(null_type()); } break; case IPL4asp_SCTP_LISTEN: case IPL4asp_SCTP: event.connClosed().proto().sctp() = SctpTuple(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE); default: setResult(result,PortError::ERROR__UNSUPPORTED__PROTOCOL, (int)connId); break; } /* if (getsockname(sock, (struct sockaddr *)&sa, &saLen) == -1) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::sendNonBlocking: getsockname error: %s", strerror(errno)); setResult(result,PortError::ERROR__HOSTNAME, (int)connId, errno); } else if (!SetNameAndPort((SockAddr *)&sa, saLen, event.connClosed().locName(), event.connClosed().locPort())) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::sendNonBlocking: SetNameAndPort failed"); setResult(result,PortError::ERROR__HOSTNAME, (int)connId); }*/ reportRemainingData_beforeConnClosed(connId, event.connClosed().remName(), event.connClosed().remPort(), event.connClosed().locName(), event.connClosed().locPort(), event.connClosed().proto(), event.connClosed().userData()); incoming_message(event); if (ConnDel((int)connId) == -1) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::sendNonBlocking: ConnDel failed"); setResult(result,PortError::ERROR__SOCKET, (int)connId); } /* if (!SetNameAndPort(&closingPeer, closingPeerLen, event.connClosed().remName(), event.connClosed().remPort())) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::sendNonBlocking: SetNameAndPort failed"); setResult(result,PortError::ERROR__HOSTNAME, (int)connId); }*/ closingPeerLen = 0; } dontCloseConnectionId = -1; break; case ENOBUFS: // try again as in EINTR break; case EBADF: // invalid file descriptor IPL4_DEBUG("IPL4asp__PT_PROVIDER::sendNonBlocking: " "invalid fd: %d", (int)sock); setResult(result,PortError::ERROR__INVALID__CONNECTION, (int)connId, EBADF); return -1; default: setResult(result,PortError::ERROR__SOCKET, (int)connId, errno); return -1; } // switch (errno) } // while IPL4_DEBUG("IPL4asp__PT_PROVIDER::sendNonBlocking: leave"); return sent_octets; } // IPL4asp__PT::sendNonBlocking #ifdef IPL4_USE_SSL void IPL4asp__PT_PROVIDER::write_ssl_message_on_fd(int* ret, int* rem, const int connId, const unsigned char *msg_ptr){ IPL4_DEBUG("IPL4asp__PT_PROVIDER::write_ssl_message_on_fd: Client ID = %d", (int)connId); int res; // check if client exists if (!isConnIdValid((int)connId)){ IPL4_DEBUG("IPL4asp__PT_PROVIDER::write_ssl_message_on_fd, Client ID %d does not exist.", (int)connId); *ret = -2; return; } IPL4_DEBUG(" one write cycle started"); if (sockList[connId].sslState == STATE_DONT_CLOSE) { //goto client_closed_connection; //process postponed connection close IPL4_DEBUG("IPL4asp__PT_PROVIDER::write_ssl_message_on_fd: Process postponed connection close."); SSL_set_quiet_shutdown(ssl_current_ssl, 1); IPL4_DEBUG("Setting SSL SHUTDOWN mode to QUIET"); // ssl_current_client=NULL; IPL4_DEBUG("leaving IPL4asp__PT_PROVIDER::write_ssl_message_on_fd()"); IPL4_DEBUG("IPL4asp__PT_PROVIDER::write_ssl_message_on_fd: setting socket state to STATE_NORMAL"); sockList[(int)connId].sslState = STATE_NORMAL; errno = EPIPE; *ret = -1; return; } else { IPL4_DEBUG("IPL4asp__PT_PROVIDER::write_ssl_message_on_fd: sending message"); res = ssl_getresult(SSL_write(ssl_current_ssl, msg_ptr, *rem)); } switch (res) { case SSL_ERROR_NONE: // ssl_current_client=NULL; IPL4_DEBUG("leaving IPL4asp__PT_PROVIDER::write_ssl_message_on_fd() %d bytes is sent.", *rem); IPL4_DEBUG("IPL4asp__PT_PROVIDER::write_ssl_message_on_fd: setting socket state to STATE_NORMAL"); sockList[(int)connId].sslState = STATE_NORMAL; *ret = *rem; //all bytes are sent without any problem break; case SSL_ERROR_WANT_WRITE: int old_bufsize, new_bufsize; if (increase_send_buffer((int)connId, old_bufsize, new_bufsize)) { IPL4_DEBUG("Sending data on on file descriptor %d",(int)connId); IPL4_DEBUG("The sending operation would block execution. The " "size of the outgoing buffer was increased from %d to " "%d bytes.",old_bufsize, new_bufsize); //retry to send *ret = 0; } else { log_warning("Sending data on file descriptor %d", (int)connId); log_warning("The sending operation would block execution and it " "is not possible to further increase the size of the " "outgoing buffer. Trying to process incoming data to " "avoid deadlock."); // ssl_current_client=NULL; IPL4_DEBUG("IPL4asp__PT_PROVIDER::write_ssl_message_on_fd: setting socket state to STATE_BLOCK_FOR_SENDING"); sockList[(int)connId].sslState = STATE_BLOCK_FOR_SENDING; //continue with EAGAIN errno = EAGAIN; *ret = -1; } break; case SSL_ERROR_WANT_READ: //receiving buffer is probably empty thus reading would block execution if(!pureNonBlocking) { IPL4_DEBUG("SSL_write cannot read data from socket %d. Trying to process data to avoid deadlock.", (int)connId); IPL4_DEBUG("IPL4asp__PT_PROVIDER::write_ssl_message_on_fd: setting socket state to STATE_DONT_RECEIVE"); sockList[(int)connId].sslState = STATE_DONT_RECEIVE; //don't call receive_message_on_fd() to this socket for (;;) { TTCN_Snapshot::take_new(TRUE); pollfd pollClientFd = {sockList[(int)connId].sock, POLLIN, 0 }; int nEvents = poll(&pollClientFd, 1, 0); if (nEvents == 1 && (pollClientFd.revents & (POLLIN | POLLHUP)) != 0) break; if (nEvents < 0 && errno != EINTR) { IPL4_DEBUG("System call poll() failed on file descriptor %d", sockList[(int)connId].sock); SSL_set_quiet_shutdown(ssl_current_ssl, 1); IPL4_DEBUG("Setting SSL SHUTDOWN mode to QUIET"); IPL4_DEBUG("leaving IPL4asp__PT_PROVIDER::write_ssl_message_on_fd()"); IPL4_DEBUG("IPL4asp__PT_PROVIDER::write_ssl_message_on_fd: setting socket state to STATE_NORMAL"); sockList[(int)connId].sslState = STATE_NORMAL; *ret = -1; break; } } IPL4_DEBUG("Deadlock resolved"); } else { errno = EAGAIN; *ret = -1; } break; case SSL_ERROR_ZERO_RETURN: log_warning("IPL4asp__PT_PROVIDER::write_ssl_message_on_fd: SSL connection was interrupted by the other side"); SSL_set_quiet_shutdown(ssl_current_ssl, 1); IPL4_DEBUG("Setting SSL SHUTDOWN mode to QUIET"); // ssl_current_client=NULL; IPL4_DEBUG("leaving IPL4asp__PT_PROVIDER::write_ssl_message_on_fd()"); IPL4_DEBUG("IPL4asp__PT_PROVIDER::write_ssl_message_on_fd: setting socket state to STATE_NORMAL"); sockList[(int)connId].sslState = STATE_NORMAL; errno = EPIPE; *ret = -1; break; default: IPL4_DEBUG("SSL error occured"); SSL_set_quiet_shutdown(ssl_current_ssl, 1); IPL4_DEBUG("Setting SSL SHUTDOWN mode to QUIET"); IPL4_DEBUG("leaving IPL4asp__PT_PROVIDER::write_ssl_message_on_fd()"); IPL4_DEBUG("IPL4asp__PT_PROVIDER::sendNonBlocking: setting socket state to STATE_NORMAL"); sockList[(int)connId].sslState = STATE_NORMAL; errno = EPIPE; *ret = -1; }//end switch res } #endif void IPL4asp__PT_PROVIDER::set_ssl_supp_option(const int& conn_id, const IPL4asp__Types::OptionList& options){ // sockList[conn_id].ssl_supp.SSLv2=globalConnOpts.ssl_supp.SSLv2; // Moveed to connAdd // sockList[conn_id].ssl_supp.SSLv3=globalConnOpts.ssl_supp.SSLv3; // sockList[conn_id].ssl_supp.TLSv1=globalConnOpts.ssl_supp.TLSv1; // sockList[conn_id].ssl_supp.TLSv1_1=globalConnOpts.ssl_supp.TLSv1_1; IPL4_DEBUG("IPL4asp__PT_PROVIDER::set_ssl_supp_option: set SSL options"); for (int k = 0; k < options.size_of(); ++k) { switch (options[k].get_selection()) { case Option::ALT_ssl__support:{ const SSL__proto__support &sp= options[k].ssl__support(); for (int i=0; i= sockListSize - 1 || sockList == NULL) { unsigned int sz = sockListSize; if (sockList != NULL) sz *= 2; SockDesc *newSockList = (SockDesc *)Realloc(sockList, sizeof(SockDesc) * sz); int i0 = (sockList == 0) ? 1 : sockListSize; sockList = newSockList; sockListSize = sz; IPL4_DEBUG("IPL4asp__PT_PROVIDER::ConnAdd: new sockListSize: %d", sockListSize); int j = firstFreeSock; for ( int i = sockListSize - 1; i >= i0; --i ) { memset(sockList + i, 0, sizeof (sockList[i])); sockList[i].sock = SockDesc::SOCK_NONEX; sockList[i].nextFree = j; j = i; } firstFreeSock = j; if (lastFreeSock == -1) lastFreeSock = sockListSize - 1; } int i = firstFreeSock; IPL4_DEBUG("IPL4asp__PT_PROVIDER::ConnAdd: connId: %d", i); if (parentIdx != -1) { // inherit the listener's properties sockList[i].userData = sockList[parentIdx].userData; sockList[i].getMsgLen = sockList[parentIdx].getMsgLen; sockList[i].getMsgLen_forConnClosedEvent = sockList[parentIdx].getMsgLen_forConnClosedEvent; sockList[i].parentIdx = parentIdx; sockList[i].msgLenArgs = new ro__integer(*sockList[parentIdx].msgLenArgs); sockList[i].msgLenArgs_forConnClosedEvent = new ro__integer(*sockList[parentIdx].msgLenArgs_forConnClosedEvent); sockList[i].ssl_supp.SSLv2=sockList[parentIdx].ssl_supp.SSLv2; sockList[i].ssl_supp.SSLv3=sockList[parentIdx].ssl_supp.SSLv3; sockList[i].ssl_supp.TLSv1=sockList[parentIdx].ssl_supp.TLSv1; sockList[i].ssl_supp.TLSv1_1=sockList[parentIdx].ssl_supp.TLSv1_1; sockList[i].ssl_supp.TLSv1_2=sockList[parentIdx].ssl_supp.TLSv1_2; sockList[i].ssl_supp.DTLSv1=sockList[parentIdx].ssl_supp.DTLSv1; sockList[i].ssl_supp.DTLSv1_2=sockList[parentIdx].ssl_supp.DTLSv1_2; if(sockList[parentIdx].dtlsSrtpProfiles){ sockList[i].dtlsSrtpProfiles = mcopystr(sockList[parentIdx].dtlsSrtpProfiles); } else { sockList[i].dtlsSrtpProfiles = NULL; } if(sockList[parentIdx].ssl_key_file){ sockList[i].ssl_key_file = mcopystr(sockList[parentIdx].ssl_key_file); } else { sockList[i].ssl_key_file = NULL; } if(sockList[parentIdx].ssl_certificate_file){ sockList[i].ssl_certificate_file = mcopystr(sockList[parentIdx].ssl_certificate_file); } else { sockList[i].ssl_certificate_file = NULL; } if(sockList[parentIdx].ssl_cipher_list){ sockList[i].ssl_cipher_list = mcopystr(sockList[parentIdx].ssl_cipher_list); } else { sockList[i].ssl_cipher_list = NULL; } if(sockList[parentIdx].ssl_trustedCAlist_file){ sockList[i].ssl_trustedCAlist_file = mcopystr(sockList[parentIdx].ssl_trustedCAlist_file); } else { sockList[i].ssl_trustedCAlist_file = NULL; } if(sockList[parentIdx].ssl_password){ sockList[i].ssl_password = mcopystr(sockList[parentIdx].ssl_password); } else { sockList[i].ssl_password = NULL; } if(sockList[parentIdx].psk_identity){ sockList[i].psk_identity = mcopystr(sockList[parentIdx].psk_identity); } else { sockList[i].psk_identity = NULL; } if(sockList[parentIdx].psk_identity_hint){ sockList[i].psk_identity_hint = mcopystr(sockList[parentIdx].psk_identity_hint); } else { sockList[i].psk_identity_hint = NULL; } if(sockList[parentIdx].psk_key){ sockList[i].psk_key = mcopystr(sockList[parentIdx].psk_key); } else { sockList[i].psk_key = NULL; } if(sockList[parentIdx].tls_hostname){ sockList[i].tls_hostname = new CHARSTRING(*sockList[parentIdx].tls_hostname); } else { sockList[i].tls_hostname = NULL; } if(sockList[parentIdx].alpn){ sockList[i].alpn = new OCTETSTRING(*sockList[parentIdx].alpn); } else { sockList[i].alpn =NULL; } } else { // otherwise initialize to defaults sockList[i].userData = 0; sockList[i].getMsgLen = defaultGetMsgLen; sockList[i].getMsgLen_forConnClosedEvent = defaultGetMsgLen_forConnClosedEvent; sockList[i].parentIdx = -1; sockList[i].msgLenArgs = new ro__integer(*defaultMsgLenArgs); sockList[i].msgLenArgs_forConnClosedEvent = new ro__integer(*defaultMsgLenArgs_forConnClosedEvent); sockList[i].ssl_supp.SSLv2=globalConnOpts.ssl_supp.SSLv2; sockList[i].ssl_supp.SSLv3=globalConnOpts.ssl_supp.SSLv3; sockList[i].ssl_supp.TLSv1=globalConnOpts.ssl_supp.TLSv1; sockList[i].ssl_supp.TLSv1_1=globalConnOpts.ssl_supp.TLSv1_1; sockList[i].ssl_supp.TLSv1_2=globalConnOpts.ssl_supp.TLSv1_2; sockList[i].ssl_supp.DTLSv1=globalConnOpts.ssl_supp.DTLSv1; sockList[i].ssl_supp.DTLSv1_2=globalConnOpts.ssl_supp.DTLSv1_2; sockList[i].dtlsSrtpProfiles = NULL; sockList[i].ssl_key_file = NULL; sockList[i].ssl_certificate_file = NULL; sockList[i].ssl_trustedCAlist_file = NULL; sockList[i].ssl_cipher_list = NULL; sockList[i].ssl_password = NULL; sockList[i].tls_hostname = NULL; sockList[i].alpn =NULL; sockList[i].psk_identity = NULL; sockList[i].psk_identity_hint = NULL; sockList[i].psk_key = NULL; if(options){ IPL4_DEBUG("IPL4asp__PT_PROVIDER::ConnAdd: connId: set ssl options for connId : %d", i); set_ssl_supp_option(i,*options); } } sockList[i].msgLen = -1; fd2IndexMap[sock] = i; sockList[i].type = type; sockList[i].ssl_tls_type = ssl_tls_type; sockList[i].localaddr=new CHARSTRING(""); sockList[i].localport=new PortNumber(-1); sockList[i].remoteaddr=new CHARSTRING(""); sockList[i].remoteport=new PortNumber(-1); #ifdef IPL4_USE_SSL sockList[i].sslObj = NULL; sockList[i].bio = NULL; sockList[i].sslCTX = NULL; #endif sockList[i].sctpHandshakeCompletedBeforeDtls = false; // Set local socket details SockAddr sa; socklen_t saLen = sizeof(SockAddr); if (getsockname(sock,(struct sockaddr *)&sa, &saLen) == -1) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::ConnAdd: getsockname error: %s", strerror(errno)); return -1; } else if (!SetNameAndPort(&sa, saLen, *(sockList[i].localaddr), *(sockList[i].localport))) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::ConnAdd: SetNameAndPort failed"); return -1; } sockList[i].buf = NULL; sockList[i].assocIdList = NULL; sockList[i].cnt = 0; switch (type) { case IPL4asp_TCP_LISTEN: case IPL4asp_SCTP_LISTEN: break; case IPL4asp_UDP: //case IPL4asp_UDP_LIGHT: case IPL4asp_TCP: case IPL4asp_SCTP: sockList[i].buf = (TTCN_Buffer **)Malloc(sizeof(TTCN_Buffer *)); *sockList[i].buf = new TTCN_Buffer; if (*sockList[i].buf == NULL) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::ConnAdd: failed to add socket %d", sock); Free(sockList[i].buf); sockList[i].buf = 0; return -1; } if(type == IPL4asp_TCP) { sockList[i].assocIdList = NULL; } else { // IPL4asp_SCTP sockList[i].assocIdList = (sctp_assoc_t *)Malloc(sizeof(sctp_assoc_t)); } sockList[i].cnt = 1; if (getpeername(sock, (struct sockaddr *)&sa, &saLen) == -1) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::ConnAdd: getpeername failed: %s", strerror(errno)); // sendError(PortError::ERROR__HOSTNAME, i, errno); } else if (!SetNameAndPort(&sa, saLen, *(sockList[i].remoteaddr), *(sockList[i].remoteport))) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::ConnAdd: SetNameAndPort failed"); sendError(PortError::ERROR__HOSTNAME, i); } break; } switch(ssl_tls_type) { case NONE: // nothing to be done break; case SERVER: sockList[i].sslState = STATE_NORMAL; break; case CLIENT: sockList[i].sslState = STATE_CONNECTING; sockList[i].server = false; break; default: IPL4_DEBUG("IPL4asp__PT_PROVIDER::ConnAdd: unhandled SSL/TLS type"); sendError(PortError::ERROR__GENERAL, i); break; } Handler_Add_Fd_Read(sock); sockList[i].sock = sock; firstFreeSock = sockList[i].nextFree; sockList[i].nextFree = -1; ++sockListCnt; if(sockListCnt==1) {lonely_conn_id=i;} else {lonely_conn_id=-1;} IPL4_DEBUG("IPL4asp__PT_PROVIDER::ConnAdd: leave: sockListCnt: %i", sockListCnt); return i; } // IPL4asp__PT::ConnAdd void SockDesc::clear() { for (unsigned int i = 0; i < cnt; ++i) delete buf[i]; cnt = 0; Free(buf); buf = 0; Free(assocIdList); assocIdList = 0; delete msgLenArgs; msgLenArgs = 0; delete msgLenArgs_forConnClosedEvent; msgLenArgs_forConnClosedEvent = 0; delete localaddr; localaddr = 0; delete localport; localport = 0; delete remoteaddr; remoteaddr = 0; delete remoteport; remoteport = 0; delete tls_hostname; tls_hostname = NULL; delete alpn; alpn=NULL; Free(ssl_key_file); ssl_key_file = NULL; Free(ssl_certificate_file ); ssl_certificate_file = NULL; Free(ssl_trustedCAlist_file); ssl_trustedCAlist_file = NULL; Free(ssl_cipher_list); ssl_cipher_list = NULL; Free(ssl_password); ssl_password = NULL; Free(psk_identity); psk_identity = NULL; Free(psk_identity_hint); psk_identity_hint = NULL; Free(psk_key); psk_key = NULL; if(dtlsSrtpProfiles){ Free(dtlsSrtpProfiles); dtlsSrtpProfiles=NULL; } sock = SOCK_NONEX; msgLen = -1; nextFree = -1; } int IPL4asp__PT_PROVIDER::ConnDel(int connId, bool forced) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::ConnDel: enter: connId: %d", connId); int sock = sockList[connId].sock; IPL4_DEBUG("IPL4asp__PT_PROVIDER::ConnDel: fd: %d", sock); if (sock <= 0) return -1; Handler_Remove_Fd(sock, EVENT_ALL); #ifdef IPL4_USE_SSL if((sockList[connId].ssl_tls_type != NONE) && (sockList[connId].type != IPL4asp_SCTP_LISTEN) && (sockList[connId].type != IPL4asp_TCP_LISTEN) && mapped) perform_ssl_shutdown(connId); sockList[connId].sctpHandshakeCompletedBeforeDtls = false; #endif if (close(sock) == -1) { TTCN_warning("IPL4asp__PT_PROVIDER::ConnDel: failed to close socket" " %d: %s, connId: %d", sock, strerror(errno), connId); } fd2IndexMap.erase(sockList[connId].sock); sockList[connId].clear(); if(!connId_release_confirmed || forced){ ConnFree(connId); } else { sockList[connId].sock = SockDesc::WAIT_FOR_RELEASE; incoming_message(ASP__ConnId__ReadyToRelease(connId)); } return connId; } // IPL4asp__PT_PROVIDER::ConnDel void IPL4asp__PT_PROVIDER::ConnFree(int connId) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::ConnFree: enter: connId: %d", connId); sockList[connId].sock = SockDesc::SOCK_NONEX; sockList[lastFreeSock].nextFree = connId; lastFreeSock = connId; sockListCnt--; if(sockListCnt==1) { unsigned int i=0; while(iget_string(oct); sockList[id].msgLen = sockList[id].getMsgLen_forConnClosedEvent.invoke(oct,*sockList[id].msgLenArgs_forConnClosedEvent); msgFound = (sockList[id].msgLen > 0) && (sockList[id].msgLen <= (int)sockList[id].buf[0]->get_len()); if (msgFound) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::reportRemainingData_beforeConnClosed: message length: (%d/%d bytes)\n", sockList[id].msgLen, (int)sockList[id].buf[0]->get_len()); ASP__RecvFrom asp; asp.connId() = id; asp.userData() = userData; asp.remName() = remoteaddr; asp.remPort() = remoteport; asp.locName() = localaddr; asp.locPort() = localport; asp.proto() = proto; asp.msg() = OCTETSTRING(sockList[id].msgLen, sockList[id].buf[0]->get_data()); sockList[id].buf[0]->set_pos((size_t)sockList[id].msgLen); sockList[id].buf[0]->cut(); if(lazy_conn_id_level && sockListCnt==1 && lonely_conn_id!=-1){ asp.connId()=-1; } incoming_message(asp); sockList[id].msgLen = -1; } } while (msgFound && sockList[id].buf[0]->get_len() != 0); if (sockList[id].buf[0]->get_len() != 0) IPL4_DEBUG("IPL4asp__PT_PROVIDER::reportRemainingData_beforeConnClosed: incomplete message remained (%d bytes)\n", (int)sockList[id].buf[0]->get_len()); } } void IPL4asp__PT_PROVIDER::sendConnClosed(const ConnectionId& id, const CHARSTRING& remoteaddr, const PortNumber& remoteport, const CHARSTRING& localaddr, const PortNumber& localport, const ProtoTuple& proto, const int& userData) { ASP__Event event_close; event_close.connClosed() = ConnectionClosedEvent(id, remoteaddr, remoteport, localaddr, localport, proto, userData); incoming_message(event_close); } // IPL4asp__PT_PROVIDER::sendConnClosed void IPL4asp__PT_PROVIDER::setResult(Socket__API__Definitions::Result& result, PortError code, const ConnectionId& id, int os_error_code) { result.errorCode() = code; result.connId() = id; if (os_error_code != 0) { result.os__error__code() = os_error_code; result.os__error__text() = strerror(os_error_code); } else { result.os__error__code() = OMIT_VALUE; result.os__error__text() = OMIT_VALUE; } } // IPL4asp__PT_PROVIDER::setResult void IPL4asp__PT_PROVIDER::starttls(const ConnectionId& connId, const BOOLEAN& server_side, Socket__API__Definitions::Result& result){ if(TTCN_Logger::log_this_event(TTCN_Logger::PORTEVENT_MMSEND)){ TTCN_Logger::begin_event(TTCN_Logger::PORTEVENT_MMSEND); TTCN_Logger::log_event("starttls connId: %d: server_side: %s", (int)connId, server_side ? "yes" : "no"); TTCN_Logger::end_event(); } #ifdef IPL4_USE_SSL if (!isConnIdValid(connId)) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::starttls: invalid connId: %i", (int)connId); setResult(result,PortError::ERROR__INVALID__CONNECTION,connId,0); return; } switch(sockList[connId].type) { case IPL4asp_UDP: //case IPL4asp_UDP_LIGHT: case IPL4asp_TCP: case IPL4asp_SCTP: case IPL4asp_TCP_LISTEN: case IPL4asp_SCTP_LISTEN: sockList[connId].ssl_tls_type = server_side ? SERVER : CLIENT; break; default: IPL4_DEBUG("IPL4asp__PT_PROVIDER::starttls: Unsupported protocol"); setResult(result,PortError::ERROR__UNSUPPORTED__PROTOCOL,connId,0); } sockList[connId].server = server_side; sockList[connId].sslState = STATE_CONNECTING; sockList[connId].sslObj = NULL; if((sockList[connId].type == IPL4asp_UDP || sockList[connId].type == IPL4asp_SCTP_LISTEN || sockList[connId].type == IPL4asp_SCTP) and server_side) { if(!ssl_create_contexts_and_obj(connId)) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::starttls: SSL initialization failed. Client: %d", (int)connId); setResult(result,PortError::ERROR__SOCKET,connId,0); return; } else { IPL4_DEBUG("IPL4asp__PT_PROVIDER::starttls: set server side BIO, connId: %d", (int)connId); if(sockList[connId].type == IPL4asp_UDP) sockList[connId].bio = BIO_new_dgram(sockList[connId].sock, BIO_NOCLOSE); if(sockList[connId].type == IPL4asp_SCTP_LISTEN || sockList[connId].type == IPL4asp_SCTP) { #ifdef OPENSSL_NO_SCTP TTCN_warning("The OpenSSL development library was compiled with disabled SCTP support. The 'OPENSSL_NO_SCTP' macro is present in the headers. Please install an OpenSSL development library with enabled SCTP support."); setResult(result,PortError::ERROR__SOCKET,connId,0); return; #endif #ifndef BIO_CTRL_DGRAM_SCTP_GET_RCVINFO TTCN_warning("The 'BIO_CTRL_DGRAM_SCTP_GET_RCVINFO' macro is not present in the OpenSSL headers. Please install a newer OpenSSL development library."); setResult(result,PortError::ERROR__SOCKET,connId,0); return; #endif #ifndef BIO_CTRL_DGRAM_SCTP_SET_SNDINFO TTCN_warning("The 'BIO_CTRL_DGRAM_SCTP_SET_SNDINFO' macro is not present in the OpenSSL headers. Please install a newer OpenSSL development library."); setResult(result,PortError::ERROR__SOCKET,connId,0); return; #endif #ifdef OPENSSL_SCTP_SUPPORT sockList[connId].bio = BIO_new_dgram_sctp(sockList[connId].sock, BIO_NOCLOSE); #endif } SSL_set_bio(sockList[connId].sslObj, sockList[connId].bio, sockList[connId].bio); /* Enable cookie exchange */ if(!(sockList[connId].type == IPL4asp_SCTP_LISTEN || sockList[connId].type == IPL4asp_SCTP)) SSL_set_options(sockList[connId].sslObj, SSL_OP_COOKIE_EXCHANGE); // in DTLS server case, wait the client to ping us, and call DTLSv1_listen in the handleevent_readable return; } } // if we are DTLS client, then add BIO, then go further with the perform handshake if((sockList[connId].type == IPL4asp_UDP || sockList[connId].type == IPL4asp_SCTP_LISTEN || sockList[connId].type == IPL4asp_SCTP) and !server_side) { if(!ssl_create_contexts_and_obj(connId)) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::starttls: SSL initialization failed. Client: %d", (int)connId); setResult(result,PortError::ERROR__SOCKET,connId,0); return; } else { IPL4_DEBUG("IPL4asp__PT_PROVIDER::starttls: set client side BIO, connId: %d", (int)connId); if(sockList[connId].type == IPL4asp_UDP) sockList[connId].bio = BIO_new_dgram(sockList[connId].sock, BIO_NOCLOSE); SockAddr sa_server; socklen_t sa_len; SetSockAddr((const char*)*sockList[connId].remoteaddr, (int)*sockList[connId].remoteport, sa_server, sa_len); if(sockList[connId].type == IPL4asp_UDP) BIO_ctrl(sockList[connId].bio, BIO_CTRL_DGRAM_SET_CONNECTED, 0, &sa_server); #ifdef OPENSSL_SCTP_SUPPORT if(sockList[connId].type == IPL4asp_SCTP) sockList[connId].bio = BIO_new_dgram_sctp(sockList[connId].sock, BIO_NOCLOSE); #endif SSL_set_bio(sockList[connId].sslObj, sockList[connId].bio, sockList[connId].bio); } } IPL4_DEBUG("IPL4asp__PT_PROVIDER::starttls: before calling perform_ssl_handshake(%d)", (int)connId); int res=perform_ssl_handshake(connId); switch(res){ case SUCCESS: IPL4_DEBUG("IPL4asp__PT_PROVIDER::starttls: handshaking is successful"); sockList[connId].sslState = STATE_NORMAL; break; case WANT_WRITE: case WANT_READ: if(!server_side) { // wake me up when the client is receiving something Handler_Add_Fd_Read(sockList[connId].sock); } else { // wake me up when a client is ringing to make an incoming connection Handler_Add_Fd_Write(sockList[connId].sock); } setResult(result,PortError::ERROR__TEMPORARILY__UNAVAILABLE,connId,0); break; default: setResult(result,PortError::ERROR__SOCKET,connId,0); } #else IPL4_DEBUG("IPL4asp__PT_PROVIDER::starttls: Unsupported protocol"); setResult(result,PortError::ERROR__UNSUPPORTED__PROTOCOL,connId,0); #endif return; } void IPL4asp__PT_PROVIDER::stoptls(const ConnectionId& connId, Socket__API__Definitions::Result& result){ if(TTCN_Logger::log_this_event(TTCN_Logger::PORTEVENT_MMSEND)){ TTCN_Logger::begin_event(TTCN_Logger::PORTEVENT_MMSEND); TTCN_Logger::log_event("stoptls connId: %d", (int)connId); TTCN_Logger::end_event(); } #ifdef IPL4_USE_SSL if(!perform_ssl_shutdown(connId)) { setResult(result,PortError::ERROR__UNSUPPORTED__PROTOCOL,connId,0); } #endif } OCTETSTRING IPL4asp__PT_PROVIDER::exportTlsKey( const IPL4asp__Types::ConnectionId& connId, const CHARSTRING& label, const OCTETSTRING& context, const INTEGER& keyLen) { if (!isConnIdValid(connId)) { TTCN_warning("Invalid connection id: %d", (int)connId); return OCTETSTRING(0, NULL); } #ifdef IPL4_USE_SSL #ifdef SRTP_AES128_CM_SHA1_80 if(!sockList[(int)connId].sslObj) { TTCN_warning("Connection id: %d is not an SSL connection", (int)connId); return OCTETSTRING(0, NULL); } unsigned char* out = (unsigned char*)Malloc(keyLen + 1); int ret = SSL_export_keying_material( sockList[(int)connId].sslObj, out, (int)keyLen, label, label.lengthof(), context, context.lengthof(), context.lengthof() > 0); if(!ret) { TTCN_warning("Can not export TLS1 key of connection: %d", (int)connId); ssl_getresult(ret); Free(out); return OCTETSTRING(0, NULL); } OCTETSTRING final = OCTETSTRING(keyLen, out); Free(out); return final; #else TTCN_error("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: DTLS is not supported by the current OpenSSL API. libopenssl >=1.0.1 is required!"); #endif #else //IPL4_USE_SSL log_warning("Compile the test with -DIPL4_USE_SSL & libopenssl >= 1.0.1 in order to use the exportTlsKey function!"); sendError(PortError::ERROR__SOCKET, connId); return OCTETSTRING(0, NULL); #endif // IPL4_USE_SSL } IPL4__SrtpKeysAndSalts IPL4asp__PT_PROVIDER::exportSrtpKeysAndSalts( const IPL4asp__Types::ConnectionId& connId) { IPL4__SrtpKeysAndSalts ret( OCTETSTRING(0, NULL), OCTETSTRING(0, NULL), OCTETSTRING(0, NULL), OCTETSTRING(0, NULL)); if (!isConnIdValid(connId)) { TTCN_warning("Invalid connection id: %d", (int)connId); return ret; } #ifdef IPL4_USE_SSL #ifdef SRTP_AES128_CM_SHA1_80 if(!sockList[(int)connId].sslObj) { TTCN_warning("Connection id: %d is not an SSL connection", (int)connId); return ret; } // SRTP (rfc3711) defines Key length as 16, Salt length as 14 // we need here space both for the client and server unsigned char* out = (unsigned char*)Malloc((16 + 14) * 2); int retv = SSL_export_keying_material( sockList[(int)connId].sslObj, out, (16 + 14) * 2, "EXTRACTOR-dtls_srtp", 19, NULL, 0, 0); if(!retv) { TTCN_warning("Can not export DTLS keys of connection: %d", (int)connId); ssl_getresult(retv); Free(out); return ret; } if(sockList[(int)connId].ssl_tls_type == CLIENT) { ret.localKey() = OCTETSTRING(16, out); ret.remoteKey() = OCTETSTRING(16, out + 16); ret.localSalt() = OCTETSTRING(14, out + 32); ret.remoteSalt() = OCTETSTRING(14, out + 46); } else { ret.remoteKey() = OCTETSTRING(16, out); ret.localKey() = OCTETSTRING(16, out + 16); ret.remoteSalt() = OCTETSTRING(14, out + 32); ret.localSalt() = OCTETSTRING(14, out + 46); } return ret; #else TTCN_error("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: DTLS is not supported by the current OpenSSL API. libopenssl >=1.0.1 is required!"); #endif #else //IPL4_USE_SSL log_warning("Compile the test with -DIPL4_USE_SSL & libopenssl >= 1.0.1 in order to use the exportSrtpKeysAndSalts function!"); sendError(PortError::ERROR__SOCKET, connId); return ret; #endif // IPL4_USE_SSL } OCTETSTRING IPL4asp__PT_PROVIDER::exportSctpKey( const IPL4asp__Types::ConnectionId& connId) { if (!isConnIdValid(connId)) { TTCN_warning("Invalid connection id: %d", (int)connId); return OCTETSTRING(0, NULL); } #ifdef IPL4_USE_SSL #ifdef OPENSSL_SCTP_SUPPORT if(!sockList[(int)connId].sslObj) { TTCN_warning("Connection id: %d is not an SSL connection", (int)connId); return OCTETSTRING(0, NULL); } // RFC 6083: 64-byte shared secret key is derived from every master secret unsigned char sctpauthkey[64]; // derive secret key from master key int ret = SSL_export_keying_material( sockList[(int)connId].sslObj, sctpauthkey, sizeof(sctpauthkey), DTLS1_SCTP_AUTH_LABEL, sizeof(DTLS1_SCTP_AUTH_LABEL), NULL, 0, 0); if(!ret) { TTCN_warning("Can not export SSL key of connection: %d", (int)connId); ssl_getresult(ret); return OCTETSTRING(0, NULL); } OCTETSTRING final = OCTETSTRING(sizeof(sctpauthkey), sctpauthkey); return final; #else TTCN_error("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: SCTP over DTLS is not supported by the current OpenSSL API. libopenssl >=1.0.1q is required!"); #endif #else //IPL4_USE_SSL log_warning("Compile the test with -DIPL4_USE_SSL & libopenssl >= 1.0.1q in order to use the exportSctpKey function!"); sendError(PortError::ERROR__SOCKET, connId); return OCTETSTRING(0, NULL); #endif // IPL4_USE_SSL } #ifdef IPL4_USE_SSL CHARSTRING IPL4_get_certificate_fingerprint(const X509 *x509, const IPL4__DigestMethods& method) { CHARSTRING ret(""); unsigned char fingerprint_buff[EVP_MAX_MD_SIZE]; unsigned int fingerprint_size; const EVP_MD* fingerprint_type = EVP_sha1(); switch(method) { case IPL4__DigestMethods::NULL__method: fingerprint_type = EVP_md_null(); break; //MD2, MDC2 is disabled in OpenSSL /*case IPL4__DigestMethods::MD2: fingerprint_type = EVP_md2(); break; case IPL4__DigestMethods::MDC2: fingerprint_type = EVP_mdc2(); break;*/ case IPL4__DigestMethods::MD4: fingerprint_type = EVP_md4(); break; case IPL4__DigestMethods::MD5: fingerprint_type = EVP_md5(); break; #if OPENSSL_VERSION_NUMBER < 0x10100000L case IPL4__DigestMethods::SHA: fingerprint_type = EVP_sha(); break; #endif case IPL4__DigestMethods::SHA1: fingerprint_type = EVP_sha1(); break; #if OPENSSL_VERSION_NUMBER < 0x10100000L case IPL4__DigestMethods::DSS: fingerprint_type = EVP_dss(); break; case IPL4__DigestMethods::DSS1: fingerprint_type = EVP_dss1(); break; case IPL4__DigestMethods::ECDSA: fingerprint_type = EVP_ecdsa(); break; #endif case IPL4__DigestMethods::SHA224: fingerprint_type = EVP_sha224(); break; case IPL4__DigestMethods::SHA256: fingerprint_type = EVP_sha256(); break; case IPL4__DigestMethods::SHA384: fingerprint_type = EVP_sha384(); break; case IPL4__DigestMethods::SHA512: fingerprint_type = EVP_sha512(); break; case IPL4__DigestMethods::RIPEMD160: fingerprint_type = EVP_ripemd160(); break; #ifdef SRTP_AES128_CM_SHA1_80 case IPL4__DigestMethods::WHIRLPOOL: fingerprint_type = EVP_whirlpool(); break; #else TTCN_error("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: DTLS is not supported by the current OpenSSL API. libopenssl >=1.0.1 is required!"); #endif default: TTCN_warning("IPL4_get_certificate_fingerprint: requested fingerprint type is not handled by IPL4 testport!"); return ret; } if(!fingerprint_type) { TTCN_warning("IPL4_get_certificate_fingerprint: requested fingerprint type is not handled by OpenSSL!"); return ret; } if (X509_digest(x509, fingerprint_type, fingerprint_buff, &fingerprint_size)) { //ssl_own_fingerprint = CHARSTRING(fingerprint_size, fingerprint_buff); CHARSTRING colon = CHARSTRING(":"); char buf[3]; //fprintf(stderr, "fingerprint: %s\n", fingerprint_buff); for (unsigned int i = 0; i < fingerprint_size; i++) { sprintf(buf, "%02X", fingerprint_buff[i]); ret = ret + CHARSTRING(2, buf); if(i < fingerprint_size - 1) { ret = ret + colon; } } } else { TTCN_warning("IPL4asp__PT_PROVIDER::IPL4_get_certificate_fingerprint: could not calculate fingerprint"); } return ret; } #endif CHARSTRING IPL4asp__PT_PROVIDER::getLocalCertificateFingerprint(const IPL4__DigestMethods& method,const ConnectionId& connId, const CHARSTRING& certificate__file) { #ifdef IPL4_USE_SSL if(!ssl_init_SSL(connId)) { return ""; } BIO* certificate_bio = BIO_new(BIO_s_file()); const char* cf=NULL; if(certificate__file.lengthof()!=0){ cf=(const char*)certificate__file; }else if(ssl_cert_per_conn && isConnIdValid(connId) && sockList[(int)connId].ssl_certificate_file){ cf=sockList[(int)connId].ssl_certificate_file; } else { cf=ssl_certificate_file; } if(!BIO_read_filename(certificate_bio, cf)) { TTCN_warning("IPL4asp__PT_PROVIDER::getLocalCertificateFingerprint: could not load certificate file %s @1!", cf); return ""; } X509 *x509 = PEM_read_bio_X509(certificate_bio, NULL, 0, NULL); if (!x509) { TTCN_warning("IPL4asp__PT_PROVIDER::getLocalCertificateFingerprint: could not load certificate file @2!"); return ""; } return IPL4_get_certificate_fingerprint(x509, method); #else //IPL4_USE_SSL log_warning("Compile the test with -DIPL4_USE_SSL & libopenssl >= 1.0.1 in order to use the getLocalCertificateFingerprint function!"); return ""; #endif // IPL4_USE_SSL } CHARSTRING IPL4asp__PT_PROVIDER::getPeerCertificateFingerprint(const ConnectionId& connId, const IPL4__DigestMethods& method){ Result result(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE); if (!isConnIdValid(connId)) { TTCN_warning("Invalid connection id: %d", (int)connId); return ""; } #ifdef IPL4_USE_SSL if(!sockList[(int)connId].sslObj) { TTCN_warning("Connection id: %d is not an SSL connection", (int)connId); return ""; } X509 *x509 = SSL_get_peer_certificate(sockList[(int)connId].sslObj); if(!x509) { TTCN_warning("Connection id: %d - peer has no certificate", (int)connId); return ""; } return IPL4_get_certificate_fingerprint(x509, method); #else //IPL4_USE_SSL log_warning("Compile the test with -DIPL4_USE_SSL & libopenssl >= 1.0.1 in order to use the getPeerCertificateFingerprint function!"); sendError(PortError::ERROR__SOCKET, connId); return ""; #endif // IPL4_USE_SSL } CHARSTRING IPL4asp__PT_PROVIDER::getSelectedSrtpProfile(const ConnectionId& connId){ Result result(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE); if (!isConnIdValid(connId)) { TTCN_warning("Invalid connection id: %d", (int)connId); return ""; } #ifdef IPL4_USE_SSL #ifdef SRTP_AES128_CM_SHA1_80 if(!sockList[(int)connId].sslObj) { TTCN_warning("Connection id: %d is not an SSL connection", (int)connId); return ""; } SRTP_PROTECTION_PROFILE* profile = SSL_get_selected_srtp_profile(sockList[(int)connId].sslObj); return profile ? profile->name : ""; #else TTCN_error("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: DTLS is not supported by the current OpenSSL API. libopenssl >=1.0.1 is required!"); #endif #else //IPL4_USE_SSL log_warning("Compile the test with -DIPL4_USE_SSL & libopenssl >= 1.0.1 in order to use the getSelectedSrtpProfile function!"); sendError(PortError::ERROR__SOCKET, connId); return ""; #endif // IPL4_USE_SSL } void f__IPL4__PROVIDER__setGetMsgLen(IPL4asp__PT_PROVIDER& portRef, const ConnectionId& connId, f__IPL4__getMsgLen& f, const ro__integer& msgLenArgs) { portRef.testIfInitialized(); if ((int)connId == -1) { portRef.defaultGetMsgLen = f; delete portRef.defaultMsgLenArgs; portRef.defaultMsgLenArgs = new Socket__API__Definitions::ro__integer(msgLenArgs); IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__setGetMsgLen: " "The default getMsgLen fn is modified"); } else { if (!portRef.isConnIdValid(connId)) { IPL4_PORTREF_DEBUG(portRef, "IPL4asp__PT_PROVIDER::f__IPL4__PROVIDER__setGetMsgLen: " "invalid connId: %i", (int)connId); return; } IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__setGetMsgLen: " "getMsgLen fn for connection %d is modified", (int)connId); portRef.sockList[(int)connId].getMsgLen = f; delete portRef.sockList[(int)connId].msgLenArgs; portRef.sockList[(int)connId].msgLenArgs = new Socket__API__Definitions::ro__integer(msgLenArgs); } } // f__IPL4__PROVIDER__setGetMsgLen void f__IPL4__PROVIDER__setGetMsgLen__forConnClosedEvent(IPL4asp__PT_PROVIDER& portRef, const ConnectionId& connId, f__IPL4__getMsgLen& f, const ro__integer& msgLenArgs) { portRef.testIfInitialized(); if ((int)connId == -1) { portRef.defaultGetMsgLen_forConnClosedEvent = f; delete portRef.defaultMsgLenArgs_forConnClosedEvent; portRef.defaultMsgLenArgs_forConnClosedEvent = new Socket__API__Definitions::ro__integer(msgLenArgs); IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__setGetMsgLen_forConnClosedEvent: " "The default getMsgLen_forConnClosedEvent fn is modified"); } else { if (!portRef.isConnIdValid(connId)) { IPL4_PORTREF_DEBUG(portRef, "IPL4asp__PT_PROVIDER::f__IPL4__PROVIDER__setGetMsgLen_forConnClosedEvent: " "invalid connId: %i", (int)connId); return; } IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__setGetMsgLen_forConnClosedEvent: " "getMsgLen_forConnClosedEvent fn for connection %d is modified", (int)connId); portRef.sockList[(int)connId].getMsgLen_forConnClosedEvent = f; delete portRef.sockList[(int)connId].msgLenArgs_forConnClosedEvent; portRef.sockList[(int)connId].msgLenArgs_forConnClosedEvent = new Socket__API__Definitions::ro__integer(msgLenArgs); } } // f__IPL4__PROVIDER__setGetMsgLen_forConnClosedEvent Result f__IPL4__PROVIDER__listen(IPL4asp__PT_PROVIDER& portRef, const HostName& locName, const PortNumber& locPort, const ProtoTuple& proto, const OptionList& options) { Result result(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE); SockAddr sockAddr; socklen_t sockAddrLen; int hp = 0; SSL_TLS_Type ssl_tls_type = NONE; ProtoTuple my_proto = proto; if(TTCN_Logger::log_this_event(TTCN_Logger::PORTEVENT_MMSEND)){ TTCN_Logger::begin_event(TTCN_Logger::PORTEVENT_MMSEND); TTCN_Logger::log_event("entering f__IPL4__PROVIDER__listen: %s:%d / %s", (const char *)locName, (int)locPort, proto.get_selection() == ProtoTuple::ALT_udp ? "UDP" : proto.get_selection() == ProtoTuple::ALT_udpLight ? "UDP Light" : proto.get_selection() == ProtoTuple::ALT_tcp ? "TCP" : proto.get_selection() == ProtoTuple::ALT_sctp ? "SCTP" : proto.get_selection() == ProtoTuple::ALT_ssl ? "SSL" : proto.get_selection() == ProtoTuple::ALT_udpLight ? "UDP Light" : proto.get_selection() == ProtoTuple::ALT_unspecified ? "Unspecified" : proto.get_selection() == ProtoTuple::ALT_dtls ? proto.dtls().get_selection() == Socket__API__Definitions::DtlsTuple::ALT_udp ? "DTLS/UDP" : proto.dtls().get_selection() == Socket__API__Definitions::DtlsTuple::ALT_sctp ? "DTLS/SCTP" : "DTLS/???" : "???"); TTCN_Logger::end_event(); } IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__listen: enter %s %d", (const char *) locName, (int) locPort); portRef.testIfInitialized(); //check if all mandatory SSL config params are present for a listening socket #ifdef IPL4_USE_SSL if((proto.get_selection() == ProtoTuple::ALT_ssl) || (proto.get_selection() == ProtoTuple::ALT_dtls)) { ssl_tls_type = SERVER; } // set tls_used if tls is used, and copy the proto coming in proto.dtls into my_proto if(proto.get_selection() == ProtoTuple::ALT_dtls) { switch (proto.dtls().get_selection()) { case Socket__API__Definitions::DtlsTuple::ALT_udp: my_proto.udp() = proto.dtls().udp(); break; case Socket__API__Definitions::DtlsTuple::ALT_sctp: my_proto.sctp() = proto.dtls().sctp(); break; default: case ProtoTuple::UNBOUND_VALUE: RETURN_ERROR(ERROR__UNSUPPORTED__PROTOCOL); } } #endif if (locPort < -1 || locPort > 65535) RETURN_ERROR(ERROR__INVALID__INPUT__PARAMETER); hp=SetLocalSockAddr("f__IPL4__PROVIDER__listen",portRef,AF_INET,locName, locPort, sockAddr, sockAddrLen); if (hp == -1) { SET_OS_ERROR_CODE; RETURN_ERROR(ERROR__HOSTNAME); } #ifdef LKSCTP_MULTIHOMING_ENABLED int addr_index=-1; int num_of_addr=0; unsigned char* sarray=NULL; #ifdef USE_IPL4_EIN_SCTP if(portRef.native_stack){ #endif for(int i=0; i %s:%d / %s", (const char *)locName, (int)locPort, (const char *)remName, (int)remPort, proto.get_selection() == ProtoTuple::ALT_udp ? "UDP" : proto.get_selection() == ProtoTuple::ALT_udpLight ? "UDP Light" : proto.get_selection() == ProtoTuple::ALT_tcp ? "TCP" : proto.get_selection() == ProtoTuple::ALT_sctp ? "SCTP" : proto.get_selection() == ProtoTuple::ALT_ssl ? "SSL" : proto.get_selection() == ProtoTuple::ALT_udpLight ? "UDP Light" : proto.get_selection() == ProtoTuple::ALT_unspecified ? "Unspecified" : proto.get_selection() == ProtoTuple::ALT_dtls ? proto.dtls().get_selection() == Socket__API__Definitions::DtlsTuple::ALT_udp ? "DTLS/UDP" : proto.dtls().get_selection() == Socket__API__Definitions::DtlsTuple::ALT_sctp ? "DTLS/SCTP" : "DTLS/???" : "???"); TTCN_Logger::end_event(); } IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connect: enter"); portRef.testIfInitialized(); if (remName == "") RETURN_ERROR(ERROR__HOSTNAME); if (remPort < 0 || remPort > 65535 || locPort < -1 || locPort > 65535) RETURN_ERROR(ERROR__INVALID__INPUT__PARAMETER); if ((hp = SetSockAddr(remName, remPort, saRem, saRemLen)) == -1) { SET_OS_ERROR_CODE; RETURN_ERROR(ERROR__HOSTNAME); } SSL_TLS_Type ssl_tls_type = NONE; ProtoTuple my_proto = proto; // set tls_used if tls is used, and copy the proto coming in proto.dtls into my_proto if(proto.get_selection() == ProtoTuple::ALT_dtls) { ssl_tls_type = CLIENT; IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connect: ssl_tls_type set to %d", ssl_tls_type); switch (proto.dtls().get_selection()) { case Socket__API__Definitions::DtlsTuple::ALT_udp: my_proto.udp() = proto.dtls().udp(); break; case Socket__API__Definitions::DtlsTuple::ALT_sctp: my_proto.sctp() = proto.dtls().sctp(); break; default: case ProtoTuple::UNBOUND_VALUE: RETURN_ERROR(ERROR__UNSUPPORTED__PROTOCOL); } } #ifdef LKSCTP_MULTIHOMING_ENABLED int num_of_addr_rem=0; unsigned char* sarray_rem=NULL; #ifdef USE_IPL4_EIN_SCTP if(portRef.native_stack){ #endif // USE_IPL4_EIN_SCTP if(my_proto.ischosen(ProtoTuple::ALT_sctp) && my_proto.sctp().remSocks().ispresent()){ num_of_addr_rem=my_proto.sctp().remSocks()().size_of(); } if(num_of_addr_rem){ sarray_rem=(unsigned char*)Malloc((num_of_addr_rem+1)* #ifdef USE_IPV6 sizeof(struct sockaddr_in6) #else sizeof(struct sockaddr_in) #endif // USE_IPV6 ); int used_bytes=0; if(hp==AF_INET){ memcpy (sarray_rem , &saRem, sizeof (struct sockaddr_in)); used_bytes += sizeof (struct sockaddr_in); } #ifdef USE_IPV6 else{ memcpy (sarray_rem , &saRem, sizeof (struct sockaddr_in6)); used_bytes += sizeof (struct sockaddr_in6); } #endif // USE_IPV6 IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__listen: addr family main: %s ",hp==-1?"Error":hp==AF_INET?"AF_INET":"AF_INET6"); int final_hp_rem=hp; for(int i=0; i 0) { if (!portRef.isConnIdValid(connId)) { IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connect:: invalid connId: %i", (int)connId); RETURN_ERROR(ERROR__INVALID__INPUT__PARAMETER); } result.connId()() = connId; sock = portRef.sockList[(int)connId].sock; } else { IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connect: " "create new socket: %s:%d -> %s:%d", (const char *)locName, (int)locPort, (const char *)remName, (int)remPort); switch(my_proto.get_selection()) { case ProtoTuple::ALT_udp: { // use the original proto here; in case DTLS is used result = f__IPL4__PROVIDER__listen(portRef, locName, locPort, proto, options); if (result.errorCode().ispresent() && (result.errorCode() != PortError::ERROR__TEMPORARILY__UNAVAILABLE)) return result; IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connect: connId: %d", (int)result.connId()()); sock = portRef.sockList[(int)result.connId()()].sock; break; } #ifdef IPL4_USE_SSL case ProtoTuple::ALT_ssl: #endif case ProtoTuple::ALT_tcp: { SockAddr saLoc; socklen_t saLocLen; //struct hostent *hp = NULL; int hp2 = SetLocalSockAddr("f__IPL4__PROVIDER__connect",portRef,hp,locName, locPort, saLoc, saLocLen); // if (locPort != -1 && locName != "") // hp = SetSockAddr(locName, locPort, saLoc, saLocLen); // else if (locName == "" && locPort == -1) { // use default host and port // IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connect: use defaults: %s:%d", // portRef.defaultLocHost, portRef.defaultLocPort); // hp = SetSockAddr(HostName(portRef.defaultLocHost), // portRef.defaultLocPort, saLoc, saLocLen); // } else if (locPort == -1) { // use default port // IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connect: use default port: %s:%d", // (const char *)locName, portRef.defaultLocPort); // hp = SetSockAddr(locName, portRef.defaultLocPort, saLoc, saLocLen); // } else { // use default host // IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connect: use default host: %s:%d", // portRef.defaultLocHost, (int)locPort); // hp = SetSockAddr(HostName(portRef.defaultLocHost), // locPort, saLoc, saLocLen); // } if (hp2 == -1) { SET_OS_ERROR_CODE; RETURN_ERROR(ERROR__HOSTNAME); } int fd = socket(hp2, SOCK_STREAM, 0); if (fd == -1) { IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connect: " "failed to create new socket"); SET_OS_ERROR_CODE; RETURN_ERROR(ERROR__SOCKET); } // set socket properties if (!portRef.setOptions(options, fd, my_proto, true)) { IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connect: Setting options on " "socket %d failed: %s", fd, strerror(errno)); SET_OS_ERROR_CODE; close(fd); RETURN_ERROR(ERROR__SOCKET); } if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) { IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connect: fcntl O_NONBLOCK on " "socket %d failed: %s", fd, strerror(errno)); SET_OS_ERROR_CODE; close(fd); RETURN_ERROR(ERROR__SOCKET); } if (bind(fd, (struct sockaddr*)&saLoc, saLocLen) == -1) { IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connect: " "bind on socket %d failed: %s", fd, strerror(errno)); SET_OS_ERROR_CODE; close(fd); RETURN_ERROR(ERROR__SOCKET); } sock = fd; portRef.set_dscp_option(sock); break; } // ProtoTuple_alt_tcp case ProtoTuple::ALT_sctp: { #ifdef USE_IPL4_EIN_SCTP if(!portRef.native_stack){ result=portRef.Listen_einsctp(locName, locPort,SockDesc::ACTION_CONNECT,remName,remPort,options, my_proto.sctp().remSocks().ispresent()?my_proto.sctp().remSocks()():IPL4asp__Types::SocketList(NULL_VALUE)); if(portRef.globalConnOpts.extendedPortEvents == GlobalConnOpts::YES) { ASP__Event event; event.result() = result; portRef.incoming_message(event); } return result; break; } #endif #ifdef USE_SCTP SockAddr saLoc; socklen_t saLocLen; //struct hostent *hp = NULL; int hp2 = SetLocalSockAddr("f__IPL4__PROVIDER__connect",portRef,hp,locName, locPort, saLoc, saLocLen); // if (locPort != -1 && locName != "") // hp = SetSockAddr(locName, locPort, saLoc, saLocLen); // else if (locName == "" && locPort == -1) { // use default host and port // IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connect: use defaults: %s:%d", // portRef.defaultLocHost, portRef.defaultLocPort); // hp = SetSockAddr(HostName(portRef.defaultLocHost), // portRef.defaultLocPort, saLoc, saLocLen); // } else if (locPort == -1) { // use default port // IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connect: use default port: %s:%d", // (const char *)locName, portRef.defaultLocPort); // hp = SetSockAddr(locName, portRef.defaultLocPort, saLoc, saLocLen); // } else { // use default host // IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connect: use default host: %s:%d", // portRef.defaultLocHost, (int)locPort); // hp = SetSockAddr(HostName(portRef.defaultLocHost), // locPort, saLoc, saLocLen); // } if (hp2 == -1) { SET_OS_ERROR_CODE; #ifdef LKSCTP_MULTIHOMING_ENABLED if(sarray_rem) {Free(sarray_rem);} #endif RETURN_ERROR(ERROR__HOSTNAME); } #ifdef LKSCTP_MULTIHOMING_ENABLED int addr_index=-1; int num_of_addr=0; unsigned char* sarray=NULL; for(int i=0; i 0) break; if (nEvents < 0 && errno != EINTR) break; if (portRef.max_num_of_poll>0 && portRef.max_num_of_poll<=kk) break; } IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connect: EAGAIN: poll returned: %i", nEvents); IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connect: EAGAIN: revents: 0x%04X", pollFd.revents); bool socketError = false; if (nEvents > 0) { if ((pollFd.revents & POLLOUT) != 0) IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connect: EAGAIN: writable"); if ((my_proto.get_selection() == ProtoTuple::ALT_tcp) || (my_proto.get_selection() == ProtoTuple::ALT_ssl)) { int conresult=0; socklen_t conresult_len = sizeof(conresult); int sendRes = getsockopt(sock, SOL_SOCKET, SO_ERROR, &conresult, &conresult_len); IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connect: Probing connection: getsockopt returned: %d, connection result code: %d", sendRes,conresult); if (sendRes < 0) { SET_OS_ERROR_CODE; IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connect: getsockopt error: %s", strerror(errno)); socketError = true; } else if (conresult!=0) { result.os__error__code()() = conresult; IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connect: connect error: %s", strerror(conresult)); socketError = true; } } } else { SET_OS_ERROR_CODE; socketError = true; } if (socketError) { if (my_proto.get_selection() != ProtoTuple::ALT_udp || (int)connId == -1) { if (portRef.ConnDel(result.connId()(),true) == -1) IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connect: unable to close socket"); result.connId() = OMIT_VALUE; } RETURN_ERROR(ERROR__SOCKET); } // socketError } // einprog #ifdef IPL4_USE_SSL //Add SSL layer if(my_proto.get_selection() == ProtoTuple::ALT_ssl) { switch(portRef.perform_ssl_handshake((int)result.connId()())) { case SUCCESS: break; case WANT_WRITE: IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connect: leave (TEMPORARILY UNAVAILABLE) fd: %i", sock); RETURN_ERROR(ERROR__TEMPORARILY__UNAVAILABLE); break; case FAIL: default: //value IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connect: SSL mapping failed for client socket: %d", portRef.sockList[(int)result.connId()()].sock); SET_OS_ERROR_CODE; if (portRef.ConnDel(result.connId()(),true) == -1)IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connect: unable to close socket"); result.connId() = OMIT_VALUE; RETURN_ERROR(ERROR__SOCKET); break; } } else if(ssl_tls_type != NONE) { // if the original proto was DTLS + UDP or DTLS + UDP Light, then start the TLS layer IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connect: starting TLS on connId: %d", (int)result.connId()()); portRef.starttls((int)result.connId()(), false, result); } #endif break; } case ProtoTuple::ALT_sctp: { #ifdef USE_SCTP IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connect: sock: %d", sock); #ifdef IPL4_USE_SSL #ifdef OPENSSL_SCTP_SUPPORT // Initialize client BIO here // This will be initialized even in case of simple SCTP. When DTLS is utilized the BIO needs to be create before the connect. // This means that if a simple SCTP connect is called first and then later on the f_IPL4_StartTLS is used, // the BIO should be initialized here, otherwise segmentation fault is triggered in OpenSSL. BIO *bio_ptr = BIO_new_dgram_sctp(sock, BIO_NOCLOSE); if(!bio_ptr) { TTCN_warning("f__IPL4__PROVIDER__connect: failed to create BIO for SCTP. Please check that 'sysctl net.sctp.auth_enable' returns 1, otherwise set it!"); close(sock); RETURN_ERROR(ERROR__SOCKET); } #endif #endif #ifdef LKSCTP_MULTIHOMING_ENABLED if(sarray_rem) { IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connectx: sock: %d, num_of_addr %d", sock, num_of_addr_rem); if (my_sctp_connectx(sock, (struct sockaddr *)sarray_rem, num_of_addr_rem) == -1) { int l_errno = errno; SET_OS_ERROR_CODE; einprog = (l_errno == EINPROGRESS); if (!einprog) { IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connect: error: %s", strerror(errno)); close(sock); Free(sarray_rem); RETURN_ERROR(ERROR__SOCKET); } } Free(sarray_rem); } else #endif if (connect(sock, (struct sockaddr *)&saRem, saRemLen) == -1) { int l_errno = errno; SET_OS_ERROR_CODE; einprog = (l_errno == EINPROGRESS); if (!einprog) { IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connect: error: %s", strerror(errno)); close(sock); RETURN_ERROR(ERROR__SOCKET); } } int l_connId = portRef.ConnAdd(IPL4asp_SCTP, sock, ssl_tls_type,&options); if (l_connId == -1) { RETURN_ERROR(ERROR__INSUFFICIENT__MEMORY); } result.connId()() = l_connId; if((*portRef.sockList[l_connId].remoteport)==-1){ *portRef.sockList[l_connId].remoteaddr=remName; *portRef.sockList[l_connId].remoteport=remPort; } #ifdef IPL4_USE_SSL #ifdef OPENSSL_SCTP_SUPPORT // Init SSL object for client and copy BIO in sockList if((portRef.sockList[l_connId].type == IPL4asp_SCTP) && (portRef.sockList[l_connId].ssl_tls_type != NONE)) { portRef.sockList[l_connId].ssl_tls_type = CLIENT; portRef.sockList[l_connId].server = false; portRef.sockList[l_connId].sslState = STATE_CONNECTING; portRef.sockList[l_connId].sslObj = NULL; if(!portRef.ssl_create_contexts_and_obj(l_connId)) { IPL4_PORTREF_DEBUG(portRef, "IPL4asp__PT_PROVIDER::connect: SSL initialization failed. Client: %d", (int)l_connId); portRef.setResult(result,PortError::ERROR__SOCKET,l_connId,0); } else { IPL4_PORTREF_DEBUG(portRef, "IPL4asp__PT_PROVIDER::connect: set client side BIO, connId: %d, bio: %p", (int)l_connId, bio_ptr); portRef.sockList[l_connId].bio = bio_ptr; SSL_set_bio(portRef.sockList[l_connId].sslObj, portRef.sockList[l_connId].bio, portRef.sockList[l_connId].bio); } } #endif #endif if (einprog) { if (portRef.pureNonBlocking) { // The socket is not writeable yet portRef.Handler_Add_Fd_Write(sock); IPL4_PORTREF_DEBUG(portRef, "DO WRITE ON %i", sock); IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connect: leave (TEMPORARILY UNAVAILABLE) fd: %i", sock); RETURN_ERROR(ERROR__TEMPORARILY__UNAVAILABLE); } result.os__error__code() = OMIT_VALUE; pollfd pollFd; IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connect: EAGAIN: waiting in poll: fd %d connId: %d", sock, (int)result.connId()()); int nEvents = -1; for (int kk=1;;kk++) { memset(&pollFd, 0, sizeof(pollFd)); pollFd.fd = sock; pollFd.events = POLLOUT | POLLIN; nEvents = poll(&pollFd, 1, portRef.poll_timeout); // infinite if (nEvents > 0) break; if (nEvents < 0 && errno != EINTR) break; if (portRef.max_num_of_poll>0 && portRef.max_num_of_poll<=kk) break; } IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connect: EAGAIN: poll returned: %i", nEvents); IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connect: EAGAIN: revents: 0x%04X", pollFd.revents); bool socketError = false; if (nEvents > 0) { if ((pollFd.revents & POLLOUT) != 0) IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connect: EAGAIN: writable"); if (connect(sock, (struct sockaddr *)&saRem, saRemLen) == -1) { if(errno == EISCONN){ IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connect: Probing connection, result: sucessfull"); } else { IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connect: Probing connection, result: unsucessfull"); SET_OS_ERROR_CODE; socketError = true; } } } else { SET_OS_ERROR_CODE; socketError = true; } if (socketError) { if (portRef.ConnDel(result.connId()(),true) == -1) IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connect: unable to close socket"); result.connId() = OMIT_VALUE; RETURN_ERROR(ERROR__SOCKET); } // socketError } // einprog #endif break; } default: case ProtoTuple::UNBOUND_VALUE: RETURN_ERROR(ERROR__UNSUPPORTED__PROTOCOL); } // switch(my_proto.get_selection()) IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__connect: leave"); if(portRef.globalConnOpts.extendedPortEvents == GlobalConnOpts::YES) { ASP__Event event; event.result() = result; portRef.incoming_message(event); } return result; } // f__IPL4__PROVIDER__connect Result f__IPL4__PROVIDER__setOpt(IPL4asp__PT_PROVIDER& portRef, const OptionList& options, const ConnectionId& connId, const ProtoTuple& proto) { portRef.testIfInitialized(); Result result(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE,OMIT_VALUE); ProtoTuple protocol = proto; int sock = -1; if ((int)connId != -1) { if (!portRef.isConnIdValid(connId)) { RETURN_ERROR(ERROR__INVALID__INPUT__PARAMETER); } sock = portRef.sockList[(int)connId].sock; SockType type = (SockType)-1; if (!portRef.getAndCheckSockType(connId, proto.get_selection(), type)) RETURN_ERROR(ERROR__SOCKET); switch (type) { case IPL4asp_TCP_LISTEN: case IPL4asp_TCP: if(portRef.sockList[(int)connId].ssl_tls_type == NONE) { protocol.tcp() = TcpTuple(null_type()); } else { protocol.ssl() = SslTuple(null_type()); } break; case IPL4asp_UDP: protocol.udp() = UdpTuple(null_type()); break; //TCP<->UDP SWITCHED VALUES FIXED -- ETHNBA case IPL4asp_SCTP_LISTEN: case IPL4asp_SCTP: protocol.sctp() = SctpTuple(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE); break; default: break; } } if (!portRef.setOptions(options, sock, protocol)) RETURN_ERROR(ERROR__SOCKET); // if (!portRef.setDtlsSrtpProfiles(connId, options)) // RETURN_ERROR(ERROR__SOCKET); if ((int)connId != -1) { portRef.set_ssl_supp_option((int)connId,options); } return result; } Extended__Result f__IPL4__PROVIDER__getOpt(IPL4asp__PT_PROVIDER& portRef, const Option& option, const ConnectionId& connId, const ProtoTuple& proto) { Extended__Result result(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE,OMIT_VALUE,OMIT_VALUE); portRef.testIfInitialized(); ProtoTuple protocol = proto; int sock = -1; if ((int)connId != -1) { if (!portRef.isConnIdValid(connId)) { RETURN_EXTENDED_ERROR(ERROR__INVALID__INPUT__PARAMETER); } sock = portRef.sockList[(int)connId].sock; SockType type = (SockType)-1; if (!portRef.getAndCheckSockType(connId, proto.get_selection(), type)) { RETURN_EXTENDED_ERROR(ERROR__SOCKET); } } int socketValue = portRef.getOption(option, sock, protocol); if (socketValue < 0) { RETURN_EXTENDED_ERROR(ERROR__SOCKET); } else { result.msg() = int2oct(socketValue, 4); } return result; } Result f__IPL4__PROVIDER__close(IPL4asp__PT_PROVIDER& portRef, const ConnectionId& connId, const ProtoTuple& proto) { IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__close: enter: connId: %d", (int)connId); portRef.testIfInitialized(); Result result(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE,OMIT_VALUE); SockType type; if (!portRef.getAndCheckSockType(connId, proto.get_selection(), type)) { if(portRef.isConnIdReleaseWait(connId)){ return result; } RETURN_ERROR(ERROR__INVALID__INPUT__PARAMETER); } if (type == IPL4asp_SCTP_LISTEN || type == IPL4asp_SCTP) { // Close SCTP associations if any, but the socket is not closed. #ifdef USE_IPL4_EIN_SCTP if(!portRef.native_stack){ portRef.sockList[connId].next_action=SockDesc::ACTION_DELETE; if(type == IPL4asp_SCTP){ EINSS7_00SctpShutdownReq(portRef.sockList[connId].sock); } else { if(portRef.sockList[connId].ref_count==0){ EINSS7_00SctpDestroyReq(portRef.sockList[connId].endpoint_id); portRef.ConnDelEin(connId); } } } else { #endif if (portRef.ConnDel(connId) == -1) RETURN_ERROR(ERROR__SOCKET); #ifdef USE_IPL4_EIN_SCTP } #endif } else { if (portRef.ConnDel(connId) == -1) RETURN_ERROR(ERROR__SOCKET); } result.connId()() = connId; if(portRef.globalConnOpts.extendedPortEvents == GlobalConnOpts::YES) { ASP__Event event; event.result() = result; portRef.incoming_message(event); } return result; } // f__IPL4__PROVIDER__close Result f__IPL4__PROVIDER__setUserData( IPL4asp__PT_PROVIDER& portRef, const ConnectionId& id, const UserData& userData) { Result result(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE,OMIT_VALUE); if (portRef.setUserData((int)id, (int)userData) == -1) { RETURN_ERROR(ERROR__GENERAL); } return result; } // f__IPL4__PROVIDER__setUserData Result f__IPL4__PROVIDER__getUserData( IPL4asp__PT_PROVIDER& portRef, const ConnectionId& connId, UserData& userData) { Result result(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE,OMIT_VALUE); int userDataTemp; if (portRef.getUserData((int)connId, userDataTemp) == -1) { RETURN_ERROR(ERROR__GENERAL); } userData = userDataTemp; return result; } // f__IPL4__PROVIDER__getUserData Result f__IPL4__PROVIDER__port__settings( IPL4asp__PT_PROVIDER& portRef, const CHARSTRING& param__name, const CHARSTRING& param__value) { portRef.set_parameter((const char *)param__name,(const char *)param__value); return Result(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE,OMIT_VALUE); } Result f__IPL4__PROVIDER__getConnectionDetails( IPL4asp__PT_PROVIDER& portRef, const ConnectionId& connId, const IPL4__Param& IPL4param, IPL4__ParamResult& IPL4paramResult) { Result result(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE,OMIT_VALUE); IPL4__ParamResult paramResult; if (portRef.getConnectionDetails((int)connId, IPL4param, paramResult) == -1) { RETURN_ERROR(ERROR__GENERAL); } IPL4paramResult = paramResult; return result; } // f__IPL4__PROVIDER__getConnectionDetails Extended__Result f__IPL4__PROVIDER__getConnectedMTU(IPL4asp__PT_PROVIDER& portRef, const ConnectionId& connId, const ProtoTuple& proto) { IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__getConnectedMTU: ENTER"); Extended__Result result(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE,OMIT_VALUE,OMIT_VALUE); portRef.testIfInitialized(); IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__getConnectedMTU: obtaining Path Mtu from socket"); Option option; option.mtu__discover()=MTU__discover::MTU; result = f__IPL4__PROVIDER__getOpt(portRef, option, connId, proto); IPL4_PORTREF_DEBUG(portRef, "f__IPL4__PROVIDER__getConnectedMTU: obtained"); return result; } Result f__IPL4__PROVIDER__StartTLS( IPL4asp__PT_PROVIDER& portRef, const ConnectionId& connId, const BOOLEAN& server__side) { if(TTCN_Logger::log_this_event(TTCN_Logger::PORTEVENT_MMSEND)){ TTCN_Logger::begin_event(TTCN_Logger::PORTEVENT_MMSEND); TTCN_Logger::log_event("%s: f_IPL4_StartTLS: connId: %d, %s side", portRef.get_name(),(int)connId,server__side?"server":"client"); TTCN_Logger::end_event(); } Result result(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE); portRef.starttls(connId,server__side,result); return result; } Result f__IPL4__PROVIDER__StopTLS( IPL4asp__PT_PROVIDER& portRef, const ConnectionId& connId) { if(TTCN_Logger::log_this_event(TTCN_Logger::PORTEVENT_MMSEND)){ TTCN_Logger::begin_event(TTCN_Logger::PORTEVENT_MMSEND); TTCN_Logger::log_event("%s: f_IPL4_StopTLS: connId: %d", portRef.get_name(),(int)connId); TTCN_Logger::end_event(); } Result result(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE); portRef.stoptls(connId,result); return result; } OCTETSTRING f__IPL4__PROVIDER__exportTlsKey( IPL4asp__PT_PROVIDER& portRef, const IPL4asp__Types::ConnectionId& connId, const CHARSTRING& label, const OCTETSTRING& context, const INTEGER& keyLen) { return portRef.exportTlsKey(connId, label, context, keyLen); } IPL4__SrtpKeysAndSalts f__IPL4__PROVIDER__exportSrtpKeysAndSalts( IPL4asp__PT_PROVIDER& portRef, const IPL4asp__Types::ConnectionId& connId) { return portRef.exportSrtpKeysAndSalts(connId); } OCTETSTRING f__IPL4__PROVIDER__exportSctpKey( IPL4asp__PT_PROVIDER& portRef, const IPL4asp__Types::ConnectionId& connId) { return portRef.exportSctpKey(connId); } CHARSTRING f__IPL4__PROVIDER__getLocalCertificateFingerprint( IPL4asp__PT_PROVIDER& portRef, const IPL4__DigestMethods& method, const ConnectionId& connId, const CHARSTRING& certificate__file) { return portRef.getLocalCertificateFingerprint(method,connId,certificate__file); } CHARSTRING f__IPL4__PROVIDER__getPeerCertificateFingerprint( IPL4asp__PT_PROVIDER& portRef, const ConnectionId& connId, const IPL4__DigestMethods& method) { return portRef.getPeerCertificateFingerprint(connId, method); } CHARSTRING f__IPL4__PROVIDER__getSelectedSrtpProfile( IPL4asp__PT_PROVIDER& portRef, const ConnectionId& connId) { return portRef.getSelectedSrtpProfile(connId); } Result f__IPL4__PROVIDER__ConnId__release( IPL4asp__PT& portRef, const IPL4asp__Types::ConnectionId& connId) { Result result(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE); if(TTCN_Logger::log_this_event(TTCN_Logger::PORTEVENT_MMSEND)){ TTCN_Logger::begin_event(TTCN_Logger::PORTEVENT_MMSEND); TTCN_Logger::log_event("%s: f__IPL4__ConnId__release: ", portRef.get_name()); TTCN_Logger::log_event(" connId "); connId.log(); TTCN_Logger::end_event(); } if(portRef.isConnIdReleaseWait(connId)){ portRef.ConnFree(connId); } else { result=Result(PortError::ERROR__INVALID__INPUT__PARAMETER, OMIT_VALUE, -1, "The f_IPL4_ConnId_release called in wrong state"); } if(TTCN_Logger::log_this_event(TTCN_Logger::PORTEVENT_MMRECV)){ TTCN_Logger::begin_event(TTCN_Logger::PORTEVENT_MMRECV); TTCN_Logger::log_event("%s: f_IPL4_ConnId_release result: ", portRef.get_name()); result.log(); TTCN_Logger::end_event(); } return result; } Result f__IPL4__listen( IPL4asp__PT& portRef, const HostName& locName, const PortNumber& locPort, const ProtoTuple& proto, const OptionList& options) { Result result=f__IPL4__PROVIDER__listen(portRef, locName, locPort, proto, options); if(TTCN_Logger::log_this_event(TTCN_Logger::PORTEVENT_MMRECV)){ TTCN_Logger::begin_event(TTCN_Logger::PORTEVENT_MMRECV); TTCN_Logger::log_event("%s: f_IPL4_listen result: ", portRef.get_name()); result.log(); TTCN_Logger::end_event(); } return result; } // f__IPL4__listen Result f__IPL4__connect( IPL4asp__PT& portRef, const HostName& remName, const PortNumber& remPort, const HostName& locName, const PortNumber& locPort, const ConnectionId& connId, const ProtoTuple& proto, const OptionList& options) { Result result=f__IPL4__PROVIDER__connect(portRef, remName, remPort, locName, locPort, connId, proto, options); if(TTCN_Logger::log_this_event(TTCN_Logger::PORTEVENT_MMRECV)){ TTCN_Logger::begin_event(TTCN_Logger::PORTEVENT_MMRECV); TTCN_Logger::log_event("%s: f_IPL4_connect result: ", portRef.get_name()); result.log(); TTCN_Logger::end_event(); } return result; } // f__IPL4__connect Result f__IPL4__setOpt( IPL4asp__PT& portRef, const OptionList& options, const ConnectionId& connId, const ProtoTuple& proto) { return f__IPL4__PROVIDER__setOpt(portRef, options, connId, proto); } // f__IPL4__setOpt Extended__Result f__IPL4__getOpt( IPL4asp__PT& portRef, const Option& option, const ConnectionId& connId, const ProtoTuple& proto) { return f__IPL4__PROVIDER__getOpt(portRef, option, connId, proto); } // f__IPL4__getOpt Result f__IPL4__close( IPL4asp__PT& portRef, const ConnectionId& connId, const ProtoTuple& proto) { if(TTCN_Logger::log_this_event(TTCN_Logger::PORTEVENT_MMSEND)){ TTCN_Logger::begin_event(TTCN_Logger::PORTEVENT_MMSEND); TTCN_Logger::log_event("%s: f__IPL4__close: ", portRef.get_name()); TTCN_Logger::log_event(" proto "); proto.log(); TTCN_Logger::log_event(" connId "); connId.log(); TTCN_Logger::end_event(); } Result result=f__IPL4__PROVIDER__close(portRef, connId, proto); if(TTCN_Logger::log_this_event(TTCN_Logger::PORTEVENT_MMRECV)){ TTCN_Logger::begin_event(TTCN_Logger::PORTEVENT_MMRECV); TTCN_Logger::log_event("%s: f__IPL4__close result: ", portRef.get_name()); result.log(); TTCN_Logger::end_event(); } return result; } // f__IPL4__close Result f__IPL4__setUserData( IPL4asp__PT& portRef, const ConnectionId& connId, const UserData& userData) { return f__IPL4__PROVIDER__setUserData(portRef, connId, userData); } // f__IPL4__setUserData Result f__IPL4__getUserData( IPL4asp__PT& portRef, const ConnectionId& connId, UserData& userData) { return f__IPL4__PROVIDER__getUserData(portRef, connId, userData); } // f__IPL4__getUserData Result f__IPL4__getConnectionDetails( IPL4asp__PT& portRef, const ConnectionId& connId, const IPL4__Param& IPL4param, IPL4__ParamResult& IPL4paramResult) { return f__IPL4__PROVIDER__getConnectionDetails(portRef, connId, IPL4param, IPL4paramResult); } // f__IPL4__getConnectionDetails Extended__Result f__IPL4__getConnectedPathMTU( IPL4asp__PT& portRef, const ConnectionId& connId, const ProtoTuple& proto) { return f__IPL4__PROVIDER__getConnectedMTU(portRef, connId, proto); } // f__IPL4__getConnectedPathMtu Result f__IPL4__port__settings( IPL4asp__PT& portRef, const CHARSTRING& param__name, const CHARSTRING& param__value ) { return f__IPL4__PROVIDER__port__settings(portRef,param__name,param__value ); } // f__IPL4__getConnectionDetails void f__IPL4__setGetMsgLen( IPL4asp__PT& portRef, const ConnectionId& connId, f__IPL4__getMsgLen& f, const ro__integer& msgLenArgs) { f__IPL4__PROVIDER__setGetMsgLen(portRef, connId, f, msgLenArgs); } // f__IPL4__setGetMsgLen void f__IPL4__setGetMsgLen__forConnClosedEvent( IPL4asp__PT& portRef, const ConnectionId& connId, f__IPL4__getMsgLen& f, const ro__integer& msgLenArgs) { f__IPL4__PROVIDER__setGetMsgLen__forConnClosedEvent(portRef, connId, f, msgLenArgs); } // f__IPL4__setGetMsgLen_forConnClosedEvent Result f__IPL4__send( IPL4asp__PT& portRef, const ASP__Send& asp, INTEGER& sent__octets) { if(TTCN_Logger::log_this_event(TTCN_Logger::PORTEVENT_MMSEND)){ TTCN_Logger::begin_event(TTCN_Logger::PORTEVENT_MMSEND); TTCN_Logger::log_event("%s: f_IPL4_send: ", portRef.get_name()); asp.log(); TTCN_Logger::end_event(); } Result result(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE); sent__octets=portRef.outgoing_send_core(asp,result); if(TTCN_Logger::log_this_event(TTCN_Logger::PORTEVENT_MMRECV)){ TTCN_Logger::begin_event(TTCN_Logger::PORTEVENT_MMRECV); TTCN_Logger::log_event("%s: f_IPL4_send result: ", portRef.get_name()); result.log(); TTCN_Logger::end_event(); } return result; } Result f__IPL4__sendto( IPL4asp__PT& portRef, const ASP__SendTo& asp, INTEGER& sent__octets) { if(TTCN_Logger::log_this_event(TTCN_Logger::PORTEVENT_MMSEND)){ TTCN_Logger::begin_event(TTCN_Logger::PORTEVENT_MMSEND); TTCN_Logger::log_event("%s: f_IPL4_sendto: ", portRef.get_name()); asp.log(); TTCN_Logger::end_event(); } Result result(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE); sent__octets=portRef.outgoing_send_core(asp,result); if(TTCN_Logger::log_this_event(TTCN_Logger::PORTEVENT_MMRECV)){ TTCN_Logger::begin_event(TTCN_Logger::PORTEVENT_MMRECV); TTCN_Logger::log_event("%s: f_IPL4_sendto result: ", portRef.get_name()); result.log(); TTCN_Logger::end_event(); } return result; } Result f__IPL4__StartTLS( IPL4asp__PT& portRef, const ConnectionId& connId, const BOOLEAN& server__side) { if(TTCN_Logger::log_this_event(TTCN_Logger::PORTEVENT_MMSEND)){ TTCN_Logger::begin_event(TTCN_Logger::PORTEVENT_MMSEND); TTCN_Logger::log_event("%s: f__IPL4__StartTLS: ", portRef.get_name()); connId.log(); TTCN_Logger::log_event(" server_side: "); server__side.log(); TTCN_Logger::end_event(); } Result result=f__IPL4__PROVIDER__StartTLS(portRef,connId,server__side); if(TTCN_Logger::log_this_event(TTCN_Logger::PORTEVENT_MMRECV)){ TTCN_Logger::begin_event(TTCN_Logger::PORTEVENT_MMRECV); TTCN_Logger::log_event("%s: f__IPL4__StartTLS result: ", portRef.get_name()); result.log(); TTCN_Logger::end_event(); } return result; } Result f__IPL4__StopTLS( IPL4asp__PT& portRef, const ConnectionId& connId) { if(TTCN_Logger::log_this_event(TTCN_Logger::PORTEVENT_MMSEND)){ TTCN_Logger::begin_event(TTCN_Logger::PORTEVENT_MMSEND); TTCN_Logger::log_event("%s: f__IPL4__StopTLS: ", portRef.get_name()); connId.log(); TTCN_Logger::end_event(); } Result result=f__IPL4__PROVIDER__StopTLS(portRef,connId); if(TTCN_Logger::log_this_event(TTCN_Logger::PORTEVENT_MMRECV)){ TTCN_Logger::begin_event(TTCN_Logger::PORTEVENT_MMRECV); TTCN_Logger::log_event("%s: f__IPL4__StopTLS result: ", portRef.get_name()); result.log(); TTCN_Logger::end_event(); } return result; } OCTETSTRING f__IPL4__exportTlsKey( IPL4asp__PT& portRef, const ConnectionId& connId, const CHARSTRING& label, const OCTETSTRING& context, const INTEGER& keyLen) { return portRef.exportTlsKey(connId, label, context, keyLen); } IPL4__SrtpKeysAndSalts f__IPL4__exportSrtpKeysAndSalts( IPL4asp__PT& portRef, const ConnectionId& connId) { return portRef.exportSrtpKeysAndSalts(connId); } OCTETSTRING f__IPL4__exportSctpKey( IPL4asp__PT& portRef, const IPL4asp__Types::ConnectionId& connId) { return portRef.exportSctpKey(connId); } Result f__IPL4__ConnId__release( IPL4asp__PT& portRef, const IPL4asp__Types::ConnectionId& connId) { return f__IPL4__PROVIDER__ConnId__release(portRef,connId); } CHARSTRING f__IPL4__getLocalCertificateFingerprint( IPL4asp__PT& portRef, const IPL4__DigestMethods& method, const ConnectionId& connId, const CHARSTRING& certificate__file) { return portRef.getLocalCertificateFingerprint(method,connId,certificate__file); } CHARSTRING f__IPL4__getPeerCertificateFingerprint( IPL4asp__PT& portRef, const ConnectionId& connId, const IPL4__DigestMethods& method) { return portRef.getPeerCertificateFingerprint(connId, method); } CHARSTRING f__IPL4__getSelectedSrtpProfile( IPL4asp__PT& portRef, const ConnectionId& connId) { return portRef.getSelectedSrtpProfile(connId); } INTEGER f__IPL4__fixedMsgLen(const OCTETSTRING& stream, ro__integer& msgLenArgs){ int length_offset=(int)msgLenArgs[0]; int nr_bytes_in_length=(int)msgLenArgs[1]; int stream_length=stream.lengthof(); if(stream_length<(length_offset+nr_bytes_in_length)){ return -1; // not enough bytes } int length_multiplier=(int)msgLenArgs[3]; int value_offset=(int)msgLenArgs[2]; int shift_diff; int shift_count; if(((int)msgLenArgs[4])==1){ shift_count=0; // Little endian shift_diff=1; } else { shift_count=nr_bytes_in_length - 1; // Big endian shift_diff=-1; } unsigned long m_length = 0; const unsigned char* buff=(const unsigned char* )stream + length_offset; for (int i = 0; i < nr_bytes_in_length; i++) { m_length |= buff[i] << (8 * shift_count); shift_count+=shift_diff; } m_length *= length_multiplier; if (value_offset < 0 && (long)m_length < -value_offset) return stream_length; else return m_length + value_offset; } //************ //SSL //************ #ifdef IPL4_USE_SSL // ssl_session ID context of the server static unsigned char ssl_server_context_name[] = "McHalls&EduardWasHere"; const unsigned char * IPL4asp__PT_PROVIDER::ssl_server_auth_session_id_context = ssl_server_context_name; // Password pointer //void *IPL4asp__PT_PROVIDER::ssl_current_client = NULL; // Not used currently. If the function ssl_verify_certificates_at_handshake will do more than return -1 // it should be used again. // Data set/get functions char * IPL4asp__PT_PROVIDER::get_ssl_password() const {return ssl_password;} /*void IPL4asp__PT_PROVIDER::set_ssl_verifycertificate(bool par) {ssl_verify_certificate=par;} void IPL4asp__PT_PROVIDER::set_ssl_use_session_resumption(bool par) {ssl_use_session_resumption=par;} void IPL4asp__PT_PROVIDER::set_ssl_key_file(char * par) { delete [] ssl_key_file; ssl_key_file=par; } void IPL4asp__PT_PROVIDER::set_ssl_certificate_file(char * par) { delete [] ssl_certificate_file; ssl_certificate_file=par; } void IPL4asp__PT_PROVIDER::set_ssl_trustedCAlist_file(char * par) { delete [] ssl_trustedCAlist_file; ssl_trustedCAlist_file=par; } void IPL4asp__PT_PROVIDER::set_ssl_cipher_list(char * par) { delete [] ssl_cipher_list; ssl_cipher_list=par; } void IPL4asp__PT_PROVIDER::set_ssl_server_auth_session_id_context(const unsigned char * par) { ssl_server_auth_session_id_context=par; } */ // Default parameter names //const char* IPL4asp__PT_PROVIDER::ssl_use_ssl_name() { return "ssl_use_ssl";} const char* IPL4asp__PT_PROVIDER::ssl_use_session_resumption_name() { return "ssl_use_session_resumption";} const char* IPL4asp__PT_PROVIDER::ssl_private_key_file_name() { return "ssl_private_key_file";} const char* IPL4asp__PT_PROVIDER::ssl_trustedCAlist_file_name() { return "ssl_trustedCAlist_file";} const char* IPL4asp__PT_PROVIDER::ssl_certificate_file_name() { return "ssl_certificate_chain_file";} const char* IPL4asp__PT_PROVIDER::ssl_password_name() { return "ssl_private_key_password";} //const char* IPL4asp__PT_PROVIDER::ssl_dtls_srtp_profiles_name() { return "ssl_dtls_srtp_profiles";} const char* IPL4asp__PT_PROVIDER::ssl_cipher_list_name() { return "ssl_allowed_ciphers_list";} const char* IPL4asp__PT_PROVIDER::ssl_verifycertificate_name() { return "ssl_verify_certificate";} const char* IPL4asp__PT_PROVIDER::psk_identity_name() { return "psk_identity";} const char* IPL4asp__PT_PROVIDER::psk_identity_hint_name() { return "psk_identity_hint";} const char* IPL4asp__PT_PROVIDER::psk_key_name() { return "psk_key";} SSL_CTX * IPL4asp__PT_PROVIDER::get_selected_ssl_ctx(int client_id) const{ if((sockList[client_id].type == IPL4asp_TCP) || (sockList[client_id].type == IPL4asp_TCP_LISTEN)) { return ssl_ctx; } else if(sockList[client_id].ssl_tls_type == CLIENT) { return ssl_dtls_client_ctx; } else { return ssl_dtls_server_ctx; } return NULL; } bool IPL4asp__PT_PROVIDER::ssl_create_contexts_and_obj(int client_id) { if(!ssl_init_SSL(client_id)) { log_warning("IPL4asp__PT_PROVIDER::ssl_create_contexts_and_obj: SSL initialization failed during client: %d connection", client_id); return false; } SSL_CTX *selected_ctx=NULL; if(ssl_cert_per_conn){ // SSL cert, key etc can be set per connection if(sockList[client_id].ssl_certificate_file || sockList[client_id].ssl_key_file || sockList[client_id].ssl_trustedCAlist_file){ // We need a separate SSL_CTX if use separate cert file. There is no API to load cert chain for SSL obj. if((sockList[client_id].type == IPL4asp_TCP) || (sockList[client_id].type == IPL4asp_TCP_LISTEN)) { selected_ctx=SSL_CTX_new (SSLv23_method()); } else if(sockList[client_id].ssl_tls_type == CLIENT) { selected_ctx=SSL_CTX_new (DTLS_client_method()); } else { selected_ctx=SSL_CTX_new (DTLS_server_method()); } sockList[client_id].sslCTX=selected_ctx; ssl_init_SSL_ctx(selected_ctx, client_id); } else { selected_ctx=get_selected_ssl_ctx(client_id); // we can use the global one } } else { selected_ctx=get_selected_ssl_ctx(client_id); } set_usePskHint(client_id,selected_ctx); IPL4_DEBUG("IPL4asp__PT_PROVIDER::ssl_create_contexts_and_obj: Create a new SSL object for client %d", client_id); if (!selected_ctx) { log_warning("IPL4asp__PT_PROVIDER::ssl_create_contexts_and_obj: No SSL CTX found, SSL not initialized!"); return false; } ssl_current_ssl=SSL_new(selected_ctx); if (ssl_current_ssl==NULL) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::ssl_create_contexts_and_obj: Creation of SSL object failed for client: %d", client_id); return false; } set_psk_ex_data(client_id); set_psk(client_id); #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME if(sockList[client_id].tls_hostname){ IPL4_DEBUG("Setting TLS hostname"); SSL_set_tlsext_host_name(ssl_current_ssl,(const char*)(*sockList[client_id].tls_hostname)) ; } #endif #if OPENSSL_VERSION_NUMBER >= 0x1000200fL if(sockList[client_id].alpn){ IPL4_DEBUG("Setting ALPN"); int ret=SSL_set_alpn_protos(ssl_current_ssl,(const unsigned char*)(*sockList[client_id].alpn),sockList[client_id].alpn->lengthof()); if(ret!=0){ ssl_getresult(ret); log_warning("Setting of ALPN failed."); return false; } } #endif if(ssl_cert_per_conn && !sockList[client_id].sslCTX){ if(sockList[client_id].ssl_cipher_list){ IPL4_DEBUG("Setting ssl_cipher list restrictions"); if (SSL_set_cipher_list(ssl_current_ssl, sockList[client_id].ssl_cipher_list)!=1) { log_warning("Cipher list restriction failed for %s", sockList[client_id].ssl_cipher_list); return false; } } } if(!setSslObj(client_id, ssl_current_ssl)) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::ssl_create_contexts_and_obj: setSslObj failed for client: %d", client_id); return false; } #ifdef SSL_OP_NO_SSLv2 if(sockList[client_id].ssl_supp.SSLv2 == GlobalConnOpts::NO){ SSL_set_options(ssl_current_ssl,SSL_OP_NO_SSLv2); } #endif #ifdef SSL_OP_NO_SSLv3 if(sockList[client_id].ssl_supp.SSLv3 == GlobalConnOpts::NO){ SSL_set_options(ssl_current_ssl,SSL_OP_NO_SSLv3); } #endif #ifdef SSL_OP_NO_TLSv1 if(sockList[client_id].ssl_supp.TLSv1 == GlobalConnOpts::NO){ SSL_set_options(ssl_current_ssl,SSL_OP_NO_TLSv1); } #endif #ifdef SSL_OP_NO_TLSv1_1 if(sockList[client_id].ssl_supp.TLSv1_1 == GlobalConnOpts::NO){ SSL_set_options(ssl_current_ssl,SSL_OP_NO_TLSv1_1); } #endif #ifdef SSL_OP_NO_TLSv1_2 if(sockList[client_id].ssl_supp.TLSv1_2 == GlobalConnOpts::NO){ SSL_set_options(ssl_current_ssl,SSL_OP_NO_TLSv1_2); } #endif #ifdef SSL_OP_NO_DTLSv1 if(sockList[client_id].ssl_supp.DTLSv1 == GlobalConnOpts::NO){ SSL_set_options(ssl_current_ssl,SSL_OP_NO_DTLSv1); } #endif #ifdef SSL_OP_NO_DTLSv1_2 if(sockList[client_id].ssl_supp.DTLSv1_2 == GlobalConnOpts::NO){ SSL_set_options(ssl_current_ssl,SSL_OP_NO_DTLSv1_2); } #endif char* dtlsSrtpProfiles = sockList[client_id].dtlsSrtpProfiles; if(!dtlsSrtpProfiles) { dtlsSrtpProfiles = globalConnOpts.dtlsSrtpProfiles; } if(dtlsSrtpProfiles) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::ssl_create_contexts_and_obj: applying SRTP profiles %s in connId %d...", dtlsSrtpProfiles, client_id); #ifdef SRTP_AES128_CM_SHA1_80 int ret = SSL_set_tlsext_use_srtp(ssl_current_ssl, dtlsSrtpProfiles); if(ret) { log_warning("IPL4asp__PT_PROVIDER::ssl_create_contexts_and_obj: could not set SRTP profiles!"); ssl_getresult(ret); return false; } else { IPL4_DEBUG("profiles applied."); } #else TTCN_error("DTLS is not supported by the current OpenSSL API. libopenssl >=1.0.1 is required!"); #endif } return true; } unsigned int psk_server_cb(SSL *ssl, const char *identity, unsigned char *psk, unsigned int max_psk_len) { int ret; (void)(ssl);//unused; prevent gcc warning; char *pskIdentity; char *pskKey; pskIdentity=(char *)SSL_get_ex_data(ssl, pskIdentityIdx); pskKey=(char *)SSL_get_ex_data(ssl, pskKeyIdx); if (!identity) { return 0; } if (strcmp(identity,pskIdentity ) != 0) { return 0; } if (strlen(pskKey)>=(max_psk_len*2)){ return 0; } /* convert the PSK key to binary */ ret = strlen(pskKey)/2; memcpy(psk,str2oct(pskKey),ret); if (ret<=0) { return 0; } return ret; } unsigned int psk_client_cb(SSL *ssl, const char *hint, char *identity, unsigned int max_identity_len, unsigned char *psk, unsigned int max_psk_len) { int ret; char *pskIdentity; char *pskKey; (void)(ssl); //unused; prevent gcc warning; pskIdentity=(char *)SSL_get_ex_data(ssl, pskIdentityIdx); pskKey=(char *)SSL_get_ex_data(ssl, pskKeyIdx); if (!hint){ TTCN_warning("NULL received PSK identity hint, continuing anyway"); } ret = snprintf(identity, max_identity_len, "%s", pskIdentity); if (ret < 0 || (unsigned int)ret > max_identity_len){ return 0; } if (strlen(pskKey)>=(max_psk_len*2)){ return 0; } ret = strlen(pskKey)/2; /* convert the PSK key to binary */ memcpy(psk,str2oct(pskKey),ret); if (ret<=0) { return 0; } return ret; } SSL_HANDSHAKE_RESULT IPL4asp__PT_PROVIDER::perform_ssl_handshake(int client_id) { IPL4_DEBUG("entering IPL4asp__PT_PROVIDER::perform_ssl_handshake() ."); //in case of purenonblocking & client reconnect if(pureNonBlocking && getSslObj(client_id, ssl_current_ssl) && ssl_current_ssl) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::perform_ssl_handshake: Reconnection for client: %d ", client_id); } else { if(!ssl_create_contexts_and_obj(client_id)) { // Warning should be used instead of debug log, It is a serious case log_warning("IPL4asp__PT_PROVIDER::perform_ssl_handshake: SSL initialization failed on connection: %d", client_id); return FAIL; } IPL4_DEBUG("IPL4asp__PT_PROVIDER::perform_ssl_handshake: New client added with key '%d'", client_id); IPL4_DEBUG("IPL4asp__PT_PROVIDER::perform_ssl_handshake: Binding SSL to the socket"); if (SSL_set_fd(ssl_current_ssl, sockList[client_id].sock)!=1) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::perform_ssl_handshake: Binding of SSL object to socket failed. Connection: %d", client_id); return FAIL; } } // Context change for SSL objects may come here in the // future. //server accepting if (sockList[client_id].ssl_tls_type == SERVER) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::perform_ssl_handshake: Accept SSL connection request"); // if (ssl_current_client!=NULL) log_warning("Warning: IPL4asp__PT_PROVIDER::perform_ssl_handshake: race condition while setting current client object pointer"); // ssl_current_client=(IPL4asp__PT_PROVIDER *)this; int attempt = 0; while(true) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::perform_ssl_handshake: SSL attempt to Accept Client Connection... %d", attempt + 1); current_conn_id=client_id; int res=ssl_getresult(SSL_accept(ssl_current_ssl)); current_conn_id=-1; switch(res) { case SSL_ERROR_NONE: break; case SSL_ERROR_WANT_READ: if(pureNonBlocking) { sockList[client_id].sslState = STATE_HANDSHAKING; Handler_Add_Fd_Read(sockList[client_id].sock); Handler_Remove_Fd_Write(sockList[client_id].sock); IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Writable: willing to continue handshake by receiving data..."); // ssl_current_client=NULL; // SSL says: SSL_WANT_READ -> do not listen to Writable events IPL4_DEBUG("IPL4asp__PT_PROVIDER::perform_ssl_handshake: leaving IPL4asp__PT_PROVIDER::perform_ssl_handshake()"); return WANT_READ; } case SSL_ERROR_WANT_WRITE: if(pureNonBlocking) { sockList[client_id].sslState = STATE_HANDSHAKING; Handler_Add_Fd_Write(sockList[client_id].sock); IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: willing to continue handshake by sending data..."); IPL4_DEBUG("DO WRITE ON %i", sockList[client_id].sock); // ssl_current_client=NULL; IPL4_DEBUG("IPL4asp__PT_PROVIDER::perform_ssl_handshake: SSL_ERROR_WANT_WRITE"); IPL4_DEBUG("IPL4asp__PT_PROVIDER::perform_ssl_handshake: leaving IPL4asp__PT_PROVIDER::perform_ssl_handshake()"); return WANT_WRITE; } if(++attempt == ssl_reconnect_attempts) { // ssl_current_client=NULL; IPL4_DEBUG("IPL4asp__PT_PROVIDER::perform_ssl_handshake: Connection accept failed"); IPL4_DEBUG("IPL4asp__PT_PROVIDER::perform_ssl_handshake: leaving IPL4asp__PT_PROVIDER::perform_ssl_handshake()"); return FAIL; } //usleep(ssl_reconnect_delay); timespec tm_val; tm_val.tv_sec=ssl_reconnect_delay/1000000; tm_val.tv_nsec=(ssl_reconnect_delay%1000000)*1000; nanosleep(&tm_val,NULL); continue; case SSL_ERROR_SYSCALL: log_warning("Warning: IPL4asp__PT_PROVIDER::perform_ssl_handshake: SSL_ERROR_SYSCALL peer is disconnected"); default: log_warning("Warning: IPL4asp__PT_PROVIDER::perform_ssl_handshake: Connection from client %d is refused", client_id); // ssl_current_client=NULL; IPL4_DEBUG("IPL4asp__PT_PROVIDER::perform_ssl_handshake: leaving IPL4asp__PT_PROVIDER::perform_ssl_handshake()"); return FAIL; } break; } sockList[client_id].sslState = STATE_NORMAL; IPL4_DEBUG("IPL4asp__PT_PROVIDER::perform_ssl_handshake: Connection from client %d is accepted", client_id); // ssl_current_client=NULL; } else {//client connecting if (ssl_use_session_resumption && ssl_session!=NULL) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::perform_ssl_handshake: Try to use ssl_session resumption"); if (ssl_getresult(SSL_set_session(ssl_current_ssl, ssl_session))!=SSL_ERROR_NONE) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::perform_ssl_handshake: SSL error occurred during set session. Client: %d", client_id); return FAIL; } } IPL4_DEBUG( "IPL4asp__PT_PROVIDER::perform_ssl_handshake: Connecting..."); // if (ssl_current_client!=NULL) log_warning("IPL4asp__PT_PROVIDER::perform_ssl_handshake: race condition while setting current client object pointer"); // ssl_current_client=(IPL4asp__PT_PROVIDER *)this; int attempt = 0; while(true) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::perform_ssl_handshake: SSL attempt to connect ... %d", attempt + 1); current_conn_id=client_id; int res=ssl_getresult(SSL_connect(ssl_current_ssl)); current_conn_id=-1; switch(res) { case SSL_ERROR_NONE: IPL4_DEBUG("IPL4asp__PT_PROVIDER::perform_ssl_handshake: Connection Success."); sockList[client_id].sslState = STATE_NORMAL; break; case SSL_ERROR_WANT_READ: if(pureNonBlocking) { // ssl_current_client=NULL; IPL4_DEBUG("IPL4asp__PT_PROVIDER::perform_ssl_handshake: SSL_ERROR_WANT_READ"); IPL4_DEBUG("IPL4asp__PT_PROVIDER::perform_ssl_handshake: leaving IPL4asp__PT_PROVIDER::perform_ssl_handshake()"); return WANT_READ; } case SSL_ERROR_WANT_WRITE: if(pureNonBlocking) { // ssl_current_client=NULL; IPL4_DEBUG("IPL4asp__PT_PROVIDER::perform_ssl_handshake: SSL_ERROR_WANT_WRITE"); IPL4_DEBUG("IPL4asp__PT_PROVIDER::perform_ssl_handshake: leaving IPL4asp__PT_PROVIDER::perform_ssl_handshake()"); return WANT_WRITE; } if(++attempt == ssl_reconnect_attempts) { // ssl_current_client=NULL; IPL4_DEBUG("IPL4asp__PT_PROVIDER::perform_ssl_handshake: Connection failed"); IPL4_DEBUG("IPL4asp__PT_PROVIDER::perform_ssl_handshake: leaving IPL4asp__PT_PROVIDER::perform_ssl_handshake()"); return FAIL; } //usleep(ssl_reconnect_delay); timespec tm_val; tm_val.tv_sec=ssl_reconnect_delay/1000000; tm_val.tv_nsec=(ssl_reconnect_delay%1000000)*1000; nanosleep(&tm_val,NULL); continue; default: // ssl_current_client=NULL; IPL4_DEBUG("IPL4asp__PT_PROVIDER::perform_ssl_handshake: Connection failed"); IPL4_DEBUG("IPL4asp__PT_PROVIDER::perform_ssl_handshake: leaving IPL4asp__PT_PROVIDER::perform_ssl_handshake()"); return FAIL; } break; } // ssl_current_client=NULL; if (ssl_use_session_resumption) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::perform_ssl_handshake: Connected, get new ssl_session"); ssl_session=SSL_get1_session(ssl_current_ssl); if (ssl_session==NULL) log_warning("IPL4asp__PT_PROVIDER::perform_ssl_handshake: Server did not send a session ID"); } } if (ssl_use_session_resumption) { if (SSL_session_reused(ssl_current_ssl)) {IPL4_DEBUG("IPL4asp__PT_PROVIDER::perform_ssl_handshake: Session was reused");} else { IPL4_DEBUG("IPL4asp__PT_PROVIDER::perform_ssl_handshake: Session was not reused");} } if (!sockList[client_id].psk_identity && !sockList[client_id].psk_key && !psk_identity && !psk_key){ if (!ssl_verify_certificates()) { // remove client log_warning("IPL4asp__PT_PROVIDER::perform_ssl_handshake: Verification failed"); IPL4_DEBUG("IPL4asp__PT_PROVIDER::perform_ssl_handshake: leaving IPL4asp__PT_PROVIDER::perform_ssl_handshake()"); return FAIL; } } IPL4_DEBUG("leaving IPL4asp__PT_PROVIDER::perform_ssl_handshake() with SUCCESS"); return SUCCESS; } bool IPL4asp__PT_PROVIDER::perform_ssl_shutdown(int client_id) { IPL4_DEBUG("entering IPL4asp__PT_PROVIDER::perform_ssl_shutdown()"); bool ret = true; if (getSslObj(client_id, ssl_current_ssl) && ssl_current_ssl!=NULL) { if(sockList[client_id].sslState != STATE_CONNECTING) { IPL4_DEBUG("performing SSL_shutdown on connection: #%d", client_id); SSL_shutdown(ssl_current_ssl); } SSL_free(ssl_current_ssl); sockList[client_id].sslObj=NULL; sockList[client_id].bio = NULL; sockList[client_id].ssl_tls_type = NONE; sockList[client_id].sslState = STATE_CONNECTING; if(sockList[client_id].sslCTX!=NULL){ SSL_CTX_free(sockList[client_id].sslCTX); sockList[client_id].sslCTX=NULL; } } else { log_warning("SSL object not found for client %d", client_id); ret = false; } IPL4_DEBUG("leaving IPL4asp__PT_PROVIDER::perform_ssl_shutdown()"); return ret; } //Currently not used (separated to listen/connect directly bool IPL4asp__PT_PROVIDER::user_all_mandatory_configparameters_present(int clientId) { if ((sockList[clientId].type == IPL4asp_TCP_LISTEN) && (sockList[clientId].ssl_tls_type == SERVER)) { if (ssl_certificate_file==NULL) { IPL4_DEBUG("%s is not defined in the configuration file", ssl_certificate_file_name()); return false; } if (ssl_trustedCAlist_file==NULL) { IPL4_DEBUG("%s is not defined in the configuration file", ssl_trustedCAlist_file_name()); return false; } if (ssl_key_file==NULL) { IPL4_DEBUG("%s is not defined in the configuration file", ssl_private_key_file_name()); return false; } } else if((sockList[clientId].type == IPL4asp_TCP) && (sockList[clientId].ssl_tls_type == CLIENT)) { if (ssl_verify_certificate && ssl_trustedCAlist_file==NULL) { IPL4_DEBUG("%s is not defined in the configuration file altough %s=yes", ssl_trustedCAlist_file_name(), ssl_verifycertificate_name()); return false; } } return true; } //STATE_WAIT_FOR_RECEIVE_CALLBACK: if the SSL_read operation would // block because the socket is not ready for writing, // I set the socket state to this state and add the file // descriptor to the Event_Handler. The Event_Handler will // wake up and call the receive_message_on_fd operation // if the socket is ready to write. //If the SSL_read operation would block because the socket is not ready for //reading, I do nothing int IPL4asp__PT_PROVIDER::receive_ssl_message_on_fd(int client_id, int* error_msg) { IPL4_DEBUG("entering IPL4asp__PT_PROVIDER::receive_message_on_fd(%d)", client_id); // if (ssl_current_client!=NULL) log_warning("Warning: race condition while setting current client object pointer"); // ssl_current_client=(IPL4asp__PT_PROVIDER *)this; TTCN_Buffer* recv_tb = *sockList[client_id].buf; if(sockList[client_id].sslState != STATE_NORMAL) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::receive_message_on_fd: leave - Client is Connecting: %d", client_id); // ssl_current_client=NULL; return -2; } if(!getSslObj(client_id, ssl_current_ssl)) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::receive_message_on_fd: current SSL invalid for client: %d", client_id); // ssl_current_client=NULL; return 0; } int messageLength=0; size_t end_len=AS_SSL_CHUNCK_SIZE; unsigned char *end_ptr; int total_read=0; while (messageLength>=0) { end_len=AS_SSL_CHUNCK_SIZE; IPL4_DEBUG(" one read cycle started"); recv_tb->get_end(end_ptr, end_len); IPL4_DEBUG(" try to read %d bytes",(int)end_len); messageLength = SSL_read(ssl_current_ssl, end_ptr, end_len); IPL4_DEBUG(" SSL_read returned %d",messageLength); if (messageLength <= 0) { *error_msg=ssl_getresult(messageLength); switch (*error_msg) { case SSL_ERROR_ZERO_RETURN: if(sockList[client_id].type==IPL4asp_UDP){return -2;} // Just ignore the zero length UDP packet IPL4_DEBUG("IPL4asp__PT_PROVIDER::receive_message_on_fd: SSL connection was interrupted by the other side"); SSL_set_quiet_shutdown(ssl_current_ssl, 1); IPL4_DEBUG("SSL_ERROR_ZERO_RETURN is received, setting SSL SHUTDOWN mode to QUIET"); // ssl_current_client=NULL; IPL4_DEBUG("leaving IPL4asp__PT_PROVIDER::receive_message_on_fd() with SSL_ERROR_ZERO_RETURN"); return total_read; case SSL_ERROR_WANT_WRITE://writing would block if(!total_read){ total_read=-2; } if (pureNonBlocking){ Handler_Add_Fd_Write(sockList[client_id].sock); IPL4_DEBUG("DO WRITE ON %i", sockList[client_id].sock); IPL4_DEBUG("IPL4asp__PT_PROVIDER::receive_message_on_fd: setting socket state to STATE_WAIT_FOR_RECEIVE_CALLBACK"); sockList[client_id].sslState = STATE_WAIT_FOR_RECEIVE_CALLBACK; // ssl_current_client=NULL; IPL4_DEBUG("leaving IPL4asp__PT_PROVIDER::receive_message_on_fd()"); } return total_read; case SSL_ERROR_WANT_READ: //reading would block, continue processing data if(!total_read){ total_read=-2; } if (pureNonBlocking){ IPL4_DEBUG("IPL4asp__PT_PROVIDER::receive_message_on_fd: reading would block, leaving IPL4asp__PT_PROVIDER::receive_message_on_fd()"); // ssl_current_client = NULL; IPL4_DEBUG("leaving IPL4asp__PT_PROVIDER::receive_message_on_fd()"); } return total_read; break; default: // On error the connection should be closed, the caller function will close the connection if we return 0 IPL4_DEBUG( "SSL error occured. Closing the connection."); SSL_set_quiet_shutdown(ssl_current_ssl, 1); IPL4_DEBUG( "SSL_ERROR is received, setting SSL SHUTDOWN mode to QUIET"); // ssl_current_client=NULL; IPL4_DEBUG( "leaving IPL4asp__PT_PROVIDER::receive_message_on_fd() with SSL_ERROR_ZERO_RETURN"); *error_msg = SSL_ERROR_ZERO_RETURN; return total_read; } } else { recv_tb->increase_length(messageLength); total_read+=messageLength; } if(sockList[client_id].type == IPL4asp_UDP) { // For UDP, we only read one packet at a time (and hope that the buffer was large enough) IPL4_DEBUG( "Returning early for UDP/DTLS"); return total_read; } } // ssl_current_client=NULL; IPL4_DEBUG("leaving IPL4asp__PT_PROVIDER::receive_message_on_fd() with number of bytes read: %d",total_read ); return total_read; } bool IPL4asp__PT_PROVIDER::increase_send_buffer(int fd, int &old_size, int& new_size) { int set_size; #if defined LINUX || defined FREEBSD || defined SOLARIS8 socklen_t #else /* SOLARIS or WIN32 */ int #endif optlen = sizeof(old_size); // obtaining the current buffer size first if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char*)&old_size, &optlen)) goto getsockopt_failure; if (old_size <= 0) { log_warning("System call getsockopt(SO_SNDBUF) " "returned invalid buffer size (%d) on file descriptor %d.", old_size, fd); return false; } // trying to double the buffer size set_size = 2 * old_size; if (set_size > old_size) { if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const char*)&set_size, sizeof(set_size))) { // the operation failed switch (errno) { case ENOMEM: case ENOBUFS: errno = 0; break; default: // other error codes indicate a fatal error goto setsockopt_failure; } } else { // the operation was successful goto success; } } // trying to perform a binary search to determine the maximum buffer size set_size = old_size; for (int size_step = old_size / 2; size_step > 0; size_step /= 2) { int tried_size = set_size + size_step; if (tried_size > set_size) { if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const char*)&tried_size, sizeof(tried_size))) { // the operation failed switch (errno) { case ENOMEM: case ENOBUFS: errno = 0; break; default: // other error codes indicate a fatal error goto setsockopt_failure; } } else { // the operation was successful set_size = tried_size; } } } if (set_size <= old_size) return false; success: // querying the new effective buffer size (it might be smaller // than set_size but should not be smaller than old_size) optlen = sizeof(new_size); if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char*)&new_size, &optlen)) goto getsockopt_failure; if (new_size > old_size) return true; else { if (new_size < old_size) log_warning("System call getsockopt(SO_SNDBUF) returned unexpected buffer size " "(%d, after increasing it from %d to %d) on file descriptor %d.", new_size, old_size, set_size, fd); return false; } getsockopt_failure: log_warning("System call getsockopt(SO_SNDBUF) failed on file " "descriptor %d. (%s)", fd, strerror(errno)); return false; setsockopt_failure: log_warning("System call setsockopt(SO_SNDBUF) failed on file " "descriptor %d. (%s)", fd, strerror(errno)); return false; } bool IPL4asp__PT_PROVIDER::ssl_verify_certificates() { char str[SSL_CHARBUF_LENGTH]; IPL4_DEBUG("entering IPL4asp__PT_PROVIDER::ssl_verify_certificates()"); ssl_log_SSL_info(); // Get the other side's certificate IPL4_DEBUG("Check certificate of the other party"); X509 *cert = SSL_get_peer_certificate (ssl_current_ssl); if (cert != NULL) { { IPL4_DEBUG("Certificate information:"); X509_NAME_oneline (X509_get_subject_name (cert), str, SSL_CHARBUF_LENGTH); IPL4_DEBUG(" subject: %s", str); } // We could do all sorts of certificate verification stuff here before // deallocating the certificate. // Just a basic check that the certificate is valid // Other checks (e.g. Name in certificate vs. hostname) shall be // done on application level if (ssl_verify_certificate) IPL4_DEBUG("Verification state is: %s", X509_verify_cert_error_string(SSL_get_verify_result(ssl_current_ssl))); X509_free (cert); } else log_warning("Other side does not have certificate."); IPL4_DEBUG("leaving IPL4asp__PT_PROVIDER::ssl_verify_certificates()"); return true; } bool IPL4asp__PT_PROVIDER::ssl_actions_to_seed_PRNG() { struct stat randstat; if(RAND_status()) { IPL4_DEBUG("PRNG already initialized, no action needed"); return true; } IPL4_DEBUG("Seeding PRND"); // OpenSSL tries to use random devives automatically // these would not be necessary if (!stat("/dev/urandom", &randstat)) { IPL4_DEBUG("Using installed random device /dev/urandom for seeding the PRNG with %d bytes.", SSL_PRNG_LENGTH); if (RAND_load_file("/dev/urandom", SSL_PRNG_LENGTH)!=SSL_PRNG_LENGTH) { IPL4_DEBUG("Could not read from /dev/urandom"); return false; } } else if (!stat("/dev/random", &randstat)) { IPL4_DEBUG("Using installed random device /dev/random for seeding the PRNG with %d bytes.", SSL_PRNG_LENGTH); if (RAND_load_file("/dev/random", SSL_PRNG_LENGTH)!=SSL_PRNG_LENGTH) { IPL4_DEBUG("Could not read from /dev/random"); return false; } } else { /* Neither /dev/random nor /dev/urandom are present, so add entropy to the SSL PRNG a hard way. */ log_warning("Solaris patches to provide random generation devices are not installed.\nSee http://www.openssl.org/support/faq.html \"Why do I get a \"PRNG not seeded\" error message?\"\nA workaround will be used."); for (int i = 0; i < 10000 && !RAND_status(); ++i) { char buf[4]; struct timeval tv; gettimeofday(&tv, 0); buf[0] = tv.tv_usec & 0xF; buf[2] = (tv.tv_usec & 0xF0) >> 4; buf[3] = (tv.tv_usec & 0xF00) >> 8; buf[1] = (tv.tv_usec & 0xF000) >> 12; RAND_add(buf, sizeof buf, 0.1); } return true; } if(!RAND_status()) { IPL4_DEBUG("Could not seed the Pseudo Random Number Generator with enough data."); return false; } else { IPL4_DEBUG("PRNG successfully initialized."); } return true; } // returns 1 on success, DTE on fail int ssl_generate_cookie_callback(SSL *ssl, unsigned char *cookie, unsigned int *cookie_len) { #ifdef SRTP_AES128_CM_SHA1_80 unsigned char *buffer, result[EVP_MAX_MD_SIZE]; unsigned int length = 0, resultlength; /* Initialize a random secret */ if (!ssl_cookie_initialized) { if (!RAND_bytes(ssl_cookie_secret, IPL4_COOKIE_SECRET_LENGTH)) { TTCN_error("generate_cookie: Could not generate secret cookie!"); } ssl_cookie_initialized = 1; } SockAddr peer; /* Read peer information */ (void) BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer); /* Create buffer with peer's address and port */ length = 0; switch (peer.ss.ss_family) { case AF_INET: length += sizeof(struct in_addr); break; case AF_INET6: length += sizeof(struct in6_addr); break; default: TTCN_error("generate_cookie: INET version not handled; please call Eduard Czimbalmos back from the pension!"); break; } length += sizeof(in_port_t); buffer = (unsigned char*) OPENSSL_malloc(length); if (buffer == NULL) { TTCN_error("generate_cookie: out of memory!"); } switch (peer.ss.ss_family) { case AF_INET: memcpy(buffer, &peer.v4.sin_port, sizeof(in_port_t)); memcpy(buffer + sizeof(peer.v4.sin_port), &peer.v4.sin_addr, sizeof(struct in_addr)); break; case AF_INET6: memcpy(buffer, &peer.v6.sin6_port, sizeof(in_port_t)); memcpy(buffer + sizeof(in_port_t), &peer.v6.sin6_addr, sizeof(struct in6_addr)); break; default: TTCN_error("generate_cookie: INET version not handled; please call Eduard Czimbalmos back from the pension!"); break; } /* Calculate HMAC of buffer using the secret */ HMAC(EVP_sha1(), (const void*) ssl_cookie_secret, IPL4_COOKIE_SECRET_LENGTH, (const unsigned char*) buffer, length, result, &resultlength); OPENSSL_free(buffer); memcpy(cookie, result, resultlength); *cookie_len = resultlength; //fprintf(stderr, "generate_cookie returning successfully\n"); return 1; #else TTCN_error("DTLS is not supported by the current OpenSSL API. libopenssl >=1.0.1 is required!"); return 0; #endif } // returns 1 on success, 0 on fail int ssl_verify_cookie_callback(SSL *ssl, #if OPENSSL_VERSION_NUMBER >= 0x10100000L const #endif unsigned char *cookie, unsigned int cookie_len) { #ifdef SRTP_AES128_CM_SHA1_80 unsigned char *buffer, result[EVP_MAX_MD_SIZE]; unsigned int length = 0, resultlength; /* If secret isn't initialized yet, the cookie can't be valid */ if (!ssl_cookie_initialized) return 0; SockAddr peer; /* Read peer information */ (void) BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer); /* Create buffer with peer's address and port */ length = 0; switch (peer.ss.ss_family) { case AF_INET: length += sizeof(struct in_addr); break; case AF_INET6: length += sizeof(struct in6_addr); break; default: TTCN_error("verify_cookie: INET version not handled; please call Eduard Czimbalmos back from the pension!"); break; } length += sizeof(in_port_t); buffer = (unsigned char*) OPENSSL_malloc(length); if (buffer == NULL) { TTCN_error("verify_cookie: out of memory!"); } switch (peer.ss.ss_family) { case AF_INET: memcpy(buffer, &peer.v4.sin_port, sizeof(in_port_t)); memcpy(buffer + sizeof(in_port_t), &peer.v4.sin_addr, sizeof(struct in_addr)); break; case AF_INET6: memcpy(buffer, &peer.v6.sin6_port, sizeof(in_port_t)); memcpy(buffer + sizeof(in_port_t), &peer.v6.sin6_addr, sizeof(struct in6_addr)); break; default: TTCN_error("verify_cookie: INET version not handled; please call Eduard Czimbalmos back from the pension!"); break; } /* Calculate HMAC of buffer using the secret */ HMAC(EVP_sha1(), (const void*) ssl_cookie_secret, IPL4_COOKIE_SECRET_LENGTH, (const unsigned char*) buffer, length, result, &resultlength); OPENSSL_free(buffer); if (cookie_len == resultlength && memcmp(result, cookie, resultlength) == 0) { return 1; } #else TTCN_error("DTLS is not supported by the current OpenSSL API. libopenssl >=1.0.1 is required!"); #endif return 0; } bool IPL4asp__PT_PROVIDER::ssl_init_SSL_ctx(SSL_CTX* in_ssl_ctx, int conn_id) { if (in_ssl_ctx==NULL) { log_warning("SSL context creation failed."); return false; } IPL4_DEBUG("IPL4asp__PT_PROVIDER::ssl_init_SSL_ctx: Init CTX connId: %d", conn_id); // valid for all SSL objects created from this context afterwards char* cf=NULL; if(ssl_cert_per_conn && isConnIdValid(conn_id) && sockList[conn_id].ssl_certificate_file){ cf=sockList[conn_id].ssl_certificate_file; } else { cf=ssl_certificate_file; } // valid for all SSL objects created from this context afterwards if(cf!=NULL) { IPL4_DEBUG("Loading certificate file"); if(SSL_CTX_use_certificate_chain_file(in_ssl_ctx, cf)!=1) { log_warning("Can't read certificate file %s", cf); return false; } } if(ssl_cert_per_conn && isConnIdValid(conn_id) && sockList[conn_id].ssl_password){ cf=sockList[conn_id].ssl_password; } else { cf=ssl_password; } if(cf!=NULL){ SSL_CTX_set_default_passwd_cb(in_ssl_ctx, ssl_password_cb); SSL_CTX_set_default_passwd_cb_userdata(in_ssl_ctx, cf); } if(ssl_cert_per_conn && isConnIdValid(conn_id) && sockList[conn_id].ssl_key_file){ cf=sockList[conn_id].ssl_key_file; } else { cf=ssl_key_file; } if(cf!=NULL) { IPL4_DEBUG("Loading key file"); // if (ssl_current_client!=NULL) log_warning("Warning: race condition while setting current client object pointer"); // ssl_current_client=(IPL4asp__PT_PROVIDER *)this; if(SSL_CTX_use_PrivateKey_file(in_ssl_ctx, cf, SSL_FILETYPE_PEM)!=1) { log_warning("Can't read key file %s", cf); return false; } // ssl_current_client=NULL; } if(ssl_cert_per_conn && isConnIdValid(conn_id) && sockList[conn_id].ssl_trustedCAlist_file){ cf=sockList[conn_id].ssl_trustedCAlist_file; } else { cf=ssl_trustedCAlist_file; } if (cf!=NULL) { IPL4_DEBUG("Loading trusted CA list file"); if (SSL_CTX_load_verify_locations(in_ssl_ctx, cf, NULL)!=1) { IPL4_DEBUG("Can't read trustedCAlist file %s", cf); return false; } } if (ssl_certificate_file!=NULL && ssl_key_file!=NULL) { IPL4_DEBUG("Check for consistency between private and public keys"); if (SSL_CTX_check_private_key(in_ssl_ctx)!=1) log_warning("Private key does not match the certificate public key"); } if(ssl_cert_per_conn && isConnIdValid(conn_id) && sockList[conn_id].ssl_cipher_list){ cf=sockList[conn_id].ssl_cipher_list; } else { cf=ssl_cipher_list; } if (cf!=NULL) { IPL4_DEBUG("Setting ssl_cipher list restrictions"); if (SSL_CTX_set_cipher_list(in_ssl_ctx, cf)!=1) { log_warning("Cipher list restriction failed for %s", cf); return false; } } // } // check the other side's certificates if (ssl_verify_certificate) { IPL4_DEBUG("Setting verification behaviour: verification required and do not allow to continue on failure"); SSL_CTX_set_verify(in_ssl_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, ssl_verify_callback); } else { IPL4_DEBUG("Setting verification behaviour: verification not required and do allow to continue on failure"); SSL_CTX_set_verify(in_ssl_ctx, SSL_VERIFY_NONE, ssl_verify_callback); } //Session id context can be set at any time but will be useful only for server(s) IPL4_DEBUG("Activate ssl_session resumption"); IPL4_DEBUG("Context is: %s; length = %lu", ssl_server_auth_session_id_context, (unsigned long)strlen((const char*)ssl_server_auth_session_id_context)); if (SSL_CTX_set_session_id_context(in_ssl_ctx, ssl_server_auth_session_id_context, strlen((const char*)ssl_server_auth_session_id_context))!=1) { log_warning("Activation of SSL ssl_session resumption failed"); return false; } SSL_CTX_set_read_ahead(in_ssl_ctx, 1); //SSL_CTX_set_verify(in_ssl_ctx, SSL_VERIFY_NONE, ssl_verify_callback); if (conn_id != -1) { // with SCTP the cookies should not be used if (!((sockList[conn_id].type == IPL4asp_SCTP_LISTEN) || (sockList[conn_id].type == IPL4asp_SCTP))) { IPL4_DEBUG("cookie generation %d for connId %d", sockList[conn_id].type,conn_id); SSL_CTX_set_cookie_generate_cb(in_ssl_ctx, ssl_generate_cookie_callback); SSL_CTX_set_cookie_verify_cb(in_ssl_ctx, ssl_verify_cookie_callback); } } else { SSL_CTX_set_cookie_generate_cb(in_ssl_ctx, ssl_generate_cookie_callback); SSL_CTX_set_cookie_verify_cb(in_ssl_ctx, ssl_verify_cookie_callback); } #if OPENSSL_VERSION_NUMBER >= 0x1000200fL SSL_CTX_set_alpn_select_cb(in_ssl_ctx,ipl4_tls_alpn_cb,this); #endif return true; } bool IPL4asp__PT_PROVIDER::ssl_init_SSL(int connId) { if (ssl_initialized) { IPL4_DEBUG("SSL already initialized, no action needed"); return true; } if(!ssl_actions_to_seed_PRNG()) { IPL4_DEBUG("Can't seed PRNG."); return false; } IPL4_DEBUG("Init SSL started"); IPL4_DEBUG("Using %s (%lx)", SSLeay_version(SSLEAY_VERSION), OPENSSL_VERSION_NUMBER); SSL_library_init(); // initialize library SSL_load_error_strings(); // readable error messages pskIdentityIdx = SSL_get_ex_new_index(0, (char *)"pskIdentity", NULL, NULL, NULL); pskKeyIdx = SSL_get_ex_new_index(0, (char *)"pskKey", NULL, NULL, NULL); IPL4_DEBUG("Creating SSL/TLS context..."); // Create context with SSLv23_method() method: both server and client understanding SSLv2, SSLv3, TLSv1 ssl_ctx = SSL_CTX_new (SSLv23_method()); if(!ssl_init_SSL_ctx(ssl_ctx, connId)) { return false; } IPL4_DEBUG("Creating DTLSv1 context..."); // Create contexts with DTLSv1_server_method() and DTLSv1_client_method() method ssl_dtls_server_ctx = SSL_CTX_new (DTLS_server_method()); if(!ssl_init_SSL_ctx(ssl_dtls_server_ctx, connId)) { return false; } ssl_dtls_client_ctx = SSL_CTX_new (DTLS_client_method()); if(!ssl_init_SSL_ctx(ssl_dtls_client_ctx, connId)) { return false; } ssl_initialized=true; IPL4_DEBUG("Init SSL successfully finished"); return true; } void IPL4asp__PT_PROVIDER::set_psk(int connId) { if(isConnIdValid(connId)){ // char *pskIdHint = get_pskIdHint(connId); static char *pskIdentity = get_pskIdentity(connId); char *pskKey = get_pskKey(connId); if(pskKey != NULL && pskIdentity != NULL){ #if OPENSSL_VERSION_NUMBER >= 0x1000000fL if(isConnIdValid(connId) && sockList[connId].ssl_tls_type == SERVER){ if(ssl_current_ssl!=NULL){ SSL_set_psk_server_callback(ssl_current_ssl, psk_server_cb); } } else if(isConnIdValid(connId) && sockList[connId].ssl_tls_type == CLIENT){ if(ssl_current_ssl!=NULL){ SSL_set_psk_client_callback(ssl_current_ssl, psk_client_cb); } } #else log_warning("The used OpenSSL doesn't support the PSK"); #endif } } } void IPL4asp__PT_PROVIDER::set_usePskHint(int connId,SSL_CTX *selectedSslCtx) { if(isConnIdValid(connId)){ char *pskIdHint = get_pskIdHint(connId); if (pskIdHint != NULL && selectedSslCtx!=NULL){ #if OPENSSL_VERSION_NUMBER >= 0x1000000fL SSL_CTX_use_psk_identity_hint(selectedSslCtx, pskIdHint); #else log_warning("The used OpenSSL doesn't support the PSK"); #endif } } } void IPL4asp__PT_PROVIDER::set_psk_ex_data(int connId) { char *pskIdentity = get_pskIdentity(connId); char *pskKey= get_pskKey(connId); if((pskIdentity != NULL) && (pskKey!=NULL) && (ssl_current_ssl!=NULL)){ SSL_set_ex_data(ssl_current_ssl, pskIdentityIdx, pskIdentity); SSL_set_ex_data(ssl_current_ssl, pskKeyIdx, pskKey); } } char *IPL4asp__PT_PROVIDER::get_pskIdentity(int connId) { char *pskIdentityLocal = NULL; if(isConnIdValid(connId) && (sockList[connId].psk_identity!=NULL)){ pskIdentityLocal = sockList[connId].psk_identity; } else if (psk_identity!=NULL) { pskIdentityLocal = psk_identity; } return pskIdentityLocal; } char *IPL4asp__PT_PROVIDER::get_pskKey(int connId) { char *pskKeyLocal = NULL; if(isConnIdValid(connId) && (sockList[connId].psk_key!=NULL)){ pskKeyLocal = sockList[connId].psk_key; } else if (psk_key!=NULL) { pskKeyLocal = psk_key; } return pskKeyLocal; } char *IPL4asp__PT_PROVIDER::get_pskIdHint(int connId) { char *pskHintLocal = NULL; if(isConnIdValid(connId) && (sockList[connId].psk_identity_hint!=NULL)){ pskHintLocal = sockList[connId].psk_identity_hint; } else if (psk_key!=NULL) { pskHintLocal = psk_identity_hint; } return pskHintLocal; } void IPL4asp__PT_PROVIDER::ssl_log_SSL_info() { char str[SSL_CHARBUF_LENGTH]; IPL4_DEBUG("Check SSL description"); // ssl_cipher=SSL_get_current_cipher(ssl_current_ssl); // if (ssl_cipher!=NULL) { SSL_CIPHER_description(SSL_get_current_cipher(ssl_current_ssl), str, SSL_CHARBUF_LENGTH); { IPL4_DEBUG("SSL description:"); IPL4_DEBUG("%s", str); } // } } // Log the SSL error and flush the error queue // Can be used after the followings: // SSL_connect(), SSL_accept(), SSL_do_handshake(), // SSL_read(), SSL_peek(), or SSL_write() int IPL4asp__PT_PROVIDER::ssl_getresult(int res) { IPL4_DEBUG("SSL operation result:"); int err = SSL_get_error(ssl_current_ssl, res); switch(err) { case SSL_ERROR_NONE: IPL4_DEBUG("SSL_ERROR_NONE"); break; case SSL_ERROR_ZERO_RETURN: IPL4_DEBUG("SSL_ERROR_ZERO_RETURN"); break; case SSL_ERROR_WANT_READ: IPL4_DEBUG("SSL_ERROR_WANT_READ"); break; case SSL_ERROR_WANT_WRITE: IPL4_DEBUG("SSL_ERROR_WANT_WRITE"); break; case SSL_ERROR_WANT_CONNECT: IPL4_DEBUG("SSL_ERROR_WANT_CONNECT"); break; case SSL_ERROR_WANT_ACCEPT: IPL4_DEBUG("SSL_ERROR_WANT_ACCEPT"); break; case SSL_ERROR_WANT_X509_LOOKUP: IPL4_DEBUG("SSL_ERROR_WANT_X509_LOOKUP"); break; case SSL_ERROR_SYSCALL: IPL4_DEBUG("SSL_ERROR_SYSCALL"); IPL4_DEBUG("EOF was observed that violates the protocol, peer disconnected; treated as a normal disconnect"); err = SSL_ERROR_ZERO_RETURN; break; case SSL_ERROR_SSL: IPL4_DEBUG("SSL_ERROR_SSL"); break; default: IPL4_DEBUG("Unknown SSL error code: %d", err); //--ethnba -may need to return to skip reading the error string } // get the copy of the error string in readable format unsigned long e=ERR_get_error(); if(!e) { IPL4_DEBUG("There is no SSL error at the moment.\n"); } while (e) { IPL4_DEBUG("SSL error queue content:"); IPL4_DEBUG(" Library: %s", ERR_lib_error_string(e)); IPL4_DEBUG(" Function: %s", ERR_func_error_string(e)); IPL4_DEBUG(" Reason: %s", ERR_reason_error_string(e)); e=ERR_get_error(); } //It does the same but more simple: // ERR_print_errors_fp(stderr); return err; } /* Not used, just a placeholder. int IPL4asp__PT_PROVIDER::ssl_verify_certificates_at_handshake(int preverify_ok, X509_STORE_CTX *ssl_ctx) { // don't care by default return -1; } */ // Callback function used by OpenSSL. // Called when a password is needed to decrypt the private key file. // NOTE: not thread safe int IPL4asp__PT_PROVIDER::ssl_password_cb(char *buf, int num, int /*rwflag*/,void *userdata) { const char* pass = (const char*) userdata; if(userdata==NULL) return 0; int pass_len = strlen(pass) + 1; if (num < pass_len) return 0; strcpy(buf, pass); return(strlen(pass)); } // Callback function used by OpenSSL. // Called during SSL handshake with a pre-verification status. int IPL4asp__PT_PROVIDER::ssl_verify_callback(int preverify_ok, X509_STORE_CTX *ssl_ctx) { SSL *ssl_pointer; SSL_CTX *ctx_pointer; // int user_result; ssl_pointer = (SSL *)X509_STORE_CTX_get_ex_data(ssl_ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); ctx_pointer = SSL_get_SSL_CTX(ssl_pointer); /* // the ssl_verify_certificates_at_handshake always return -1. No sense to call it. Later if more check is implemented // the code can be reactivated. if (ssl_current_client!=NULL) { user_result=((IPL4asp__PT_PROVIDER *)ssl_current_client)->ssl_verify_certificates_at_handshake(preverify_ok, ssl_ctx); if (user_result>=0) return user_result; } else { // go on with default authentication fprintf(stderr, "Warning: no current SSL object found but ssl_verify_callback is called, programming error\n"); } */ // if ssl_verifiycertificate == "no", then always accept connections if (SSL_CTX_get_verify_mode(ctx_pointer) && SSL_VERIFY_NONE) return 1; // if ssl_verifiycertificate == "yes", then accept connections only if the // certificate is valid else if (SSL_CTX_get_verify_mode(ctx_pointer) && SSL_VERIFY_PEER) return preverify_ok; // something went wrong else return 0; } bool IPL4asp__PT_PROVIDER::setSslObj(int connId, SSL* sslObj) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::setSslObj enter: connId %d", connId); testIfInitialized(); if (!isConnIdValid(connId)) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::setSslObj: invalid connId: %i", connId); return false; } sockList[connId].sslObj = sslObj; return true; } // IPL4asp__PT_PROVIDER::setSslObj bool IPL4asp__PT_PROVIDER::getSslObj(int connId, SSL*& sslObj) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::getSslObj enter: connId %d", connId); testIfInitialized(); if (!isConnIdValid(connId)) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::getSslObj: invalid connId: %i", connId); return false; } sslObj = sockList[connId].sslObj; return true; } // IPL4asp__PT_PROVIDER::getSslObj #endif //////////////////////////////////////////////////////////////////////// ///// Default SSL log functions //////////////////////////////////////////////////////////////////////// void IPL4asp__PT_PROVIDER::log_debug(const char *fmt, ...) const { if (debugAllowed) { TTCN_Logger::begin_event(TTCN_DEBUG); TTCN_Logger::log_event_str("IPL4asp__PT_PROVIDER - SSL socket: "); va_list args; va_start(args, fmt); TTCN_Logger::log_event_va_list(fmt, args); va_end(args); TTCN_Logger::end_event(); } } void IPL4asp__PT_PROVIDER::log_warning(const char *fmt, ...) const { TTCN_Logger::begin_event(TTCN_WARNING); TTCN_Logger::log_event_str("IPL4asp__PT_PROVIDER - SSL socket Warning: "); va_list args; va_start(args, fmt); TTCN_Logger::log_event_va_list(fmt, args); va_end(args); TTCN_Logger::end_event(); } void IPL4asp__PT_PROVIDER::log_hex(const char *prompt, const unsigned char *msg, size_t length) const { if (debugAllowed) { TTCN_Logger::begin_event(TTCN_DEBUG); TTCN_Logger::log_event_str("IPL4asp__PT_PROVIDER - SSL socket: "); if (prompt != NULL) TTCN_Logger::log_event_str(prompt); TTCN_Logger::log_event("Size: %lu, Msg:", (unsigned long)length); for (size_t i = 0; i < length; i++) TTCN_Logger::log_event(" %02x", msg[i]); TTCN_Logger::end_event(); } } #ifdef USE_IPL4_EIN_SCTP IPL4asp__PT_PROVIDER *IPL4asp__PT_PROVIDER::port_ptr=NULL; void IPL4asp__PT_PROVIDER::do_bind() { unsigned char bindRequestCounter = 0; exiting = FALSE; int otherId = SCTP_ID; IPL4_DEBUG("entering IPL4asp__PT_PROVIDER::do_bind() userId: %d, otherId: %d, userInstanceId: %d, sctpInstanceId: %d, cpManagerIPA %s", userId, otherId, userInstanceId, sctpInstanceId,(const char*)cpManagerIPA); SS7Common::setDebug(debugAllowed); SS7Common::connect_ein(userId, otherId, (const TEXT_T*)cpManagerIPA, userInstanceId, sctpInstanceId); if (userId == GENERATE_BY_CP_ID) { userId = SS7Common::getUsedMPOwner(); userInstanceId = SS7Common::getUsedMPInstance(); } #ifdef EIN_R3B EINSS7_00SCTPFUNCNEW_T newFunc; memset(&newFunc,0,sizeof(newFunc)); newFunc.EINSS7_00SctpSetEpAliasConf= EINSS7_00SCTPSETEPALIASCONF; newFunc.EINSS7_00SctpSetUserCongestionLevelConf= EINSS7_00SCTPSETUSERCONGESTIONLEVELCONF; newFunc.EINSS7_00SctpGetUserCongestionLevelConf= EINSS7_00SCTPGETUSERCONGESTIONLEVELCONF; newFunc.EINSS7_00SctpRedirectInd= EINSS7_00SCTPREDIRECTIND; newFunc.EINSS7_00SctpInfoConf= EINSS7_00SCTPINFOCONF; newFunc.EINSS7_00SctpInfoInd= EINSS7_00SCTPINFOIND; newFunc.EINSS7_00SctpUpdateConf= EINSS7_00SCTPUPDATECONF; EINSS7_00SCTPRegFuncNew(&newFunc); #endif USHORT_T ret_val; MSG_T msg; msg.receiver = userId; do { bindRequestCounter++; /* Bind to stack*/ // hardcoded value: ANSI 1996 IPL4_DEBUG("Sending:\n" "EINSS7_00SctpBindReq(\n" "userId=%d\n" "sctpInstanceId=%d\n" "api_type=%d" "bind_type=%d)\n", userId, sctpInstanceId, EINSS7_00SCTP_APITYPE_API, EINSS7_00SCTP_BIND_IF_NOT_BOUND); ret_val = EINSS7_00SctpBindReq( userId, sctpInstanceId, EINSS7_00SCTP_APITYPE_API, EINSS7_00SCTP_BIND_IF_NOT_BOUND ); if (ret_val != RETURN_OK) TTCN_error("EINSS7_00SctpBindReq failed: %d (%s)", ret_val, get_ein_sctp_error_message(ret_val,API_RETURN_CODES)); else IPL4_DEBUG("EINSS7_00SctpBindReq was successful"); IPL4_DEBUG("IPL4asp__PT_PROVIDER::do_bind(): Waiting for BindConf for user %d...", userId); do { ret_val = SS7Common::CallMsgRecv(&msg); } while(ret_val == MSG_TIMEOUT); if (ret_val != MSG_RECEIVE_OK) TTCN_error("IPL4asp__PT_PROVIDER::do_bind(): CallMsgRecv failed: %d (%s)", ret_val, SS7Common::get_ein_error_message(ret_val)); /* Print the message into the log */ log_msg("IPL4asp__PT_PROVIDER::do_bind(): Received message", &msg); /*Init the global variable*/ port_ptr = this; ret_val = EINSS7_00SctpHandleInd(&msg); if (ret_val != RETURN_OK) TTCN_error("IPL4 test port (%s): EINSS7_00SctpHandleInd failed: " "%d (%s) Message is ignored.", get_name(), ret_val, SS7Common::get_ein_error_message(ret_val)); else IPL4_DEBUG("PL4asp__PT_PROVIDER::do_bind(): message processing " "was successful"); /* Release the buffer */ ret_val = SS7Common::CallReleaseMsgBuffer(&msg); if (ret_val != RETURN_OK) TTCN_warning("IPL4 test port (%s): CallReleaseMsgBuffer " "failed: %d (%s)", get_name(), ret_val, SS7Common::get_ein_error_message(ret_val)); else IPL4_DEBUG("IPL4asp__PT_PROVIDER::do_bind(): message was released " "successfully"); /* Reset the global variable */ port_ptr = NULL; if (bindResult != EINSS7_00SCTP_OK) TTCN_warning("Bind failed: %d, %s, tries: %d.", bindResult, get_ein_sctp_error_message(ret_val,API_RETURN_CODES), bindRequestCounter); else { IPL4_DEBUG("The bind was successful."); } } while (bindResult != EINSS7_00SCTP_NTF_OK && bindRequestCounter <= 3); create_pipes(); IPL4_DEBUG("IPL4asp__PT_PROVIDER::do_bind() : starting the second thread."); start_thread(); } void IPL4asp__PT_PROVIDER::create_pipes() { if (pipe(pipe_to_TTCN_thread_fds)) TTCN_error("IPL4asp__PT_PROVIDER::create_pipe() @place1: pipe system call failed"); if (pipe(pipe_to_TTCN_thread_log_fds)) TTCN_error("IPL4asp__PT_PROVIDER::create_pipe() @place1: pipe system call failed"); Handler_Add_Fd_Read(pipe_to_TTCN_thread_fds[0]); Handler_Add_Fd_Read(pipe_to_TTCN_thread_log_fds[0]); if (pipe(pipe_to_EIN_thread_fds)) TTCN_error("IPL4asp__PT_PROVIDER::create_pipe() @place2: pipe system call failed"); } void IPL4asp__PT_PROVIDER::start_thread() { if (thread_started) return; if (pthread_create(&thread, NULL, IPL4asp__PT_PROVIDER::thread_main, this)) TTCN_error("TCAPasp_PT_EIN_Interface::launch_thread(): pthread_create failed."); thread_started = TRUE; } void *IPL4asp__PT_PROVIDER::thread_main(void *arg) { pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); static_cast(arg)->ein_receive_loop(); return NULL; } void IPL4asp__PT_PROVIDER::ein_receive_loop() { for (; !exiting; ) { MSG_T msg; USHORT_T ret_val; msg.receiver = userId; do { ret_val = SS7Common::CallMsgRecv(&msg); } while(!exiting && ret_val == MSG_TIMEOUT); //IPL4_DEBUG("A message arrived from the stack."); if(exiting) break; if (ret_val != MSG_RECEIVE_OK) { log_thread(TTCN_DEBUG,"IPL4asp__PT_PROVIDER::ein_receive_loop(): EINSS7CpMsgRecv_r failed: %d (%s)", ret_val, SS7Common::get_ein_error_message(ret_val)); return; } write_pipe(pipe_to_TTCN_thread_fds); if(exiting) break; read_pipe(pipe_to_EIN_thread_fds); if(exiting) break; log_msg("IPL4asp__PT_PROVIDER::ein_receive_loop(): Received message", &msg); /* Set the global variable so that the EIN callback functions reach * our member functions */ port_ptr = this; /* Pass the message to the EIN stack TCAP layer */ log_thread(TTCN_DEBUG,"IPL4asp__PT_PROVIDER::ein_receive_loop(): passing incoming message to EIN"); ret_val = EINSS7_00SctpHandleInd(&msg); if (ret_val != RETURN_OK) log_thread(TTCN_WARNING,"IPL4 test port (%s): EINSS7_00SctpHandleInd failed: " "%d (%s) Message is ignored.", get_name(), ret_val, SS7Common::get_ein_error_message(ret_val)); else log_thread(TTCN_DEBUG,"IPL4asp__PT_PROVIDER::ein_receive_loop(): message processing " "was successful"); port_ptr = NULL; write_pipe(pipe_to_TTCN_thread_fds); /* Release the buffer */ ret_val = SS7Common::CallReleaseMsgBuffer(&msg); if (ret_val != RETURN_OK) log_thread(TTCN_WARNING,"IPL4 test port (%s): CallReleaseMsgBuffer " "failed: %d (%s)", get_name(), ret_val, SS7Common::get_ein_error_message(ret_val)); else log_thread(TTCN_DEBUG,"IPL4asp__PT_PROVIDER::ein_receive_loop(): message was released " "successfully"); /* Reset the global variable */ } log_thread(TTCN_DEBUG,"IPL4asp__PT_PROVIDER::ein_receive_loop(): exiting... "); } void IPL4asp__PT_PROVIDER::destroy_pipes() { Handler_Remove_Fd_Read(pipe_to_TTCN_thread_fds[0]); Handler_Remove_Fd_Read(pipe_to_TTCN_thread_log_fds[0]); close(pipe_to_TTCN_thread_fds[0]); pipe_to_TTCN_thread_fds[0] = -1; close(pipe_to_TTCN_thread_fds[1]); pipe_to_TTCN_thread_fds[1] = -1; close(pipe_to_TTCN_thread_log_fds[0]); pipe_to_TTCN_thread_log_fds[0] = -1; close(pipe_to_TTCN_thread_log_fds[1]); pipe_to_TTCN_thread_log_fds[1] = -1; close(pipe_to_EIN_thread_fds[0]); pipe_to_EIN_thread_fds[0] = -1; close(pipe_to_EIN_thread_fds[1]); pipe_to_EIN_thread_fds[1] = -1; } void IPL4asp__PT_PROVIDER::read_pipe(int pipe_fds[]) { //IPL4_DEBUG("TCAPasp_PT_EIN_Interface: Waiting in read_pipe()..."); unsigned char buf; if (read(pipe_fds[0], &buf, 1) != 1){ exiting=TRUE; TTCN_warning("IPL4asp__PT_PROVIDER::read_pipe(): read system call failed"); } } void IPL4asp__PT_PROVIDER::write_pipe(int pipe_fds[]) { //IPL4_DEBUG("TCAPasp_PT_EIN_Interface: Writing in the pipe..."); unsigned char buf = '\0'; if (write(pipe_fds[1], &buf, 1) != 1){ exiting=TRUE; TTCN_warning("IPL4asp__PT_PROVIDER::write_pipe(): write system call failed"); } } void IPL4asp__PT_PROVIDER::log_thread(TTCN_Logger::Severity severity, const char *fmt, ...){ if(exiting) {return;} if (severity!=TTCN_DEBUG || debugAllowed) { thread_log *log_msg=(thread_log *)Malloc(sizeof(thread_log)); va_list args; va_start(args, fmt); log_msg->severity=severity; log_msg->msg=mprintf_va_list(fmt, args); int len = write(pipe_to_TTCN_thread_log_fds[1], &log_msg, sizeof(thread_log*)); if(exiting) {return;} if (len == 0) { TTCN_error("Internal queue shutdown"); } else if (len < 0) { TTCN_error("Error while writing to internal queue (errno = %d)", errno); } else if (len != sizeof(thread_log*)){ TTCN_error("Partial write to the queue: %d bytes written (errno = %d)", len, errno); } } } void IPL4asp__PT_PROVIDER::log_thread_msg(const char *header, const MSG_T *msg){ if (debugAllowed) { char *msgstr=mprintf("TCAP test port (%s): ", get_name()); if (header != NULL) msgstr=mputprintf(msgstr,"%s: ", header); msgstr=mputprintf(msgstr,"{"); msgstr=mputprintf(msgstr," Sender: %d,", msg->sender); msgstr=mputprintf(msgstr," Receiver: %d,", msg->receiver); msgstr=mputprintf(msgstr," Primitive: %d,", msg->primitive); msgstr=mputprintf(msgstr," Size: %d,", msg->size); msgstr=mputprintf(msgstr," Message:"); for (USHORT_T i = 0; i < msg->size; i++) msgstr=mputprintf(msgstr," %02X", msg->msg_p[i]); msgstr=mputprintf(msgstr," }"); log_thread(TTCN_DEBUG,msgstr); Free(msgstr); } } void IPL4asp__PT_PROVIDER::do_unbind() { USHORT_T ret_val; int otherId = SCTP_ID; /* UnBind */ if (bindResult == EINSS7_00SCTP_NTF_OK) { exiting = TRUE; IPL4_DEBUG("Sending:\n" "EINSS7_00SctpBindReq(\n" "sctpInstanceId=%d)", sctpInstanceId); ret_val = EINSS7_00SctpUnbindReq(sctpInstanceId); switch (ret_val) { case RETURN_OK: IPL4_DEBUG("EINSS7_00SctpBindReq(%d) was successful", sctpInstanceId); break; case MSG_NOT_CONNECTED: TTCN_warning("IPL4 test port (%s): " "The EIN stack was not bound", get_name()); break; default: TTCN_error("EINSS7_00SctpBindReq(%d) failed: %d (%s)", sctpInstanceId, ret_val, SS7Common::get_ein_error_message(ret_val)); } }else TTCN_warning("IPL4 test port (%s): " "was not bound.", get_name()); bindResult = EINSS7_00SCTP_NOT_BOUND; // wait 0.5 sec to unbind reach the stack // before closing connection // 0.5 sec was recommended by Ulf.Melin@tietoenator.com // TR ID: 6801 usleep (500000); /* Disconnect from EIN stack */ SS7Common::disconnect_ein(userId, otherId, userInstanceId, sctpInstanceId); /* Clean up resources */ IPL4_DEBUG("IPL4asp__PT_PROVIDER::do_unbind() : destroying the pipes."); destroy_pipes(); ein_connected = false; thread_started = false; } Socket__API__Definitions::Result IPL4asp__PT_PROVIDER::Listen_einsctp(const HostName& locName, const PortNumber& locPort, int next_action , const HostName& remName, const PortNumber& remPort, const IPL4asp__Types::OptionList& options, const IPL4asp__Types::SocketList &sock_list){ Result result(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE); SockAddr sockAddr; socklen_t sockAddrLen; //struct hostent *hp = NULL; int hp = 0; IPL4_DEBUG("f__IPL4__PROVIDER__listen: enter %s %d", (const char *) locName, (int) locPort); testIfInitialized(); int addr_index=-1; int num_of_addr=1; int config_group=0; for(int i=0; i 65535) RETURN_ERROR_STACK(PortError::ERROR__INVALID__INPUT__PARAMETER); IPADDRESS_T *ip_struct=(IPADDRESS_T *)Malloc(num_of_addr*sizeof(IPADDRESS_T)); memset((void *)ip_struct,0,num_of_addr*sizeof(IPADDRESS_T)); hp=SetLocalSockAddr("f__IPL4__PROVIDER__listen",*this,AF_INET,locName, locPort, sockAddr, sockAddrLen); if (hp == -1) { SET_OS_ERROR_CODE; Free(ip_struct); RETURN_ERROR_STACK(PortError::ERROR__HOSTNAME); } char ip_addr[46]; memset((void *)ip_addr,0,46); if(hp == AF_INET){ inet_ntop(AF_INET,&sockAddr.v4.sin_addr.s_addr,ip_addr,46); ip_struct[0].addrType=EINSS7_00SCTP_IPV4; } #ifdef USE_IPV6 else { inet_ntop(AF_INET6,&sockAddr.v6.sin6_addr.s6_addr,ip_addr,46); ip_struct[0].addrType=EINSS7_00SCTP_IPV6; } #endif ip_struct[0].addr=(unsigned char*)mcopystr(ip_addr); ip_struct[0].addrLength=strlen(ip_addr)+1; for(int i=1; i= sockListSize - 1 || sockList == NULL) { unsigned int sz = sockListSize; if (sockList != NULL) sz *= 2; SockDesc *newSockList = (SockDesc *)Realloc(sockList, sizeof(SockDesc) * sz); int i0 = (sockList == 0) ? 1 : sockListSize; sockList = newSockList; sockListSize = sz; IPL4_DEBUG("IPL4asp__PT_PROVIDER::ConnAdd: new sockListSize: %d", sockListSize); int j = firstFreeSock; for ( int i = sockListSize - 1; i >= i0; --i ) { memset(sockList + i, 0, sizeof (sockList[i])); sockList[i].sock = SockDesc::SOCK_NONEX; sockList[i].nextFree = j; j = i; } firstFreeSock = j; if (lastFreeSock == -1) lastFreeSock = sockListSize - 1; } int i = firstFreeSock; IPL4_DEBUG("IPL4asp__PT_PROVIDER::ConnAdd: connId: %d", i); if (parentIdx != -1) { // inherit the listener's properties sockList[i].userData = sockList[parentIdx].userData; sockList[i].getMsgLen = sockList[parentIdx].getMsgLen; sockList[i].getMsgLen_forConnClosedEvent = sockList[parentIdx].getMsgLen_forConnClosedEvent; sockList[i].parentIdx = parentIdx; sockList[parentIdx].ref_count++; sockList[i].msgLenArgs = new ro__integer(*sockList[parentIdx].msgLenArgs); } else { // otherwise initialize to defaults sockList[i].userData = 0; sockList[i].getMsgLen = defaultGetMsgLen; sockList[i].getMsgLen_forConnClosedEvent = defaultGetMsgLen_forConnClosedEvent; sockList[i].parentIdx = -1; sockList[i].msgLenArgs = new ro__integer(*defaultMsgLenArgs); } if (sockList[i].msgLenArgs == NULL) return -1; sockList[i].msgLen = -1; // ae2IndexMap[assoc_enpoint] = i; sockList[i].ref_count=0; sockList[i].type = type; sockList[i].localaddr=new CHARSTRING(locName); sockList[i].localport=new PortNumber(locPort); sockList[i].remoteaddr=new CHARSTRING(remName); sockList[i].remoteport=new PortNumber(remPort); sockList[i].next_action=next_action; sockList[i].remote_addr_index=0; sockList[i].remote_addr_list=IPL4asp__Types::SocketList(NULL_VALUE); switch (type) { case IPL4asp_SCTP_LISTEN: sockList[i].buf = NULL; sockList[i].assocIdList = NULL; sockList[i].cnt = 0; break; case IPL4asp_SCTP: sockList[i].buf = (TTCN_Buffer **)Malloc(sizeof(TTCN_Buffer *)); *sockList[i].buf = new TTCN_Buffer; if (*sockList[i].buf == NULL) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::ConnAdd: failed to add socket %d", assoc_enpoint); Free(sockList[i].buf); sockList[i].buf = 0; return -1; } sockList[i].assocIdList = (sctp_assoc_t *)Malloc(sizeof(sctp_assoc_t)); sockList[i].cnt = 1; break; default: break; } sockList[i].sock = assoc_enpoint; firstFreeSock = sockList[i].nextFree; sockList[i].nextFree = -1; ++sockListCnt; if(sockListCnt==1) {lonely_conn_id=i;} else {lonely_conn_id=-1;} IPL4_DEBUG("IPL4asp__PT_PROVIDER::ConnAdd: leave: sockListCnt: %i", sockListCnt); return i; } // IPL4asp__PT::ConnAdd int IPL4asp__PT_PROVIDER::ConnDelEin(int connId,bool forced) { IPL4_DEBUG("IPL4asp__PT_PROVIDER::ConnDel: enter: connId: %d", connId); if(sockList[connId].parentIdx!=-1){ int parentIdx=sockList[connId].parentIdx; sockList[parentIdx].ref_count--; if(sockList[parentIdx].ref_count==0 && sockList[parentIdx].next_action==SockDesc::ACTION_DELETE){ EINSS7_00SctpDestroyReq(sockList[parentIdx].endpoint_id); ep2IndexMap.erase(sockList[parentIdx].endpoint_id); ConnDelEin(parentIdx); } } else { if(sockList[connId].ref_count!=0) { sockList[connId].next_action=SockDesc::ACTION_DELETE; return connId; } EINSS7_00SctpDestroyReq(sockList[connId].endpoint_id); } sockList[connId].clear(); if(!connId_release_confirmed || forced){ ConnFree(connId); } else { sockList[connId].sock = SockDesc::WAIT_FOR_RELEASE; incoming_message(ASP__ConnId__ReadyToRelease(connId)); } return connId; } // IPL4asp__PT_PROVIDER::ConnDel USHORT_T IPL4asp__PT_PROVIDER::SctpInitializeConf( UCHAR_T returnCode, ULONG_T sctpEndpointId, USHORT_T assignedMis, USHORT_T assignedOsServerMode, USHORT_T maxOs, ULONG_T pmtu, ULONG_T mappingKey, USHORT_T localPort ){ IPL4_DEBUG("SctpInitializeConf sctpEndpointId %ul mappingKey %ul returnCode %d ",sctpEndpointId,mappingKey,returnCode); if(EINSS7_00SCTP_NTF_DUPLICATE_INIT==returnCode && sockList[mappingKey].next_action==SockDesc::ACTION_CONNECT){ std::map::iterator it = ep2IndexMap.find(sctpEndpointId); int parent_id=it->second; sockList[parent_id].ref_count++; sockList[mappingKey].parentIdx=parent_id; } else if(EINSS7_00SCTP_NTF_OK!=returnCode){ Result result(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE); EINSS7_00SctpDestroyReq(sctpEndpointId); result.errorCode()=PortError::ERROR__GENERAL; result.os__error__code()=returnCode; result.os__error__text()=get_ein_sctp_error_message(returnCode,CONF_RETURNCODE); result.connId()=mappingKey; ASP__Event event; event.result() = result; incoming_message(event); ProtoTuple proto; proto.sctp()=SctpTuple(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE); sendConnClosed(mappingKey, *(sockList[mappingKey].remoteaddr), *(sockList[mappingKey].remoteport), *(sockList[mappingKey].localaddr), localPort, proto, sockList[mappingKey].userData); ConnDelEin(mappingKey); return RETURN_OK; } sockList[mappingKey].sock=sctpEndpointId; sockList[mappingKey].maxOs=maxOs; sockList[mappingKey].endpoint_id=sctpEndpointId; *(sockList[mappingKey].localport)=localPort; if(sockList[mappingKey].next_action==SockDesc::ACTION_CONNECT){ if(EINSS7_00SCTP_NTF_OK==returnCode){ sockList[mappingKey].ref_count=0; ep2IndexMap[sctpEndpointId] = mappingKey; } char rem_addr[46]; memset((void *)rem_addr,0,46); IPADDRESS_T ip_struct; strcpy(rem_addr,(const char*)*(sockList[mappingKey].remoteaddr)); if(!strchr(rem_addr,':')){ ip_struct.addrType=EINSS7_00SCTP_IPV4; } #ifdef USE_IPV6 else { ip_struct.addrType=EINSS7_00SCTP_IPV6; } #endif ip_struct.addr=(unsigned char*)rem_addr; ip_struct.addrLength=strlen(rem_addr)+1; USHORT_T req_result=EINSS7_00SctpAssociateReq( sctpEndpointId, maxOs<(int) globalConnOpts.sinit_num_ostreams?maxOs:(int) globalConnOpts.sinit_num_ostreams, mappingKey, *(sockList[mappingKey].remoteport), ip_struct ); if(EINSS7_00SCTP_OK!=req_result){ Result result(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE); EINSS7_00SctpDestroyReq(sctpEndpointId); result.errorCode()=PortError::ERROR__GENERAL; result.os__error__code()=returnCode; result.os__error__text()=get_ein_sctp_error_message(returnCode,API_RETURN_CODES); result.connId()=mappingKey; ASP__Event event; event.result() = result; incoming_message(event); ProtoTuple proto; proto.sctp()=SctpTuple(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE); sendConnClosed(mappingKey, *(sockList[mappingKey].remoteaddr), *(sockList[mappingKey].remoteport), *(sockList[mappingKey].localaddr), localPort, proto, sockList[mappingKey].userData); ConnDelEin(mappingKey); } } else { Result result(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE); sockList[mappingKey].next_action=SockDesc::ACTION_NONE; sockList[mappingKey].ref_count=0; ep2IndexMap[sctpEndpointId] = mappingKey; result.connId()=mappingKey; result.errorCode()=PortError::ERROR__AVAILABLE; ASP__Event event; event.result() = result; incoming_message(event); } return RETURN_OK; } USHORT_T IPL4asp__PT_PROVIDER::SctpAssociateConf( UCHAR_T returnCode, ULONG_T assocId, ULONG_T ulpKey ){ IPL4_DEBUG(" SctpAssociateConf assocId %ul ulpKey %ul returnCode %d ",assocId,ulpKey,returnCode); if(EINSS7_00SCTP_NTF_OK!=returnCode){ Result result(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE); EINSS7_00SctpDestroyReq(sockList[ulpKey].endpoint_id); result.errorCode()=PortError::ERROR__GENERAL; result.os__error__code()=returnCode; result.os__error__text()=get_ein_sctp_error_message(returnCode,CONF_RETURNCODE); result.connId()=ulpKey; ASP__Event event; event.result() = result; incoming_message(event); ProtoTuple proto; proto.sctp()=SctpTuple(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE); sendConnClosed(ulpKey, *(sockList[ulpKey].remoteaddr), *(sockList[ulpKey].remoteport), *(sockList[ulpKey].localaddr), *(sockList[ulpKey].localport), proto, sockList[ulpKey].userData); ConnDelEin(ulpKey); return RETURN_OK; } sockList[ulpKey].sock=assocId; Result result(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE); // sockList[ulpKey].next_action=SockDesc::ACTION_NONE; result.connId()=ulpKey; result.errorCode()=PortError::ERROR__AVAILABLE; ASP__Event event; event.result() = result; incoming_message(event); return RETURN_OK; } // Sometimes the stack is too fast and puts the indicatin into buffer before we can set the correct ulpkey // Stack IPL4 TP // // SctpCommUpInd(ulpKey of listening socket) --------| // SctpDataArriveInd(ulpKey of listening socket) --| | // | |-------------> EINSS7_00SctpSetUlpKeyReq(new ulpKey) // | | // EINSS7_00SctpSetUlpKeyReq processed <-----------------------------------------| // |----------------->SctpDataArriveInd(ulpKey of listening socket) // // // The verify_and_set_connid tries to detect the case and find the correct ulpKey, which is the connId of the IPL4 port // the verification is based on the stored assocId // The possible source of the ulpKey mixup is the parallel threads in the EIN stack int IPL4asp__PT_PROVIDER::verify_and_set_connid(ULONG_T ulpKey, ULONG_T assocId){ if(isConnIdValid(ulpKey) && sockList[ulpKey].sock==(int)assocId && sockList[ulpKey].type==IPL4asp_SCTP ){ return ulpKey; // correct ulpKey } // the key is not correct // Try to find in the database for(unsigned int a=0; a::iterator it = ep2IndexMap.find(sctpEndpointId); int parent_id=it->second; int conn_id; if(sockList[parent_id].next_action==SockDesc::ACTION_DELETE){ conn_id=ConnAddEin(IPL4asp_SCTP,assocId,parent_id, *(sockList[parent_id].localaddr), *(sockList[parent_id].localport), CHARSTRING(remoteIpAddrList_sp[0].addrLength-1,(const char*)remoteIpAddrList_sp[0].addr) ,remotePort, SockDesc::ACTION_DELETE); sockList[conn_id].endpoint_id=sctpEndpointId; EINSS7_00SctpSetUlpKeyReq(assocId,conn_id); EINSS7_00SctpAbortReq(assocId); return RETURN_OK; } conn_id=ConnAddEin(IPL4asp_SCTP,assocId,parent_id, *(sockList[parent_id].localaddr), *(sockList[parent_id].localport), CHARSTRING(remoteIpAddrList_sp[0].addrLength-1,(const char*)remoteIpAddrList_sp[0].addr) ,remotePort, SockDesc::ACTION_NONE); sockList[conn_id].endpoint_id=sctpEndpointId; ASP__Event event; reportConnOpened(conn_id); EINSS7_00SctpSetUlpKeyReq(assocId,conn_id); event.sctpEvent().sctpAssocChange().clientId() = conn_id; event.sctpEvent().sctpAssocChange().proto().sctp() = SctpTuple(OMIT_VALUE, OMIT_VALUE, OMIT_VALUE, OMIT_VALUE); event.sctpEvent().sctpAssocChange().sac__state() = IPL4asp__Types::SAC__STATE::SCTP__COMM__UP; incoming_message(event); } return RETURN_OK; } void IPL4asp__PT_PROVIDER::handle_message_from_ein(int fd){ if(pipe_to_TTCN_thread_log_fds[0]== fd){ thread_log *r; int len = read(pipe_to_TTCN_thread_log_fds[0], &r, sizeof(thread_log *)); if (len == sizeof(thread_log *)) { TTCN_Logger::begin_event(r->severity); TTCN_Logger::log_event("%s", r->msg); TTCN_Logger::end_event(); Free(r->msg); Free(r); } else if (len == 0) { TTCN_warning(get_name(), "Internal queue shutdown"); } else if (len < 0) { TTCN_warning(get_name(), "Error while reading from internal queue (errno = %d)", errno); } else { TTCN_warning(get_name(), "Partial read from the queue: %d bytes read (errno = %d)", len, errno); } } else if(pipe_to_TTCN_thread_fds[0] == fd){ read_pipe(pipe_to_TTCN_thread_fds); write_pipe(pipe_to_EIN_thread_fds); read_pipe(pipe_to_TTCN_thread_fds); } } USHORT_T IPL4asp__PT_PROVIDER::SctpDataArriveInd( ULONG_T assocId, USHORT_T streamId, ULONG_T ulpKey, ULONG_T payloadProtId, BOOLEAN_T unorderFlag, USHORT_T streamSequenceNumber, UCHAR_T partialDeliveryFlag, ULONG_T dataLength, UCHAR_T * data_p ){ IPL4_DEBUG("SctpDataArriveInd assocId %ul ulpKey %ul streamId %ud payloadProtId %ul dataLength %ul",assocId,ulpKey,streamId,payloadProtId,dataLength); int connid=verify_and_set_connid(ulpKey,assocId); IPL4_DEBUG( "SctpDataArriveInd corretced connid %d",connid); switch(partialDeliveryFlag){ case EINSS7_00SCTP_LAST_PARTIAL_DELIVERY: case EINSS7_00SCTP_NO_PARTIAL_DELIVERY: { ASP__RecvFrom asp; asp.connId() = connid; asp.userData() = sockList[connid].userData; asp.remName() = *(sockList[connid].remoteaddr); asp.remPort() = *(sockList[connid].remoteport); asp.locName() = *(sockList[connid].localaddr); asp.locPort() = *(sockList[connid].localport); sockList[connid].buf[0]->put_s(dataLength, data_p); // IPL4_DEBUG("PL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: Incoming data (%ld bytes): stream = %hu, ssn = %hu, flags = %hx, ppid = %u \n", n, // sri->sinfo_stream,(unsigned int)sri->sinfo_ssn, sri->sinfo_flags, sri->sinfo_ppid); INTEGER i_ppid; i_ppid.set_long_long_val(payloadProtId); asp.proto().sctp() = SctpTuple(streamId, i_ppid, OMIT_VALUE, OMIT_VALUE); sockList[connid].buf[0]->get_string(asp.msg()); incoming_message(asp); if(sockList[connid].buf) sockList[connid].buf[0]->clear(); } break; case EINSS7_00SCTP_FIRST_PARTIAL_DELIVERY: case EINSS7_00SCTP_MIDDLE_PARTIAL_DELIVERY: IPL4_DEBUG("IPL4asp__PT_PROVIDER::Handle_Fd_Event_Readable: partial receive: %ud bytes", dataLength); sockList[connid].buf[0]->put_s(dataLength, data_p); break; default: break; } return RETURN_OK; } USHORT_T IPL4asp__PT_PROVIDER::SctpCommLostInd( ULONG_T assocId, ULONG_T ulpKey, UCHAR_T eventType, UCHAR_T origin ){ IPL4_DEBUG(" SctpCommLostInd assocId %ul ulpKey %ul eventType %d origin %d ",assocId,ulpKey,eventType,origin); if(sockList[ulpKey].next_action==SockDesc::ACTION_CONNECT && globalConnOpts.connection_method==GlobalConnOpts::METHOD_ONE && sockList[ulpKey].remote_addr_indexsender); TTCN_Logger::log_event(" Receiver: %d,", msg->receiver); TTCN_Logger::log_event(" Primitive: %d,", msg->primitive); TTCN_Logger::log_event(" Size: %d,", msg->size); TTCN_Logger::log_event_str(" Message:"); for (USHORT_T i = 0; i < msg->size; i++) TTCN_Logger::log_event(" %02X", msg->msg_p[i]); TTCN_Logger::log_event_str(" }"); TTCN_Logger::end_event(); } } #endif } // namespace IPL4asp__PortType #ifdef USE_IPL4_EIN_SCTP USHORT_T EINSS7_00SctpAssocRestartInd( ULONG_T assocId, ULONG_T ulpKey, USHORT_T outboundStreams, USHORT_T inboundStreams, UCHAR_T numOfRemoteIpAddrs, IPADDRESS_T * remoteIpAddrList_sp ){ return IPL4asp__PortType::IPL4asp__PT_PROVIDER::port_ptr->SctpAssocRestartInd( assocId, ulpKey, outboundStreams, inboundStreams, numOfRemoteIpAddrs, remoteIpAddrList_sp ); } USHORT_T EINSS7_00SctpCommUpInd( ULONG_T sctpEndpointId, ULONG_T assocId, ULONG_T ulpKey, UCHAR_T origin, USHORT_T outboundStreams, USHORT_T inboundStreams, USHORT_T remotePort, UCHAR_T numOfRemoteIpAddrs, IPADDRESS_T * remoteIpAddrList_sp ){ return IPL4asp__PortType::IPL4asp__PT_PROVIDER::port_ptr->SctpCommUpInd( sctpEndpointId, assocId, ulpKey, origin, outboundStreams, inboundStreams, remotePort, numOfRemoteIpAddrs, remoteIpAddrList_sp ); } USHORT_T EINSS7_00SctpCommLostInd( ULONG_T assocId, ULONG_T ulpKey, UCHAR_T eventType, UCHAR_T origin ){ return IPL4asp__PortType::IPL4asp__PT_PROVIDER::port_ptr->SctpCommLostInd( assocId, ulpKey, eventType, origin ); } USHORT_T EINSS7_00SctpCommErrorInd( ULONG_T assocId, ULONG_T ulpKey, UCHAR_T errorCode ){ return IPL4asp__PortType::IPL4asp__PT_PROVIDER::port_ptr->SctpCommErrorInd( assocId, ulpKey, errorCode ); } USHORT_T EINSS7_00SctpDataArriveInd( ULONG_T assocId, USHORT_T streamId, ULONG_T ulpKey, ULONG_T payloadProtId, BOOLEAN_T unorderFlag, USHORT_T streamSequenceNumber, UCHAR_T partialDeliveryFlag, ULONG_T dataLength, UCHAR_T * data_p ){ return IPL4asp__PortType::IPL4asp__PT_PROVIDER::port_ptr->SctpDataArriveInd( assocId, streamId, ulpKey, payloadProtId, unorderFlag, streamSequenceNumber, partialDeliveryFlag, dataLength, data_p ); } USHORT_T EINSS7_00SctpShutdownConf( UCHAR_T returnCode, ULONG_T assocId, ULONG_T ulpKey ){ return IPL4asp__PortType::IPL4asp__PT_PROVIDER::port_ptr->SctpShutdownConf( returnCode, assocId, ulpKey ); } USHORT_T EINSS7_00SctpCongestionInd( ULONG_T assocId, ULONG_T ulpKey ){ return IPL4asp__PortType::IPL4asp__PT_PROVIDER::port_ptr->SctpCongestionInd( assocId, ulpKey ); } USHORT_T EINSS7_00SctpCongestionCeaseInd( ULONG_T assocId, ULONG_T ulpKey ){ return IPL4asp__PortType::IPL4asp__PT_PROVIDER::port_ptr->SctpCongestionCeaseInd( assocId, ulpKey ); } USHORT_T EINSS7_00SctpSendFailureInd( UCHAR_T returnCode, ULONG_T assocId, ULONG_T ulpKey, ULONG_T dataLength, UCHAR_T * data_p, ULONG_T payloadProtId, USHORT_T streamId, ULONG_T userSequence, IPADDRESS_T * remoteIpAddr_s, BOOLEAN_T unorderFlag ){ return IPL4asp__PortType::IPL4asp__PT_PROVIDER::port_ptr->SctpSendFailureInd( returnCode, assocId, ulpKey, dataLength, data_p, payloadProtId, streamId, userSequence, remoteIpAddr_s, unorderFlag ); } USHORT_T EINSS7_00SctpNetworkStatusChangeInd( ULONG_T assocId, ULONG_T ulpKey, UCHAR_T newStatus, IPADDRESS_T remoteIpAddr_s ){ return IPL4asp__PortType::IPL4asp__PT_PROVIDER::port_ptr->SctpNetworkStatusChangeInd( assocId, ulpKey, newStatus, remoteIpAddr_s ); } USHORT_T EINSS7_00SctpIndError( USHORT_T errorCode, MSG_T * msg_sp ){ return IPL4asp__PortType::IPL4asp__PT_PROVIDER::port_ptr->SctpIndError( errorCode, msg_sp ); } USHORT_T EINSS7_00SctpBindConf( EINSS7INSTANCE_T sctpInstanceId, UCHAR_T error ){ return IPL4asp__PortType::IPL4asp__PT_PROVIDER::port_ptr->SctpBindConf( sctpInstanceId, error ); } USHORT_T EINSS7_00SctpStatusConf( UCHAR_T returnCode, ULONG_T mappingKey, ULONG_T sctpEndpointId, ULONG_T numOfAssociations, ASSOC_T * assocStatusList_sp ){ return IPL4asp__PortType::IPL4asp__PT_PROVIDER::port_ptr->SctpStatusConf( returnCode, mappingKey, sctpEndpointId, numOfAssociations, assocStatusList_sp ); } USHORT_T EINSS7_00SctpTakeoverConf( UCHAR_T returnCode, ULONG_T assocId, ULONG_T sctpEndpointId ){ return IPL4asp__PortType::IPL4asp__PT_PROVIDER::port_ptr->SctpTakeoverConf( returnCode, assocId, sctpEndpointId ); } USHORT_T EINSS7_00SctpTakeoverInd( UCHAR_T returnCode, ULONG_T assocId, ULONG_T sctpEndpointId ){ return IPL4asp__PortType::IPL4asp__PT_PROVIDER::port_ptr->SctpTakeoverConf( returnCode, assocId, sctpEndpointId ); } USHORT_T EINSS7_00SctpInitializeConf( UCHAR_T returnCode, ULONG_T sctpEndpointId, USHORT_T assignedMis, USHORT_T assignedOsServerMode, USHORT_T maxOs, ULONG_T pmtu, ULONG_T mappingKey, USHORT_T localPort ){ return IPL4asp__PortType::IPL4asp__PT_PROVIDER::port_ptr->SctpInitializeConf( returnCode, sctpEndpointId, assignedMis, assignedOsServerMode, maxOs, pmtu, mappingKey, localPort ); } USHORT_T EINSS7_00SctpAssociateConf( UCHAR_T returnCode, ULONG_T assocId, ULONG_T ulpKey ){ return IPL4asp__PortType::IPL4asp__PT_PROVIDER::port_ptr->SctpAssociateConf( returnCode, assocId, ulpKey ); } #endif