Textfiles and unix-domain sockets lazarus / 66-Unix ---------------------------------------------------------------------- MarkMLl · 2022-01-01 20:56 Has anybody ever explored the situation where output is to go to a "named file" which can either be on disc or a unix-domain socket? I think that they are distinct: true files need WriteLn() etc. while sockets need fpSend(). However I'd be interested in anybody else's experience in this area. MarkMLl ---------------------------------------------------------------------- marcov · 2022-01-01 21:54 You really never realized that many socket functions have text overloads? https://www.freepascal.org/docs-html/current/rtl/sockets/connect.html ---------------------------------------------------------------------- MarkMLl · 2022-01-02 09:04 I was- ovbiously- aware of the fact that both files and sockets are handle-based. I wasn't confident that the higher-level FPC functions would work transparently, hence my question. Thanks for the example, which will be useful particularly if I end up looking at both ends of the connection. I'll report back if unix- domain sockets appear special in any way: I've only used them for datagrams so far. MarkMLl ---------------------------------------------------------------------- marcov · 2022-01-02 11:02 I tried to use them a few times, but error handling gets more complex, so I abandoned it. When I wanted to remove them at some point, Michael says he used them in a work environment ---------------------------------------------------------------------- MarkMLl · 2022-01-02 15:13 Quote from: marcov on January 02, 2022, 12:02:40 pmI tried to use them a few times, but error handling gets more complex, so I abandoned it. When I wanted to remove them at some point, Michael says he used them in a work environment I think the key thing is that the "handle" parameter is the same, i.e. it's not simply WriteLn() overloaded for different "handle" types. What I'm doing is collecting instrument state via HPIB, then decoding it to a text file... and I find myself in the position that the more flexible the output is (i.e. not just stdout) the better. MarkMLl ---------------------------------------------------------------------- MarkMLl · 2022-01-02 20:09 Couple of questions arising from this. The first is that Connect() is marked deprecated but fpConnect() isn't overlaid with Text or File parameters... what should I be using here? The second is that Connect() doesn't have an overlaid variant with the TUnixSockAddr parameter which is needed for a unix-domain socket (which is /specifically/ what I was asking about when I stared the thread)... any comments? I could probably hack this from the sockets POV, but I'm concerned that this would be merely a slippery slope and that changes would be needed in WriteLn() etc. if the existing socket support is entirely for the inet domain. MarkMLl ---------------------------------------------------------------------- marcov · 2022-01-02 22:08 Quote from: MarkMLl on January 02, 2022, 09:09:15 pmCouple of questions arising from this. The first is that Connect() is marked deprecated but fpConnect() isn't overlaid with Text or File parameters... what should I be using here? Non FP version might have 1.0.x errorhandling that is not entirely ok. fp* versions have error handling the same as the APIs it connects too. ---------------------------------------------------------------------- MarkMLl · 2022-01-03 10:29 Connect() fails with a unix-domain socket since the length of the address structure is truncated when it's passed to fpConnect() internally. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   var    reopenedInput: Text;                (* Placeholder, probably not needed     *)    procedure reopenUDSocket(var t: Text; const n: string);   type    TSockAddr= record                 case boolean of                 false: (inet: TInetSockAddr);                   true:  (udom: TUnixSockAddr)                 end;   var    skt: TSocket;    ipcAddr: TSockAddr;     i: integer;   begin    CloseFile(t);    skt:= fpSocket(PF_UNIX, SOCK_STREAM, 0);    if skt < 0 then begin      if not quiet then        WriteLn(stderr, 'Cannot create unix-domain socket handle');      Halt(9)    end;    FillChar(ipcAddr, SizeOf(ipcAddr), 0);    ipcAddr.udom.family:= AF_UNIX;    StrPCopy(ipcAddr.udom.path, n);  i := fpConnect(skt, @ipcAddr.inet, SizeOf(ipcAddr.inet));   // <---- this fails i := fpConnect(skt, @ipcAddr.inet, SizeOf(ipcAddr.udom));   // <---- this works     if not Connect(skt, ipcAddr.inet, reopenedInput, t) then begin // <---- this fails      if not quiet then        WriteLn(stderr, 'Cannot open unix- domain socket "' + n + '"');      Halt(9)    end;    Rewrite(t)  end { reopenUDSocket } ;  MarkMLl ---------------------------------------------------------------------- MarkMLl · 2022-01-03 11:07 I've added this: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   (* This is a reimplementation of the standard Connect() since it doesn't    support a unix-domain address and truncates it if told to cast it to an    inet domain address structure.  *)  Function Connect(Sock:longint;const addr: TUnixSockAddr;var SockIn,SockOut:text):Boolean;      Function DoConnect(Sock:longint;const addr: TUnixSockAddr): Boolean;     var    res: longint;    begin      repeat        res:=fpconnect(Sock,@Addr,SizeOF(TUnixSockAddr)); (* NOTA BENE *)    until (res<>-1) or (SocketError <> EsockEINTR);      DoConnect:= res = 0;    end;    begin    Connect:=DoConnect(Sock,addr);    If Connect then       Sock2Text(Sock,SockIn,SockOut);  end { Connect } ;  If it fails, check whether the file exists; if it exists then it probably means that the listener has terminated. Test with e.g. $ nc -lkU ~/dsocket If the -k option is omitted then Netcat will terminate without deleting the placeholder in the filesystem when the writer closes the connection. MarkMLl ---------------------------------------------------------------------- RickE · 2022-03-07 15:27 I got a little "sequential packet Unix (local) socket" unit working, and was impressed with the sequential packet vs. stream socket type. Linux rightly brags about such a useful feature. In years past I would make a formatted web page to down load, but please forgive if I just try insert some code here; Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i UNIT LocalP acketSockets_Text_Unit;{********************************************** ********************************        FREEPASCAL LINUX C LIBRARY SOCKETS INTERFACE***************************************************** *************************} {****************************************** ***********************************}INTERFACE{$PACKRECORDS C}Uses Sock ets_Text_Unit;{******************************************************* **********************} {============================================= =================================        LOCAL (UNIX) PACKET SOCKETS I NTERFACE============================================================== ================}Const{ Unix/Local Domain Socket Address Family }      AF_LOCAL = 1;        AF_UNIX = AF_LOCAL; { Unix/Local Domain Socket Types }        SOCK_STREAM = 1;                { Sequenced, reliable, connection-based byte streams. }        SOCK_SEQPACKET = 5;           { Sequenced, reliable, connection-based datagrams of fixed maximum length.} { Unix/Local Protocol Family }        PF_UNSPEC = 0;                { Unspecified. Normally OK. }        PF_LOCAL = 1;                 { Local to host (pipes and file-domain). }        PF_UNIX = PF_LOCAL;             { POSIX name for PF_LOCAL. }         SOMAXCONN =     128;            { Maximum connect queue length specifiable by listen. }        Max_ConnectQueue = SOMAXCONN;         Max_SockAddrLength = 110;{ longest possible unix local domain socket address record } Type{ FreePascal String Type variable to hold a "FileName" }        t_UnixSocket_FilePathName = String[107]; { FreePascal Record Type variable to hold the C Structure parameter }      p_UnixSocket_AddressRecord = ^t_UnixSocket_AddressRecord ;        t_UnixSocket_AddressRecord = Record                                                              AddressFamily: word;                                                              FilePathName: array[0..107] of char;                                                              End; { t_UnixSocket_AddressRecord } { =============================== ============================================= }{ Create a New Local Packet Type Socket FileDescriptor. Returns False for errors. }Function CreateNew_LocalPacketSocket_OK( var param_var_NewSocketFD: Longint ): Boolean;  { Bind a Local Packet Type Socket FileDescriptor to a New Socket FilePathName. Returns False for errors. }Function Bind_LocalPacketSocket_PathName_OK( param_SocketFD: longint;                                                                              const param_NewSocketFilePathName: t_UnixSocket_FilePathName ):                                                                            Boolean; { Server Listens on a Local Packet Type Socket FileDescriptor for Client Connection Requests. Returns False for errors. }Function Listen_LocalPacketSocket_OK( param_ServerSocketFD,                                                                            param_MaxConnectRequests: Longint ):                                                                              Boolean; { Client Requests a Connection to a Listening  Local Packet Type Socket FileName. Create New Text Type I/O Channels on Client FileDescriptor. Returns False for errors. }Function ConnectRequest_NewTextPacketSocket_OK( param_ClientSocketFD: longint;                                                                                              const param_ServerSocket_FilePathName: t_UnixSocket_FilePathName;                                                                                              var param_var_NewClientTextInputChannel: Text;                                                                                              var param_var_NewClientTextOutputChannel: Text ):                                                                                              Boolean; { Server Accepts a Client Connection Request on a Listening Local Domain Server Socket FileDescriptor. Create a New AcceptConnection FileDescriptor on Server Socket. Create New Text Type I/O Channels on New Server Socket AcceptConnection FileDescriptor. Returns False for errors. }Function AcceptRequest_NewTextPacketSocket_OK( param_ServerSocketFD : longint;                                                                                              var param_var_NewAcceptConnectFD: longint;                                                                                            var param_var_ClientSocket_FilePathName: t_UnixSocket_FilePathName ;                                                                                              var param_var_NewServerTextInputChannel: Text;                                                                                              var param_var_NewServerTextOutputChannel: Text ):                                                                                              Boolean; {************************************************************ *****************}IMPLEMENTATION{************************************* ****************************************} { Construct t_UnixSocket_AddressRecord }Procedure PathName_to_SockAddrRec(const param_UnixSocket_FilePathName: t_UnixSocket_FilePathName;                                                              var param_var_SockAddrRecord: t_UnixSocket_AddressRecord;                                                              var param_var_SockAddrRecordLength: longint );        Begin        { Fill in AddressFamily field }                param_var_SockAddrRecord.AddressFamily := 1 ;   {AF_UNIX}         { Fill in FilePathName field with all 0s ==>> null terminated }          FillByte ( param_var_SockAddrRecord.FilePathName,                              SizeOf( param_var_SockAddrRecord.FilePathName ),                              0 );         { Assign FilePathName field }              Move( param_UnixSocket_FilePathName[1],                              param_var_SockAddrRecord.FilePathName,                              length( param_UnixSocket_FilePathName ) );         { Calculate sizeof(sockaddr_un) := sizeof(sa_family_t) + sizeof(sun_path) + sizeof(null character ) }                param_var_SockAddrRecordLength:= 2 + Length( param_UnixSocket_FilePathName ) + 1 ;         End; { Procedure PathName_to_SockAddrRec } { ========================================== ================================== }{ Create a NEW SOCKET of DOMAIN, TYPE, PROTOCOL. }{ Returns a new file descriptor for the new socket, or -1 for errors.   }{ Uses domain: AF_LOCAL = 1, type: SOCK_SEQPACKET = 5. }{ ============================================================== ============== }{libc}        Function LibcCall_Socket( __domain: longint;                                                              __type: longint;                                                              __protocol: longint ):                                                              longint; cdecl; external 'c' name 'socket'; { ---------------------------------------------------------------------- ------ }{ Libc Functions ==>> Pascal Functions }{ -------------------- -------------------------------------------------------- }Function CreateNew_LocalPacketSocket_OK( var param_var_NewSocketFD: Longint ): Boolean;        Var                loc_var_LibcCall_Return : longint ;        Begin        { Initialize }                param_var_NewSocketFD := -1;                CreateNew_LocalPacketSocket_OK := False;         { Do Linux libc call }                loc_var_LibcCall_Return := LibcCall_Socket( 1, 5, 0 );         { If Success }                If loc_var_LibcCall_Return > 0                        Then                        Begin                              param_var_NewSocketFD := loc_var_LibcCall_Return;                              CreateNew_LocalPacketSocket_OK := True;                      End;         End; { Function CreateNew_LocalPacketSocket_OK } { =================================== ========================================= }{ Bind a Local Unix Socket FileName to a Local Unix Socket FileDescriptor }{ Give the Local Unix Socket FD the Local Unix Socket Address Record (which is LEN bytes long). }{ ============================================================ ================ }{libc}        Function LibcCall_Bind( __fd: longint ;                                                                __addr: p_UnixSocket_AddressRecord;                                                              __len: longint ):                                                              longint; cdecl; external 'c' name 'bind'; { ------------------------------------------------------- --------------------- }{ Libc Functions ==>> Pascal Functions }{ ----- ---------------------------------------------------------------------- - }Function Bind_LocalPacketSocket_PathName_OK( param_SocketFD: longint;                                                                                      const param_NewSocketFilePathName: t_UnixSocket_FilePathName ):                                                                                      Boolean;        Var              loc_var_SockAddrRecord:                 t_UnixSocket_AddressRecord;                loc_var_SockAddrRecordLength:   longint;                loc_var_LibcCall_Return:        longint;        Begin        { Initialize }                Bind_LocalPacketSocket_PathName_OK := False;         { Construct UnixDomainSocketAddress_Record }              PathName_to_SockAddrRec( param_NewSocketFilePathName,                                                                      loc_var_SockAddrRecord,                                                                      loc_var_SockAddrRecordLength );        { Do Linux libc call }                loc_var_LibcCall_Return := LibcCall_Bind( param_SocketFD,                                                                                              @loc_var_SockAddrRecord,                                                                                              loc_var_SockAddrRecordLength );        { If Success }                If loc_var_LibcCall_Return = 0                        Then Bind_LocalPacketSocket_PathName_OK := True;         End; { Function Bind_LocalPacketSocket_PathName_OK } { =============================== ============================================= }{ Listen and Wait until a Client Connection Request on Server Socket FD. }{ Server Listens prepared to accept connections on socket FD. }{ N connection requests will be queued before further requests are refused.}{ ================ ============================================================ }{libc}      Function LibcCall_Listen( __fd : longint ;                                                              __n : longint ):                                                              longint; cdecl; external 'c' name 'listen'; { ---------------------------------------- ------------------------------------ }{ Libc Functions ==>> Pascal Functions }{ --------------------------------------------------------- ------------------- }Function Listen_LocalPacketSocket_OK( param_ServerSocketFD,                                                                                      param_MaxConnectRequests: Longint ):                                                                                      Boolean;        Var                loc_var_LibcCall_Return: longint;        Begin        { Initialize }              Listen_LocalPacketSocket_OK := False ;         { Do Linux libc call }                loc_var_LibcCall_Return := LibcCall_Listen( param_ServerSocketFD,                                                                                                      param_MaxConnectRequests );        { If Success }                If loc_var_LibcCall_Return = 0                        Then Listen_LocalPacketSocket_OK := True;         End; { Function Listen_LocalPacketSocket_OK } { ====================================== ====================================== }{ Client Requests a connection to a Listening Server Socket FileName }{ Open a Connection on Client Socket FD to Server Socket at ADDR .}{ =============================== ============================================= }{libc}        Function LibcCall_Connect( __fd : longint ;                                                              __addr : p_UnixSocket_AddressRecord ;                                                              __len : longint ):                                                              longint; cdecl; external 'c' name 'connect'; { -------------------- -------------------------------------------------------- }{ Libc Functions ==>> Pascal Functions }{ ----------------------------------- ----------------------------------------- }Function ConnectRequest_NewTextPacketSocket_OK( param_ClientSocketFD: longint;                                                                                      const param_ServerSocket_FilePathName: t_UnixSocket_FilePathName ;                                                                                      var param_var_NewClientTextInputChannel: Text ;                                                                                      var param_var_NewClientTextOutputChannel: Text ):                                                                                      Boolean;        Var                loc_var_ServerSockAddrRecord:         t_UnixSocket_AddressRecord;                loc_var_ServerSockAddrRecordLength:     longint;                loc_var_LibcCall_Return:                longint;         Begin        { Initialize }                ConnectRequest_NewTextPacketSocket_OK := False ;         { Construct UnixSockAddrRecord Path to Server }              PathName_to_SockAddrRec( param_ServerSocket_FilePathName,                                                                            loc_var_ServerSockAddrRecord,                                                                              loc_var_ServerSockAddrRecordLength ) ;        { Do Linux libc call }              loc_var_LibcCall_Return := LibcCall_Connect( param_ClientSocketFD,                                                                                                      @loc_var_ServerSockAddrRecord,                                                                                                      loc_var_ServerSockAddrRecordLength ) ;        { If Success }              If loc_var_LibcCall_Return = 0                        Then                      { Construct NEW Socket Communication channels }                      Begin                                Assign_SocketFD_to_SocketIO_TextChannels( param_ClientSocketFD,                                                                                                                    param_var_NewClientTextInputChannel,                                                                                                                    param_var_NewClientTextOutputChannel );                               ConnectRequest_NewTextPacketSocket_OK := True ;                      End         End; { Function ConnectRequest_NewTextPacketSocket_OK } { ============================ ================================================ }{ When a Client Connection Request arrives, }{  create a NEW Server AcceptConnect Socket FD to communicate with it, }{  set  ADDR to the Address Record of the connecting Client Peer, }{  and return the new Server AcceptConnect Socket File Descriptor, or -1 for errors. }{ =========== ================================================================= }{libc}        Function LibcCall_Accept( __fd: longint;                                                              __addr: p_UnixSocket_AddressRecord;                                                              __addr_len: pLongint ):                                                              longint; cdecl; external 'c' name 'accept'; { ---------------------------------------------------------- ------------------ }{ Libc Functions ==>> Pascal Functions }{ -------- -------------------------------------------------------------------- }Function AcceptRequest_NewTextPacketSocket_OK( param_ServerSocketFD : longint ;                                                                                              var param_var_NewAcceptConnectFD: longint;                                                                                              var param_var_ClientSocket_FilePathName: t_UnixSocket_FilePathName;                                                                                            var param_var_NewServerTextInputChannel: Text;                                                                                            var param_var_NewServerTextOutputChannel : Text ):                                                                                            Boolean;        var                loc_var_NewAcceptConnectFD: longint;                loc_var_ClientSockAddrRecord: t_UnixSocket_AddressRecord;              loc_var_ClientSockAddrRecordLength: longint;                loc_var_LibcCall_Return: longint;         Begin        { Initialize }                AcceptRequest_NewTextPacketSocket_OK := False;         { Initialize SockAddrRecord }                loc_var_ClientSockAddrRecord.FilePathName := '' ;         { Create enough space for return variable }                loc_var_ClientSockAddrRecordLength := Max_SockAddrLength;         { Do Linux libc call }                loc_var_LibcCall_Return := LibcCall_Accept( param_ServerSocketFD,                                                                                              @loc_var_ClientSockAddrRecord,                                                                                              @loc_var_ClientSockAddrRecordLength ) ;        { If Success }              If loc_var_LibcCall_Return > 0                        Then                      Begin                        { Set the NEW Server Connection ID }                                param_var_NewAcceptConnectFD := loc_var_LibcCall_Return ;                              loc_var_NewAcceptConnectFD := loc_var_LibcCall_Return ;                         { Construct returned Client Name String }                                Move( loc_var_ClientSockAddrRecord.FilePathName,                                              param_var_ClientSocket_FilePathName[1],                                              loc_var_ClientSockAddrRecordLength - 3 );                                 SetLength( param_var_ClientSocket_FilePathName,                                                      loc_var_ClientSockAddrRecordLength - 3 );                        { Construct NEW Socket Communication channels }                              Assign_SocketFD_to_SocketIO_TextChannels( loc_var_NewAcceptConnectFD,                                                                                                                    param_var_NewServerTextInputChannel,                                                                                                                    param_var_NewServerTextOutputChannel );                               AcceptRequest_NewTextPacketSocket_OK := True;                      End         End ; { Function AcceptRequest_NewTextPacketSocket_OK } {****************************** ************************************************Initialize Unit******* ********************************************************************** *}Begin{ nothing }End.    And always to thank the FreePascal team for their wonderful development system. ---------------------------------------------------------------------- MarkMLl · 2022-03-07 18:24 UD sockets are a nice feature, but I think their real strength is as a "short circuit" if data is to be transferred locally (e.g. an X11 connection between client and server on the same system). (Named) FIFOs are somewhat easier to work with if a stream (rather than a sequence of datagrams) is to be handled and there is absolutely no need to map it over the network. In either case a nodding familiarity with POSIX capabilities is useful, so that if the (name representing the) socket or FIFO has to be in a directory owned by root a program can manipulate it during startup. MarkMLl ---------------------------------------------------------------------- RickE · 2022-03-07 20:28 Here is the "Sockets_Text_Unit" required above in the Uses clause; Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i  UNIT Socke ts_Text_Unit;{******************************************************** **********************        FREEPASCAL SOCKETS TEXT FILE I/O INTERFA CE******************************************************************** **********} {********************************************************* ********************}INTERFACE{$PACKRECORDS C}{*********************** ******************************************************}{Text FileType RecordRead + Write Support Types and Constants from FreePascal System Unit textrec.inc const        TextRecNameLength = 256;        TextRecBufSize    = 256; type        TFileTextRecChar = widechar;      TLineEndStr = string [3];        TextBuf = array[0..TextRecBufSize-1] of ansichar;        TTextBuf = TextBuf;       TextRec = Record                                Handle    : THandle;                                Mode      : longint;                              bufsize   : SizeInt;                              _private  : SizeInt;                                bufpos,                              bufend    : SizeInt;                              bufptr    : ^textbuf;                                openfunc,                              inoutfunc,                                flushfunc,                                closefunc : codepointer;                              UserData  : array[1..32] of byte;                              name      : array[0..textrecnamelength-1] of TFileTextRecChar;                                LineEnd   : TLineEndStr; Line ending to use                                buffer  : textbuf;        End;} Procedure Assign_SocketFD_to_SocketIO_TextChannels( param_SocketFD: Longint;                                                                                            Var param_var_Input_TextFile: Text;                                                                                            Var param_var_Output_TextFile: Text ); {********************* ********************************************************}IMPLEMENTATIO NUses SysUtils;{****************************************************** ***********************} Function Read_SocketInput_TextChannel( var param_var_TextRecord: TextRec ): Longint;        var loc_var_CharCount : longint;        Begin        { System Read from Socket FileDescriptor into Socket Text Buffer. }                loc_var_CharCount := FileRead( param_var_TextRecord.handle,                                                                              param_var_TextRecord.bufptr^,                                                                              param_var_TextRecord.bufsize ) ;                 If (loc_var_CharCount < 0) then Exit(-1) ;         { Returns number of bytes read to TextRecord.BufEnd. }                param_var_TextRecord.BufEnd := loc_var_CharCount ;         { ReSet Read TextRecord buffer position to 0 when done. }                param_var_TextRecord.bufpos := 0 ;         { Done }                Read_SocketInput_TextChannel := 0 ;        End; { Function Read_SocketInput_TextChannel } { ===================================== ======================================= }Function Write_SocketOutput_TextChannel( var param_var_TextRecord: TextRec ): Longint;        var loc_var_CharCount : longint;        Begin        { System Write from Socket Text Buffer into Socket FileDescriptor. }      { Writes bufpos number of bytes. }                loc_var_CharCount := FileWrite( param_var_TextRecord.handle,                                                                              param_var_TextRecord.bufptr^,                                                                              param_var_TextRecord.bufpos );                 If (loc_var_CharCount < 0) then Exit(-1) ;         { ReSet buffer position to 0 when done. }                param_var_TextRecord.bufpos := 0;         { Done }                Write_SocketOutput_TextChannel := 0;        End; { Function Write_SocketOutput_TextChannel } { =================================== ========================================= }Function Flush_SocketOutput_TextChannel( var param_var_TextRecord: TextRec ): Longint;        Begin        { If needs flush. }                If ( param_var_TextRecord.bufpos > 0 )                        Then Write_SocketOutput_TextChannel( param_var_TextRecord );         { Done }                Flush_SocketOutput_TextChannel := 0;        End; { Function Flush_SocketOutput_TextChannel } { ========================== ================================================== }{ Assign two FreePascal Text FileTypes to Socket FileDescriptor for Read, Write calls. } Procedure Assign_SocketInput_TextChannel( param_SocketFD: Longint;                                                                                      Var param_var_Input_TextFile: Text );        Begin                FillChar(TextRec( param_var_Input_TextFile), SizeOf(TextRec), 0 );                TextRec(param_var_Input_TextFile).Mode                  := fmInput;              TextRec(param_var_Input_TextFile).Handle                := param_SocketFD ;                TextRec(param_var_Input_TextFile).InOutFunc             := @Read_SocketInput_TextChannel ;                TextRec(param_var_Input_TextFile).FlushFunc             := nil ;              TextRec(param_var_Input_TextFile).OpenFunc              := nil ;                TextRec(param_var_Input_TextFile).CloseFunc           := nil ;                TextRec(param_var_Input_TextFile).BufSize               := TextRecBufSize ;                TextRec(param_var_Input_TextFile).Bufptr                := @TextRec(param_var_Input_TextFile).Buffer;                TextRec(param_var_Input_TextFile).LineEnd               := #10;      End; { Procedure Assign_SocketInput_TextChannel } Procedure Assign_SocketOutput_TextChannel( param_SocketFD: Longint;                                                                                    Var param_var_Output_TextFile: Text );        Begin                FillChar( TextRec(param_var_Output_TextFile), SizeOf(TextRec), 0 );              TextRec(param_var_Output_TextFile).Mode                 := fmOutput;                TextRec(param_var_Output_TextFile).Handle             := param_SocketFD;                TextRec(param_var_Output_TextFile).InOutFunc    := @Write_SocketOutput_TextChannel;                TextRec(param_var_Output_TextFile).FlushFunc    := @Flush_SocketOutput_TextChannel;                TextRec(param_var_Output_TextFile).OpenFunc             := nil ;              TextRec(param_var_Output_TextFile).CloseFunc    := nil ;              TextRec(param_var_Output_TextFile).BufSize              := TextRecBufSize;                TextRec(param_var_Output_TextFile).Bufptr               := @TextRec(param_var_Output_TextFile).Buffer;                TextRec(param_var_Output_TextFile).LineEnd              := #10;      End; { Procedure Assign_SocketOutput_TextChannel } { ================= =========================================================== }{ Interface Procedure }Procedure Assign_SocketFD_to_SocketIO_TextChannels( param_SocketFD: Longint;                                                                                            Var param_var_Input_TextFile: Text;                                                                                            Var param_var_Output_TextFile: Text );        Begin        { First, Assign the reading channel.}                Assign_SocketInput_TextChannel( param_SocketFD, param_var_Input_TextFile );         { Now, Assign the writing channel. }                Assign_SocketOutput_TextChannel( param_SocketFD, param_var_Output_TextFile );        End; { Procedure Assign_SocketFD_to_SocketIO_TextChannels } {************************** ****************************************************Initialize Unit*** ********************************************************************** *****}Begin{ nothing }End.     I could also load sample server and client programs. Rather nice is how the client can also bind to a filename. Sincere thanks. Rick. ---------------------------------------------------------------------- MarkMLl · 2022-03-07 20:57 Quote from: RickE on March 07, 2022, 09:28:23 pmRather nice is how the client can also bind to a filename. Yes, but in the case of UD sockets watch out for the case where a filesystem name has been created but there is no longer an associated process. Particularly if deletion requires elevated privilege. MarkMLl ---------------------------------------------------------------------- RickE · 2022-03-08 16:06 I hope you find these two little test programs, UD server and client, fun to try compile and run. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Program LocalPacketSocket_Server;{$PACKRECORDS C} Uses BaseUnix, LocalPacketSockets_Text_Unit;  Const         pgm_const_ServerName = 'Socket_LocalServer.soc' ;        pgm_const_ConnectQueueLimit = 3 ; Var         pgm_var_SocketFD,        pgm_var_ConnectFD: Longint;       pgm_var_Connect_ClientName: String[107];        pgm_var_ConnectCount: Longint;        pgm_var_Accept_New_Connections: Boolean;         pgm_var_Socket_TextInput,        pgm_var_Socket_TextOutput: Text;        pgm_var_Message_String: String[255]; { ======================================================= ===================== }Procedure Handle_Socket_Error( const socket_error_message: string );         Begin                 writeln( socket_error_message );                halt;        End;  { ========== ================================================================== }Begin { Program LocalPacketSocket_Server }{*** Initialize variables. ***}        pgm_var_Connect_ClientName := '' ;        pgm_var_ConnectCount := 0 ;        pgm_var_Accept_New_Connections := True ;        pgm_var_Message_String := '' ; {*** Initialize file system. ***}        FpUnlink( pgm_const_ServerName );  { CreateNew Server Socket FileDescriptor. }        If ( CreateNew_LocalPacketSocket_OK( pgm_var_SocketFD ) = False )              Then Handle_Socket_Error( 'CreateNew Socket Error ==>> Quit !! ' ); { Bind; Assign Local FileName to Server Socket FileDescriptor. }      If (Bind_LocalPacketSocket_PathName_OK( pgm_var_SocketFD, pgm_const_ServerName ) = False )                Then Handle_Socket_Error( 'Bind Socket Error ==>> Quit !! ' );  { Run Unix Local Server }{ Listen; Enable and Wait For New Client ConnectRequests. }        If ( Listen_LocalPacketSocket_OK( pgm_var_SocketFD, pgm_const_ConnectQueueLimit ) = False )              Then Handle_Socket_Error( 'Listen Socket Error ==>> Quit !! ' ); { Notify User that Server Program is Waiting for Client ConnectRequests. }        Writeln;        Writeln( 'Starting Unix Local Packet Server using FileName = ', pgm_const_ServerName );        Writeln( 'With Server Socket FileDescriptor = ', pgm_var_SocketFD );        Writeln( 'Server is now Listening for Connect Requests from Clients.' );      Writeln( 'Next, run a Unix Local Packet Socket Client connect program in a separate xterm.' );        Writeln;  {The  accept()  system  call  is used with connection-based socket types    (SOCK_STREAM,  SOCK_SEQPACKET).   It  extracts  the  first   connection    request  on  the queue of pending connections for the listening socket,    sockfd, creates a new connected socket, and returns a new file descrip-    tor  referring  to that socket.  The newly created socket is not in the    listening state.  The original socket  sockfd  is  unaffected  by  this    call. If no pending connections are present on the queue, and the  socket  is    not  marked  as nonblocking, accept() blocks the caller until a connec-    tion is present.  If the socket is marked nonblocking  and  no  pending    connections  are  present  on  the queue, accept() fails with the error    EAGAIN or EWOULDBLOCK.}        While pgm_var_Accept_New_Connections              Do                Begin                { Accept Function Waits (default) while Listening for New Client ConnectRequest. }              { Accept; Create New Socket Interface and Assign Server New TextStream Socket I/O Channels to New Client. }                       If ( AcceptRequest_NewTextPacketSocket_OK( pgm_var_SocketFD,                                                                                                            pgm_var_ConnectFD,                                                                                                            pgm_var_Connect_ClientName,                                                                                                            pgm_var_Socket_TextInput,                                                                                                            pgm_var_Socket_TextOutput ) = True )                       Then    { Use Unix Text Stream Socket Connection }                              Begin                                { Notify User of Begin Client Connection. }                                        Writeln ;                                        Writeln( 'Begin Connect to ClientName = ', pgm_var_Connect_ClientName );                                      Writeln( 'on Server AcceptConnect FileDescriptor = ', pgm_var_ConnectFD );                                      Writeln ;                                 { Notify Client program of New Connection. }                                        Writeln( pgm_var_Socket_TextOutput,                                                              pgm_var_Connect_ClientName,                                                              ', this is a message from ', pgm_const_ServerName );                                 { Serve the connection until it is finished. }                                      Repeat                                                  Readln( pgm_var_Socket_TextInput, pgm_var_Message_String );                                              Writeln( 'Received message "', pgm_var_Message_String, '"' );                                              Writeln ;                                        Until ( pgm_var_Message_String = 'quit' );                                 { Notify Server program of End Client Connection. }                                      Writeln ;                                        Writeln( 'End Connect to ClientName = ', pgm_var_Connect_ClientName );                                        Writeln( 'Close Connection FileDescriptor = ', pgm_var_ConnectFD );                                      Writeln ;                                 { Close Server AcceptConnect FileDescriptor.}                                        FpClose( pgm_var_ConnectFD );                                 { Clean up Server Variables. }                                        pgm_var_Connect_ClientName := '' ;                                      pgm_var_Accept_New_Connections := False ;                              End                         Else                                Begin                                        pgm_var_Accept_New_Connections := False ;                                      FpUnlink( pgm_const_ServerName );                                      Handle_Socket_Error( 'Server : Accept : ' );                               End;                 End ; { While..Do } { Notify User that Server program is Quitting. }        Writeln ;        Writeln( 'Quitting Server using Socket FileDescriptor = ', pgm_var_SocketFD ) ;        Writeln ; { Remove Named File }        FpClose( pgm_var_SocketFD ) ;        FpUnlink( pgm_const_ServerName );  End. { Program LocalPacketSocket_Server }    Program LocalPacketSocket_ClientLoop; Uses BaseUnix, LocalPacketSockets_Text_Unit;  Const        pgm_const_ServerName = 'Socket_LocalServer.soc' ; Var         pgm_var_ClientName : String[100] ;        pgm_var_ClientSocketFD  : Longint;         pgm_var_Socket_TextInput,        pgm_var_Socket_TextOutput       : Text;         pgm_var_Message_String  : String[255]; { =============== ============================================================= }Procedure Handle_Socket_Error( const socket_error_message : string );         Begin                 writeln ( socket_error_message );              halt;        End;  { ========================================= =================================== }Begin { Initialize program variables }        pgm_var_ClientName      := 'Socket_LocalClient.soc' ;         FpUnlink( pgm_var_ClientName );  { CreateNew Socket FileDescriptor. }        If ( CreateNew_LocalPacketSocket_OK( pgm_var_ClientSocketFD ) = False )                Then Handle_Socket_Error( 'CreateNew Socket Error ==>> Quit !! ' ); { Bind; Assign Named File to Socket FileDescriptor. }        If (Bind_LocalPacketSocket_PathName_OK( pgm_var_ClientSocketFD, pgm_var_ClientName ) = False )                Then Handle_Socket_Error( 'Bind Socket Error ==>> Quit !! ' );  { ConnectRequest; Create New Socket Interface and Assign Client Socket Channels to Named Server. }        If (ConnectRequest_NewTextPacketSocket_OK( pgm_var_ClientSocketFD,                                                                                            pgm_const_ServerName,                                                                                              pgm_var_Socket_TextInput,                                                                                              pgm_var_Socket_TextOutput) = False)                Then Handle_Socket_Error( 'ConnectRequest Socket Error ==>> Quit !! ' ); {*** Use New Connection to Server. ***}{ Notify Client program Begin Connection. }        Writeln ;        Writeln( pgm_var_ClientName, ' Begin Connect to ServerName = ', pgm_const_ServerName );        Writeln( 'Client FileDescriptor = ',  pgm_var_ClientSocketFD );        Writeln ; { Read messages from connected input channel. }        Readln( pgm_var_Socket_TextInput, pgm_var_Message_String );         WriteLn( pgm_var_Message_String );       Writeln ; { Write messages to connected output channel. }      Writeln( pgm_var_Socket_TextOutput, 'just a quickie' );        Writeln ; Write( 'Hit return to continue.' );Readln();        Writeln( pgm_var_Socket_TextOutput, 'just a longsecond quickie' ) ;         Writeln ;Write( 'Hit return to continue.' );Readln();        Writeln( pgm_var_Socket_TextOutput, 'third quickie' ) ;         Writeln ;Write( 'Hit return to quit.' );Readln();        Writeln( pgm_var_Socket_TextOutput, 'quit' ); { Notify Client program End Connection. }        Writeln ;        Writeln( pgm_var_ClientName, ' Ending Connect to ServerName = ', pgm_const_ServerName );        Writeln( 'Close Client FileDescriptor = ',  pgm_var_ClientSocketFD );        Writeln ; { Close and Remove Client File. }        FpClose( pgm_var_ClientSocketFD ) ;        FpUnlink( pgm_var_ClientName );  End. { Program LocalPacketSocket_ClientLoop }       It works on my 32 bit opensuse 13.2. Best of luck with all your ambitions. Most important is to remember the suse motto, "have a lot of fun." I will always be grateful to the suse linux community, the tcl/tk community, and the freepascal community for keeping me what I regard as sane. Amazing treasures.