ANSC_STATUS AnscSctoEngage ( ANSC_HANDLE hThisObject ) { ANSC_STATUS returnStatus = ANSC_STATUS_SUCCESS; PANSC_SIMPLE_CLIENT_TCP_OBJECT pMyObject = (PANSC_SIMPLE_CLIENT_TCP_OBJECT)hThisObject; PANSC_SCTO_WORKER_OBJECT pWorker = (PANSC_SCTO_WORKER_OBJECT )pMyObject->hWorker; int s_error = 0; ansc_socket_addr_in ansc_client_addr; ansc_socket_addr_in ansc_server_addr; xskt_socket_addr_in xskt_client_addr; xskt_socket_addr_in xskt_server_addr; #ifdef _ANSC_IPV6_COMPATIBLE_ ansc_addrinfo ansc_hints = {0}; ansc_addrinfo* pansc_server_addrinfo = NULL; ansc_addrinfo* pansc_client_addrinfo = NULL; xskt_addrinfo xskt_hints = {0}; xskt_addrinfo* pxskt_server_addrinfo = NULL; xskt_addrinfo* pxskt_client_addrinfo = NULL; USHORT usPort = 0; char port[6] = {0}; #endif if ( pMyObject->bActive ) { return ANSC_STATUS_SUCCESS; } else if ( !pWorker ) { return ANSC_STATUS_UNAPPLICABLE; } else { /* * Just like any other socket-based ANSC object, we will create a separate async recv task * which is dedicated to receiving packets. This async recv task is controlled by 'bActive' * flag. What if at this moment right before we're about to enable the socket operation and * setting 'bActive' flag to TRUE, the old recv task created by the last call of Engage() * is still running? While it may not cause crash, but it certainly confuses the owner * object because all async recv tasks share the same worker interface. The most obvious * solution is to wait for previous recv task to exit before creating a new one. */ while ( pMyObject->EngineTaskCount != 0 ) { AnscSleep(50); } pMyObject->bActive = TRUE; pMyObject->bClosed = FALSE; } /* * The underlying socket wrapper may require an explicit startup() call, such is the case on * Microsoft windows platforms. The wrapper initialization has to done for each task. On most * real-time operating systems, this call is not required. */ if ( pMyObject->Mode & ANSC_SCTO_MODE_XSOCKET ) { AnscStartupXsocketWrapper((ANSC_HANDLE)pMyObject); } else { AnscStartupSocketWrapper((ANSC_HANDLE)pMyObject); } #ifdef _ANSC_IPV6_COMPATIBLE_ if ( pMyObject->Mode & ANSC_SCTO_MODE_XSOCKET ) { xskt_hints.ai_family = AF_UNSPEC; xskt_hints.ai_socktype = XSKT_SOCKET_STREAM; xskt_hints.ai_flags = AI_CANONNAME; usPort = pMyObject->GetPeerPort((ANSC_HANDLE)pMyObject); _ansc_sprintf(port, "%d", usPort); AnscTrace("!!! Peer Port: %s !!!\n", port); char * pPeerName = pMyObject->GetPeerName((ANSC_HANDLE)pMyObject); AnscTrace("Peer Name: %s!!!\n", pPeerName); /* struct addrinfo hints,*res=NULL; memset(&hints,0,sizeof(hints)); hints.ai_family=PF_UNSPEC; hints.ai_socktype=SOCK_DGRAM; hints.ai_protocol=IPPROTO_UDP; s_error=getaddrinfo("127.0.0.1","123",&hints,&res); */ /* s_error = _xskt_getaddrinfo ( "10.74.52.92", port, &xskt_hints, &pxskt_server_addrinfo ); AnscTrace("!!!!!! _xskt_getaddrinfo returns: %d %s !!!\n", s_error, gai_strerror(s_error)); */ if ( _xskt_getaddrinfo ( pMyObject->GetPeerName((ANSC_HANDLE)pMyObject), port, &xskt_hints, &pxskt_server_addrinfo ) || _xskt_getaddrinfo ( "localhost", NULL, &xskt_hints, &pxskt_client_addrinfo ) ) { AnscTrace("!!! error 1 !!!\n"); if ( pMyObject->Mode & ANSC_SCTO_MODE_NO_BSP_NOTIFY_CONN_ERR == 0 ) { pWorker->Notify ( pWorker->hWorkerContext, ANSC_SCTOWO_EVENT_SOCKET_ERROR, (ANSC_HANDLE)NULL ); } returnStatus = ANSC_STATUS_FAILURE; goto EXIT1; } AnscTrace("!!! after getaddrinfo !!!\n"); } else { ansc_hints.ai_family = AF_UNSPEC; ansc_hints.ai_socktype = ANSC_SOCKET_STREAM; ansc_hints.ai_flags = AI_CANONNAME; usPort = pMyObject->GetPeerPort((ANSC_HANDLE)pMyObject); _ansc_sprintf(port, "%d", usPort); if ( _ansc_getaddrinfo ( pMyObject->GetPeerName((ANSC_HANDLE)pMyObject), port, &ansc_hints, &pansc_server_addrinfo ) || _ansc_getaddrinfo ( "localhost", NULL, &ansc_hints, &pansc_client_addrinfo ) ) { if ( pMyObject->Mode & ANSC_SCTO_MODE_NO_BSP_NOTIFY_CONN_ERR == 0 ) { pWorker->Notify ( pWorker->hWorkerContext, ANSC_SCTOWO_EVENT_SOCKET_ERROR, (ANSC_HANDLE)NULL ); } returnStatus = ANSC_STATUS_FAILURE; goto EXIT1; } } #endif /* * To engage the Tcp Client, we need to perform following acts in the respective order: * * (1) create the os-dependent socket * (2) bind to the newly socket * (3) connect to the specified server address * (4) allocate a buffer for receiving * (5) spawn a separate thread and start receiving */ if ( pMyObject->Mode & ANSC_SCTO_MODE_XSOCKET ) { #ifdef _ANSC_IPV6_COMPATIBLE_ pMyObject->Socket = (ANSC_SOCKET)_xskt_socket(pxskt_server_addrinfo->ai_family, pxskt_server_addrinfo->ai_socktype, 0); #else pMyObject->Socket = (ANSC_SOCKET)_xskt_socket(XSKT_SOCKET_AF_INET, XSKT_SOCKET_STREAM, 0); #endif if ( (XSKT_SOCKET)pMyObject->Socket == XSKT_SOCKET_INVALID_SOCKET ) { AnscTrace("!!!!!!!!!! _xskt_socket error !!!!!!!!!!\n"); if ( pMyObject->Mode & ANSC_SCTO_MODE_NO_BSP_NOTIFY_CONN_ERR == 0 ) { pWorker->Notify ( pWorker->hWorkerContext, ANSC_SCTOWO_EVENT_SOCKET_ERROR, (ANSC_HANDLE)NULL ); } returnStatus = ANSC_STATUS_FAILURE; goto EXIT1; } else AnscTrace("Opening IPv4 socket Ok\n"); } else { #ifdef _ANSC_IPV6_COMPATIBLE_ pMyObject->Socket = _ansc_socket(pansc_server_addrinfo->ai_family, pansc_server_addrinfo->ai_socktype, 0); #else pMyObject->Socket = _ansc_socket(ANSC_SOCKET_AF_INET, ANSC_SOCKET_STREAM, 0); #endif if ( pMyObject->Socket == ANSC_SOCKET_INVALID_SOCKET ) { if ( pMyObject->Mode & ANSC_SCTO_MODE_NO_BSP_NOTIFY_CONN_ERR == 0 ) { pWorker->Notify ( pWorker->hWorkerContext, ANSC_SCTOWO_EVENT_SOCKET_ERROR, (ANSC_HANDLE)NULL ); } returnStatus = ANSC_STATUS_FAILURE; goto EXIT1; } } /* * Normally we don't need to know which local network interface we shall bind to, and the * underlying operating system usually supports such notation as "any address". */ #ifndef _ANSC_IPV6_COMPATIBLE_ if ( pMyObject->Mode & ANSC_SCTO_MODE_XSOCKET ) { xskt_client_addr.sin_family = XSKT_SOCKET_AF_INET; xskt_client_addr.sin_port = _xskt_htons(pMyObject->HostPort); if (pMyObject->bSocketBindToDevice && *(pMyObject->SocketDeviceName)) { if (_xskt_setsocketopt ( pMyObject->Socket, XSKT_SOCKET_SOL_SOCKET, XSKT_SOCKET_SO_BINDTODEVICE, pMyObject->SocketDeviceName, _ansc_strlen(pMyObject->SocketDeviceName) + 1 ) < 0) { perror("setsockopt-SOL_SOCKET-SO_BINDTODEVICE"); returnStatus = ANSC_STATUS_FAILURE; goto EXIT2; } } // fprintf(stderr, "<RT XSKT> Binding socket to Device '%s'.\n", pMyObject->SocketDeviceName); if ( pMyObject->HostAddress.Value == 0 ) { ((pansc_socket_addr_in)&xskt_client_addr)->sin_addr.s_addr = XSKT_SOCKET_ANY_ADDRESS; } else { ((pansc_socket_addr_in)&xskt_client_addr)->sin_addr.s_addr = pMyObject->HostAddress.Value; } if ( _xskt_bind((XSKT_SOCKET)pMyObject->Socket, (xskt_socket_addr*)&xskt_client_addr, sizeof(xskt_client_addr)) != 0 ) { AnscTrace("!!!!!!!!!! _xskt_bind error: socket=%d, error=%d !!!!!!!!!!\n", (XSKT_SOCKET)pMyObject->Socket, errno); { int j; char s[256]; char *ptr1 = ((xskt_socket_addr*)(&xskt_client_addr))->sa_data; char stmp[16]; s[0] = '\0'; for(j=0; j<13; j++) { sprintf(stmp, "%.2x:", *(ptr1++)); strcat(s, stmp); } sprintf(stmp, "%.2x", *ptr1); strcat(s, stmp); AnscTrace("!!!!!!!!!! _xskt_bind error: client_addr=%s\n", s); } perror("_xskt_bind error"); if ( pMyObject->Mode & ANSC_SCTO_MODE_NO_BSP_NOTIFY_CONN_ERR == 0 ) { pWorker->Notify ( pWorker->hWorkerContext, ANSC_SCTOWO_EVENT_SOCKET_ERROR, (ANSC_HANDLE)NULL ); } returnStatus = ANSC_STATUS_FAILURE; goto EXIT2; } } else { ansc_client_addr.sin_family = ANSC_SOCKET_AF_INET; ansc_client_addr.sin_port = _ansc_htons(pMyObject->HostPort); if (pMyObject->bSocketBindToDevice && *(pMyObject->SocketDeviceName)) { if (_xskt_setsocketopt ( pMyObject->Socket, ANSC_SOCKET_SOL_SOCKET, ANSC_SOCKET_SO_BINDTODEVICE, pMyObject->SocketDeviceName, _ansc_strlen(pMyObject->SocketDeviceName) + 1 ) < 0) { perror("setsockopt-SOL_SOCKET-SO_BINDTODEVICE"); returnStatus = ANSC_STATUS_FAILURE; goto EXIT2; } } // fprintf(stderr, "<RT AnscSKT> Binding socket to Device '%s'.\n", pMyObject->SocketDeviceName); if ( pMyObject->HostAddress.Value == 0 ) { ansc_client_addr.sin_addr.s_addr = ANSC_SOCKET_ANY_ADDRESS; } else { ansc_client_addr.sin_addr.s_addr = pMyObject->HostAddress.Value; } if ( _ansc_bind(pMyObject->Socket, (ansc_socket_addr*)&ansc_client_addr, sizeof(ansc_client_addr)) != 0 ) { AnscTrace("!!!!!!!!!! _ansc_bind error: socket=%d, error=%d !!!!!!!!!!\n", (XSKT_SOCKET)pMyObject->Socket, errno); { int j; char s[256]; char *ptr1 = ((ansc_socket_addr*)(&ansc_client_addr))->sa_data; char stmp[16]; s[0] = '\0'; for(j=0; j<13; j++) { sprintf(stmp, "%.2x:", *(ptr1++)); strcat(s, stmp); } sprintf(stmp, "%.2x", *ptr1); strcat(s, stmp); AnscTrace("!!!!!!!!!! _ansc_bind error: client_addr=%s\n", s); } perror("_ansc_bind error"); if ( pMyObject->Mode & ANSC_SCTO_MODE_NO_BSP_NOTIFY_CONN_ERR == 0 ) { pWorker->Notify ( pWorker->hWorkerContext, ANSC_SCTOWO_EVENT_SOCKET_ERROR, (ANSC_HANDLE)NULL ); } returnStatus = ANSC_STATUS_FAILURE; goto EXIT2; } } #endif /* * As a Tcp client application, we now try to connect the network server, whose address is * specified by the "peer address" and "peer port" fields. */ if ( pMyObject->Mode & ANSC_SCTO_MODE_XSOCKET ) { #ifdef _ANSC_IPV6_COMPATIBLE_ BOOL bNoConn = TRUE; #endif _ansc_memset(&xskt_server_addr, 0, sizeof(xskt_server_addr)); xskt_server_addr.sin_family = XSKT_SOCKET_AF_INET; xskt_server_addr.sin_addr.s_addr = pMyObject->PeerAddress.Value; xskt_server_addr.sin_port = _xskt_htons(pMyObject->PeerPort); #ifdef _ANSC_IPV6_COMPATIBLE_ while ( bNoConn && pxskt_server_addrinfo ) { if ( _xskt_connect((XSKT_SOCKET)pMyObject->Socket, pxskt_server_addrinfo->ai_addr, pxskt_server_addrinfo->ai_addrlen) != 0 ) { pxskt_server_addrinfo = pxskt_server_addrinfo->ai_next; /* try next ip address */ } else { bNoConn = FALSE; break; } } if ( bNoConn ) #else if ( _xskt_connect((XSKT_SOCKET)pMyObject->Socket, (xskt_socket_addr*)&xskt_server_addr, sizeof(xskt_server_addr)) != 0 ) #endif { AnscTrace("!!!!!!!!!! _xskt_connect error: socket=%d, error=%d !!!!!!!!!!\n", (XSKT_SOCKET)pMyObject->Socket, errno); { int j; char s[256]; char *ptr1 = ((xskt_socket_addr*)(&xskt_server_addr))->sa_data; char stmp[16]; s[0] = '\0'; for(j=0; j<13; j++) { sprintf(stmp, "%.2x:", *(ptr1++)); strcat(s, stmp); } sprintf(stmp, "%.2x", *ptr1); strcat(s, stmp); AnscTrace("!!!!!!!!!! _xskt_connect error: server_addr=%s\n", s); } perror("_xskt_connect error"); s_error = _xskt_get_last_error(); if ( pMyObject->Mode & ANSC_SCTO_MODE_NO_BSP_NOTIFY_CONN_ERR == 0 ) { pWorker->Notify ( pWorker->hWorkerContext, ANSC_SCTOWO_EVENT_SOCKET_TIMEOUT, (ANSC_HANDLE)NULL ); } returnStatus = ANSC_STATUS_FAILURE; goto EXIT2; } } else { _ansc_memset(&ansc_server_addr, 0, sizeof(ansc_server_addr)); ansc_server_addr.sin_family = ANSC_SOCKET_AF_INET; ansc_server_addr.sin_addr.s_addr = pMyObject->PeerAddress.Value; ansc_server_addr.sin_port = _ansc_htons(pMyObject->PeerPort); #ifdef _ANSC_IPV6_COMPATIBLE_ if ( _ansc_connect(pMyObject->Socket, pansc_server_addrinfo->ai_addr, pansc_server_addrinfo->ai_addrlen) != 0 ) #else if ( _ansc_connect(pMyObject->Socket, (ansc_socket_addr*)&ansc_server_addr, sizeof(ansc_server_addr)) != 0 ) #endif { s_error = _ansc_get_last_error(); AnscTrace("!!! Connect error: %d, %s !!!\n", s_error, strerror(s_error)); if ( pMyObject->Mode & ANSC_SCTO_MODE_NO_BSP_NOTIFY_CONN_ERR == 0 ) { pWorker->Notify ( pWorker->hWorkerContext, ANSC_SCTOWO_EVENT_SOCKET_TIMEOUT, (ANSC_HANDLE)NULL ); } returnStatus = ANSC_STATUS_FAILURE; goto EXIT2; } } /* * We have gone so far that all socket operations succeeded, we want to allocate a buffer that * is big enough for any incoming message. */ if ( !pMyObject->RecvBuffer && !(pMyObject->Mode & ANSC_SCTO_MODE_FOREIGN_BUFFER) ) { pMyObject->RecvBuffer = AnscAllocateMemory(pMyObject->RecvBufferSize); pMyObject->RecvPacketSize = 0; pMyObject->RecvOffset = 0; if ( !pMyObject->RecvBuffer ) { returnStatus = ANSC_STATUS_RESOURCES; goto EXIT2; } } pMyObject->RecvBytesCount = 0; pMyObject->SendBytesCount = 0; pMyObject->LastRecvAt = AnscGetTickInSeconds(); pMyObject->LastSendAt = AnscGetTickInSeconds(); /* * If the compilation option '_ANSC_SOCKET_TLS_LAYER_' is enabled, we can simply let the ANSC * socket layer to perform the SSL/TLS functionality; otherwise, we need to prepare for doing * SSL/TLS internally. */ if ( pMyObject->Mode & ANSC_SCTO_MODE_TLS_ENABLED ) { #ifdef _ANSC_USE_OPENSSL_ pMyObject->bTlsEnabled = TRUE; if ( !openssl_init(SSL_CLIENT_CALLS) ) { AnscTrace("AnscSctoEngage - openssl_init() failed!\n"); returnStatus = ANSC_STATUS_FAILURE; goto EXIT2; } #else #ifdef _ANSC_SOCKET_TLS_LAYER_ { _ansc_en_usetls(pMyObject->Socket); pMyObject->bTlsEnabled = FALSE; } #else { pMyObject->hTlsScsIf = (pMyObject->hTlsScsIf != NULL)? pMyObject->hTlsScsIf : AnscSocketTlsGetScsIf(); pMyObject->bTlsEnabled = TRUE; } #endif #endif } /* * To save the worker object from having to deal with blocking/non-blocking/async receiving * functions provided by underlying socket layer, we create a separate task to do that. */ returnStatus = pMyObject->SpawnTask3 ( (ANSC_HANDLE)pMyObject, (void* )pMyObject->RecvTask, (ANSC_HANDLE)pMyObject, ANSC_SCTO_RECV_TASK_NAME, USER_DEFAULT_TASK_PRIORITY, 11*USER_DEFAULT_TASK_STACK_SIZE ); #ifdef _ANSC_USE_OPENSSL_ if ( pMyObject->bTlsEnabled ) { SSL *ssl = NULL; ssl = openssl_connect (pMyObject->Socket); if ( !ssl ) { pMyObject->bTlsConnected = FALSE; returnStatus = ANSC_STATUS_FAILURE; //PANSC_SCTO_WORKER_OBJECT pWorker = (PANSC_SCTO_WORKER_OBJECT)pMyObject->hWorker; if ( pMyObject->Mode & ANSC_SCTO_MODE_NO_BSP_NOTIFY_CONN_ERR == 0 ) { pWorker->Notify ( pWorker->hWorkerContext, ANSC_SCTOWO_EVENT_TLS_ERROR, (ANSC_HANDLE)0L ); } } else { s_error = openssl_validate_certificate (pMyObject->Socket, pMyObject->HostName, ssl, SSL_CLIENT_CALLS); if ( s_error == 0 ) { AnscTrace("AnscSctoEngage - openssl_validate_certificate() failed %p.\n", ssl); //PANSC_SCTO_WORKER_OBJECT pWorker = (PANSC_SCTO_WORKER_OBJECT )pMyObject->hWorker; if ( pMyObject->Mode & ANSC_SCTO_MODE_NO_BSP_NOTIFY_CONN_ERR == 0 ) { pWorker->Notify ( pWorker->hWorkerContext, ANSC_SCTOWO_EVENT_TLS_ERROR, (ANSC_HANDLE)NULL ); } returnStatus = ANSC_STATUS_FAILURE; } pMyObject->hTlsConnection = ssl; pMyObject->bTlsConnected = TRUE; } } #else /* * If SSL/TLS is enabled, we should complete TLS handshake before returning from Engage(). This * behavior allows a single consistent API to used between this object and the worker object. * Since the handshake will take multiple messages to complete, we need to block the current * task until being notified by the TLS module. */ if ( pMyObject->bTlsEnabled && pMyObject->hTlsScsIf ) { pMyObject->bTlsConnected = FALSE; pMyObject->InitTlsClient((ANSC_HANDLE)pMyObject); } #endif if ( returnStatus != ANSC_STATUS_SUCCESS ) { goto EXIT2; } return ANSC_STATUS_SUCCESS; /****************************************************************** GRACEFUL ROLLBACK PROCEDURES AND EXIT DOORS ******************************************************************/ EXIT2: AnscTrace("AnscSctoEngage - failed with status %lu, socket error %d!\n", returnStatus, s_error); if ( pMyObject->Mode & ANSC_SCTO_MODE_XSOCKET ) { _xskt_closesocket((XSKT_SOCKET)pMyObject->Socket); } else { _ansc_closesocket(pMyObject->Socket); } EXIT1: if ( returnStatus != ANSC_STATUS_SUCCESS ) { pMyObject->bActive = FALSE; pMyObject->Reset((ANSC_HANDLE)pMyObject); } return returnStatus; }
ANSC_STATUS AnscBetoSendTask ( ANSC_HANDLE hThisObject ) { ANSC_STATUS returnStatus = ANSC_STATUS_SUCCESS; PANSC_BROKER_ENGINE_TCP_OBJECT pMyObject = (PANSC_BROKER_ENGINE_TCP_OBJECT)hThisObject; ansc_fd_set* pSendSet1 = (ansc_fd_set* )pMyObject->SendSocketSet; xskt_fd_set* pSendSet2 = (xskt_fd_set* )pMyObject->SendSocketSet; PANSC_BROKER_SERVER_TCP_OBJECT pServer = (PANSC_BROKER_SERVER_TCP_OBJECT)pMyObject->hBrokerServer; PANSC_BSTO_WORKER_OBJECT pWorker = (PANSC_BSTO_WORKER_OBJECT )pServer->hWorker; PANSC_BETO_PACKET_OBJECT pPacket = NULL; PANSC_BROKER_SOCKET_TCP_OBJECT pSocket = NULL; PSINGLE_LINK_ENTRY pSLinkEntry = NULL; BOOL bSendable = FALSE; int s_result = 0; int s_error = 0; AnscTrace("AnscBetoSendTask is activated ...!\n"); /* * As a scalable server implemention, we shall accept as many incoming client connections as * possible and can only be limited by the system resources. Once the listening socket becomes * readable, which means an incoming connection attempt has arrived. We create a new socket * object and associate it with the client. This is a repeated process until the socket owner * closes the socket. */ while ( pMyObject->bStarted ) { AnscAcquireLock(&pMyObject->PacketQueueLock); pSLinkEntry = AnscQueuePopEntry(&pMyObject->PacketQueue); AnscReleaseLock(&pMyObject->PacketQueueLock); if ( !pSLinkEntry ) { continue; } else { pPacket = ACCESS_ANSC_BETO_PACKET_OBJECT(pSLinkEntry); pSocket = (PANSC_BROKER_SOCKET_TCP_OBJECT)pPacket->hSocket; } #if !defined(_ANSC_KERNEL) || !defined(_ANSC_LINUX) AnscAcquireLock(&pMyObject->SendSocketSetLock); bSendable = (pServer->Mode & ANSC_BSTO_MODE_XSOCKET)? XSKT_SOCKET_FD_ISSET(pSocket->Socket, pSendSet2) : ANSC_SOCKET_FD_ISSET(pSocket->Socket, pSendSet1); AnscReleaseLock(&pMyObject->SendSocketSetLock); if ( !bSendable ) { returnStatus = pWorker->SendComplete ( pWorker->hWorkerContext, (ANSC_HANDLE)pSocket, pPacket->hWorkerReserved, ANSC_STATUS_FAILURE ); AnscFreeMemory(pPacket); continue; } #endif if ( pServer->Mode & ANSC_BSTO_MODE_XSOCKET ) { s_result = _xskt_send(((XSKT_SOCKET)pSocket->Socket), pPacket->PacketBuffer, (int)pPacket->PacketSize, 0); } else { s_result = _ansc_send(pSocket->Socket, pPacket->PacketBuffer, (int)pPacket->PacketSize, 0); } if ( ((s_result == XSKT_SOCKET_ERROR) && (pServer->Mode & ANSC_BSTO_MODE_XSOCKET)) || ((s_result == ANSC_SOCKET_ERROR) && !(pServer->Mode & ANSC_BSTO_MODE_XSOCKET)) ) { s_error = (pServer->Mode & ANSC_BSTO_MODE_XSOCKET)? _xskt_get_last_error() : _ansc_get_last_error(); returnStatus = pWorker->SendComplete ( pWorker->hWorkerContext, (ANSC_HANDLE)pSocket, pPacket->hWorkerReserved, ANSC_STATUS_FAILURE ); if ( pServer->Mode & ANSC_BSTO_MODE_AUTO_CLOSE ) { pMyObject->DelSocket((ANSC_HANDLE)pMyObject, (ANSC_HANDLE)pSocket); } } else { returnStatus = pWorker->SendComplete ( pWorker->hWorkerContext, (ANSC_HANDLE)pSocket, pPacket->hWorkerReserved, ANSC_STATUS_SUCCESS ); pSocket->SendBytesCount += pPacket->PacketSize; pSocket->LastSendAt = AnscGetTickInSeconds(); } } AnscSetEvent(&pMyObject->SendEvent); return ANSC_STATUS_SUCCESS; }
ANSC_STATUS AnscDetoRecvTask ( ANSC_HANDLE hThisObject ) { ANSC_STATUS returnStatus = ANSC_STATUS_SUCCESS; PANSC_DAEMON_ENGINE_TCP_OBJECT pMyObject = (PANSC_DAEMON_ENGINE_TCP_OBJECT)hThisObject; PANSC_DAEMON_SERVER_TCP_OBJECT pServer = (PANSC_DAEMON_SERVER_TCP_OBJECT)pMyObject->hDaemonServer; PANSC_DSTO_WORKER_OBJECT pWorker = (PANSC_DSTO_WORKER_OBJECT )pServer->hWorker; #if !defined(_ANSC_KERNEL) || !defined(_ANSC_LINUX) ansc_fd_set* pRecvSet1 = (ansc_fd_set* )pMyObject->RecvSocketSet; xskt_fd_set* pRecvSet2 = (xskt_fd_set* )pMyObject->RecvSocketSet; #endif PANSC_DAEMON_SOCKET_TCP_OBJECT pSocket = NULL; ULONG ulLastCleanAt = AnscGetTickInSecondsAbs(); ANSC_SOCKET s_socket = ANSC_SOCKET_INVALID_SOCKET; int s_result = 0; int s_result_excp = 0; int s_error = 0; int i = 0; #if !defined(_ANSC_KERNEL) || !defined(_ANSC_LINUX) ansc_fd_set* read_fd_set1 = NULL; xskt_fd_set* read_fd_set2 = NULL; ansc_fd_set* excp_fd_set1 = NULL; xskt_fd_set* excp_fd_set2 = NULL; ansc_timeval timeval1; xskt_timeval timeval2; #endif AnscTrace("AnscDetoRecvTask is activated ...!\n"); #if !defined(_ANSC_KERNEL) || !defined(_ANSC_LINUX) read_fd_set1 = (ansc_fd_set*)AnscAllocateMemory(sizeof(ansc_fd_set)); read_fd_set2 = (xskt_fd_set*)AnscAllocateMemory(sizeof(xskt_fd_set)); excp_fd_set1 = (ansc_fd_set*)AnscAllocateMemory(sizeof(ansc_fd_set)); excp_fd_set2 = (xskt_fd_set*)AnscAllocateMemory(sizeof(xskt_fd_set)); if ( !read_fd_set1 || !read_fd_set2 || !excp_fd_set1 || !excp_fd_set2 ) { goto EXIT1; } #endif /* * As a scalable server implemention, we shall accept as many incoming client connections as * possible and can only be limited by the system resources. Once the listening socket becomes * readable, which means an incoming connection attempt has arrived. We create a new socket * object and associate it with the client. This is a repeated process until the socket owner * closes the socket. */ while ( pMyObject->bStarted ) { ANSC_COMMIT_TASK(); /* * To avoid letting the old half-dead sockets hogging up the system resource, we need to * periodically invoke the cleaning routine. The default interval is 10 seconds, and the * idle timeout value is 90 seconds. */ #if !defined(_ANSC_KERNEL) || !defined(_ANSC_LINUX) if ( pMyObject->bCleaningDemanded ) #else if ( FALSE ) /*if ( pMyObject->bCleaningDemanded )*/ #endif { pMyObject->Clean((ANSC_HANDLE)pMyObject); ulLastCleanAt = AnscGetTickInSecondsAbs(); pMyObject->bCleaningDemanded = FALSE; } else if ( (AnscGetTickInSecondsAbs() - ulLastCleanAt) >= ANSC_DETO_CLEAN_TASK_INTERVAL ) { pMyObject->Clean((ANSC_HANDLE)pMyObject); ulLastCleanAt = AnscGetTickInSecondsAbs(); pMyObject->bCleaningDemanded = FALSE; } /* * Since the original bsd compatible socket api doesn't support asynchronous operation, the * nonblocking status polling is the best we can get. As a matter of fact, the current unix * and linux actually still don't support asynchronous notification on any socket operation. */ #if defined(_ANSC_KERNEL) && defined(_ANSC_LINUX) if ( !pMyObject->CurSocketCount) { if ( pServer->Mode & ANSC_DSTO_MODE_EVENT_SYNC ) { AnscWaitEvent (&pMyObject->NewSocketEvent, ANSC_DETO_WAIT_EVENT_INTERVAL); AnscResetEvent(&pMyObject->NewSocketEvent); if (!pMyObject->CurSocketCount) { AnscTaskRelinquish(); continue; } } else { AnscSleep(ANSC_DETO_TASK_BREAK_INTERVAL); continue; } } #else if ( pServer->Mode & ANSC_DSTO_MODE_XSOCKET ) { AnscAcquireLock(&pMyObject->RecvSocketSetLock); *read_fd_set2 = *pRecvSet2; AnscReleaseLock(&pMyObject->RecvSocketSetLock); } else { AnscAcquireLock(&pMyObject->RecvSocketSetLock); *read_fd_set1 = *pRecvSet1; AnscReleaseLock(&pMyObject->RecvSocketSetLock); } if ( ( (pServer->Mode & ANSC_DSTO_MODE_XSOCKET) && XSKT_SOCKET_FD_ISNUL(read_fd_set2)) || (!(pServer->Mode & ANSC_DSTO_MODE_XSOCKET) && ANSC_SOCKET_FD_ISNUL(read_fd_set1)) ) { if ( pServer->Mode & ANSC_DSTO_MODE_EVENT_SYNC ) { AnscWaitEvent (&pMyObject->NewSocketEvent, ANSC_DETO_WAIT_EVENT_INTERVAL); AnscResetEvent(&pMyObject->NewSocketEvent); if ( pServer->Mode & ANSC_DSTO_MODE_XSOCKET ) { AnscAcquireLock(&pMyObject->RecvSocketSetLock); *read_fd_set2 = *pRecvSet2; AnscReleaseLock(&pMyObject->RecvSocketSetLock); } else { AnscAcquireLock(&pMyObject->RecvSocketSetLock); *read_fd_set1 = *pRecvSet1; AnscReleaseLock(&pMyObject->RecvSocketSetLock); } if ( ( (pServer->Mode & ANSC_DSTO_MODE_XSOCKET) && XSKT_SOCKET_FD_ISNUL(read_fd_set2)) || (!(pServer->Mode & ANSC_DSTO_MODE_XSOCKET) && ANSC_SOCKET_FD_ISNUL(read_fd_set1)) ) { AnscTaskRelinquish(); continue; } } else { AnscSleep(ANSC_DETO_TASK_BREAK_INTERVAL); continue; } } if ( pServer->Mode & ANSC_DSTO_MODE_XSOCKET ) { timeval2.tv_sec = (ANSC_DETO_POLL_INTERVAL_MS / 1000); /* number of seconds */ timeval2.tv_usec = (ANSC_DETO_POLL_INTERVAL_MS % 1000) * 1000; /* number of microseconds */ } else { timeval1.tv_sec = (ANSC_DETO_POLL_INTERVAL_MS / 1000); /* number of seconds */ timeval1.tv_usec = (ANSC_DETO_POLL_INTERVAL_MS % 1000) * 1000; /* number of microseconds */ } /* * The _ansc_select() function returns the total number of socket handles that are ready * and contained in the fd_set structures, zero if the time limit expired, or SOCKET_ERROR * if an error occurred. Upon return, the structures are updated to reflect the subset of * these sockets that meet the specified condition. */ if ( pServer->Mode & ANSC_DSTO_MODE_XSOCKET ) { s_result = _xskt_select(XSKT_SOCKET_FD_SETSIZE, read_fd_set2, NULL, NULL, &timeval2); } else { s_result = _ansc_select(ANSC_SOCKET_FD_SETSIZE, read_fd_set1, NULL, NULL, &timeval1); } if ( s_result == 0 ) { continue; } else if ( ( (pServer->Mode & ANSC_DSTO_MODE_XSOCKET) && (s_result == XSKT_SOCKET_ERROR)) || (!(pServer->Mode & ANSC_DSTO_MODE_XSOCKET) && (s_result == ANSC_SOCKET_ERROR)) ) { s_error = (pServer->Mode & ANSC_DSTO_MODE_XSOCKET)? _xskt_get_last_error() : _ansc_get_last_error(); /* * Previously we simply reset everything when _ansc_select() fails, which is not a good * solution: we shall notify the worker module and gracefully shutdown the socket(s) * that caused the error. */ /* pMyObject->Reset((ANSC_HANDLE)pMyObject); */ pMyObject->ExpAllSockets((ANSC_HANDLE)pMyObject); continue; } else if ( !pMyObject->bStarted ) { break; } #endif /* * If there're multiple sockets are receiving data, we loop through the returned fd_set * structure and process them one-by-one. However, we have a slight problem: the resulted * fd_set consists of only the native socket handles, not the associated Socket Objects. * We have to first retrieve the peer's IP address from the socket, and use it to find * the associated socket object. */ #if defined(_ANSC_KERNEL) && defined(_ANSC_LINUX) if (TRUE) { int i; PSINGLE_LINK_ENTRY pSLinkEntry; for ( i = 0; i < ANSC_DETO_SOCKET_TABLE_SIZE ; i++) { if (!AnscSListQueryDepth(&pMyObject->SocketTable[i])) { continue; } AnscAcquireLock(&pMyObject->SocketTableLock); pSLinkEntry = AnscSListGetFirstEntry(&pMyObject->SocketTable[i]); AnscReleaseLock(&pMyObject->SocketTableLock); while ( pSLinkEntry ) { pSocket = ACCESS_ANSC_DAEMON_SOCKET_TCP_OBJECT(pSLinkEntry); pSLinkEntry = AnscSListGetNextEntry(pSLinkEntry); if ( pSocket->bTlsEnabled ) { pMyObject->bBusy = TRUE; returnStatus = pMyObject->Recv2 ( (ANSC_HANDLE)pMyObject, (ANSC_HANDLE)pSocket ); pMyObject->bBusy = FALSE; } else { pMyObject->bBusy = TRUE; returnStatus = pMyObject->Recv ( (ANSC_HANDLE)pMyObject, (ANSC_HANDLE)pSocket ); pMyObject->bBusy = FALSE; } } if ( !pMyObject->bStarted ) { break; } } AnscSleep(10); } #else for ( i = 0; i < s_result; i++ ) { if ( pServer->Mode & ANSC_DSTO_MODE_XSOCKET ) { XSKT_SOCKET_FD_GET(read_fd_set2, s_socket, (ULONG)i); } else { ANSC_SOCKET_FD_GET(read_fd_set1, s_socket, (ULONG)i); } if ( ( (pServer->Mode & ANSC_DSTO_MODE_XSOCKET) && (s_socket == XSKT_SOCKET_INVALID_SOCKET)) || (!(pServer->Mode & ANSC_DSTO_MODE_XSOCKET) && (s_socket == ANSC_SOCKET_INVALID_SOCKET)) ) { break; } else { pSocket = (PANSC_DAEMON_SOCKET_TCP_OBJECT)pMyObject->GetSocketByOsocket ( (ANSC_HANDLE)pMyObject, s_socket ); /* * We should make sure this socket is still valid before proceeding with the socket * receive operations. For example, the peer may have already closed or reset the * TCP connection while we're serving the previous socket request. * * 10/06/04 - It's believed this modification is slowing down the GUI and we're not * seeing tangible evidence that GUI responsivenss has been improved. So we disable * it for now. */ /* if ( pServer->Mode & ANSC_DSTO_MODE_XSOCKET ) { XSKT_SOCKET_FD_ZERO(excp_fd_set2); XSKT_SOCKET_FD_SET ((XSKT_SOCKET)s_socket, excp_fd_set2); timeval2.tv_sec = 0; timeval2.tv_usec = 0; s_result_excp = _xskt_select(XSKT_SOCKET_FD_SETSIZE, NULL, NULL, excp_fd_set2, &timeval2); } else { ANSC_SOCKET_FD_ZERO(excp_fd_set1); ANSC_SOCKET_FD_SET (s_socket, excp_fd_set1); timeval1.tv_sec = 0; timeval1.tv_usec = 0; s_result_excp = _ansc_select(ANSC_SOCKET_FD_SETSIZE, NULL, NULL, excp_fd_set1, &timeval1); } */ } /* if ( ((s_result_excp == 1 ) ) || ((s_result_excp == XSKT_SOCKET_ERROR) && (pServer->Mode & ANSC_DSTO_MODE_XSOCKET)) || ((s_result_excp == ANSC_SOCKET_ERROR) && !(pServer->Mode & ANSC_DSTO_MODE_XSOCKET)) ) { if ( TRUE ) { pSocket->bBroken = TRUE; pMyObject->EnableRecv((ANSC_HANDLE)pMyObject, (ANSC_HANDLE)pSocket, FALSE); pMyObject->EnableSend((ANSC_HANDLE)pMyObject, (ANSC_HANDLE)pSocket, FALSE); } if ( pSocket->bTlsEnabled ) { if ( pSocket->bTlsEnabled && pSocket->bTlsConnected && !pSocket->bTlsInitializing ) { returnStatus = pWorker->Notify ( pWorker->hWorkerContext, (ANSC_HANDLE)pSocket, ANSC_DSTOWO_EVENT_SOCKET_ERROR, (ANSC_HANDLE)NULL ); } else { AnscSetEvent(&pSocket->TlsConnEvent); } } else { returnStatus = pWorker->Notify ( pWorker->hWorkerContext, (ANSC_HANDLE)pSocket, ANSC_DSTOWO_EVENT_SOCKET_ERROR, (ANSC_HANDLE)NULL ); } if ( pServer->Mode & ANSC_DSTO_MODE_AUTO_CLOSE ) { pMyObject->DelSocket((ANSC_HANDLE)pMyObject, (ANSC_HANDLE)pSocket); } pMyObject->TrcCount++; continue; } else { pSocket = (PANSC_DAEMON_SOCKET_TCP_OBJECT)pMyObject->GetSocketByOsocket ( (ANSC_HANDLE)pMyObject, s_socket ); } */ if ( !pSocket ) { continue; } else if ( pSocket->bTlsEnabled ) { #ifdef _ANSC_USE_OPENSSL_ pMyObject->bBusy = TRUE; returnStatus = pMyObject->Recv ( (ANSC_HANDLE)pMyObject, (ANSC_HANDLE)pSocket ); pMyObject->bBusy = FALSE; #else pMyObject->bBusy = TRUE; returnStatus = pMyObject->Recv2 ( (ANSC_HANDLE)pMyObject, (ANSC_HANDLE)pSocket ); pMyObject->bBusy = FALSE; #endif } else { pMyObject->bBusy = TRUE; returnStatus = pMyObject->Recv ( (ANSC_HANDLE)pMyObject, (ANSC_HANDLE)pSocket ); pMyObject->bBusy = FALSE; } /* * Check whether 'bToBeCleaned' flag is set for this socket: if it is, we should close * this socket right away; otherwise, we continue the processing. WARNING!!! This new * change seems to incur instability in SLAP, we have to roll back to the initial * approach. */ /* if ( pSocket->bToBeCleaned ) { returnStatus = pMyObject->DelSocket ( (ANSC_HANDLE)pMyObject, (ANSC_HANDLE)pSocket ); } */ if ( !pMyObject->bStarted ) { break; } } #endif } /****************************************************************** GRACEFUL ROLLBACK PROCEDURES AND EXIT DOORS ******************************************************************/ EXIT1: AnscSetEvent(&pMyObject->RecvEvent); #if !defined(_ANSC_KERNEL) || !defined(_ANSC_LINUX) if ( read_fd_set1 ) { AnscFreeMemory(read_fd_set1); } if ( read_fd_set2 ) { AnscFreeMemory(read_fd_set2); } if ( excp_fd_set1 ) { AnscFreeMemory(excp_fd_set1); } if ( excp_fd_set2 ) { AnscFreeMemory(excp_fd_set2); } #endif return ANSC_STATUS_SUCCESS; }
ANSC_STATUS AnscDstoEngage ( ANSC_HANDLE hThisObject ) { ANSC_STATUS returnStatus = ANSC_STATUS_SUCCESS; PANSC_DAEMON_SERVER_TCP_OBJECT pMyObject = (PANSC_DAEMON_SERVER_TCP_OBJECT)hThisObject; PANSC_DSTO_WORKER_OBJECT pWorker = (PANSC_DSTO_WORKER_OBJECT )pMyObject->hWorker; int s_result = 0; #ifdef _ANSC_IPV6_COMPATIBLE_ ansc_addrinfo ansc_hints = {0}; ansc_addrinfo* pansc_local_addrinfo = NULL; xskt_addrinfo xskt_hints = {0}; xskt_addrinfo* pxskt_local_addrinfo = NULL; USHORT usPort = 0; char port[6] = {0}; #else /*RDKB-6151, CID-24487,24794; initializing variable before use*/ ansc_socket_addr_in local_addr1 = {0}; xskt_socket_addr_in local_addr2 = {0}; #endif if ( pMyObject->bActive ) { return ANSC_STATUS_SUCCESS; } else if ( !pWorker ) { return ANSC_STATUS_UNAPPLICABLE; } else { pWorker->Init(pWorker->hWorkerContext); pMyObject->StartTime = AnscGetTickInSecondsAbs(); pMyObject->bActive = TRUE; } /* * The underlying socket wrapper may require an explicit startup() call, such is the case on * Microsoft windows platforms. The wrapper initialization has to done for each task. On most * real-time operating systems, this call is not required. */ if ( pMyObject->Mode & ANSC_DSTO_MODE_XSOCKET ) { AnscStartupXsocketWrapper((ANSC_HANDLE)pMyObject); } else { AnscStartupSocketWrapper((ANSC_HANDLE)pMyObject); } #ifdef _ANSC_IPV6_COMPATIBLE_ if ( pMyObject->Mode & ANSC_DSTO_MODE_XSOCKET ) { xskt_hints.ai_family = AF_UNSPEC; xskt_hints.ai_socktype = XSKT_SOCKET_STREAM; xskt_hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; usPort = pMyObject->GetHostPort((ANSC_HANDLE)pMyObject); _ansc_sprintf(port, "%d", usPort); CcspTraceInfo(("!!! Host Name: %s, Host Port: %s !!!\n", pMyObject->HostName, port)); if ( _xskt_getaddrinfo ( pMyObject->HostName[0] ? pMyObject->HostName : "::", port, &xskt_hints, &pxskt_local_addrinfo ) ) { CcspTraceError(("!!! error 1 !!!\n")); returnStatus = ANSC_STATUS_FAILURE; goto EXIT1; } pMyObject->pHostAddr2 = pxskt_local_addrinfo; } else { ansc_hints.ai_family = AF_UNSPEC; ansc_hints.ai_socktype = ANSC_SOCKET_STREAM; ansc_hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; usPort = pMyObject->GetHostPort((ANSC_HANDLE)pMyObject); _ansc_sprintf(port, "%d", usPort); CcspTraceInfo(("!!! Host Name: %s, Host Port: %s !!!\n", pMyObject->HostName, port)); if ( _ansc_getaddrinfo ( pMyObject->HostName[0] ? pMyObject->HostName : "::", port, &ansc_hints, &pansc_local_addrinfo ) ) { returnStatus = ANSC_STATUS_FAILURE; goto EXIT1; } pMyObject->pHostAddr1 = pansc_local_addrinfo; } #endif /* * To engage the Tcp Daemon, we need to perform following acts in the respective order: * * (1) create the os-dependent socket * (2) manufacture and start all the engines objects * (3) manufacture the global socket object pool * (4) bind to the socket and listen on it */ if ( pMyObject->Mode & ANSC_DSTO_MODE_XSOCKET ) { #ifdef _ANSC_IPV6_COMPATIBLE_ pMyObject->Socket = _xskt_socket(pxskt_local_addrinfo->ai_family, pxskt_local_addrinfo->ai_socktype, 0); #else pMyObject->Socket = _xskt_socket(XSKT_SOCKET_AF_INET, XSKT_SOCKET_STREAM, 0); #endif } else { #ifdef _ANSC_IPV6_COMPATIBLE_ pMyObject->Socket = _ansc_socket(pansc_local_addrinfo->ai_family, pansc_local_addrinfo->ai_socktype, 0); #else pMyObject->Socket = _ansc_socket(ANSC_SOCKET_AF_INET, ANSC_SOCKET_STREAM, 0); #endif } if ( ((pMyObject->Socket == XSKT_SOCKET_INVALID_SOCKET) && (pMyObject->Mode & ANSC_DSTO_MODE_XSOCKET)) || ((pMyObject->Socket == ANSC_SOCKET_INVALID_SOCKET) && !(pMyObject->Mode & ANSC_DSTO_MODE_XSOCKET)) ) { returnStatus = ANSC_STATUS_FAILURE; goto EXIT1; } _ansc_en_reuseaddr(pMyObject->Socket); #ifndef _ANSC_IPV6_COMPATIBLE_ if ( pMyObject->Mode & ANSC_DSTO_MODE_XSOCKET ) { local_addr2.sin_family = XSKT_SOCKET_AF_INET; local_addr2.sin_port = _xskt_htons(pMyObject->HostPort); if ( pMyObject->HostAddress.Value == 0 ) { ((pansc_socket_addr_in)&local_addr2)->sin_addr.s_addr = XSKT_SOCKET_ANY_ADDRESS; } else { ((pansc_socket_addr_in)&local_addr2)->sin_addr.s_addr = pMyObject->HostAddress.Value; } } else { local_addr1.sin_family = ANSC_SOCKET_AF_INET; local_addr1.sin_port = _ansc_htons(pMyObject->HostPort); if ( pMyObject->HostAddress.Value == 0 ) { local_addr1.sin_addr.s_addr = ANSC_SOCKET_ANY_ADDRESS; } else { local_addr1.sin_addr.s_addr = pMyObject->HostAddress.Value; } } #endif #if !defined(_ANSC_KERNEL) || !defined(_ANSC_LINUX) if ( pMyObject->Mode & ANSC_DSTO_MODE_XSOCKET ) { #ifdef _ANSC_IPV6_COMPATIBLE_ s_result = _xskt_bind(pMyObject->Socket, pxskt_local_addrinfo->ai_addr, pxskt_local_addrinfo->ai_addrlen); #else AnscTrace("AnscDstoEngage -- the address is 0x%lX:%d, familty %d.\n", _ansc_ntohl(local_addr2.sin_addr.s_addr), _ansc_ntohs(local_addr2.sin_port), local_addr2.sin_family); s_result = _xskt_bind(pMyObject->Socket, (xskt_socket_addr*)&local_addr2, sizeof(local_addr2)); #endif } else { #ifdef _ANSC_IPV6_COMPATIBLE_ s_result = _ansc_bind(pMyObject->Socket, pansc_local_addrinfo->ai_addr, pansc_local_addrinfo->ai_addrlen); #else s_result = _ansc_bind(pMyObject->Socket, (ansc_socket_addr*)&local_addr1, sizeof(local_addr1)); #endif } #else if ( pMyObject->Mode & ANSC_DSTO_MODE_XSOCKET ) { while ( _xskt_bind(pMyObject->Socket, (ansc_socket_addr*)&local_addr2, sizeof(local_addr2)) != 0 ) { AnscTrace ( "AnscDstoEngage -- failure to bind try again !socket %d family %d port %d address %X \n", pMyObject->Socket, local_addr2.sin_family, local_addr2.sin_port, ((pansc_socket_addr_in)&local_addr2)->sin_addr.s_addr ); AnscSleep(10); } } else { while ( _ansc_bind(pMyObject->Socket, (ansc_socket_addr*)&local_addr1, sizeof(local_addr1)) != 0 ) { AnscTrace ( "AnscDstoEngage -- failure to bind try again !socket %d family %d port %d address %X \n", pMyObject->Socket, local_addr1.sin_family, local_addr1.sin_port, local_addr1.sin_addr.s_addr ); AnscSleep(10); } } #endif if ( s_result != 0 ) { AnscTrace ( "AnscDstoEngage -- failed to bind to the socket, error code is %d!!!\n", (pMyObject->Mode & ANSC_DSTO_MODE_XSOCKET) ? _xskt_get_last_error() : _ansc_get_last_error() ); returnStatus = ANSC_STATUS_FAILURE; goto EXIT2; } pMyObject->ManufactureEnginePool((ANSC_HANDLE)pMyObject); pMyObject->ManufactureSocketPool((ANSC_HANDLE)pMyObject); pMyObject->StartEngines ((ANSC_HANDLE)pMyObject); if ( pMyObject->Mode & ANSC_DSTO_MODE_XSOCKET ) { s_result = _xskt_listen(pMyObject->Socket, ANSC_SOCKET_BACKLOG_VALUE); } else { s_result = _ansc_listen(pMyObject->Socket, ANSC_SOCKET_BACKLOG_VALUE); } if ( s_result != 0 ) { AnscTrace("AnscDstoEngage -- failed to listen on the socket!\n"); returnStatus = ANSC_STATUS_FAILURE; goto EXIT2; } /* * If the compilation option '_ANSC_SOCKET_TLS_LAYER_' is enabled, we can simply let the ANSC * socket layer to perform the SSL/TLS functionality; otherwise, we need to prepare for doing * SSL/TLS internally. */ if ( pMyObject->Mode & ANSC_DSTO_MODE_TLS_ENABLED ) { #ifdef _ANSC_USE_OPENSSL_ pMyObject->bTlsEnabled = TRUE; if ( !openssl_init(SSL_SERVER_CALLS) ) { AnscTrace("AnscSctoEngage - openssl_init() failed!\n"); returnStatus = ANSC_STATUS_FAILURE; goto EXIT2; } #else #ifdef _ANSC_SOCKET_TLS_LAYER_ { _ansc_en_usetls(pMyObject->Socket); pMyObject->bTlsEnabled = FALSE; } #else { pMyObject->hTlsScsIf = (pMyObject->hTlsScsIf != NULL)? pMyObject->hTlsScsIf : AnscSocketTlsGetScsIf(); pMyObject->bTlsEnabled = TRUE; pMyObject->bTlsReqCert = (pMyObject->Mode & ANSC_DSTO_MODE_TLS_REQ_CERT); } #endif #endif } AnscResetEvent(&pMyObject->AcceptEvent); returnStatus = pMyObject->SpawnTask3 ( (ANSC_HANDLE)pMyObject, (void* )pMyObject->AcceptTask, (ANSC_HANDLE)pMyObject, ANSC_DSTO_ACCEPT_TASK_NAME, USER_DEFAULT_TASK_PRIORITY, 2*USER_DEFAULT_TASK_STACK_SIZE ); return ANSC_STATUS_SUCCESS; /****************************************************************** GRACEFUL ROLLBACK PROCEDURES AND EXIT DOORS ******************************************************************/ EXIT2: if ( pMyObject->Mode & ANSC_DSTO_MODE_XSOCKET ) { _xskt_closesocket(pMyObject->Socket); } else { _ansc_closesocket(pMyObject->Socket); } EXIT1: if ( returnStatus != ANSC_STATUS_SUCCESS ) { pMyObject->bActive = FALSE; } return returnStatus; }
ANSC_STATUS AnscBetoRecvTask ( ANSC_HANDLE hThisObject ) { ANSC_STATUS returnStatus = ANSC_STATUS_SUCCESS; PANSC_BROKER_ENGINE_TCP_OBJECT pMyObject = (PANSC_BROKER_ENGINE_TCP_OBJECT)hThisObject; PANSC_BROKER_SERVER_TCP_OBJECT pServer = (PANSC_BROKER_SERVER_TCP_OBJECT)pMyObject->hBrokerServer; ansc_fd_set* pRecvSet1 = (ansc_fd_set* )pMyObject->RecvSocketSet; xskt_fd_set* pRecvSet2 = (xskt_fd_set* )pMyObject->RecvSocketSet; PANSC_BROKER_SOCKET_TCP_OBJECT pSocket = NULL; ULONG ulLastCleanAt = AnscGetTickInSeconds(); ANSC_SOCKET s_socket = ANSC_SOCKET_INVALID_SOCKET; int s_result = 0; int s_result_excp = 0; int s_error = 0; int i = 0; uni_fd_set read_fd_set; /*uni_fd_set excp_fd_set;*/ uni_timeval timeval; AnscTrace("AnscBetoRecvTask is activated ...!\n"); /* * As a scalable server implemention, we shall accept as many incoming client connections as * possible and can only be limited by the system resources. Once the listening socket becomes * readable, which means an incoming connection attempt has arrived. We create a new socket * object and associate it with the client. This is a repeated process until the socket owner * closes the socket. */ while ( pMyObject->bStarted ) { ANSC_COMMIT_TASK(); /* * To avoid letting the old half-dead sockets hogging up the system resource, we need to * periodically invoke the cleaning routine. The default interval is 10 seconds, and the * idle timeout value is 90 seconds. */ if ( pMyObject->bCleaningDemanded || (AnscGetTickInSeconds() - ulLastCleanAt) >= ANSC_BETO_CLEAN_TASK_INTERVAL ) { pMyObject->Clean((ANSC_HANDLE)pMyObject); ulLastCleanAt = AnscGetTickInSeconds(); pMyObject->bCleaningDemanded = FALSE; } /* * The _ansc_select() function returns the total number of socket handles that are ready * and contained in the fd_set structures, zero if the time limit expired, or SOCKET_ERROR * if an error occurred. Upon return, the structures are updated to reflect the subset of * these sockets that meet the specified condition. */ if ( pServer->Mode & ANSC_BSTO_MODE_XSOCKET ) { /* * no need to use lock for read_fd_set here, dirty read does not matter. */ read_fd_set.xset = *pRecvSet2; if( XSKT_SOCKET_FD_ISNUL(&read_fd_set.xset) ) { if ( pServer->Mode & ANSC_BSTO_MODE_EVENT_SYNC ) { AnscWaitEvent (&pMyObject->NewSocketEvent, ANSC_BETO_WAIT_EVENT_INTERVAL); AnscResetEvent(&pMyObject->NewSocketEvent); } else { AnscSleep(ANSC_BETO_TASK_BREAK_INTERVAL); } continue; } timeval.xtv.tv_sec = (ANSC_BETO_POLL_INTERVAL_MS / 1000); /* number of seconds */ timeval.xtv.tv_usec = (ANSC_BETO_POLL_INTERVAL_MS % 1000) * 1000; /* number of microseconds */ s_result = _xskt_select(XSKT_SOCKET_FD_SETSIZE, &read_fd_set.xset, NULL, NULL, &timeval.xtv); if ( s_result == 0 ) { continue; } if ( s_result == XSKT_SOCKET_ERROR ) { s_error = _xskt_get_last_error(); pMyObject->Reset((ANSC_HANDLE)pMyObject); continue; } } else { /* * no need to use lock for read_fd_set here, dirty read does not matter. */ read_fd_set.aset = *pRecvSet1; if( ANSC_SOCKET_FD_ISNUL(&read_fd_set.aset) ) { if ( pServer->Mode & ANSC_BSTO_MODE_EVENT_SYNC ) { AnscWaitEvent (&pMyObject->NewSocketEvent, ANSC_BETO_WAIT_EVENT_INTERVAL); AnscResetEvent(&pMyObject->NewSocketEvent); } else { AnscSleep(ANSC_BETO_TASK_BREAK_INTERVAL); } continue; } timeval.atv.tv_sec = (ANSC_BETO_POLL_INTERVAL_MS / 1000); /* number of seconds */ timeval.atv.tv_usec = (ANSC_BETO_POLL_INTERVAL_MS % 1000) * 1000; /* number of microseconds */ s_result = _ansc_select(ANSC_SOCKET_FD_SETSIZE, &read_fd_set.aset, NULL, NULL, &timeval.atv); if ( s_result == 0 ) { continue; } if ( s_result == ANSC_SOCKET_ERROR ) { s_error = _ansc_get_last_error(); pMyObject->Reset((ANSC_HANDLE)pMyObject); continue; } } /* * If there're multiple sockets are receiving data, we loop through the returned fd_set * structure and process them one-by-one. However, we have a slight problem: the resulted * fd_set consists of only the native socket handles, not the associated Socket Objects. * We have to first retrieve the peer's IP address from the socket, and use it to find * the associated socket object. */ for ( i = 0; i < s_result; i++ ) { if ( !pMyObject->bStarted ) { break; } if ( pServer->Mode & ANSC_BSTO_MODE_XSOCKET ) { XSKT_SOCKET_FD_GET(&read_fd_set.xset, s_socket, (ULONG)i); if( s_socket == XSKT_SOCKET_INVALID_SOCKET ) { break; } if( ! XSKT_SOCKET_FD_ISSET(s_socket, pRecvSet2) ) { AnscTraceError(("AnscBetoRecvTask: XSKT_SOCKET_FD_ISSET returned FALSE.\n")); continue; } } else { ANSC_SOCKET_FD_GET(&read_fd_set.aset, s_socket, (ULONG)i); if( s_socket == ANSC_SOCKET_INVALID_SOCKET ) { break; } if( ! ANSC_SOCKET_FD_ISSET(s_socket, pRecvSet1) ) { AnscTraceError(("AnscBetoRecvTask: XSKT_SOCKET_FD_ISSET returned FALSE.\n")); continue; } } pSocket = (PANSC_BROKER_SOCKET_TCP_OBJECT)pMyObject->GetSocketByOsocket ( (ANSC_HANDLE)pMyObject, s_socket ); if ( !pSocket ) { continue; } /* * We should make sure this socket is still valid before proceeding with the socket * receive operations. For example, the peer may have already closed or reset the * TCP connection while we're serving the previous socket request. * * 10/06/04 - It's believed this modification is slowing down the GUI and we're not * seeing tangible evidence that GUI responsivenss has been improved. So we disable * it for now. * * 11/20/09 - Re-activate the following code segment to validate the socket before * proceeding. */ /* if ( pServer->Mode & ANSC_BSTO_MODE_XSOCKET ) { XSKT_SOCKET_FD_ZERO((&excp_fd_set.xset)); XSKT_SOCKET_FD_SET ((XSKT_SOCKET)s_socket, (&excp_fd_set.xset)); timeval.xtv.tv_sec = 0; timeval.xtv.tv_usec = 0; s_result_excp = _xskt_select(XSKT_SOCKET_FD_SETSIZE, NULL, NULL, &excp_fd_set.xset, &timeval.xtv); } else { ANSC_SOCKET_FD_ZERO((&excp_fd_set.aset)); ANSC_SOCKET_FD_SET (s_socket, (&excp_fd_set.aset)); timeval.atv.tv_sec = 0; timeval.atv.tv_usec = 0; s_result_excp = _ansc_select(ANSC_SOCKET_FD_SETSIZE, NULL, NULL, &excp_fd_set.aset, &timeval.atv); } if ( ((s_result_excp == 1 ) ) || ((s_result_excp == XSKT_SOCKET_ERROR) && (pServer->Mode & ANSC_BSTO_MODE_XSOCKET)) || ((s_result_excp == ANSC_SOCKET_ERROR) && !(pServer->Mode & ANSC_BSTO_MODE_XSOCKET)) ) { if ( TRUE ) { pSocket->bBroken = TRUE; pSocket->bToBeCleaned = TRUE; pMyObject->EnableRecv((ANSC_HANDLE)pMyObject, (ANSC_HANDLE)pSocket, FALSE); pMyObject->EnableSend((ANSC_HANDLE)pMyObject, (ANSC_HANDLE)pSocket, FALSE); } if ( pServer->Mode & ANSC_BSTO_MODE_AUTO_CLOSE ) { pMyObject->DelSocket((ANSC_HANDLE)pMyObject, (ANSC_HANDLE)pSocket); } continue; } */ returnStatus = pMyObject->Recv ( (ANSC_HANDLE)pMyObject, (ANSC_HANDLE)pSocket ); } } AnscSetEvent(&pMyObject->RecvEvent); return ANSC_STATUS_SUCCESS; }