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.