// 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 OdVisualizeStreamingClient */ #include "OdaCommon.h" #include "Client.h" //Winsock #include #include #include #include #pragma comment(lib, "Ws2_32.lib") class OdTvClientImpl : public OdTvStreamingClient { WSADATA m_wsadata; SOCKET m_socket; addrinfo* m_socketResult = nullptr; fd_set m_readfds; fd_set m_writefds; public: OdTvClientImpl() { int iResult = 0; iResult = WSAStartup( MAKEWORD( 2, 2 ), &m_wsadata ); if( iResult != 0 ) { throw( "WSAStartup failed" ); } m_socket = INVALID_SOCKET; m_socketResult = nullptr; zeroFD(); } virtual ~OdTvClientImpl() { zeroFD(); if( m_socket != INVALID_SOCKET ) { closesocket( m_socket ); } if( m_socketResult ) { freeaddrinfo( m_socketResult ); m_socketResult = nullptr; } WSACleanup(); } virtual bool initialize( const char* ip, const char* port ) override { if( hasConnection() ) return false; ULONG uNonBlockingMode = 1; addrinfo hints; m_socketResult = nullptr; ZeroMemory( &hints, sizeof( hints ) ); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; if( getaddrinfo( ip, port, &hints, &m_socketResult ) != 0 ) { return false; } m_socket = socket( m_socketResult->ai_family, m_socketResult->ai_socktype, m_socketResult->ai_protocol ); if( m_socket == INVALID_SOCKET ) { freeaddrinfo( m_socketResult ); m_socketResult = nullptr; return false; } //make socket non-blocking if( ioctlsocket( m_socket, FIONBIO, &uNonBlockingMode ) == SOCKET_ERROR ) { freeaddrinfo( m_socketResult ); m_socketResult = nullptr; closesocket( m_socket ); m_socket = INVALID_SOCKET; return false; } return true; } virtual bool hasConnection() const override { return m_socket != INVALID_SOCKET && m_socketResult == nullptr; } virtual bool readFromServer( char* pBuffer, int bufferMaxLen, int& bytesRead ) override { if( !hasConnection() ) return false; if( !FD_ISSET( m_socket, &m_readfds ) ) //nothing to read { bytesRead = 0; return true; } bytesRead = recv( m_socket, pBuffer, bufferMaxLen, 0 ); if( bytesRead > 0 ) { return true; } else if( bytesRead == 0 ) { printf( "Connection closed\n" ); return true; } else { printf( "recv failed: %d\n", WSAGetLastError() ); return false; } return true; } virtual bool writeToServer( const char* pBuffer, int bufferLen, int& bytesSent ) override { if( !hasConnection() ) return false; if( !FD_ISSET( m_socket, &m_writefds ) ) //nothing to read { bytesSent = 0; return true; } bytesSent = send( m_socket, pBuffer, bufferLen, 0 ); printf( "Bytes sent: %d\n", bytesSent ); return true; } virtual bool connectServer() override { if( hasConnection() || m_socketResult == nullptr ) return false; if( connect( m_socket, m_socketResult->ai_addr, (int)m_socketResult->ai_addrlen ) == SOCKET_ERROR ) { int err = WSAGetLastError(); if( WSAGetLastError() == WSAEWOULDBLOCK ) //OK { //freeaddrinfo( result ); return true; } else if( err == WSAEISCONN ) //connected { freeaddrinfo( m_socketResult ); m_socketResult = nullptr; return true; } closesocket( m_socket ); m_socket = INVALID_SOCKET; freeaddrinfo( m_socketResult ); m_socketResult = nullptr; return false; } freeaddrinfo( m_socketResult ); m_socketResult = nullptr; return true; } virtual bool onClientLoopIteration() override { if( !hasConnection() ) return true; setupServerFD(); timeval tm = { 0,0 }; if( select( 0, &m_readfds, &m_writefds, NULL, &tm ) == SOCKET_ERROR ) { fprintf( stderr, "select failed %d\n", WSAGetLastError() ); return false; } return true; } virtual bool shutdownClient() override { if( shutdown( m_socket, SD_BOTH ) == SOCKET_ERROR ) { printf( "shutdown failed: %d\n", WSAGetLastError() ); closesocket( m_socket ); return false; } closesocket( m_socket ); m_socket = INVALID_SOCKET; return true; } void setupServerFD() { zeroFD(); //Check read/write on server socket FD_SET( m_socket, &m_readfds ); FD_SET( m_socket, &m_writefds ); } void zeroFD() { FD_ZERO( &m_readfds ); FD_ZERO( &m_writefds ); } }; std::shared_ptr< OdTvStreamingClient > OdTvStreamingClient::createClient() { return std::make_shared< OdTvClientImpl >(); }