Lazarus

Free Pascal => Unix => Topic started by: TCH on February 15, 2025, 11:53:59 pm

Title: Can't find unit unixsockets
Post by: TCH on February 15, 2025, 11:53:59 pm
I am porting some C code to FreePascal which relies on macros like CMSG_LEN, CMSG_DATA, etc. and types like struct msghdr, struct cmsghdr, etc.

I found these listed in here (https://www.freepascal.org/daily/packages/libc/libc/index-8.html); for instance: https://www.freepascal.org/daily/packages/libc/libc/cmsghdr.html (https://www.freepascal.org/daily/packages/libc/libc/cmsghdr.html). It says, it is in unit libc. However, after putting uses libc into the code, i get this message:
Code: [Select]
Fatal: Can't find unit libc used by unit_nameAfter some searching for this error message, i found this topic (https://forum.lazarus.freepascal.org/index.php?topic=12865.0) and this manual page (https://wiki.lazarus.freepascal.org/libc_unit).
Okay, so unit libc is not allowed. But what to use instead? The manuals do not say at all...

After some more searching, i found this mail thread (https://lists.freepascal.org/fpc-pascal/2024-December/062741.html), which states, these are in unit unixsockets. Well, unixsockets is under packages/rtl-extra/src/unix/ all right, but when i put uses unixsockets into the code, i get this message:
Code: [Select]
Fatal: Can't find unit unixsockets used by unit nameSearching for this error message only yielded a supplementary unixsockets unit, but i'd rather use the one provided by the RTL.

How can i use CMSG_LEN, struct msghdr, etc. with FreePascal?
Title: Re: Can't find unit unixsockets
Post by: Thaddy on February 16, 2025, 12:42:06 pm
Why would you want a unit named linux sockets?
The sockets unit is pure berkely sockets, so unix sockets...
Their structures should also have equivalents in fcl-net.
Maybe you want the translated syntax to mimic the C code simply too close and so you would want to work with code that is deprecated.
Any code that requires the libc unit is deprecated, afaik, not the libc library.
This may help:
https://wiki.freepascal.org/libc_unit
That also describes you should use sockets not unixsockets.
In general it will help you port code in a more sane way,
Title: Re: Can't find unit unixsockets
Post by: Alexx2000 on February 16, 2025, 02:27:54 pm
Quote
How can i use CMSG_LEN, struct msghdr, etc. with FreePascal?
Something like this (https://github.com/doublecmd/doublecmd/blob/master/src/rpc/sys/unix/ulocalsockets.pas).
Title: Re: Can't find unit unixsockets
Post by: Thaddy on February 16, 2025, 02:30:16 pm
That would do the trick.. 8)
Title: Re: Can't find unit unixsockets
Post by: TCH on February 16, 2025, 04:35:39 pm
Why would you want a unit named linux sockets?
The sockets unit is pure berkely sockets, so unix sockets...
:o What...? Seriously...what? Who wanted a unit named linux sockets? I explicitly wrote unixsockets several times. My post did not even contain the word "Linux". I have no idea what are you talking about.
Their structures should also have equivalents in fcl-net.
Which are...?
Maybe you want the translated syntax to mimic the C code simply too close and so you would want to work with code that is deprecated.
Any code that requires the libc unit is deprecated, afaik, not the libc library.
This may help:
https://wiki.freepascal.org/libc_unit
I know. I've even linked in the very same manual page what you did...
That also describes you should use sockets not unixsockets.
In general it will help you port code in a more sane way,
sockets has already been pulled in (i just forgot to mention it), but it did not provide CMSG_LEN and the rest.
Quote
How can i use CMSG_LEN, struct msghdr, etc. with FreePascal?
Something like this (https://github.com/doublecmd/doublecmd/blob/master/src/rpc/sys/unix/ulocalsockets.pas).
Thank you, but this is also just a supplementary unixsockets unit, just like the one (https://lists.freepascal.org/pipermail/fpc-pascal/2014-June/042244.html) made by md (https://forum.lazarus.freepascal.org/index.php?action=profile;u=55475) and what i use now. I'd like to stick to the RTL. Or do you mean, it is not possible to do it with unixsockets and that one has to provide those functions and structures by hand?
Title: Re: Can't find unit unixsockets
Post by: Alexx2000 on February 16, 2025, 04:54:05 pm
I guess unixsockets unit simply is not installed (binary unixsockets.ppu). What Linux distro do you use?
Title: Re: Can't find unit unixsockets
Post by: TCH on February 16, 2025, 04:58:16 pm
Debian 11, but i use the packages provided by the Lazarus Team, not by Debian Team. unixsockets.pp does exist in packages/rtl-extra/src/unix/. You say, it should be compiled to a PPU? I thought FreePascal automatically does that: if the .ppu does not exist, but the .pp or .pas does, then it compiles the source to a binary unit. Or that only applies to the local units, not the global ones?
Title: Re: Can't find unit unixsockets
Post by: Alexx2000 on February 16, 2025, 05:03:05 pm
Quote
You say, it should be compiled to a PPU?
Yes. It is a standard practice of binary distro.

Quote
I thought FreePascal automatically does that
It can do it. But only if unit in the unit search paths.
Title: Re: Can't find unit unixsockets
Post by: TCH on February 16, 2025, 05:17:18 pm
I see, thank you. I've tried to do fpc unixsockets.pp, but:
Code: [Select]
Free Pascal Compiler version 3.2.2 [2021/07/09] for x86_64
Copyright (c) 1993-2021 by Florian Klaempfl and others
Target OS: Linux for x86-64
Compiling unixsockets.pp
unixsockets.pp(12,2) Warning: Illegal compiler directive "$UNIXSOCKETSH"
unixsockets.pp(16,2) Warning: Illegal compiler directive "$UNIXSOCKETS"
19 lines compiled, 0.0 sec
2 warning(s) issued
The PPU was created, but i guess it is erroneous. Or not? What flags i should provide?
Title: Re: Can't find unit unixsockets
Post by: Alexx2000 on February 16, 2025, 05:35:57 pm
Looks like this unit are buggy. It should be:
Code: Pascal  [Select][+][-]
  1. unit unixsockets;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. {$packrecords C}
  6.  
  7. interface
  8.  
  9. uses
  10.   cTypes, BaseUnix;
  11.  
  12. {$I unixsocketsh.inc}
  13.  
  14. implementation
  15.  
  16. {$I unixsockets.inc}
  17.  
  18. end.
  19.  
also you need to have files:
Quote
rtl-extra\src\linux\unixsockets.inc
rtl-extra\src\linux\unixsocketsh.inc
in the include files search paths.

It looks like no one has even tried to compile it.
Title: Re: Can't find unit unixsockets
Post by: TCH on February 16, 2025, 05:57:50 pm
Thanks, i fixed the file, but i cannot compile it. I tried to include the path with both -I and -Fi, but no avail. I tried /usr/share/fpcsrc/3.2.2/packages/rtl-extra/src/linux/, 3.2.2/packages/rtl-extra/src/linux/, packages/rtl-extra/src/linux/ and rtl-extra/src/linux/, but:
Code: [Select]
unixsockets.pp(12,2) Fatal: Cannot open include file "$unixsocketsh.inc"The file does exist, i've checked it.
Title: Re: Can't find unit unixsockets
Post by: Alexx2000 on February 16, 2025, 06:07:17 pm
Are you fixed a unit as I show above?

Quote
-Fi/usr/share/fpcsrc/3.2.2/packages/rtl-extra/src/linux
should work.


But, looks like this unit a totally broken. I don't know why it is included in the FPC distro at all.
Title: Re: Can't find unit unixsockets
Post by: TCH on February 16, 2025, 06:28:48 pm
I did, but i screwed up, i left the dollar sign at the beginning of the files... :/

Thanks, now it tries to compile, but fails:
Code: [Select]
unixsockets.inc(12,12) Error: Identifier not found "__cmsg_nxthdr"
unixsockets.pp(20) Fatal: There were 1 errors compiling module, stopping
This is caused by rtl-extra/src/linux/unixsockets.inc:12:
Code: Pascal  [Select][+][-]
  1. function CMSG_NXTHDR(mhdr: Pmsghdr; cmsg: Pcmsghdr): Pcmsghdr;
  2. begin
  3.    Result:=__cmsg_nxthdr(mhdr, cmsg);
  4. end;
rtl-extra/src/linux/unixsockets.inc seems to be also buggy: it lacks this line:
Code: Pascal  [Select][+][-]
  1. function __cmsg_nxthdr(__mhdr:Pmsghdr; __cmsg:Pcmsghdr):Pcmsghdr;cdecl;external 'c' name '__cmsg_nxthdr';
If i include it, then it dies with this message:
Code: [Select]
unixsocketsh.inc(32,12) Error: Forward declaration not solved "CMSG_DATA(Pcmsghdr):^Byte;"Which is caused, that rtl-extra/src/linux/unixsocketsh.inc:32 says:
Code: Pascal  [Select][+][-]
  1.   function CMSG_DATA(cmsg : pcmsghdr) : Pbyte;
while rtl-extra/src/linux/unixsockets.inc:32 says:
Code: Pascal  [Select][+][-]
  1. function CMSG_DATA(cmsg: Pointer): PByte;
I am not sure, but i guess, the header is correct and the body is erroneous. After changing cmsg: Pointer to cmsg: Pcmsghdr, the unit finally compiles. Whew...

You were right. It was totally broken. Even the includes were. But now my unit finally compiles with using the bundled unixsockets unit. Thank you very much for your help. :)

I think these fixes on the unit and the includes should be sent to FPC team.
Title: Re: Can't find unit unixsockets
Post by: Thaddy on February 17, 2025, 08:18:06 am
But, looks like this unit a totally broken. I don't know why it is included in the FPC distro at all.
It should be broken, must be broken otherwise and marked as deprecated, because it is deprecated and not maintained. It's presence is unwarranted and it should be removed to prevent people using it.

I told you so, use sockets. Now somebody is writing code that is close to its grave at its conception. You should discourage such code, not try to fix it.
Title: Re: Can't find unit unixsockets
Post by: Thaddy on February 17, 2025, 08:30:38 am
Reported as request to mark deprecated on the bug tracker:
#41152 but I temporary closed it because I can provide a patch.
[edit]
Re-opened without patch. That would be counter to the report.
Title: Re: Can't find unit unixsockets
Post by: TCH on February 17, 2025, 04:51:36 pm
I told you so, use sockets.
If by sockets, you mean unit sockets, it was pulled in for other types, but did not provide CMSG_LEN and the rest.
Title: Re: Can't find unit unixsockets
Post by: MarkMLl on February 17, 2025, 05:06:04 pm
I don't like getting involved /but/...

I told you so, use sockets.
If by sockets, you mean unit sockets, it was pulled in for other types, but did not provide CMSG_LEN and the rest.

...and certain people who have been somewhat forward in telling you that you were doing everything wrong could instead have usefully turned their formidable intellects to answering your original question.

Macros, particularly function-like macros that take one or more parameters, are very poorly served by FPC.

However I have to ask here: what are you actually trying to do? I regularly mess around with sockets at a fairly low level (since the sort of thing I do isn't merely passing parameters to a website), but I don't immediately recognise the macros and structures you mention.

Obligatory xkcd https://xkcd.com/1481/

MarkMLl
Title: Re: Can't find unit unixsockets
Post by: Thaddy on February 17, 2025, 05:24:51 pm
Mark, the structures are elsewhere in the basic unix units, but may have slightly different names. After all these structures are needed for sockets.
I maintain what I stated and I still haven't seen anything that warrants NOT to mark that unit as deprecated.
Title: Re: Can't find unit unixsockets
Post by: MarkMLl on February 17, 2025, 05:40:44 pm
Mark, the structures are elsewhere in the basic unix units, but may have slightly different names. After all these structures are needed for sockets.
I maintain what I stated and I still haven't seen anything that warrants NOT to mark that unit as deprecated.

Come on, you don't weasel out of it that easily.

WHERE ARE THEY?

MarkMLl
Title: Re: Can't find unit unixsockets
Post by: Alexx2000 on February 17, 2025, 07:22:08 pm
It should be broken, must be broken otherwise and marked as deprecated

The libc unit (https://www.freepascal.org/daily/packages/libc/libc/index.html) are deprecated, unixsockets are not deprecated. But it has bugs which we discussed above.
Title: Re: Can't find unit unixsockets
Post by: MarkMLl on February 17, 2025, 07:42:29 pm
It should be broken, must be broken otherwise and marked as deprecated

The libc unit (https://www.freepascal.org/daily/packages/libc/libc/index.html) are deprecated, unixsockets are not deprecated. But it has bugs which we discussed above.

As would be apparent to anybody who took the trouble to read the thread.

In practice, I'm fairly sure that fpSend() (for connected sockets, i.e. TCP) or fpSendTo() (for unconnected sockets, i.e. UDP) would do the trick. Having said that, and emphasising that OP hasn't told us what he's actually trying to do, I do have to say that there's areas in which the network stack (as implemented in FPC's RTL) hasn't had as much love as it deserves: things like SCTP support and a few of the more obscure ways of interacting with Pascal's Input/Output devices come to mind.

MarkMLl
Title: Re: Can't find unit unixsockets
Post by: TCH on February 17, 2025, 10:29:18 pm
Macros, particularly function-like macros that take one or more parameters, are very poorly served by FPC.
They were there, although as functions. But that too works for me.
However I have to ask here: what are you actually trying to do?
I was porting a C unit which transmits/receives live socket descriptors through datagram sockets. (To be able to pass an opened socket to another process.)
It should be broken, must be broken otherwise and marked as deprecated

The libc unit (https://www.freepascal.org/daily/packages/libc/libc/index.html) are deprecated, unixsockets are not deprecated. But it has bugs which we discussed above.
We've already fixed the bugs, or have we? You've fixed the unit, i've fixed the includes and now both unixsockets and my unit compile.
Sure, there is no patch (yet), but all of the fixes are documented here and there are only three small changes.

Should i make a patch?
Title: Re: Can't find unit unixsockets
Post by: MarkMLl on February 17, 2025, 11:09:15 pm
They were there, although as functions. But that too works for me.

Yes, but functions aren't macros.

Quote
I was porting a C unit which transmits/receives live socket descriptors through datagram sockets. (To be able to pass an opened socket to another process.)

OK, fpSendTo() works fine with datagrams. For strictly local use consider unix-domain sockets rather than UDP.

Quote
Should i make a patch?

Not necessarily, but you should certainly raise a bug report for those malformed include directives (possibly referencing anything incoherent that Thaddy attempted).

MarkMLl
Title: Re: Can't find unit unixsockets
Post by: TCH on February 17, 2025, 11:27:25 pm
Yes, but functions aren't macros.
I know, but in this case they were usable as a drop-in replacement.
OK, fpSendTo() works fine with datagrams. For strictly local use consider unix-domain sockets rather than UDP.
But i did use unix domain sockets; they can be datagram ones and AFAIK to pass an FD to another process, one has to use datagram sockets. (Fixme?)
Not necessarily, but you should certainly raise a bug report for those malformed include directives (possibly referencing anything incoherent that Thaddy attempted).
Okay. Where should i do that? On SourceForge, or GitLab, or GitHub, or here in a specific zone/group?

Edit: Okay, i found, that it is GitLab. (https://wiki.freepascal.org/How_do_I_create_a_bug_report)

Edit: But i cannot log in to my GitLab account, because that stupid CloudFlare botchecker does not let me in. From Chromium, it simply gives back the checkbox each time i check in and from Pale Moon it simply never gives the checkbox. Great...
Title: Re: Can't find unit unixsockets
Post by: MarkMLl on February 18, 2025, 09:19:00 am
I know, but in this case they were usable as a drop-in replacement.

Yes, it's the only way to do it but there's things that quite simply can't be expressed like that.

Quote
But i did use unix domain sockets; they can be datagram ones and AFAIK to pass an FD to another process, one has to use datagram sockets. (Fixme?)

I don't entirely understand what you're doing with FDs, and it sounds- at the minimum- to be highly OS-specific (i.e. even if it works on Linux it might not work on Berkeley derivatives). But if you can do something with unix domain sockets, then I see no reason why UDP wouldn't work... until somebody tried to use it to send info between different hosts, or potentially different namespaces (i.e. containers etc.).

Quote
Okay. Where should i do that? On SourceForge, or GitLab, or GitHub, or here in a specific zone/group?

Edit: Okay, i found, that it is GitLab. (https://wiki.freepascal.org/How_do_I_create_a_bug_report)

Edit: But i cannot log in to my GitLab account, because that stupid CloudFlare botchecker does not let me in. From Chromium, it simply gives back the checkbox each time i check in and from Pale Moon it simply never gives the checkbox. Great...

That one I can't help with, hopefully one of the core team will spot it.

MarkMLl
Title: Re: Can't find unit unixsockets
Post by: TCH on February 18, 2025, 02:26:15 pm
There is a process, which opens a listener socket and waits for incoming connections, then accepts them. Then it passes the socket descriptor of the just connected client to a worker process. That's all. This works on BSD-s too, actually the code i used to build the original C unit is a BSD4.3/BSD4.4 code (with separate branches for them), so it should work on all POSIX systems.
I don't entirely understand what you're doing with FDs, and it sounds- at the minimum- to be highly OS-specific (i.e. even if it works on Linux it might not work on Berkeley derivatives).
But if you can do something with unix domain sockets, then I see no reason why UDP wouldn't work... until somebody tried to use it to send info between different hosts, or potentially different namespaces (i.e. containers etc.).
UDP does work, these are UDP unix domain sockets. This is for incoming FD-s:
Code: Pascal  [Select][+][-]
  1. var
  2.         name: string
  3.         sock: cint;
  4.         sa: sockaddr_un;
  5.  
  6. ...
  7.  
  8.         name := '/tmp/my_socket';
  9.         fpunlink(name);
  10.         sock := fpsocket(PF_UNIX, SOCK_DGRAM, 0);
  11.         fillbyte(sa, sizeof(sockaddr_un), 0);
  12.         sa.sun_family := AF_UNIX;
  13.         sa.sun_path := name;
  14.         fpbind(sock, Psockaddr(@sa), sizeof(sa.sun_family) + length(name));
and this is for sending FD-s:
Code: Pascal  [Select][+][-]
  1. var
  2.         name: string;
  3.         sock: cint;
  4.         sa: sockaddr_un;
  5.  
  6. ...
  7.  
  8.         name := '/tmp/my_socket';
  9.         sock := fpsocket(PF_UNIX, SOCK_DGRAM, 0);
  10.         fillbyte(sa, sizeof(sockaddr_un), 0);
  11.         sa.sun_family := AF_UNIX;
  12.         sa.sun_path := name;
  13.         fpconnect(sock, Psockaddr(@sa), sizeof(sa.sun_family) + length(name));
These are unix domain sockets, but datagram ones. And through these, you can send or receive live descriptors.
Title: Re: Can't find unit unixsockets
Post by: MarkMLl on February 18, 2025, 03:01:23 pm
I think I've heard of such things, but am still somewhat wary. However

UDP does work, these are UDP unix domain sockets. This is for incoming FD-s:
Code: Pascal  [Select][+][-]
  1. ...
  2.         sock := fpsocket(PF_UNIX, SOCK_DGRAM, 0);
  3. ...

I think you mean that they're /datagram/ UD sockets, UDP looks like

Code: Pascal  [Select][+][-]
  1. ...
  2. dnsClientSocketHandle := fpSocket(PF_INET, SOCK_DGRAM, 0);
  3. ...
  4.  

MarkMLl
Title: Re: Can't find unit unixsockets
Post by: TCH on February 18, 2025, 03:44:51 pm
I was not sure. I've misinterpreted some sources and thought UDP sockets are the datagram sockets (never worked with them before), but i realized now, that UDP sockets are network datagram sockets. I used unix domain datagram sockets, not network ones, of course.

I was working with these sources (and some other snippets): passfd.c from Sampo Kellomaki (attached, inlined at the end of the post) and http://web.archive.org/web/20161002061943/http://users.cs.cf.ac.uk/Dave.Marshall/C/node28.html (http://web.archive.org/web/20161002061943/http://users.cs.cf.ac.uk/Dave.Marshall/C/node28.html)

However, with SOCK_STREAM, i could not pass FD-s. Then i found this source, with portlisten.c: https://www.mail-archive.com/kragen-hacks@canonical.org/msg00002.html (https://www.mail-archive.com/kragen-hacks@canonical.org/msg00002.html) and tried SOCK_DGRAM. And with that it worked.

passfd.c:
Code: C  [Select][+][-]
  1. /* passfd.c  -  BSD style file descriptor passing over unix domain sockets
  2.  *
  3.  * Copyright (c) 2000 Sampo Kellomaki <sampo@iki.fi>, All Rights Reserved.
  4.  * This module may be copied under the same terms as the perl itself.
  5.  *
  6.  * See also:
  7.  * recvmsg(2)
  8.  * sendmsg(2)
  9.  * Richard Stevens: Unix Network Programming, Prentice Hall, 1990; chapter 6.10
  10.  * /usr/include/socketbits.h
  11.  * /usr/include/sys/socket.h
  12.  */
  13.  
  14. #include <sys/types.h>
  15. #include <sys/socket.h>
  16. #include <sys/uio.h>
  17. #include <errno.h>
  18.  
  19. /* I test here for __sun for lack of anything better, but I
  20.  * mean Solaris 2.6. The idea of undefining SCM_RIGHTS is
  21.  * to force the headers to behave BSD 4.3 way which I have
  22.  * tested to work.
  23.  *
  24.  * In general, if you have compilation errors, you might consider
  25.  * adding a test for your platform here.
  26.  */
  27. #if defined(__sun)
  28. #undef SCM_RIGHTS
  29. #endif
  30.  
  31. #ifdef SCM_RIGHTS
  32.  
  33. /* It seems various versions of glibc headers (i.e.
  34.  * /usr/include/socketbits.h) miss one or more of these */
  35.  
  36. #ifndef CMSG_DATA
  37. # define CMSG_DATA(cmsg) ((cmsg)->cmsg_data)
  38. #endif
  39.  
  40. #ifndef CMSG_NXTHDR
  41. # define CMSG_NXTHDR(mhdr, cmsg) __cmsg_nxthdr (mhdr, cmsg)
  42. #endif
  43.  
  44. #ifndef CMSG_FIRSTHDR
  45. # define CMSG_FIRSTHDR(mhdr) \
  46.   ((size_t) (mhdr)->msg_controllen >= sizeof (struct cmsghdr)          \
  47.    ? (struct cmsghdr *) (mhdr)->msg_control : (struct cmsghdr *) NULL)
  48. #endif
  49.  
  50. #ifndef CMSG_ALIGN
  51. # define CMSG_ALIGN(len) (((len) + sizeof (size_t) - 1) \
  52.                          & ~(sizeof (size_t) - 1))
  53. #endif
  54.  
  55. #ifndef CMSG_SPACE
  56. # define CMSG_SPACE(len) (CMSG_ALIGN (len) \
  57.                          + CMSG_ALIGN (sizeof (struct cmsghdr)))
  58. #endif
  59.  
  60. #ifndef CMSG_LEN
  61. # define CMSG_LEN(len)   (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
  62. #endif
  63.  
  64. union fdmsg {
  65.         struct cmsghdr h;
  66.         char buf[CMSG_SPACE(sizeof(int))];
  67. };
  68. #endif
  69.  
  70. /* Tested to work on perl 5.005_03
  71.  *   Linux-2.2.14 glibc-2.0.7 (libc.so.6) i586  BSD4.4
  72.  *   Linux-2.0.38 glibc-2.0.7 (libc.so.6) i586  BSD4.4
  73.  *   SunOS-5.6, gcc-2.7.2.3, Sparc BSD4.3
  74.  * see also: linux/net/unix/af_unix.c
  75.  */
  76.  
  77. int
  78. sendfd(sock_fd, send_me_fd)
  79.         int sock_fd;
  80.         int send_me_fd;
  81. {
  82.         int ret = 0;
  83.         struct iovec  iov[1];
  84.         struct msghdr msg;
  85.        
  86.         iov[0].iov_base = &ret;  /* Don't send any data. Note: der Mouse
  87.                                   * <mouse@Rodents.Montreal.QC.CA> says
  88.                                   * that might work better if at least one
  89.                                   * byte is sent. */
  90.         iov[0].iov_len  = 1;
  91.        
  92.         msg.msg_iov     = iov;
  93.         msg.msg_iovlen  = 1;
  94.         msg.msg_name    = 0;
  95.         msg.msg_namelen = 0;
  96.  
  97.         {
  98. #ifdef SCM_RIGHTS
  99.                 /* New BSD 4.4 way (ouch, why does this have to be
  100.                  * so convoluted). */
  101.  
  102.                 union  fdmsg  cmsg;
  103.                 struct cmsghdr* h;
  104.  
  105.                 msg.msg_control = cmsg.buf;
  106.                 msg.msg_controllen = sizeof(union fdmsg);
  107.                 msg.msg_flags = 0;
  108.                
  109.                 h = CMSG_FIRSTHDR(&msg);
  110.                 h->cmsg_len   = CMSG_LEN(sizeof(int));
  111.                 h->cmsg_level = SOL_SOCKET;
  112.                 h->cmsg_type  = SCM_RIGHTS;
  113.                 *((int*)CMSG_DATA(h)) = send_me_fd;
  114. #else
  115.                 /* Old BSD 4.3 way. Not tested. */
  116.                 msg.msg_accrights = &send_me_fd;
  117.                 msg.msg_accrightslen = sizeof(send_me_fd);
  118. #endif 
  119.  
  120.                 if (sendmsg(sock_fd, &msg, 0) < 0) {
  121.                         ret = 0;
  122.                 } else {
  123.                         ret = 1;
  124.                 }
  125.         }
  126.         /*fprintf(stderr,"send %d %d %d %d\n",sock_fd, send_me_fd, ret, errno);*/
  127.         return ret;
  128. }
  129.  
  130. int
  131. recvfd(sock_fd)
  132.         int sock_fd;
  133. {
  134.         int count;
  135.         int ret = 0;
  136.         struct iovec  iov[1];
  137.         struct msghdr msg;
  138.        
  139.         iov[0].iov_base = &ret;  /* don't receive any data */
  140.         iov[0].iov_len  = 1;
  141.        
  142.         msg.msg_iov = iov;
  143.         msg.msg_iovlen = 1;
  144.         msg.msg_name = NULL;
  145.         msg.msg_namelen = 0;
  146.  
  147.         {
  148. #ifdef SCM_RIGHTS
  149.                 union fdmsg  cmsg;
  150.                 struct cmsghdr* h;
  151.  
  152.                 msg.msg_control = cmsg.buf;
  153.                 msg.msg_controllen = sizeof(union fdmsg);
  154.                 msg.msg_flags = 0;
  155.                
  156.                 h = CMSG_FIRSTHDR(&msg);
  157.                 h->cmsg_len   = CMSG_LEN(sizeof(int));
  158.                 h->cmsg_level = SOL_SOCKET;  /* Linux does not set these */
  159.                 h->cmsg_type  = SCM_RIGHTS;  /* upon return */
  160.                 *((int*)CMSG_DATA(h)) = -1;
  161.                
  162.                 if ((count = recvmsg(sock_fd, &msg, 0)) < 0) {
  163.                         ret = 0;
  164.                 } else {
  165.                         h = CMSG_FIRSTHDR(&msg);   /* can realloc? */
  166.                         if (   h == NULL
  167.                             || h->cmsg_len    != CMSG_LEN(sizeof(int))
  168.                             || h->cmsg_level  != SOL_SOCKET
  169.                             || h->cmsg_type   != SCM_RIGHTS ) {
  170.                                 /* This should really never happen */
  171.                                 if (h)
  172.                                   fprintf(stderr,
  173.                                     "%s:%d: protocol failure: %d %d %d\n",
  174.                                     __FILE__, __LINE__,
  175.                                     h->cmsg_len,
  176.                                     h->cmsg_level, h->cmsg_type);
  177.                                 else
  178.                                   fprintf(stderr,
  179.                                     "%s:%d: protocol failure: NULL cmsghdr*\n",
  180.                                     __FILE__, __LINE__);
  181.                                 ret = 0;
  182.                         } else {
  183.                                 ret = *((int*)CMSG_DATA(h));
  184.                                 /*fprintf(stderr, "recv ok %d\n", ret);*/
  185.                         }
  186.                 }
  187. #else
  188.                 int receive_fd;
  189.                 msg.msg_accrights = &receive_fd;
  190.                 msg.msg_accrightslen = sizeof(receive_fd);
  191.  
  192.                 if (recvmsg(sock_fd, &msg, 0) < 0) {
  193.                         ret = 0;
  194.                 } else {
  195.                         ret = receive_fd;
  196.                 }
  197. #endif
  198.         }
  199.        
  200.         /*fprintf(stderr, "recv %d %d %d %d\n",sock_fd, ret, errno, count);*/
  201.         return ret;
  202. }
  203.  
  204. /* EOF  -  passfd.c */
Title: Re: Can't find unit unixsockets
Post by: MarkMLl on February 18, 2025, 04:12:38 pm
Note that you've got PF_something (program family) and then an indication of whether something's a datagram or a stream. You've also separately got AF_something (address family).

SOCK_DGRAM usually means UDP (on PF_INET) or unix-domain sockets (on PF_UNIX), I'm not sure that SOCK_STREAM on PF_UNIX is a valid comobination.

If you're using PF_INET then you also need AF_INET to specify an IP address... minor variations in there for v6. However like a FIFO a unix-domain socket is named:

Code: Pascal  [Select][+][-]
  1. (* Return true if the parameter is blank, representing an anonymous pipe
  2.   normally set up by the shell.
  3. *)
  4. function isPipe(const name: string): boolean;
  5.  
  6. begin
  7.   result := name = ''
  8. end { isPipe } ;
  9.  
  10.  
  11. (* Return true if the parameter represents a regular file.
  12. *)
  13. function isFile(const name: string): boolean;
  14.  
  15. var
  16.   s: stat;
  17.  
  18. begin
  19.   if name = '' then
  20.     exit(false);
  21.   if fpStat(name, s{%H-}) <> 0 then
  22.     exit(false);
  23.  
  24. (* The low 9 bits of the mode are the usual permissions, the next 3 bits are  *)
  25. (* the sticky, setgid and setuid bits, leaving 4 bits to define the type of   *)
  26. (* object i.e. ordinary file, directory and so on. There might be additional  *)
  27. (* filesystem-specific attribute bits stored elsewhere, e.g. in an extension  *)
  28. (* to the inode structure.                                                    *)
  29.  
  30. // Does this need special handling for symlinks, or are they followed?
  31.  
  32.   result := ((s.st_mode and S_IFMT) = S_IFREG) or ((s.st_mode and S_IFMT) = S_IFCHR)
  33. end { isFile } ;
  34.  
  35.  
  36. (* Return true if the parameter represents a FIFO (named pipe).
  37. *)
  38. function isFifo(const name: string): boolean;
  39.  
  40. var
  41.   s: stat;
  42.  
  43. begin
  44.   if name = '' then
  45.     exit(false);
  46.   if fpStat(name, s{%H-}) <> 0 then
  47.     exit(false);
  48.  
  49. (* The low 9 bits of the mode are the usual permissions, the next 3 bits are  *)
  50. (* the sticky, setgid and setuid bits, leaving 4 bits to define the type of   *)
  51. (* object i.e. ordinary file, directory and so on. There might be additional  *)
  52. (* filesystem-specific attribute bits stored elsewhere, e.g. in an extension  *)
  53. (* to the inode structure.                                                    *)
  54.  
  55. // Does this need special handling for symlinks, or are they followed?
  56.  
  57.   result := (s.st_mode and S_IFMT) = S_IFIFO
  58. end { isFifo } ;
  59.  
  60.  
  61. (* Return true if the parameter represents a unix domain socket.
  62. *)
  63. function isUDSocket(const name: string): boolean;
  64.  
  65. var
  66.   s: stat;
  67.  
  68. begin
  69.   if name = '' then
  70.     exit(false);
  71.   if fpStat(name, s{%H-}) <> 0 then
  72.     exit(false);
  73.  
  74. (* The low 9 bits of the mode are the usual permissions, the next 3 bits are  *)
  75. (* the sticky, setgid and setuid bits, leaving 4 bits to define the type of   *)
  76. (* object i.e. ordinary file, directory and so on. There might be additional  *)
  77. (* filesystem-specific attribute bits stored elsewhere, e.g. in an extension  *)
  78. (* to the inode structure.                                                    *)
  79.  
  80. // Does this need special handling for symlinks, or are they followed?
  81.  
  82.   result := (s.st_mode and S_IFMT) = S_IFSOCK
  83. end { isUDSocket } ;
  84.  
  85.  
  86. (* Reopen something that isn't a unix-domain socket.
  87. *)
  88. procedure reopenFile(var t: Text; const n: string; alreadyClosed: boolean= false);
  89.  
  90. begin
  91.   if not alreadyClosed then
  92.     CloseFile(t);
  93.   AssignFile(t, n);
  94.   Rewrite(t)
  95. end { reopenFile } ;
  96.  
  97.  
  98. (* This is a reimplementation of the standard Connect() since it doesn't
  99.   support a unix-domain address and truncates it if told to cast it to an
  100.   inet domain address structure.
  101.  
  102.   Test using e.g.  $ nc -lkU ~/dsocket  noting the -k to prevent the listener
  103.   terminating when the writer (this program) closes the connection.
  104. *)
  105. Function Connect(Sock:longint;const addr: TUnixSockAddr;var SockIn,SockOut:text):Boolean;
  106.  
  107.  
  108.   Function DoConnect(Sock:longint;const addr: TUnixSockAddr): Boolean;
  109.  
  110.   var
  111.     res: longint;
  112.   begin
  113.     repeat
  114.       res:=fpconnect(Sock,@Addr,SizeOF(TUnixSockAddr)); (* NOTA BENE *)
  115.     until (res<>-1) or (SocketError <> EsockEINTR);
  116.     DoConnect:= res = 0;
  117.   end;
  118.  
  119.  
  120. begin
  121.   Connect:=DoConnect(Sock,addr);
  122.   If Connect then
  123.      Sock2Text(Sock,SockIn,SockOut);
  124. end { Connect } ;
  125.  
  126.  
  127. var
  128.   reopenedInput: Text;                  (* Dummy since only output is used      *)
  129.  
  130.  
  131. (* Reopen a unix-domain socket. This needs special implementation of Connect()
  132.   as above.
  133. *)
  134. procedure reopenUDSocket(var t: Text; const n: string; alreadyClosed: boolean= false);
  135.  
  136. var
  137.   skt: TSocket;
  138.   ipcAddr: TUnixSockAddr;
  139.  
  140. begin
  141.   if not alreadyClosed then
  142.     CloseFile(t);
  143.   skt:= fpSocket(PF_UNIX, SOCK_STREAM, 0);
  144.   if skt < 0 then begin
  145.     if not quiet then
  146.       WriteLn(erroutput, 'Cannot create unix-domain socket handle');
  147.     Halt(9)
  148.   end;
  149.   FillChar(ipcAddr{%H-}, SizeOf(ipcAddr), 0);
  150.   ipcAddr.family:= AF_UNIX;
  151.   StrPCopy(ipcAddr.path, n);
  152.   if not Connect(skt, ipcAddr, reopenedInput, t) then begin
  153.     if not quiet then begin
  154.       Write(erroutput, 'Cannot open unix-domain socket "' + n + '" ');
  155.       if not FileExists(n) then
  156.         WriteLn(erroutput, '(does not exist)')
  157.       else
  158.         WriteLn(erroutput, '(check listener is running)');
  159.       Halt(9)
  160.     end
  161.   end;
  162. {$push }{$I- }
  163.   Reset(reopenedInput);
  164. {$pop        }
  165.   Rewrite(t)
  166. end { reopenUDSocket } ;
  167.  

...and that you might need to remove the names from the filesystem when your program finishes, or take special precautions when it starts and finds that the name already exists.

Updated: C&P more example code so that it includes reworked Connect() etc.

MarkMLl
Title: Re: Can't find unit unixsockets
Post by: TCH on February 18, 2025, 07:57:09 pm
Note that you've got PF_something (program family) and then an indication of whether something's a datagram or a stream.
I think you meant protocol family.
SOCK_DGRAM usually means UDP (on PF_INET) or unix-domain sockets (on PF_UNIX), I'm not sure that SOCK_STREAM on PF_UNIX is a valid comobination.
It is not? This SO-topic says, it is (https://stackoverflow.com/questions/13953912/difference-between-unix-domain-stream-and-datagram-sockets):
Quote
The main difference is that one is connection based (STREAM) and the other is connection-less (DGRAM) - the difference between stream and packet oriented communication is usually much less important.

With SOCK_STREAM you still get all the connection handling, i.e. listen/accept and you can tell if a connection is closed by the other side.
Of course, he might be wrong, i am not an expert on sockets.
If you're using PF_INET then you also need AF_INET to specify an IP address...
Yep, i know, but this was IPC, not network.
...and that you might need to remove the names from the filesystem when your program finishes, or take special precautions when it starts and finds that the name already exists.
Yes, i did: i do fpunlink(name) before the fpsocket call.

Edit: Forgot to thank you for your pipe code; thanks. :)
Title: Re: Can't find unit unixsockets
Post by: MarkMLl on February 19, 2025, 09:07:15 am
I think you meant protocol family.

You are of course quite right.

Apropos _DGRAM vs _STREAM: more to the point, unix(7) says that both are acceptable, albeit with a couple of protocol caveats... and I'd need to think hard about some of the things I've used it for. However in the current case I thing it's best to focus on the "dgram vs stream" rather than "connected vs unconnected" aspect, since if you're passing block data around (i.e. FDs) you really do need datagrams.

Quote
Edit: Forgot to thank you for your pipe code; thanks. :)

You're welcome, I grabbed it in a hurry but forgot to check the dgram vs stream aspect... that might actually have all been streams since I was handling piped (etc.) data from a logic analyser to convert it into a standard format (and had checked the various channels fairly thoroughly).

MarkMLl
Title: Re: Can't find unit unixsockets
Post by: TCH on February 19, 2025, 03:51:51 pm
Apropos _DGRAM vs _STREAM: more to the point, unix(7) says that both are acceptable, albeit with a couple of protocol caveats... and I'd need to think hard about some of the things I've used it for. However in the current case I thing it's best to focus on the "dgram vs stream" rather than "connected vs unconnected" aspect, since if you're passing block data around (i.e. FDs) you really do need datagrams.
So, that's why SOCK_STREAM did not worked: no blocks, just a stream of bytes without any particular meaning. Thanks, for pointing out.
Title: Re: Can't find unit unixsockets
Post by: MarkMLl on February 19, 2025, 04:23:33 pm
So, that's why SOCK_STREAM did not worked: no blocks, just a stream of bytes without any particular meaning. Thanks, for pointing out.

Probably, or at the very least blocks getting merged arbitrarily. That's one reason why, when it was still unclear what you were doing, I threw SCTP into the mix: it's somewhat (!) more complex ("designed by committee" is the phrase that springs to mind), but offers reliable block delivery over a network (provided that the in-path routers etc. support it, which is rare).

I've realised that I missed out some very juicy stuff from the example code I C&Ped yesterday, and am about to go back and extend it.

MarkMLl
Title: Re: Can't find unit unixsockets
Post by: TCH on February 20, 2025, 01:36:37 am
So, that's why SOCK_STREAM did not worked: no blocks, just a stream of bytes without any particular meaning. Thanks, for pointing out.
Probably, or at the very least blocks getting merged arbitrarily. That's one reason why, when it was still unclear what you were doing, I threw SCTP into the mix: it's somewhat (!) more complex ("designed by committee" is the phrase that springs to mind), but offers reliable block delivery over a network (provided that the in-path routers etc. support it, which is rare).
No, i've never worked with SCTP. As a matter of fact, i did not even ever heard of it, but after a quick search, i think i am not alone with that: it is not very widespread.
I've realised that I missed out some very juicy stuff from the example code I C&Ped yesterday, and am about to go back and extend it.
I think you should make a unit of it and commit it into the FPC RTL, or publish it in your repo.
Title: Re: Can't find unit unixsockets
Post by: PascalDragon on February 20, 2025, 09:48:48 pm
So, that's why SOCK_STREAM did not worked: no blocks, just a stream of bytes without any particular meaning. Thanks, for pointing out.
Probably, or at the very least blocks getting merged arbitrarily. That's one reason why, when it was still unclear what you were doing, I threw SCTP into the mix: it's somewhat (!) more complex ("designed by committee" is the phrase that springs to mind), but offers reliable block delivery over a network (provided that the in-path routers etc. support it, which is rare).
No, i've never worked with SCTP. As a matter of fact, i did not even ever heard of it, but after a quick search, i think i am not alone with that: it is not very widespread.

It's more widespread than you might realize, cause it's one of the core protocols used by WebRTC (https://en.wikipedia.org/wiki/WebRTC) which is supported by all modern browsers and other applications that use WebRTC to provide peer-to-peer communication.
Title: Re: Can't find unit unixsockets
Post by: TCH on February 20, 2025, 10:09:24 pm
Perhaps the found topics and articles were too old.
Title: Re: Can't find unit unixsockets
Post by: MarkMLl on February 20, 2025, 10:09:42 pm
It's more widespread than you might realize, cause it's one of the core protocols used by WebRTC (https://en.wikipedia.org/wiki/WebRTC) which is supported by all modern browsers and other applications that use WebRTC to provide peer-to-peer communication.

In fairness, /can/ be used by would be a better way of putting it. It works peer-to-peer on a local LAN, it works over a tunnel provided that the relevant ISPs are competent ** , but IME is not at all well-supported across commodity routers and firewalls.

It's definitely got its good points, but an "SCTP lite" which offered reliable datagram transmission (i.e. like UD sockets but between systems) would go down well.

** Which is a strong argument for end-to-end encryption: if intermediate carriers can't see what's in there they aren't likely to try to filter it.

MarkMLl
Title: Re: Can't find unit unixsockets
Post by: duralast on February 20, 2025, 10:56:29 pm
No, i've never worked with SCTP. As a matter of fact, i did not even ever heard of it, but after a quick search, i think i am not alone with that: it is not very widespread.
The Stream Control Transmission Protocol (SCTP) was originally designed by the Signaling Transport (SIGTRAN) group of IETF for Signalling System 7 (SS7) transport over IP-based networks. It is a reliable transport protocol operating on top of an unreliable connectionless service, such as IP.

More info on SCTP is available in the Oracle Help Center at https://docs.oracle.com/cd/E95618_01/html/sbc_scz810_acliconfiguration/GUID-8D95AA21-4530-4E02-90FB-032E3856CC80.htm (https://docs.oracle.com/cd/E95618_01/html/sbc_scz810_acliconfiguration/GUID-8D95AA21-4530-4E02-90FB-032E3856CC80.htm)
Title: Re: Can't find unit unixsockets
Post by: TCH on February 20, 2025, 11:17:02 pm
Thanks, i'll read it.
Title: Re: Can't find unit unixsockets
Post by: PascalDragon on February 22, 2025, 04:08:25 pm
It's more widespread than you might realize, cause it's one of the core protocols used by WebRTC (https://en.wikipedia.org/wiki/WebRTC) which is supported by all modern browsers and other applications that use WebRTC to provide peer-to-peer communication.

In fairness, /can/ be used by would be a better way of putting it. It works peer-to-peer on a local LAN, it works over a tunnel provided that the relevant ISPs are competent ** , but IME is not at all well-supported across commodity routers and firewalls.

I can personally attest that it works rather well if it's set up correctly. We use it in one of our products at work to provide remote VNC in the browser. As long as one side is not connected to a symmetric NAT it will most likely be able to establish a connection using hole punching and otherwise a TURN relay will be used. This is completely transparent to the user of WebRTC (and it will use SCTP in any case, because the WebRTC suite is based on UDP sockets and thus needs something(TM) to make it reliable).

It's definitely got its good points, but an "SCTP lite" which offered reliable datagram transmission (i.e. like UD sockets but between systems) would go down well.

Then you might want to take a look at QUIC (https://en.wikipedia.org/wiki/QUIC).
TinyPortal © 2005-2018