+2017-11-08 Keith Marshall <keith@users.osdn.me>
+
+ Overhaul WinSock fd_set content management macros.
+
+ * include/winsock.h (FD_SET, FD_ISSET, FD_CLR, FD_ZERO): Replace the
+ original implementations of each of these macros, redirecting to...
+ (__FD_SET, __FD_ISSET, __FD_CLR, __FD_ZERO): ...these new, equivalent
+ inline functions, respectively; these are more robust, and correct a
+ defect in the original FD_SET macro implementation, whereby duplicate
+ descriptors could be added to an fd_set array, but would not then be
+ removed by the corresponding FD_CLR macro.
+
+ * tests/winsock.at (MINGW_AT_CHECK_WINSOCK): Ensure that all test
+ programs are linked with -lwsock32 or -lws2_32, as appropriate; the
+ __FD_SET and __FD_ISSET functions are dependent on the __WSAFDIsSet()
+ function, which is implemented in each of these libraries.
+
2017-11-07 Keith Marshall <keith@users.osdn.me>
Identify features which have been deprecated in WinSock v2.
SOCKET fd_array[FD_SETSIZE];
} fd_set;
-int PASCAL __WSAFDIsSet (SOCKET, fd_set *);
+#ifndef FD_ISSET
+int FD_ISSET (SOCKET, fd_set *);
+#define FD_ISSET( __fd, __set ) __FD_ISSET ((__fd), (__set))
-#ifndef FD_CLR
-#define FD_CLR( fd, set ) do \
- { u_int __i; \
- for (__i = 0; __i < ((fd_set *)(set))->fd_count ; __i++) \
- { if (((fd_set *)(set))->fd_array[__i] == (fd)) \
- { while (__i < ((fd_set *)(set))->fd_count-1) \
- { ((fd_set *)(set))->fd_array[__i] \
- = ((fd_set *)(set))->fd_array[__i + 1]; __i++; \
- } \
- ((fd_set *)(set))->fd_count--; \
- break; \
- } \
- } \
- } while (0)
-#endif /* ! defined FD_CLR */
+/* Microsoft provide this library function equivalent of the FD_ISSET
+ * macro, and erroneously claim that it is neccessary to implement the
+ * macro. We could just as easily implement it entirely inline...
+ */
+int PASCAL __WSAFDIsSet (SOCKET, fd_set *);
+/* ...but, given the availability of the library function, we may just
+ * as well use it.
+ */
+__CRT_ALIAS int __FD_ISSET( SOCKET __fd, fd_set *__set )
+{ return __WSAFDIsSet (__fd, __set); }
+#endif /* ! defined FD_ISSET */
#ifndef FD_SET
-#define FD_SET( fd, set ) do \
- { if (((fd_set *)(set))->fd_count < FD_SETSIZE) \
- ((fd_set *)(set))->fd_array[((fd_set *)(set))->fd_count++] = (fd); \
- } while (0)
+void FD_SET (SOCKET, fd_set *);
+#define FD_SET( __fd, __set ) __FD_SET ((__fd), (__set))
+__CRT_ALIAS void __FD_SET (SOCKET __fd, fd_set *__set)
+{ if( (__set->fd_count < FD_SETSIZE) && ! FD_ISSET (__fd, __set) )
+ __set->fd_array[__set->fd_count++] = __fd;
+}
#endif /* ! defined FD_SET */
+#ifndef FD_CLR
+void FD_CLR (SOCKET, fd_set *);
+#define FD_CLR( __fd, __set ) __FD_CLR ((__fd), (__set))
+__CRT_ALIAS void __FD_CLR (SOCKET __fd, fd_set *__set)
+{ u_int __m, __n; for (__m = __n = 0; __n < __set->fd_count; __n++)
+ { if (__fd != __set->fd_array[__n])
+ { if (__m < __n) __set->fd_array[__m] = __set->fd_array[__n];
+ ++__m;
+ }
+ } __set->fd_count = __m;
+}
+#endif /* ! defined FD_CLR */
+
#ifndef FD_ZERO
-#define FD_ZERO( set ) (((fd_set *)(set))->fd_count = 0)
+void FD_ZERO (fd_set *);
+#define FD_ZERO( __set ) __FD_ZERO (__set)
+__CRT_ALIAS void __FD_ZERO (fd_set *__set)
+{ __set->fd_count = 0; }
#endif /* ! defined FD_ZERO */
-#ifndef FD_ISSET
-#define FD_ISSET( fd, set ) __WSAFDIsSet((SOCKET)(fd), (fd_set *)(set))
-#endif /* ! defined FD_ISSET */
-
#elif ! defined _USE_SYS_TYPES_FD_SET
/* Definitions from <sys/types.h> probably aren't what the user wants;
* if they know what they are doing, and they are sure that this really
#define WSAGETSELECTEVENT(l) LOWORD(l)
#define WSAGETSELECTERROR(l) HIWORD(l)
-typedef struct fd_set FD_SET, *PFD_SET, *LPFD_SET;
+typedef struct fd_set /* FD_SET, */ *PFD_SET, *LPFD_SET;
typedef struct sockaddr SOCKADDR, *PSOCKADDR, *LPSOCKADDR;
typedef struct sockaddr_in SOCKADDR_IN, *PSOCKADDR_IN, *LPSOCKADDR_IN;
typedef struct linger LINGER, *PLINGER, *LPLINGER;
#
m4_define([MINGW_AT_CHECK_WINSOCK],[dnl
AT_BANNER([Windows Sockets $1 fd_set macro checks.])
+MINGW_AT_LINK_LIBS([m4_case([$1],[v2],[-lws2_32],[-lwsock32])])
# Verify that the FD_ZERO macro clears all descriptors from the
# predefined, non-empty fd_set {1, 2, 3, 4}
# function, we must ensure that the test code is linked with
# the appropriate version of the WinSock library.
#
-MINGW_AT_LINK_LIBS([m4_case([$1],[v2],[-lws2_32],[-lwsock32])])
MINGW_AT_CHECK_FD_ISSET_MACRO([$2],[4])
MINGW_AT_CHECK_FD_ISSET_MACRO([$2],[2])