// Copyright (C) 2002-2025, Open Design Alliance (the "Alliance"). // All rights reserved. // // This software and its documentation and related materials are owned by // the Alliance. The software may only be incorporated into application // programs owned by members of the Alliance, subject to a signed // Membership Agreement and Supplemental Software License Agreement with the // Alliance. The structure and organization of this software are the valuable // trade secrets of the Alliance and its suppliers. The software is also // protected by copyright law and international treaty provisions. Application // programs incorporating this software must include the following statement // with their copyright notices: // // This application incorporates Open Design Alliance software pursuant to a license // agreement with Open Design Alliance. // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance. // All rights reserved. // // By use of this software, its documentation or related materials, you // acknowledge and accept the above terms. /////////////////////////////////////////////////////////////////////////////// /* Winsock-based OdVisualizeStreamingServer */ #include "OdaCommon.h" #include "Server.h" //Winsock #include #include #include #include #pragma comment(lib, "Ws2_32.lib") class OdTvServerImpl : public OdTvStreamingServer { WSADATA m_wsadata; SOCKET m_socket = INVALID_SOCKET; SOCKET m_clientSocket = INVALID_SOCKET; fd_set m_readfds; fd_set m_writefds; SOCKADDR_STORAGE m_clientStorage; public: OdTvServerImpl() { int iResult = 0; iResult = WSAStartup( MAKEWORD( 2, 2 ), &m_wsadata ); if( iResult != 0 ) { throw( "WSAStartup failed" ); } m_socket = INVALID_SOCKET; FD_ZERO( &m_readfds ); FD_ZERO( &m_writefds ); } ~OdTvServerImpl() { if( m_clientSocket != INVALID_SOCKET ) { closesocket( m_clientSocket ); } if( m_socket != INVALID_SOCKET ) { closesocket( m_socket ); } WSACleanup(); } virtual bool initialize( const char* port ) override { ULONG uNonBlockingMode = 1; //Setup connection addrinfo hints; ZeroMemory( &hints, sizeof ( hints ) ); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; hints.ai_flags = AI_PASSIVE; struct addrinfo* result = nullptr; int iResult = getaddrinfo( NULL, port, &hints, &result ); if( iResult != 0 ) return false; //Create socket m_socket = socket( result->ai_family, result->ai_socktype, result->ai_protocol ); if( m_socket == INVALID_SOCKET ) { freeaddrinfo( result ); return false; } //Bind iResult = bind( m_socket, result->ai_addr, (int)result->ai_addrlen ); if( iResult == SOCKET_ERROR ) { freeaddrinfo( result ); closesocket( m_socket ); m_socket = INVALID_SOCKET; return false; } freeaddrinfo( result ); //Listen if( listen( m_socket, SOMAXCONN ) == SOCKET_ERROR ) { closesocket( m_socket ); m_socket = INVALID_SOCKET; return false; } //make socket non-blocking if( ioctlsocket( m_socket, FIONBIO, &uNonBlockingMode ) == SOCKET_ERROR ) { freeaddrinfo( result ); closesocket( m_socket ); m_socket = INVALID_SOCKET; return false; } FD_SET( m_socket, &m_readfds ); //wait read for connection return true; } virtual bool hasClient() const override { return m_clientSocket != INVALID_SOCKET; } virtual bool readFromClient( char* pBuffer, int bufferMaxLen, int& bytesRead ) override { if( m_clientSocket == INVALID_SOCKET ) return false; if( !FD_ISSET( m_clientSocket, &m_readfds ) ) //nothing to read { bytesRead = 0; return true; } int retVal = recv( m_clientSocket, pBuffer, bufferMaxLen, 0 ); if( retVal == 0 ) { //TO DO: close client connection //zeroFD(); //closesocket( m_clientSocket ); //m_clientSocket = INVALID_SOCKET; return true; } else if( retVal == SOCKET_ERROR ) { if( WSAGetLastError() == WSAEWOULDBLOCK ) //OK { bytesRead = 0; return true; } closesocket( m_clientSocket ); m_clientSocket = INVALID_SOCKET; zeroFD(); return false; } bytesRead = retVal; m_logger.logMessage( "Received %d bytes", retVal ); return true; } virtual bool writeToClient( const char* pBuffer, int bufferLen, int& bytesSent ) override { if( m_clientSocket == INVALID_SOCKET ) return false; if( !FD_ISSET( m_clientSocket, &m_writefds ) ) { bytesSent = 0; return true; } int retVal = send( m_clientSocket, pBuffer, bufferLen, 0 ); if( retVal == 0 ) { //TO DO: close client connection //zeroFD(); //closesocket( m_clientSocket ); //m_clientSocket = INVALID_SOCKET; return true; } else if( retVal == SOCKET_ERROR ) { if( WSAGetLastError() == WSAEWOULDBLOCK ) //OK { bytesSent = 0; return true; } closesocket( m_clientSocket ); m_clientSocket = INVALID_SOCKET; zeroFD(); return false; } else { bytesSent = retVal; static OdUInt64 nTotal = 0; nTotal += bytesSent; if( nTotal < 1024 ) { m_logger.updateMessage( "Sent %d bytes, total %d bytes", bytesSent, nTotal ); } else if( nTotal < 1024*1024 ) { m_logger.updateMessage( "Sent %d bytes, total %f KB", bytesSent, (float)nTotal / 1024.f ); } else { m_logger.updateMessage( "Sent %d bytes, total %f MB", bytesSent, (float)nTotal / ( 1024.f * 1024.f ) ); } return true; } } virtual bool connectClient() override { if( FD_ISSET( m_socket, &m_readfds ) ) { // Accept the connection int clientlen = sizeof( m_clientStorage ); m_clientSocket = accept( m_socket, (SOCKADDR*)&m_clientStorage, &clientlen ); if( m_clientSocket == INVALID_SOCKET ) { m_logger.logMessage( "accept failed: %d\n", WSAGetLastError() ); return false; } m_logger.logMessage( "Accepted client connection \n" ); } return true; } virtual bool onServerLoopIteration() override { if( m_clientSocket != INVALID_SOCKET ) { //Setup FD here setupClientFD(); } timeval tm = { 0,0 }; if( select( 0, &m_readfds, &m_writefds, NULL, m_clientSocket != INVALID_SOCKET ? &tm : nullptr ) == SOCKET_ERROR ) { m_logger.logMessage( "select failed %d\n", WSAGetLastError() ); return false; } return true; } void setupClientFD() { zeroFD(); //Check read/write on client socket FD_SET( m_clientSocket, &m_readfds ); FD_SET( m_clientSocket, &m_writefds ); } void zeroFD() { FD_ZERO( &m_readfds ); FD_ZERO( &m_writefds ); } }; std::shared_ptr< OdTvStreamingServer > OdTvStreamingServer::createServer() { return std::make_shared< OdTvServerImpl >(); }