This is an appendix to Understanding Unix/Linux Programming written for people interested in Ada programming on POSIX systems.

Connecting to Processes Near and Far: Servers and Sockets

Section 11.3.1, page 352-355

Here is the code for tinybc.adb, a simple version of bc that parses input and speaks with dc through two pipes:

% gnatmake tinybc
[...]
% ./tinybc
tinybc: 2+2
2 + 2 = 4
tinybc: 55^5
55 ^ 5 = 503284375
tinybc: 

Section 11.3.3, page 355

There is nothing properly equivalent to fdopen in the Ada POSIX interface.

Section 11.4, page 356-359

There is nothing properly equivalent to popen in the Ada POSIX interface, but we can write it ourselves.

Section 11.4.1, page 356-357

POSIX.IO.Open opens a connection to a named file:

declare
   F : POSIX.IO.File_Descriptor;
begin
   F := POSIX.IO.Open (Name => "some_file",
                       Mode => POSIX.IO.Read_Only);
   [...]
   POSIX.IO.Close (File => F);
end;

We want to write a similar function, Open_Process, which opens a connection to a process running a shell command:

declare
   F : POSIX.IO.File_Descriptor;
begin
   F := Open_Process (Name => "ls -l",
                      Mode => POSIX.IO.Read_Only);
   [...]
   Close_Process (File => F);
end;

Here we have a program, in which the command who | sort is a source of data, where we use Open_Process to obtain a sorted list of users: popendemo.adb

This second example uses Open_Process to connect to the mail program and notify some users of system trouble: popen_ex3.adb

Close_Process is required

When you are done reading from (or writing to) a connection created by Open_Process, you should call Close_Process rather than POSIX.IO.Close to close the connection.

Section 11.4.2, page 357-359

Here is the source code for Open_Process and Close_Process:

Section 11.5.4, page 366-370

Unfortunately the POSIX Ada interface included with Debian and Ubuntu doesn't include networking, so we have to manage with a non-standard interface.

Here is the code: timeserv.adb

procedure GNAT.Sockets.Create_Socket:
Creates a socket.
procedure GNAT.Sockets.Bind_Socket:
Assigns an address to a socket.
procedure GNAT.Sockets.Listen_Socket:
Makes a socket listen for connections.
procedure GNAT.Sockets.Accept_Socket:
Accepts a connection on a socket.

Section 11.5.5, page 371

We can now compile and run our time server:

% make timeserv
[...]
% ./timeserv &
[1] 17335
%

We can connect to our server using telnet:

% telnet localhost 13000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Wow! Got a call!
The time here is 11:19.
Connection closed by foreign host.
% telnet 10.0.1.202 13000
Trying 10.0.1.202...
Connected to 10.0.1.202.
Escape character is '^]'.
Wow! Got a call!
The time here is 11:24.
Connection closed by foreign host.
%

[...] The server will continue to run until we kill it:

% kill 17335
[1]  + terminated  ./timeserv
%

Section 11.5.6, page 371-373

Here is the code: timeclnt.adb

procedure GNAT.Sockets.Connect_Socket:
Connects a socket to the specified address (server).

Section 11.5.8, page 375-380

The Client: rls

rls.adb

The Server: rlsd

rlsd.adb

Explorations, page 381

Programming exercises, pages 381-383

11.8

(already done)

11.11

Write an Ada program, which tests if pipes created by POSIX.IO.Create_Pipe are bidirectional. [...]

-- 

Go to next chapter.

Collected examples:
posix-in-ada.zip
Based on:
Understanding Unix/Linux Programming, Bruce Molay, ISBN 0-13-008396-8.
Main page:
http://edb.jacob-sparre.dk/Posix_in_Ada/
Written by:
Jacob Sparre Andersen.
Latest update:
21th of October, 2007