stephane / libmodbus

A Modbus library for Linux, Mac OS, FreeBSD and Windows
http://libmodbus.org
GNU Lesser General Public License v2.1
3.44k stars 1.75k forks source link

errno not propagated between DLLs on Windows #579

Closed ralfixx closed 3 years ago

ralfixx commented 3 years ago

libmodbus version

libmodbus-3.1.6

OS and/or distribution

Windows 10

Environment

64bit

References

Socket brutally closed by peer not correctly detected #133 errno not reliable on Windows #349 Error codes on Windows #571

Description

Modbus over TCP

On Windows, errno is not propagated properly between DLLs, so the mechanism used in libmodbus to transport error information does not work properly there. My DLL contains code like

   int rc = modbus_receive_message(...);
   if (-1 == rc) {
    if (ECONNRESET == errno)  // handle "connection reset"

When the TCP connection is closed by the remote side, the recv() which is eventually called returns 0 as documented which then is turned into "errno = ECONNRESET" by _modbus_receive_message(). But when the call returns to my DLL, the errno there is set to some other value. This is due to Windows not sharing these globals between DLLs/modules. Even calling _set_errno() in libmodbus and _get_errno() in my DLL return different values. I confirmed in the debugger that "errno" points to different memory locations in libmodbus and my DLL.

IMHO a possibly solution would be to add an "errnum" member to the modbus context and set that, so the calling code could inspect the errno from there. I would wrap that in

int modbus_set_errno(modbus_t *ctx, int errnum) {
  // set both errno and ctx->errnum
}
int modbus_get_errno(modbus_t *ctx) {
  return ctx->errnum;
}

where libmodbus code would need to change

errno = ECONNRESET;
=>
modbus_set_errno(ctx, ECONNRESET);

and client code addressing windows

if (-1 == modbus_xxx()) {
  if (ECONNRESET == errno)
  =>
  if (ECONNRESET == modbus_get_errno(ctx)

This way also the difference between windows socket functions requiring WSAGetLastError() calls to obtain error information could be addressed, plus client code on Linux would not need to change at all (since errno works properly there).

I would be willing to provide patches if required.

ralfixx commented 3 years ago

Please disregard this issue. The proper solution is noted in Change the "modbus.vcproj" Visual Studio project file in order to correct an ERRNO problem in the Win32 platform #485 The modbus DLL and all code using it needs to get compiled with /MD compiler flag, not /MT. It would be very nice if the provided Visual Studio Project files in src/win32 could get adjusted ASAP.