@@ -385,6 +385,7 @@ iperf_udp_accept(struct iperf_test *test)
385385 socklen_t len ;
386386 int sz , s ;
387387 int rc ;
388+ int port ;
388389
389390 /*
390391 * Get the current outstanding socket. This socket will be used to handle
@@ -455,11 +456,30 @@ iperf_udp_accept(struct iperf_test *test)
455456 }
456457 }
457458
459+ port = test -> server_port ;
460+ buf = UDP_CONNECT_REPLY ;
461+
462+ /*
463+ * Since Windows does not support parallel UDP streams using the same local and remote ports,
464+ * different server port is used for each steam - indicated by replying with UDP_CONNECT_REPLY_NEXT_PORT.
465+ * Each stream, the listening port number is increased by 1.
466+ */
467+ #if (defined(WINDOWS_ANY ))
468+ if (test -> num_server_ports > 1 ) {
469+ test -> server_udp_streams_accepted ++ ;
470+
471+ /* Change port number for next stream (but not for the last for backward compatibility) */
472+ if (test -> server_udp_streams_accepted < test -> num_streams * ((test -> bidirectional ? 2 : 1 ))) {
473+ port += test -> server_udp_streams_accepted ;
474+ buf = UDP_CONNECT_REPLY_NEXT_PORT ;
475+ }
476+ }
477+ #endif /* WINDOWS_ANY */
478+
458479 /*
459480 * Create a new "listening" socket to replace the one we were using before.
460481 */
461- FD_CLR (test -> prot_listener , & test -> read_set ); // No control messages from old listener
462- test -> prot_listener = netannounce (test -> settings -> domain , Pudp , test -> bind_address , test -> bind_dev , test -> server_port );
482+ test -> prot_listener = netannounce (test -> settings -> domain , Pudp , test -> bind_address , test -> bind_dev , port );
463483 if (test -> prot_listener < 0 ) {
464484 i_errno = IESTREAMLISTEN ;
465485 return -1 ;
@@ -468,8 +488,10 @@ iperf_udp_accept(struct iperf_test *test)
468488 FD_SET (test -> prot_listener , & test -> read_set );
469489 test -> max_fd = (test -> max_fd < test -> prot_listener ) ? test -> prot_listener : test -> max_fd ;
470490
471- /* Let the client know we're ready "accept" another UDP "stream" */
472- buf = UDP_CONNECT_REPLY ;
491+ /*
492+ * Let the client know we're ready "accept" another UDP "stream",
493+ * and send the listening port when applicable.
494+ */
473495 if (write (s , & buf , sizeof (buf )) < 0 ) {
474496 i_errno = IESTREAMWRITE ;
475497 return -1 ;
@@ -606,19 +628,34 @@ iperf_udp_connect(struct iperf_test *test)
606628 do {
607629 if ((sz = recv (s , & buf , sizeof (buf ), 0 )) < 0 ) {
608630 i_errno = IESTREAMREAD ;
631+ if (test -> num_server_ports > 1 && test -> num_streams > 1 ) {
632+ iperf_err (test , "accept response receive failed - may be caused by an old Windows client that does not support parallel UDP streams" );
633+ }
609634 return -1 ;
610635 }
611636 if (test -> debug ) {
612637 printf ("Connect received for Socket %d, sz=%d, buf=%x, i=%d, max_len_wait_for_reply=%d\n" , s , sz , buf , i , max_len_wait_for_reply );
613638 }
614639 i += sz ;
615- } while (buf != UDP_CONNECT_REPLY && buf != LEGACY_UDP_CONNECT_REPLY && i < max_len_wait_for_reply );
640+ } while (buf != UDP_CONNECT_REPLY && buf != UDP_CONNECT_REPLY_NEXT_PORT && buf != LEGACY_UDP_CONNECT_REPLY && i < max_len_wait_for_reply );
616641
617- if (buf != UDP_CONNECT_REPLY && buf != LEGACY_UDP_CONNECT_REPLY ) {
642+ /*
643+ * Since Windows does not support parallel UDP streams using the same local and remote ports,
644+ * different server port is used for each steam - indicated by UDP_CONNECT_REPLY_NEXT_PORT.
645+ */
646+ if (buf != UDP_CONNECT_REPLY && buf != UDP_CONNECT_REPLY_NEXT_PORT && buf != LEGACY_UDP_CONNECT_REPLY ) {
618647 i_errno = IESTREAMREAD ;
619648 return -1 ;
620649 }
621650
651+ /*
652+ * On WIndows, to overcome the limit of not supporting parallel UDP streams using the same port,
653+ * `buf` will be UDP_CONNECT_REPLY_NEXT_PORT - indicating different server port for the next connection.
654+ */
655+ if (buf == UDP_CONNECT_REPLY_NEXT_PORT ) {
656+ test -> server_port += 1 ;
657+ }
658+
622659 return s ;
623660}
624661
0 commit comments