0

All my experience in networking has been on linux so I'm an absolute beginner at windows networking. This is probably a stupid question but I can't seem to find the answer anywhere. Consider the following code snippet:

    DWORD Index = WSAWaitForMultipleEvents(EventTotal, EventArray, FALSE, WSA_INFINITE, FALSE);
    WSAResetEvent( EventArray[Index - WSA_WAIT_EVENT_0]);

Every time an event is selected from the EventArray WSA_WAIT_EVENT_0 is subtracted from the index but WSA_WAIT_EVENT_0 is defined in winsock2.h as being equal to zero.

Why is code cluttered with this seemingly needless subtraction? Obviously the compiler will optimize it out but still don't understand why it's there.

poby
  • 1,572
  • 15
  • 39
  • 1
    this is done for for greater clarity and self-documentability of the code. the value of `WSA_WAIT_EVENT_0` of course can not be changed - it always will be 0 in all versions – RbMm Jun 18 '18 at 10:09

2 Answers2

1

The fact that WSA_WAIT_EVENT_0 is defined as 0 is irrelevant (it is just an alias for WAIT_OBJECT_0 from the WaitFor(Single|Multiple)Object(s)() API, which is also defined as 0 - WSAWaitForMultipleEvents() is itself just a wrapper for WaitForMultipleObjectsEx(), though Microsoft reserves the right to change the implementation in the future without breaking existing user code).

WSAWaitForMultipleEvents() can operate on multiple events at a time, and its return value will be one of the following possibilities:

WSA_WAIT_EVENT_0 .. (WSA_WAIT_EVENT_0 + cEvents - 1)

A specific event object was signaled.

WSA_WAIT_IO_COMPLETION

One or more alertable I/O completion routines were executed.

WSA_WAIT_TIMEOUT

A timeout occurred.

WSA_WAIT_FAILED

The function failed.

Typically, code should be looking at the return value and act accordingly, eg:

DWORD ReturnValue = WSAWaitForMultipleEvents(...);
if ((ReturnValue >= WSA_WAIT_EVENT_0) && (ReturnValue < (WSA_WAIT_EVENT_0 + EventTotal))
{
    DWORD Index = ReturnValue - WSA_WAIT_EVENT_0;
    // handle event at Index as needed...
}
else if (ReturnValue == WSA_WAIT_IO_COMPLETION)
{
    // handle I/O as needed...
}
else if (RetunValue == WSA_WAIT_TIMEOUT)
{
    // handle timeout as needed...
}
else
{
    // handle error as needed...
}

Which can be simplified given the fact that bAlertable is FALSE (no I/O routines can be called) and dwTimeout is WSA_INFINITE (no timeout can elapse), so there are only 2 possible outcomes - an event is signaled or an error occurred:

DWORD ReturnValue = WSAWaitForMultipleEvents(EventTotal, EventArray, FALSE, WSA_INFINITE, FALSE);
if (ReturnValue != WSA_WAIT_FAILED)
{
    DWORD Index = ReturnValue - WSA_WAIT_EVENT_0;
    WSAResetEvent(EventArray[Index]);
}
else
{
    // handle error as needed...
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
0

The documentation says it will return WSA_WAIT_EVENT_0 if event 0 was signaled, WSA_WAIT_EVENT_0 + 1 if event 1 was signaled, and so on.

Sure, they set WSA_WAIT_EVENT_0 to 0 in this version of Windows, but what if it's 1 in the next version, or 100?

user253751
  • 57,427
  • 7
  • 48
  • 90
  • `WSA_WAIT_EVENT_0` can not be changed in new versions of windows, because this is break already build binaries. it always will be 0 – RbMm Jun 18 '18 at 10:05
  • @RbMm It can be changed on different processor architectures, it can be changed if there's some way for Windows to know which version it was built for (such as a manifest), and it can be changed if Microsoft suddenly decides they don't care about backwards compatibility (e.g. it could've had a different value on UWP). You also might be using some kind of Windows simulator library to port to Linux (for example) which would require recompiling and might not have the value of 0 (because the library authors also read the documentation). – user253751 Jun 19 '18 at 00:17
  • this is of course absolute not depend from processor architectures. if Microsoft suddenly decides not support all already build app, which use and hard-code this value - yes, can change. – RbMm Jun 19 '18 at 07:53