This is an automated email from Gerrit.

"Brian Kuschak <[email protected]>" just uploaded a new patch set to Gerrit, 
which you can find at https://review.openocd.org/c/openocd/+/9136

-- gerrit

commit 3af64dc0bb2d5a09705fd0e4f1147e93845334bd
Author: Brian Kuschak <[email protected]>
Date:   Thu Sep 18 13:41:24 2025 +0800

    jtag/drivers/cmsis_dap_tcp: fix socket handling for Windows
    
    Windows does not support socket recv() with a combination of MSG_PEEK
    and MSG_WAITALL flags. Work around this limitation in a way that works
    for both Windows and other platforms.
    
    Checkpatch-ignore: CAMELCASE
    Change-Id: Ib77e2cc872e5fe3d1fc41034010b86390131fff3
    Fixes: https://sourceforge.net/p/openocd/tickets/457/
    Signed-off-by: Brian Kuschak <[email protected]>

diff --git a/src/jtag/drivers/cmsis_dap_tcp.c b/src/jtag/drivers/cmsis_dap_tcp.c
index 8a96cd6244..ac84542c47 100644
--- a/src/jtag/drivers/cmsis_dap_tcp.c
+++ b/src/jtag/drivers/cmsis_dap_tcp.c
@@ -20,6 +20,10 @@
 #include "config.h"
 #endif
 
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#include <errno.h>
 #ifdef HAVE_NETDB_H
 #include <netdb.h>
 #endif
@@ -28,10 +32,19 @@
 #endif
 #include <stdbool.h>
 #include <string.h>
+#include <sys/ioctl.h>
 #ifdef HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
 #endif
 #include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#endif
 
 #include "helper/command.h"
 #include "helper/log.h"
@@ -193,19 +206,112 @@ static void cmsis_dap_tcp_close(struct cmsis_dap *dap)
        cmsis_dap_tcp_free(dap);
 }
 
+static int socket_bytes_available(int sock, unsigned int *out_avail)
+{
+#ifdef _WIN32
+       u_long avail = 0;
+       if (ioctlsocket((SOCKET)sock, FIONREAD, &avail) == SOCKET_ERROR)
+               return -1;
+#else
+       int avail = 0;
+       if (ioctl(sock, FIONREAD, &avail) < 0)
+               return -1;
+#endif
+       *out_avail = avail;
+       return 0;
+}
+
 static inline int readall_socket(int handle, void *buffer, unsigned int count)
 {
        // Return after all count bytes available, or timeout, or error.
        return recv(handle, buffer, count, MSG_WAITALL);
 }
 
-static inline int peekall_socket(int handle, void *buffer, unsigned int count)
+static int peekall_socket(int handle, void *buffer, unsigned int count,
+               enum cmsis_dap_blocking blocking, unsigned int timeout_ms)
 {
-       /* Data remains unread on the socket until recv() is called later 
without
+       /* Windows doesn't support MSG_PEEK in combination with MSG_WAITALL:
+        *       return recv(handle, buffer, count, MSG_PEEK | MSG_WAITALL);
+        *
+        * So, use this method instead which should work for Windows and others.
+        *
+        * Data remains unread on the socket until recv() is called later 
without
         * the MSG_PEEK flag. Return after all count bytes available, or 
timeout,
         * or error.
         */
-       return recv(handle, buffer, count, MSG_PEEK | MSG_WAITALL);
+
+       if (count == 0)
+               return 0;
+
+       while (true) {
+               int ret;
+               unsigned int avail;
+               if (socket_bytes_available(handle, &avail) < 0)
+                       return -1;
+
+               if (avail >= count) {
+#ifdef _WIN32
+                       ret = recv(handle, (char *)buffer, (int)count, 
MSG_PEEK);
+                       if (ret == SOCKET_ERROR) {
+                               int err = WSAGetLastError();
+                               if (err == WSAEWOULDBLOCK || err == WSAEINTR)
+                                       return -1;      // Timeout or 
nonblocking.
+                               return -1;
+                       }
+#else
+                       ret = recv(handle, buffer, count, MSG_PEEK);
+                       if (ret < 0) {
+                               if (errno == EINTR)
+                                       continue;
+                               if (errno == EAGAIN || errno == EWOULDBLOCK)
+                                       return -1;      // Timeout or 
nonblocking.
+                               return -1;
+                       }
+#endif
+                       if (ret == 0)
+                               return 0;       // Connection closed.
+                       return ret;             // Success.
+               }
+
+               // Not enough data available.
+               if (blocking == CMSIS_DAP_NON_BLOCKING) {
+#ifdef _WIN32
+                       WSASetLastError(WSAEWOULDBLOCK);
+#else
+                       errno = EAGAIN;
+#endif
+                       return -1;
+               }
+
+#ifdef _WIN32
+               WSAPOLLFD pfd;
+               pfd.fd = (SOCKET)sock;
+               pfd.events = POLLIN;
+               pfd.revents = 0;
+               ret = WSAPoll(&pfd, 1, timeout_ms);
+               if (ret == SOCKET_ERROR)
+                       return -1;
+               if (ret == 0) {         // Timeout.
+                       WSASetLastError(WSAEWOULDBLOCK);
+                       return -1;
+               }
+#else
+               struct pollfd pfd;
+               pfd.fd = handle;
+               pfd.events = POLLIN;
+               pfd.revents = 0;
+               ret = poll(&pfd, 1, timeout_ms);
+               if (ret < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       return -1;
+               }
+               if (ret == 0) {         // Timeout.
+                       errno = EAGAIN;
+                       return -1;
+               }
+#endif
+       }
 }
 
 static int cmsis_dap_tcp_read(struct cmsis_dap *dap, int transfer_timeout_ms,
@@ -232,7 +338,7 @@ static int cmsis_dap_tcp_read(struct cmsis_dap *dap, int 
transfer_timeout_ms,
 
        // Peek at the header first to find the length.
        int retval = peekall_socket(dap->bdata->sockfd, dap->packet_buffer,
-                       HEADER_SIZE);
+                       HEADER_SIZE, blocking, wait_ms);
        LOG_DEBUG_IO("Reading header returned %d", retval);
        if (retval == 0) {
                LOG_DEBUG_IO("CMSIS-DAP: tcp timeout reached 1");

-- 

Reply via email to