Author Topic: Networking: socket() returns positive `non-socket`  (Read 1932 times)

agena.info

  • Newbie
  • *
  • Posts: 9
  • Karma: +1/-0
    • View Profile
    • Agena Programming Language
Networking: socket() returns positive `non-socket`
« on: July 06, 2025, 08:46:50 am »
Hello,

I am having a big problem with socket programming in C:

Every time I open a socket with:

int sock = socket(AF_INET, SOCK_STREAM, 0);

and try to bind or connect later on I get an 38 error code, claiming that these functions have been called with a non-socket (`Socket operation on non-socket`).

The result returned by socket is always a positive integer, mostly starting from 3.

I even included a call to the undocumented addsockettolist() function after opening the socket, but to no avail.

What am I doing wrong ?  I use ArcaOS 5.0.6 and Paul Smedley's GCC 4.4.6 and 8.3.0. I do not use any OS/2-specific flags like _EMX_TCPIP or TCPV40HDRS in the code (they wouldn't help anyway). Do I need to load any specific TCP/IP-related drivers during boot time other than the ones that are already included in CONFIG.SYS, or do I have to link against additional TCP/IP-specific libraries other than socket (-lsocket flag) ?

The C code that is run on ArcaOS to open, bind, connect, etc. is the very same as with Windows, Solaris, Linux, Mac OS X, where everyting works fine.

Any help would be appreciated.

Thank you,

Alex
« Last Edit: July 06, 2025, 09:00:33 am by agena.info »

Dave Yeo

  • Hero Member
  • *****
  • Posts: 5475
  • Karma: +132/-1
    • View Profile
Re: Networking: socket() returns positive `non-socket`
« Reply #1 on: July 06, 2025, 09:07:40 pm »
Post to the latest thread.
I'd patiently wait for a response from someone who knows this stuff. For many it is a long weekend.
Which headers are you using? Are you linking against libcx (-lcx). Also what cflags/ldflags are you using?

Steven Levine

  • Jr. Member
  • **
  • Posts: 87
  • Karma: +12/-0
    • View Profile
Re: Networking: socket() returns positive `non-socket`
« Reply #2 on: July 07, 2025, 02:42:50 am »
As Dave mentioned, we need know a bit more about your development setup and build options.

Since you are building with gcc, I'm going to assume for now that you are building with kLIBC and you are using the most recent versions of libn0.dll and libcx0.dll from the netlabs repos.

You should be using the OS/2 toolkit headers provided by the libc-devel package.  They work better with gcc and kLIBC than the IBM supplied headers.

FWIW, addsockettolist and removesocketfromlist are documented and they are used by kLIBC.  kLIBC needs them to implement fork().

Another FWIW, I have seen the ENOTSOCK failure mode when running git against large repositories on a busy system, but perhaps not for the same reason you are.  In my case the failure is intermittent and retrying the git operation when the system is less busy typically avoids the failure.

Note that OS/2 has separate namepaces for sockets and file handles, unlike Linux.  kLIBC emulates the Linux way to make porting apps simpler.  This requires using kLIBC for all file and socket operations.

agena.info

  • Newbie
  • *
  • Posts: 9
  • Karma: +1/-0
    • View Profile
    • Agena Programming Language
Re: Networking: socket() returns positive `non-socket`
« Reply #3 on: July 07, 2025, 01:55:49 pm »
Hello,

thanks for your two replies. What I am trying to implement is a simple IPv4 library for a fork of the Lua programming language. What works fine in Windows, Solaris, Linux and Mac obviously does not work with ArcaOS:

1) Have one C function that opens a socket and returns its descriptor, a positive integer, to the Lua environment.

2) Have additional, separate C functions that take the socket descriptor from 1) and that bind, connect, etc.

I guess that as soon as the scope of C function 1) in ArcaOS is left and the interpreter returns to the Lua environment, any info on the socket descriptor is lost and the socket is automatically closed so that all the other functions 2) reject it ?

It only works in ArcaOS if I combine a call to socket() and bind() in one and the same C function, see below, but this does not work for me.

Here are the essential code snippets, compiled with GCC 8.3.0 as follows:

gcc -o agena.exe -s agena.o -L. -lm -lagena -lm -lmapm -lz -lreadline -lncurses -ltinfo  -lhistory -liconv -lexpat -lmpfr -lgmp -lg2 -lgd -lpcre2-posix -lpcre2-8 -lfi_lib -lsocket

