Forum > Unix
Textfiles and unix-domain sockets
MarkMLl:
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:
--- Quote from: MarkMLl on January 02, 2022, 09:09:15 pm ---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?
--- End quote ---
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:
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 [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} --- 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:
I've added this:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} --- (* 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:
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 [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---UNIT LocalPacketSockets_Text_Unit;{****************************************************************************** FREEPASCAL LINUX C LIBRARY SOCKETS INTERFACE******************************************************************************} {*****************************************************************************}INTERFACE{$PACKRECORDS C}Uses Sockets_Text_Unit;{*****************************************************************************} {============================================================================== LOCAL (UNIX) PACKET SOCKETS INTERFACE==============================================================================}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.
Navigation
[0] Message Index
[#] Next page
[*] Previous page