1 /*
2  * Trace Recorder for Tracealyzer v4.9.2
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 <trcRecorder.h>
15 
16 #if (TRC_USE_TRACEALYZER_RECORDER == 1)
17 
18 #if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)
19 
20 /* TCP/IP includes - for lwIP in this case */
21 #include <lwip/tcpip.h>
22 #include <lwip/sockets.h>
23 #include <lwip/errno.h>
24 
25 int sock = -1, new_sd = -1;
26 int flags = 0;
27 int remoteSize;
28 struct sockaddr_in address, remote;
29 
30 typedef struct TraceStreamPortTCPIP
31 {
32 #if (TRC_USE_INTERNAL_BUFFER)
33 	uint8_t buffer[(TRC_ALIGNED_STREAM_PORT_BUFFER_SIZE)];
34 #else
35 	TraceUnsignedBaseType_t buffer[1];
36 #endif
37 } TraceStreamPortTCPIP_t;
38 
39 static TraceStreamPortTCPIP_t* pxStreamPortTCPIP TRC_CFG_RECORDER_DATA_ATTRIBUTE;
40 
41 static int32_t prvSocketSend(void* pvData, uint32_t uiSize, int32_t* piBytesWritten);
42 static int32_t prvSocketReceive(void* pvData, uint32_t uiSize, int32_t* piBytesRead);
43 static int32_t prvSocketInitializeListener(void);
44 static int32_t prvSocketAccept(void);
45 static void prvCloseAllSockets(void);
46 
prvSocketSend(void * pvData,uint32_t uiSize,int32_t * piBytesWritten)47 static int32_t prvSocketSend( void* pvData, uint32_t uiSize, int32_t* piBytesWritten )
48 {
49   if (new_sd < 0)
50     return -1;
51 
52   if (piBytesWritten == (void*)0)
53 	return -1;
54 
55   *piBytesWritten = send( new_sd, pvData, uiSize, 0 );
56 
57   if (*piBytesWritten < 0)
58   {
59     *piBytesWritten = 0;
60 
61     /* EWOULDBLOCK may be expected when buffers are full */
62     if (errno != EWOULDBLOCK)
63 	{
64 		close(new_sd);
65 		new_sd = -1;
66 		return -1;
67 	}
68   }
69 
70   return 0;
71 }
72 
prvSocketReceive(void * pvData,uint32_t uiSize,int32_t * piBytesRead)73 static int32_t prvSocketReceive( void* pvData, uint32_t uiSize, int32_t* piBytesRead )
74 {
75   if (new_sd < 0)
76     return -1;
77 
78   if (piBytesRead == (void*)0)
79 	  return -1;
80 
81   *piBytesRead = recv( new_sd, pvData, uiSize, 0 );
82 
83   if (*piBytesRead < 0)
84   {
85 	  *piBytesRead = 0;
86 
87 		/* EWOULDBLOCK may be expected when there is no pvData to receive */
88 	  if (errno != EWOULDBLOCK)
89 	  {
90 		close(new_sd);
91 		new_sd = -1;
92 		return -1;
93 	  }
94   }
95 
96   return 0;
97 }
98 
prvSocketInitializeListener(void)99 static int32_t prvSocketInitializeListener(void)
100 {
101   if (sock >= 0)
102   {
103 	  return 0;
104   }
105 
106   sock = socket(AF_INET, SOCK_STREAM, 0);
107 
108   if (sock < 0)
109   {
110     return -1;
111   }
112 
113   address.sin_family = AF_INET;
114   address.sin_port = htons(TRC_CFG_STREAM_PORT_TCPIP_PORT);
115   address.sin_addr.s_addr = INADDR_ANY;
116 
117   if (bind(sock, (struct sockaddr *)&address, sizeof (address)) < 0)
118   {
119     close(sock);
120     sock = -1;
121     return -1;
122   }
123 
124   if (listen(sock, 5) < 0)
125   {
126     close(sock);
127     sock = -1;
128     return -1;
129   }
130 
131   return 0;
132 }
133 
prvSocketAccept(void)134 static int32_t prvSocketAccept(void)
135 {
136   if (sock < 0)
137       return -1;
138 
139   if (new_sd >= 0)
140       return 0;
141 
142   remoteSize = sizeof( remote );
143   new_sd = accept( sock, (struct sockaddr *)&remote, (socklen_t*)&remoteSize );
144 
145   if( new_sd < 0 )
146   {
147    	close(new_sd);
148     new_sd = -1;
149    	close(sock);
150     sock = -1;
151     return -1;
152   }
153 
154   flags = fcntl( new_sd, F_GETFL, 0 );
155   fcntl( new_sd, F_SETFL, flags | O_NONBLOCK );
156 
157   return 0;
158 }
159 
prvCloseAllSockets(void)160 static void prvCloseAllSockets(void)
161 {
162 	if (new_sd > 0)
163 	{
164 		close(new_sd);
165 	}
166 
167 	if (sock > 0)
168 	{
169 		close(sock);
170 	}
171 }
172 /************** MODIFY THE ABOVE PART TO USE YOUR TPC/IP STACK ****************/
173 
prvTraceTcpWrite(void * pvData,uint32_t uiSize,int32_t * piBytesWritten)174 int32_t prvTraceTcpWrite(void* pvData, uint32_t uiSize, int32_t *piBytesWritten)
175 {
176 	prvSocketInitializeListener();
177 
178 	prvSocketAccept();
179 
180     return prvSocketSend(pvData, uiSize, piBytesWritten);
181 }
182 
prvTraceTcpRead(void * pvData,uint32_t uiSize,int32_t * piBytesRead)183 int32_t prvTraceTcpRead(void* pvData, uint32_t uiSize, int32_t *piBytesRead)
184 {
185     prvSocketInitializeListener();
186 
187     prvSocketAccept();
188 
189     return prvSocketReceive(pvData, uiSize, piBytesRead);
190 }
191 
xTraceStreamPortInitialize(TraceStreamPortBuffer_t * pxBuffer)192 traceResult xTraceStreamPortInitialize(TraceStreamPortBuffer_t* pxBuffer)
193 {
194 	TRC_ASSERT_EQUAL_SIZE(TraceStreamPortBuffer_t, TraceStreamPortTCPIP_t);
195 
196 	if (pxBuffer == 0)
197 	{
198 		return TRC_FAIL;
199 	}
200 
201 	pxStreamPortTCPIP = (TraceStreamPortTCPIP_t*)pxBuffer;
202 
203 #if (TRC_USE_INTERNAL_BUFFER == 1)
204 	return xTraceInternalEventBufferInitialize(pxStreamPortTCPIP->buffer, sizeof(pxStreamPortTCPIP->buffer));
205 #else
206 	return TRC_SUCCESS;
207 #endif
208 }
209 
xTraceStreamPortOnTraceEnd(void)210 traceResult xTraceStreamPortOnTraceEnd(void)
211 {
212 	prvCloseAllSockets();
213 
214 	return TRC_SUCCESS;
215 }
216 
217 #endif /*(TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)*/
218 
219 #endif /*(TRC_USE_TRACEALYZER_RECORDER == 1)*/
220