1 /*
2  * Trace Recorder for Tracealyzer v4.6.6
3  * Copyright 2021 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_STREAM_PORT_BUFFER_SIZE)];
34 #else
35 	TraceUnsignedBaseType_t buffer[1];
36 #endif
37 } TraceStreamPortTCPIP_t;
38 
39 static TraceStreamPortTCPIP_t* pxStreamPortFile;
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* bytesRead);
43 static int32_t prvSocketInitializeListener();
44 static int32_t prvSocketAccept();
45 static void prvCloseAllSockets();
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 == 0)
53 	return -1;
54 
55   *piBytesWritten = send( new_sd, pvData, uiSize, 0 );
56   if (*piBytesWritten < 0)
57   {
58     /* EWOULDBLOCK may be expected when buffers are full */
59     if ((errno != 0) && (errno != EWOULDBLOCK))
60 	{
61 		closesocket(new_sd);
62 		new_sd = -1;
63 		return -1;
64 	}
65     else
66         *piBytesWritten = 0;
67   }
68 
69   return 0;
70 }
71 
prvSocketReceive(void * pvData,uint32_t uiSize,int32_t * bytesRead)72 static int32_t prvSocketReceive( void* pvData, uint32_t uiSize, int32_t* bytesRead )
73 {
74   if (new_sd < 0)
75     return -1;
76 
77   *bytesRead = recv( new_sd, pvData, uiSize, 0 );
78   /* EWOULDBLOCK may be expected when there is no pvData to receive */
79   if (errno != 0 && errno != EWOULDBLOCK)
80   {
81     closesocket(new_sd);
82     new_sd = -1;
83     return -1;
84   }
85 
86   return 0;
87 }
88 
prvSocketInitializeListener()89 static int32_t prvSocketInitializeListener()
90 {
91   if (sock >= 0)
92 	return 0;
93 
94   sock = lwip_socket(AF_INET, SOCK_STREAM, 0);
95 
96   if (sock < 0)
97     return -1;
98 
99   address.sin_family = AF_INET;
100   address.sin_port = htons(TRC_CFG_STREAM_PORT_TCPIP_PORT);
101   address.sin_addr.s_addr = INADDR_ANY;
102 
103   if (bind(sock, (struct sockaddr *)&address, sizeof (address)) < 0)
104   {
105     closesocket(sock);
106     sock = -1;
107     return -1;
108   }
109 
110   if (lwip_listen(sock, 5) < 0)
111   {
112     closesocket(sock);
113     sock = -1;
114     return -1;
115   }
116 
117   return 0;
118 }
119 
prvSocketAccept()120 static int32_t prvSocketAccept()
121 {
122   if (sock < 0)
123       return -1;
124 
125   if (new_sd >= 0)
126       return 0;
127 
128   remoteSize = sizeof( remote );
129   new_sd = accept( sock, (struct sockaddr *)&remote, (socklen_t*)&remoteSize );
130 
131   if( new_sd < 0 )
132   {
133    	closesocket(new_sd);
134     new_sd = -1;
135    	closesocket(sock);
136     sock = -1;
137     return -1;
138   }
139 
140   flags = fcntl( new_sd, F_GETFL, 0 );
141   fcntl( new_sd, F_SETFL, flags | O_NONBLOCK );
142 
143   return 0;
144 }
145 
prvCloseAllSockets()146 static void prvCloseAllSockets()
147 {
148 	if (new_sd > 0)
149 	{
150 		closesocket(new_sd);
151 	}
152 
153 	if (sock > 0)
154 	{
155 		closesocket(sock);
156 	}
157 }
158 /************** MODIFY THE ABOVE PART TO USE YOUR TPC/IP STACK ****************/
159 
prvTraceTcpWrite(void * pvData,uint32_t uiSize,int32_t * piBytesWritten)160 int32_t prvTraceTcpWrite(void* pvData, uint32_t uiSize, int32_t *piBytesWritten)
161 {
162 	prvSocketInitializeListener();
163 
164 	prvSocketAccept();
165 
166     return prvSocketSend(pvData, uiSize, piBytesWritten);
167 }
168 
prvTraceTcpRead(void * pvData,uint32_t uiSize,int32_t * piBytesRead)169 int32_t prvTraceTcpRead(void* pvData, uint32_t uiSize, int32_t *piBytesRead)
170 {
171     prvSocketInitializeListener();
172 
173     prvSocketAccept();
174 
175     return prvSocketReceive(pvData, uiSize, piBytesRead);
176 }
177 
xTraceStreamPortInitialize(TraceStreamPortBuffer_t * pxBuffer)178 traceResult xTraceStreamPortInitialize(TraceStreamPortBuffer_t* pxBuffer)
179 {
180 	TRC_ASSERT_EQUAL_SIZE(TraceStreamPortBuffer_t, TraceStreamPortTCPIP_t);
181 
182 	if (pxBuffer == 0)
183 	{
184 		return TRC_FAIL;
185 	}
186 
187 	pxStreamPortFile = (TraceStreamPortTCPIP_t*)pxBuffer;
188 
189 #if (TRC_USE_INTERNAL_BUFFER == 1)
190 	return xTraceInternalEventBufferInitialize(pxStreamPortFile->buffer, sizeof(pxStreamPortFile->buffer));
191 #else
192 	return TRC_SUCCESS;
193 #endif
194 }
195 
xTraceStreamPortOnTraceEnd(void)196 traceResult xTraceStreamPortOnTraceEnd(void)
197 {
198 	prvCloseAllSockets();
199 
200 	return TRC_SUCCESS;
201 }
202 
203 #endif /*(TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)*/
204 
205 #endif /*(TRC_USE_TRACEALYZER_RECORDER == 1)*/
206