#include <errno.h>
#include <fcntl.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>

#include <sys/types.h>   /* to be put before sys/socket.h */
#include <stddef.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>  /* must come before arpa/inet.h */
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <unistd.h>

... further Lua-specific includes ...

The following function, successfully returns a positive socket descriptor, mostly starting from 3:

static int net_openos2 (lua_State *L) {
  int sock;
  sock = socket(AF_INET, SOCK_STREAM, 0);
  if (sock < 0) {
    errornosock(L, "socket could not be created", "net.openos2");  /* bails out */
  }
  lua_pushinteger(L, sock);
  return 1;
}

The next function net_bindos2, however, rejects the socket descriptor returned by net_openos2, and quits with a `Socket operation on non-socket` error:

static int net_bindos2 (lua_State *L) {
  struct in_addr addr;
  struct sockaddr_in server;
  int port = 1234;
  const char *address = "127.0.0.1";
  int sock = luaL_checkinteger(L, 1);
  if (sock < 2) {
    errornosock(L, "socket is invalid", "net.bindos2");  /* bails out */
  }
  /* initiate binding */
  tools_memset(&server, 0, sizeof(struct sockaddr_in));
  if ((inet_aton(address, &addr)) != 0) {  /* valid address ? */
    tools_memcpy((char *)&server.sin_addr, &addr, sizeof(addr));
  } else {
    errornosock(L, "failure", "net.bindos2");  /* bails out */
  }
  server.sin_family = AF_INET;
  server.sin_port = htons(port);
  /* do it */
  if (bind(sock, (struct sockaddr*)&server, sizeof(server)) < 0) {
    agn_neterror(L);  /* bails out */
  }
  lua_pushstring(L, inet_ntoa(server.sin_addr));
  return 1;
}

This one works fine in ArcaOS:

static int net_openandbind (lua_State *L) {
  int sock;
  struct in_addr addr;
  struct sockaddr_in server;
  int port = 1234;
  const char *address = "127.0.0.1";
  /* open socket */
  sock = socket(AF_INET, SOCK_STREAM, 0);
  if (sock < 0) {
    errornosock(L, "socket could not be created", "net.openandbind");  /* bails out */
  }
  /* initiate binding */
  tools_memset(&server, 0, sizeof(struct sockaddr_in));
  if ((inet_aton(address, &addr)) != 0) {  /* valid address ? */
    tools_memcpy((char *)&server.sin_addr, &addr, sizeof(addr));
  } else {
    errornosock(L, "failure", "net.bindos2");  /* bails out */
  }
  server.sin_family = AF_INET;
  server.sin_port = htons(port);
  /* do it */
  if (bind(sock, (struct sockaddr*)&server, sizeof(server)) < 0) {
    agn_neterror(L);  /* bails out */
  }
  lua_pushinteger(L, sock);
  return 1;
}
« Last Edit: July 07, 2025, 02:03:17 pm by agena.info »

Dave Yeo

  • Hero Member
  • *****
  • Posts: 5475
  • Karma: +132/-1
    • View Profile
Re: Networking: socket() returns positive `non-socket`
« Reply #4 on: July 07, 2025, 06:07:59 pm »
Hi, not much of a programmer so I'll let others comment on the code.
For your linking line, I'd drop the -lsocket, it's not needed with current libc. Add -lcx (libc extensions) and also use -Zomf, probably before the -L.
-Zomf will convert the object files to native OMF and use the system linker rather then the ancient ld. You may have to install watcom-wlink-hll using yum and set things up to use wl.exe as the linker. Run emxomfld with no parameters to see the needed environment variables. -Zomf is also required to use debuggers, of which only native ones work.
Once working -Zhigh-mem is a good LDFLAG to use memory in the high arena (above 1GB). -Zmap is handy to build a map file for debugging purposes.

Is there a reason not to start out using the yum installed GCC 9.2.0? Includes, libs etc will just work and after you have it working, you can rebuild with the older GCC's if you choose.

agena.info

  • Newbie
  • *
  • Posts: 9
  • Karma: +1/-0
    • View Profile
    • Agena Programming Language
Re: Networking: socket() returns positive `non-socket`
« Reply #5 on: July 07, 2025, 06:49:18 pm »
Hi Dave,

thank you so much for your help and the great tips you have given me over all the many years to get my interpreter running in OS/2.

I just discovered that I have already GCC 9.2.0 installed but any compilation attempt fails because of this `swab`conflict that has been haunting me for years.

