SWI-Prolog (threaded, 64 bits, version 8.3.2) on Windows 10
In creating a port scanner for a web site tcp_connect/2 is wrapped with setup_call_catcher_cleanup/4. The catcher is catching the error and the clause to the handle the error is getting called but the code is not completing successfully and the error message is being printed.
The code uses :- set_prolog_flag(report_error,false).
to suppress the printing of the error message so I don’t know why the error message is being printed.
The code runs correctly for an open port, e.g. 80, and causes a timeout exception for a port that is not handled, e.g. 79, but is not completing successfully to display the desired result: Port 79: closed
Example run
?- port_scan_range(80,80).
Port 80: open
true.
?- port_scan_range(79,79).
ERROR: Unhandled exception: Socket error: Connection timed out
ERROR: In:
ERROR: [13] socket:tcp_connect(<socket>(0000000006D179B0),'140.211.166.101':79)
ERROR: [12] setup_call_catcher_cleanup(user:tcp_socket(<socket>(0000000006D179B0)),user:tcp_connect(<socket>(0000000006D179B0),...),_22258,user:(...,...)) at c:/program files/swipl/boot/init.pl:562
ERROR: [10] port_scan_range(79,79) at c:/users/eric/documents/notes/discourse swi-prolog osu osl/osu osl prolog/tcp_test.pl:33
ERROR: [9] <user>
ERROR:
ERROR: Note: some frames are missing due to last-call optimization.
ERROR: Re-run your program in debug mode (:- debug.) to get more detail.
Timeout error caught
?- current_prolog_flag(report_error,Flag).
Flag = false.
Code
:- set_prolog_flag(debug_on_error,false). % Do not drop into debugger on error. Errors and exceptions are different with errors being more severe.
:- set_prolog_flag(report_error,false). % Do not print error messages to screen.
% -----------------------------------------------------------------------------
port_scan_range(Start,End) :-
must_be(positive_integer,Start),
must_be(positive_integer,End),
Start =< End,
IP_address = '140.211.166.101',
between(Start,End,Port),
port_scan(IP_address,Port,Result),
format('Port ~w: ~w~n',[Port,Result]).
port_scan(IP_address,Port,Result) :-
setup_call_catcher_cleanup(
tcp_socket(Socket),
% Open stream socket based on TCP/IP which uses IP address and port number, i.e. INET socket
tcp_connect(Socket, IP_address:Port),
Catcher,
(
catcher(Catcher,Result),
tcp_close_socket(Socket)
)
).
catcher(exit,open).
catcher(
exception(
error(socket_error(wsaetimedout, 'Connection timed out'),
_Context)
),
closed
) :-
format('Timeout error caught~n',[]).
catcher(Catcher,unknown) :-
format('Catcher default case~n',[]),
format('~w~n',[Catcher]).