/* * Trace Recorder for Tracealyzer v4.6.0 * Copyright 2021 Percepio AB * www.percepio.com * * SPDX-License-Identifier: Apache-2.0 * * Supporting functions for trace streaming, used by the "stream ports" * for reading and writing data to the interface. * Existing ports can easily be modified to fit another setup, e.g., a * different TCP/IP stack, or to define your own stream port. */ #include #include #include #if ( TRC_USE_TRACEALYZER_RECORDER == 1 ) #if ( TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING ) #pragma comment(lib,"ws2_32.lib") /*Winsock Library */ typedef struct TraceStreamPortTCPIP { #if ( TRC_USE_INTERNAL_BUFFER ) uint8_t buffer[ ( TRC_STREAM_PORT_BUFFER_SIZE ) ]; #else TraceUnsignedBaseType_t buffer[ 1 ]; #endif } TraceStreamPortTCPIP_t; static TraceStreamPortTCPIP_t * pxStreamPortFile; static SOCKET server_socket = ( UINT_PTR ) 0, trace_socket = ( UINT_PTR ) 0; struct sockaddr_in server, client; static int prvInitServerSocketIfNeeded( void ); static int prvInitWinsockIfNeeded( void ); static int prvInitTraceSocketIfNeeded( void ); static void prvCloseAllSockets( void ); static int prvInitWinsockIfNeeded( void ) { WSADATA wsa; if( server_socket ) { return 0; } if( WSAStartup( MAKEWORD( 2, 2 ), &wsa ) != 0 ) { return -1; } return 0; } static int prvInitServerSocketIfNeeded( void ) { if( prvInitWinsockIfNeeded() < 0 ) { return -1; } if( server_socket ) { return 0; } if( ( server_socket = socket( AF_INET, SOCK_STREAM, 0 ) ) == INVALID_SOCKET ) { return -1; } server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; server.sin_port = htons( TRC_CFG_STREAM_PORT_TCPIP_PORT ); if( bind( server_socket, ( struct sockaddr * ) &server, sizeof( server ) ) == SOCKET_ERROR ) { closesocket( server_socket ); WSACleanup(); server_socket = ( UINT_PTR ) 0; return -1; } if( listen( server_socket, 3 ) < 0 ) { closesocket( server_socket ); WSACleanup(); server_socket = ( UINT_PTR ) 0; return -1; } return 0; } static int prvInitTraceSocketIfNeeded( void ) { int c; if( !server_socket ) { return -1; } if( trace_socket ) { return 0; } c = sizeof( struct sockaddr_in ); trace_socket = accept( server_socket, ( struct sockaddr * ) &client, &c ); if( trace_socket == INVALID_SOCKET ) { trace_socket = ( UINT_PTR ) 0; closesocket( server_socket ); WSACleanup(); server_socket = ( UINT_PTR ) 0; return -1; } return 0; } int32_t prvTraceWriteToSocket( void * data, uint32_t size, int32_t * ptrBytesWritten ) { int ret; if( prvInitServerSocketIfNeeded() < 0 ) { return -1; } if( prvInitTraceSocketIfNeeded() < 0 ) { return -1; } if( !trace_socket ) { if( ptrBytesWritten != 0 ) { *ptrBytesWritten = 0; } return -1; } ret = send( trace_socket, data, size, 0 ); if( ret <= 0 ) { if( ptrBytesWritten != 0 ) { *ptrBytesWritten = 0; } closesocket( trace_socket ); trace_socket = ( UINT_PTR ) 0; return ret; } if( ptrBytesWritten != 0 ) { *ptrBytesWritten = ret; } return 0; } int32_t prvTraceReadFromSocket( void * data, uint32_t bufsize, int32_t * ptrBytesRead ) { unsigned long bytesAvailable = 0; if( prvInitServerSocketIfNeeded() < 0 ) { return -1; } if( prvInitTraceSocketIfNeeded() < 0 ) { return -1; } if( ioctlsocket( trace_socket, FIONREAD, &bytesAvailable ) != NO_ERROR ) { closesocket( trace_socket ); trace_socket = ( UINT_PTR ) 0; return -1; } if( bytesAvailable > 0 ) { *ptrBytesRead = recv( trace_socket, data, bufsize, 0 ); if( *ptrBytesRead == SOCKET_ERROR ) { closesocket( trace_socket ); trace_socket = ( UINT_PTR ) 0; return -1; } } return 0; } static void prvCloseAllSockets( void ) { if( trace_socket != 0 ) { closesocket( trace_socket ); trace_socket = 0; } if( server_socket != 0 ) { closesocket( server_socket ); server_socket = 0; } } traceResult xTraceStreamPortInitialize( TraceStreamPortBuffer_t * pxBuffer ) { TRC_ASSERT_EQUAL_SIZE( TraceStreamPortBuffer_t, TraceStreamPortTCPIP_t ); if( pxBuffer == 0 ) { return TRC_FAIL; } pxStreamPortFile = ( TraceStreamPortTCPIP_t * ) pxBuffer; #if ( TRC_USE_INTERNAL_BUFFER == 1 ) return xTraceInternalEventBufferInitialize( pxStreamPortFile->buffer, sizeof( pxStreamPortFile->buffer ) ); #else return TRC_SUCCESS; #endif } traceResult xTraceStreamPortOnTraceEnd( void ) { prvCloseAllSockets(); return TRC_SUCCESS; } #endif /*(TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)*/ #endif /*(TRC_USE_TRACEALYZER_RECORDER == 1)*/