I will try all your other tips now.

Thanks again,

Alex

Steven Levine

  • Jr. Member
  • **
  • Posts: 87
  • Karma: +12/-0
    • View Profile
Re: Networking: socket() returns positive `non-socket`
« Reply #6 on: July 07, 2025, 10:31:59 pm »
Are your C functions statically linked into agena.exe?  It's not clear from your example.

If your C functions are linked into agena.exe or are in a DLL linked to agena, baring defects, the code should work as you expect.

While sock only has a value during the function call, you have exported the value to L and I assume the exported value is global and persistent.

I recommend adding a bit of debugging code to printf the value of sock in both functions.

Just returning from a function call is not going to close the socket.  The socket will stay open until explicitly closed by your code or when the executable terminates.

You can watch the state of the socket with netstat -s.

To understand how kLIBC maps sockets to file handles see:

  src\emx\src\libsocket\socket.c:41
  int socket(int af, int type, int protocol)

at

  https://github.com/bitwiseworks/libc

agena.info

  • Newbie
  • *
  • Posts: 9
  • Karma: +1/-0
    • View Profile
    • Agena Programming Language
Re: Networking: socket() returns positive `non-socket`
« Reply #7 on: July 07, 2025, 11:16:05 pm »
Hello Steven,

thank you for your kind answer. It does not work with either statically or dynamcially linked Agena. Checking my vintage OS2World questions about the same subject ten years ago and my change logs, my ipv4 package has actually never worked on OS/2, eCS and ArcaOS.

It's a real pity. I will check your tip on src\emx\src\libsocket\socket.c, though. Maybe it will give me a clue.

> Just returning from a function call is not going to close the socket. The socket will stay open until explicitly closed by your code or when the executable terminates.

Frightening Google AI tells me the very same: a socket assertively is not bound to any scope and can only be closed explicitly by the user, not the OS.

My own experiments, though, tell me the opposite as proven by my own experiments, see above. ArcaOS only shows this strange behaviour. The very same code works beautifully in Windows, Solaris, Linux and Mac OS X, with even Valgrind not complaining about anything there.

Yours,

Alex
« Last Edit: July 07, 2025, 11:29:17 pm by agena.info »

Dave Yeo

  • Hero Member
  • *****
  • Posts: 5475
  • Karma: +132/-1
    • View Profile
Re: Networking: socket() returns positive `non-socket`
« Reply #8 on: July 07, 2025, 11:22:35 pm »

I just discovered that I have already GCC 9.2.0 installed but any compilation attempt fails because of this `swab`conflict that has been haunting me for years.


Hi Alex, what error does the 'swab' conflict give?

agena.info

  • Newbie
  • *
  • Posts: 9
  • Karma: +1/-0
    • View Profile
    • Agena Programming Language
Re: Networking: socket() returns positive `non-socket`
« Reply #9 on: July 07, 2025, 11:45:28 pm »
Dave,

in file included from agnhlps.c:67:

C:/usr/lib/gcc/i686-pc-os2-emx/9/include-fixed/unistd.h:478:7: error: conflicting types for 'swab'
 478 | void  swab(const void * __restrict, void __restrictm ssize_t);
 
In file included from agnhlps.c:14:
C:/usr/include/string.h:122:7: note: previous declaration of 'swab' was here
 122 | void  swab(const void *, void *, size_t);
 
The agnhlps.c file is my own collection of primarily math and string-related C functions.

If I initiate Pauls's GCC 4.4.6 or 8.3.0 via

usr\local446\gcc446   or
usr\local830\gcc830

everything is working fine, though, and no such messages show up.

The sources are all here:

https://sourceforge.net/projects/agena/files/Sources/agena-5.1.1-src.tar.gz/download

but surely: do not study them.

Dave, this is not for you but for the ArcaOS team who might read this once upon a time:

I am expecting a fully working out-of-the-box GCC environment for my paid ArcaOS licence, EUR 150.-, not experiencing this weird behaviour, see above:

socket() and bind() in just one C function -> everything is fine
socket() and bind() split upon two C functions -> does not work

Yours,

Alex
« Last Edit: July 08, 2025, 12:16:19 am by agena.info »

Dave Yeo

  • Hero Member
  • *****
  • Posts: 5475
  • Karma: +132/-1
    • View Profile
