1 /*
2  * Trace Recorder for Tracealyzer v4.10.3
3  * Copyright 2023 Percepio AB
4  * www.percepio.com
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  *
8  * Supporting functions for trace streaming, used by the "stream ports"
9  * for reading and writing data to the interface.
10  * Existing ports can easily be modified to fit another setup, e.g., a
11  * different TCP/IP stack, or to define your own stream port.
12  */
13 
14 #include<stdio.h>
15 #include<winsock2.h>
16 
17 #include <trcRecorder.h>
18 
19 #if (TRC_USE_TRACEALYZER_RECORDER == 1)
20 
21 #if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)
22 
23 #pragma comment(lib,"ws2_32.lib") //Winsock Library
24 
25 typedef struct TraceStreamPortTCPIP
26 {
27 #if (TRC_USE_INTERNAL_BUFFER)
28 	uint8_t buffer[(TRC_ALIGNED_STREAM_PORT_BUFFER_SIZE)];
29 #else
30 	TraceUnsignedBaseType_t buffer[1];
31 #endif
32 } TraceStreamPortTCPIP_t;
33 
34 static TraceStreamPortTCPIP_t* pxStreamPortTCPIP TRC_CFG_RECORDER_DATA_ATTRIBUTE;
35 static SOCKET server_socket = (UINT_PTR)0, trace_socket = (UINT_PTR)0;
36 struct sockaddr_in server, client;
37 
38 static int prvInitServerSocketIfNeeded(void);
39 static int prvInitWinsockIfNeeded(void);
40 static int prvInitTraceSocketIfNeeded(void);
41 static void prvCloseAllSockets(void);
42 
prvInitWinsockIfNeeded(void)43 static int prvInitWinsockIfNeeded(void)
44 {
45 	WSADATA wsa;
46 
47 	if (server_socket)
48 		return 0;
49 
50 	if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
51 	{
52 		return -1;
53 	}
54 
55 	return 0;
56 }
57 
prvInitServerSocketIfNeeded(void)58 static int prvInitServerSocketIfNeeded(void)
59 {
60 	if (prvInitWinsockIfNeeded() < 0)
61 	{
62 		return -1;
63 	}
64 
65 	if (server_socket)
66 		return 0;
67 
68 	if ((server_socket = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
69 	{
70 		return -1;
71 	}
72 
73 	server.sin_family = AF_INET;
74 	server.sin_addr.s_addr = INADDR_ANY;
75 	server.sin_port = htons(TRC_CFG_STREAM_PORT_TCPIP_PORT);
76 
77 	if (bind(server_socket, (struct sockaddr *)&server, sizeof(server)) == SOCKET_ERROR)
78 	{
79 		closesocket(server_socket);
80 		WSACleanup();
81 		server_socket = (UINT_PTR)0;
82 		return -1;
83 	}
84 
85 	if (listen(server_socket, 3) < 0)
86 	{
87 		closesocket(server_socket);
88 		WSACleanup();
89 		server_socket = (UINT_PTR)0;
90 		return -1;
91 	}
92 
93 	return 0;
94 }
95 
prvInitTraceSocketIfNeeded(void)96 static int prvInitTraceSocketIfNeeded(void)
97 {
98 	int c;
99 
100 	if (!server_socket)
101 		return -1;
102 
103 	if (trace_socket)
104 		return 0;
105 
106 	c = sizeof(struct sockaddr_in);
107 	trace_socket = accept(server_socket, (struct sockaddr *)&client, &c);
108 	if (trace_socket == INVALID_SOCKET)
109 	{
110 		trace_socket = (UINT_PTR)0;
111 
112 		closesocket(server_socket);
113 		WSACleanup();
114 		server_socket = (UINT_PTR)0;
115 
116 		return -1;
117 	}
118 
119 	return 0;
120 }
121 
prvTraceWriteToSocket(void * data,uint32_t size,int32_t * ptrBytesWritten)122 int32_t prvTraceWriteToSocket(void* data, uint32_t size, int32_t *ptrBytesWritten)
123 {
124 	int ret;
125 
126 	if (prvInitServerSocketIfNeeded() < 0)
127 	{
128 		return -1;
129 	}
130 
131 	if (prvInitTraceSocketIfNeeded() < 0)
132 	{
133 		return -1;
134 	}
135 
136 	if (!trace_socket)
137 	{
138 		if (ptrBytesWritten != 0)
139 		{
140 			*ptrBytesWritten = 0;
141 		}
142 		return -1;
143 	}
144 	ret = send(trace_socket, data, size, 0);
145 	if (ret <= 0)
146 	{
147 		if (ptrBytesWritten != 0)
148 		{
149 			*ptrBytesWritten = 0;
150 		}
151 
152 		closesocket(trace_socket);
153 		trace_socket = (UINT_PTR)0;
154 		return ret;
155 	}
156 
157 	if (ptrBytesWritten != 0)
158 	{
159 		*ptrBytesWritten = ret;
160 	}
161 
162 	return 0;
163 }
164 
prvTraceReadFromSocket(void * data,uint32_t bufsize,int32_t * ptrBytesRead)165 int32_t prvTraceReadFromSocket(void* data, uint32_t bufsize, int32_t *ptrBytesRead)
166 {
167 	unsigned long bytesAvailable = 0;
168 
169 	if (prvInitServerSocketIfNeeded() < 0)
170 		return -1;
171 
172 	if (prvInitTraceSocketIfNeeded() < 0)
173 		return -1;
174 
175 	if (ioctlsocket(trace_socket, FIONREAD, &bytesAvailable) != NO_ERROR)
176 	{
177 		closesocket(trace_socket);
178 		trace_socket = (UINT_PTR)0;
179 		return -1;
180 	}
181 
182 	if (bytesAvailable > 0)
183 	{
184 		*ptrBytesRead = recv(trace_socket, data, bufsize, 0);
185 		if (*ptrBytesRead == SOCKET_ERROR)
186 		{
187 			closesocket(trace_socket);
188 			trace_socket = (UINT_PTR)0;
189 			return -1;
190 		}
191 	}
192 
193 	return 0;
194 }
195 
prvCloseAllSockets(void)196 static void prvCloseAllSockets(void)
197 {
198 	if (trace_socket != 0)
199 	{
200 		closesocket(trace_socket);
201 		trace_socket = 0;
202 	}
203 
204 	if (server_socket != 0)
205 	{
206 		closesocket(server_socket);
207 		server_socket = 0;
208 	}
209 }
210 
xTraceStreamPortInitialize(TraceStreamPortBuffer_t * pxBuffer)211 traceResult xTraceStreamPortInitialize(TraceStreamPortBuffer_t* pxBuffer)
212 {
213 	TRC_ASSERT_EQUAL_SIZE(TraceStreamPortBuffer_t, TraceStreamPortTCPIP_t);
214 
215 	if (pxBuffer == 0)
216 	{
217 		return TRC_FAIL;
218 	}
219 
220 	pxStreamPortTCPIP = (TraceStreamPortTCPIP_t*)pxBuffer;
221 
222 #if (TRC_USE_INTERNAL_BUFFER == 1)
223 	return xTraceInternalEventBufferInitialize(pxStreamPortTCPIP->buffer, sizeof(pxStreamPortTCPIP->buffer));
224 #else
225 	return TRC_SUCCESS;
226 #endif
227 }
228 
xTraceStreamPortOnTraceEnd(void)229 traceResult xTraceStreamPortOnTraceEnd(void)
230 {
231 	prvCloseAllSockets();
232 
233 	return TRC_SUCCESS;
234 }
235 
236 #endif /*(TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)*/
237 
238 #endif /*(TRC_USE_TRACEALYZER_RECORDER == 1)*/
239