2020#include "config.h"
2121#endif
2222
23+ #ifdef HAVE_ARPA_INET_H
24+ #include <arpa/inet.h>
25+ #endif
26+ #include <errno.h>
2327#ifdef HAVE_NETDB_H
2428#include <netdb.h>
2529#endif
2832#endif
2933#include <stdbool.h>
3034#include <string.h>
35+ #ifdef HAVE_SYS_IOCTL_H
36+ #include <sys/ioctl.h>
37+ #endif
3138#ifdef HAVE_SYS_SOCKET_H
3239#include <sys/socket.h>
3340#endif
3441#include <sys/types.h>
42+ #ifdef HAVE_UNISTD_H
43+ #include <unistd.h>
44+ #endif
45+
46+ #ifdef _WIN32
47+ #include <winsock2.h>
48+ #include <ws2tcpip.h>
49+ #endif
3550
3651#include "helper/command.h"
3752#include "helper/log.h"
@@ -193,19 +208,107 @@ static void cmsis_dap_tcp_close(struct cmsis_dap *dap)
193208 cmsis_dap_tcp_free (dap );
194209}
195210
211+ static int socket_bytes_available (int sock , unsigned int * out_avail )
212+ {
213+ #ifdef _WIN32
214+ u_long avail = 0 ;
215+ if (ioctlsocket ((SOCKET )sock , FIONREAD , & avail ) == SOCKET_ERROR )
216+ return -1 ;
217+ #else
218+ int avail = 0 ;
219+ if (ioctl (sock , FIONREAD , & avail ) < 0 )
220+ return -1 ;
221+ #endif
222+ * out_avail = avail ;
223+ return 0 ;
224+ }
225+
196226static inline int readall_socket (int handle , void * buffer , unsigned int count )
197227{
198228 // Return after all count bytes available, or timeout, or error.
199229 return recv (handle , buffer , count , MSG_WAITALL );
200230}
201231
202- static inline int peekall_socket (int handle , void * buffer , unsigned int count )
232+ static int peekall_socket (int handle , void * buffer , unsigned int count ,
233+ enum cmsis_dap_blocking blocking , unsigned int timeout_ms )
203234{
204- /* Data remains unread on the socket until recv() is called later without
235+ /* Windows doesn't support MSG_PEEK in combination with MSG_WAITALL:
236+ * return recv(handle, buffer, count, MSG_PEEK | MSG_WAITALL);
237+ *
238+ * So, use this method instead which should work for Windows and others.
239+ *
240+ * Data remains unread on the socket until recv() is called later without
205241 * the MSG_PEEK flag. Return after all count bytes available, or timeout,
206242 * or error.
207243 */
208- return recv (handle , buffer , count , MSG_PEEK | MSG_WAITALL );
244+
245+ if (count == 0 )
246+ return 0 ;
247+
248+ while (true) {
249+ int ret ;
250+ unsigned int avail ;
251+ if (socket_bytes_available (handle , & avail ) < 0 )
252+ return -1 ;
253+
254+ if (avail >= count ) {
255+ ret = recv (handle , (char * )buffer , (int )count , MSG_PEEK );
256+ if (ret < 0 ) {
257+ #ifdef _WIN32
258+ int err = WSAGetLastError ();
259+ if (err == WSAEINTR )
260+ continue ;
261+ if (err == WSAEWOULDBLOCK )
262+ return -1 ;
263+ #else
264+ if (errno == EINTR )
265+ continue ;
266+ if (errno == EAGAIN || errno == EWOULDBLOCK )
267+ return -1 ; // Timeout or nonblocking.
268+ #endif
269+ }
270+ return ret ; // 0: Closed, <0: Other error, >0 Success.
271+ }
272+
273+ // Not enough data available.
274+ if (blocking == CMSIS_DAP_NON_BLOCKING ) {
275+ #ifdef _WIN32
276+ WSASetLastError (WSAEWOULDBLOCK );
277+ #else
278+ errno = EAGAIN ;
279+ #endif
280+ return -1 ;
281+ }
282+
283+ // Blocking wait.
284+ fd_set rfds ;
285+ FD_ZERO (& rfds );
286+ FD_SET (handle , & rfds );
287+
288+ struct timeval tv ;
289+ tv .tv_sec = timeout_ms / 1000 ;
290+ tv .tv_usec = (timeout_ms % 1000 ) * 1000 ;
291+
292+ ret = select (handle + 1 , & rfds , NULL , NULL , & tv );
293+ if (ret > 0 )
294+ continue ; // Readable
295+
296+ if (ret == 0 ) { // Timeout
297+ #ifdef _WIN32
298+ WSASetLastError (WSAEWOULDBLOCK );
299+ #else
300+ errno = EAGAIN ;
301+ #endif
302+ return -1 ;
303+ }
304+
305+ // Error
306+ #ifndef _WIN32
307+ if (errno == EINTR )
308+ continue ;
309+ #endif
310+ return ret ;
311+ }
209312}
210313
211314static int cmsis_dap_tcp_read (struct cmsis_dap * dap , int transfer_timeout_ms ,
@@ -232,7 +335,7 @@ static int cmsis_dap_tcp_read(struct cmsis_dap *dap, int transfer_timeout_ms,
232335
233336 // Peek at the header first to find the length.
234337 int retval = peekall_socket (dap -> bdata -> sockfd , dap -> packet_buffer ,
235- HEADER_SIZE );
338+ HEADER_SIZE , blocking , wait_ms );
236339 LOG_DEBUG_IO ("Reading header returned %d" , retval );
237340 if (retval == 0 ) {
238341 LOG_DEBUG_IO ("CMSIS-DAP: tcp timeout reached 1" );
0 commit comments