Re: Networking: socket() returns positive `non-socket`
« Reply #10 on: July 08, 2025, 05:14:12 am »
So, wondering why the guard around swab in W:\usr\lib\gcc\i686-pc-os2-emx\9\include-fixed\unistd.h fails for you yet the same one in unistd.h works, I thought to download the source.
Rather my sourceforge cookie expired or they've changed their code as all I get is the cloudflare verifying you are human thingy now. Tried on my phone, got something like "downloading to this device is not allowed" in 3 different browsers. Fell back to using Thunderbird, which actually still works. This is a problem on OS/2 as all our browsers fail to get by cloudflare now. Previously I've been asked for help downloading agena due to cloudflare and due to having a cookie, I could.
Next problem, makefile.os2 says https://sourceforge.net/projects/agena/files/Packages/mapmagena-1.1.2a.tar.gz/download is a prerequisite. Sourceforge says it doesn't exist. So using Thunderbird, I found mapmagena-2.0.4.tar.gz in your files area.
I'll try compiling soon.
BTW, Arca Noae does not support GCC and recommends using OpenWatcom, see https://www.arcanoae.com/wiki/information-for-developers/ Most of GCC development is done by Paul now, previously Bitwise who helped Paul and tweaked 9.2.0 and for klibc, originally IBM paid for it to build Mozilla.
« Last Edit: July 08, 2025, 05:20:12 am by Dave Yeo »

KO Myung-Hun

  • Jr. Member
  • **
  • Posts: 82
  • Karma: +11/-0
    • View Profile
Re: Networking: socket() returns positive `non-socket`
« Reply #11 on: July 08, 2025, 06:03:47 am »
@agena.info

I have some questions.

1. net_openos2() and net_bindos2() are called in the same process ?
2. What is the result of fstat() in net_bindos2() when returing 'Socket operation on non-socket' error ? And what is the value of (stat.st_mode & S_IFMT) ?

Dave Yeo

  • Hero Member
  • *****
  • Posts: 5475
  • Karma: +132/-1
    • View Profile
Re: Networking: socket() returns positive `non-socket`
« Reply #12 on: July 08, 2025, 06:47:11 am »
Building agena with makefile.os2 renamed to makefile, so 'make os2' with gcc 9.2.0 dies with,
Code: [Select]
make all MYCFLAGS="-O2 -static-libgcc -DLUA_BUILD_AS_DLL -D_FILE_OFFSET_BITS=64 -D_DIRENT_HAVE_D_TYPE -DPCRE2_CODE_UNIT_WIDTH=8 -D__ST_MT_ERRNO__ -DLUA_USE_LINUX -DINCL_BASE -DHAVE_NCURSES_H"
make[1]: Entering directory 'H:/tmp/agena-5.1.1-src/src'
gcc -Wall -Wno-attributes -Wno-strict-aliasing -Wno-deprecated-declarations -Wno-unknown-pragmas -fgnu89-inline -fomit-frame-pointer -DLUA_BUILD_AS_DLL -D_FILE_OFFSET_BITS=64 -D_DIRENT_HAVE_D_TYPE -DPCRE2_CODE_UNIT_WIDTH=8 -D__ST_MT_ERRNO__ -DLUA_USE_LINUX -DINCL_BASE -DHAVE_NCURSES_H -O2 -static-libgcc -DLUA_BUILD_AS_DLL -D_FILE_OFFSET_BITS=64 -D_DIRENT_HAVE_D_TYPE -DPCRE2_CODE_UNIT_WIDTH=8 -D__ST_MT_ERRNO__ -DLUA_USE_LINUX -DINCL_BASE -DHAVE_NCURSES_H   -c -o lvm.o lvm.c
In file included from ldo.h:11,
                 from lvm.h:10,
                 from lvm.c:24:
lvm.c: In function 'luaV_execute':
lobject.h:217:37: error: incompatible types when assigning to type 'complex double' from type 'lua_Number *' {aka 'double *'}
  217 |   { TValue *i_o=(obj); i_o->value.c=(x); i_o->tt=LUA_TCOMPLEX; }
      |                                     ^
lvm.c:9121:15: note: in expansion of macro 'setcvalue'
 9121 |               setcvalue(ra, z);
      |               ^~~~~~~~~
make[1]: *** [<builtin>: lvm.o] Error 1
make[1]: Leaving directory 'H:/tmp/agena-5.1.1-src/src'
make: *** [makefile:117: os2] Error 2

Similar error with gcc 4.4.6, just less informative.
Need a cast?

Lars

  • Hero Member
  • *****
  • Posts: 1444
  • Karma: +72/-0
    • View Profile
Re: Networking: socket() returns positive `non-socket`
« Reply #13 on: July 08, 2025, 08:45:15 am »
1) Have one C function that opens a socket and returns its descriptor, a positive integer, to the Lua environment.

2) Have additional, separate C functions that take the socket descriptor from 1) and that bind, connect, etc.

I guess that as soon as the scope of C function 1) in ArcaOS is left and the interpreter returns to the Lua environment, any info on the socket descriptor is lost and the socket is automatically closed so that all the other functions 2) reject it ?

What exactly do you want to say with "the interpreter returns to the Lua environment" ? Your agena.exe code sample is a self-contained executable. I cannot see anything returning to anywhere (granted that the code sample is not complete ...).

I could image that if the "socket" implementation maps socket handles to "virtual" file handles that then handle inheritance and such come into play. That would mean that you will have to know what process or processes access these handles. I have no clue how you would make a socket handle created in process A known to a process B but I suppose that there are ways to do that.
Another thing that I could think of (intentionally or erroneously) is if there is some "tcperrno" variable that might get globally set and that you might have to reset before a call.
I hope that you will only ever get a socket handle >= 3. Because 0 would be for stdin, 1 for stdout and 2 for stderr if we follow the logic that socket handles are mapped to file handles.
« Last Edit: July 08, 2025, 08:56:47 am by Lars »

Lars

  • Hero Member
  • *****
  • Posts: 1444
  • Karma: +72/-0
    • View Profile
Re: Networking: socket() returns positive `non-socket`
« Reply #14 on: July 08, 2025, 09:04:11 am »
Building agena with makefile.os2 renamed to makefile, so 'make os2' with gcc 9.2.0 dies with,
Code: [Select]
make all MYCFLAGS="-O2 -static-libgcc -DLUA_BUILD_AS_DLL -D_FILE_OFFSET_BITS=64 -D_DIRENT_HAVE_D_TYPE -DPCRE2_CODE_UNIT_WIDTH=8 -D__ST_MT_ERRNO__ -DLUA_USE_LINUX -DINCL_BASE -DHAVE_NCURSES_H"
make[1]: Entering directory 'H:/tmp/agena-5.1.1-src/src'
gcc -Wall -Wno-attributes -Wno-strict-aliasing -Wno-deprecated-declarations -Wno-unknown-pragmas -fgnu89-inline -fomit-frame-pointer -DLUA_BUILD_AS_DLL -D_FILE_OFFSET_BITS=64 -D_DIRENT_HAVE_D_TYPE -DPCRE2_CODE_UNIT_WIDTH=8 -D__ST_MT_ERRNO__ -DLUA_USE_LINUX -DINCL_BASE -DHAVE_NCURSES_H -O2 -static-libgcc -DLUA_BUILD_AS_DLL -D_FILE_OFFSET_BITS=64 -D_DIRENT_HAVE_D_TYPE -DPCRE2_CODE_UNIT_WIDTH=8 -D__ST_MT_ERRNO__ -DLUA_USE_LINUX -DINCL_BASE -DHAVE_NCURSES_H   -c -o lvm.o lvm.c
In file included from ldo.h:11,
                 from lvm.h:10,
                 from lvm.c:24:
lvm.c: In function 'luaV_execute':
lobject.h:217:37: error: incompatible types when assigning to type 'complex double' from type 'lua_Number *' {aka 'double *'}
  217 |   { TValue *i_o=(obj); i_o->value.c=(x); i_o->tt=LUA_TCOMPLEX; }
      |                                     ^
lvm.c:9121:15: note: in expansion of macro 'setcvalue'
 9121 |               setcvalue(ra, z);
      |               ^~~~~~~~~
make[1]: *** [<builtin>: lvm.o] Error 1
make[1]: Leaving directory 'H:/tmp/agena-5.1.1-src/src'
make: *** [makefile:117: os2] Error 2

Similar error with gcc 4.4.6, just less informative.
Need a cast?

I`d try this:
 { TValue *i_o=(obj); i_o->value.c=(*(complex *)(x)); i_o->tt=LUA_TCOMPLEX; }

Looks like the macro is being passed a pointer to double whereas the macro itself uses "complex" which is likely a struct with 2 doubles.
« Last Edit: July 08, 2025, 09:09:02 am by Lars »