com_tcp.pl

来自「SRI international 发布的OAA框架软件」· PL 代码 · 共 1,050 行 · 第 1/3 页

PL
1,050
字号
%*****************************************************************************
%   File    : libcom_tcp.pl
%   Primary Authors  : Adam Cheyer, David Martin
%   Purpose : TCP instantiation of lowlevel communication primitives for OAA
%   Updated : 01/98
%
%   ------------------------------------------------------------------------
%   The contents of this file are subject to the OAA  Community Research 
%   License Version 2.0 (the "License"); you may not use this file except 
%   in compliance with the License. You may obtain a copy of the License 
%   at http://www.ai.sri.com/~oaa/.  Software distributed under the License 
%   is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either 
%   express or implied. See the License for the specific language governing 
%   rights and limitations under the License.  Portions of the software are 
%   Copyright (c) SRI International, 1999.  All rights reserved.  
%   "OAA" is a registered trademark, and "Open Agent Architecture" is a 
%   trademark, of SRI International, a California nonprofit public benefit 
%   corporation.
%   ------------------------------------------------------------------------
%
%



%*****************************************************************************
%* RCS Header and internal version
%*****************************************************************************
 
:- module(com,
	  [com_StandardizeAddress/2,
	   com_Connect/3,
	   com_Connect/4,
	   com_Disconnect/1,
	   com_ShutdownAll/0,
	   com_Connected/4,
	   com_ReportConnections/1,
	   com_ListenAt/4,
	   com_SendData/2,
	   com_SelectEvent/2,
	   com_AddInfo/2,
	   com_GetInfo/2,

           % The following are for backwards compatibility only:
	   com_ListenAt/3,
	   % The following are called from other OAA2 distribution
	   % files, but are currently unsupported and undocumented:
	   com_write_term/1
	  ]).

% rcs version number
rcsid(libcom_tcp, '$Header: /home/zuma1/OAA/CVSRepository/oaa2/src/oaalib/prolog/com_tcp.pl,v 1.36 2005/02/08 03:43:20 martin Exp $').

%# The set of library modules to be loaded depends on the Prolog.

:- ( prolog_flag(source_info, _) -> 
  % sicstus
  use_module(library(lists)),
  use_module(library(charsio)),  % for sprintf and with_output_to_chars
  use_module(library(terms)),
  use_module(library(sockets)),
  use_module(library(system)),
  use_module(spcompat)
|
  % quintus
  use_module(library(sets)),
  use_module(library(basics)),
  use_module(library(lists)),
  use_module(library(environ)),  % read environment vars
  use_module(library(charsio)),  % for sprintf and with_output_to_chars
  use_module(library(ask)),      % for ask_oneof
  use_module(library(files)),	  % can_open_file
  use_module(library(strings))  % for concat
).


% Hack: On UNIX load regular tcp library and new tcp_extra module.
% On PC, we have modified the tcp library to add the function in tcp_extra
% so we load the local version, not the one in the library directory.
% One day, we should create a tcp_extra module for PC, but couldn't get
% it to compile right for some reason.
:- ( prolog_flag(source_info, _) -> 
     % Sicstus: tcp_inet_addr defined in spcompat.pl
     true
   | prolog_flag(host_type, ix86) ->
     % Quintus / PC
     use_module(tcp)	
   | otherwise ->
     % Quintus / Unix
     use_module(tcp_extra),	  % for tcp_inet_addr()	
     use_module(library(tcp))
   ).

:- dynamic
        % id, commtype, client/server/child/peer, commInfo, status
	com_connection_info/5,	
	% Maximum number of connections that can be open at once.  
	max_connections/1.

% declaration needed per Quintus documentation:
:- multifile portray/1.   

% Default value.  (Quintus usually accepts connections numbered 5 - 63 before
% an exception is raised, under Solaris.)
max_connections(58).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% name:    com_StandardizeAddress(+Address, -Standardized)
% purpose: Given a com address supported by this library, such as
%          tcp(Host, Port), returns its standardized form.
% remarks: The standardized form expresses the host as an IP number.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
com_StandardizeAddress(tcp(Host, Port), tcp(IPNum, Port)) :-
    tcp_inet_addr(Host, IPNum).


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% name:    com_Connect(+ConnectionId, +Params, ?ConnectAddress, -ActualAddress)
% purpose: Given a connection ID and an address, initiates a client connection
% remarks:
%  - if Address is a variable, instantiates the Address by using
%     oaa_ResolveVariables, which looks in a setup file, command line, and
%     environment variables for the required info.
%     * Unless Params include resolve_vars(false)
%  - ActualAddress may differ from ConnectAddress, because certain parameters
%    can cause a different port to be used.
%  - stores the connection info for connection ID in com_connection_info/5.
%  - fails if connection can't be made
%  - 6 June, 2002 (DLM):  We now distinguish between the address connected to,
%    and the primary address of the other agent.  The primary address
%    serves as a unique identifier for the other agent (but this could
%    change in the future; see comments for oaa:oaa_PrimaryAddress).
%    By default they are the same, but a different primary
%    address can be specified in Params.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% This clause is for backwards compatibility:
com_Connect(ConnectionId, Params, tcp(Host,Port)) :-
    format('~w: com_Connect/3 is obsolete; use com_Connect/4~n', ['WARNING']),
    com_Connect(ConnectionId, Params, tcp(Host,Port), _Actual).

com_Connect(ConnectionId, Params, tcp(Host,Port), tcp(ActualHost, ActualPort)) :-
    com_Connect(ConnectionId, Params, tcp(Host,Port), 0, tcp(ActualHost, ActualPort)).

com_Connect(ConnectionId, Params, tcp(Host,Port), NumAttempts, ActualAddress) :-
    ground(ConnectionId),
    ( memberchk(resolve_vars(false), Params) ->
        true
    % if variable address, look it up...
    | ((var(Host) ; var(Port)) ->
        oaa:oaa_ResolveVariables([
	         [cmd('-oaa_connect',tcp(Host,Port))],
	         [env('OAA_CONNECT',tcp(Host,Port))],
	         [setup(_, default_facilitator, tcp(Host,Port))]
	       ])
	   | true)
    ),

    repeat,
    ( on_exception(E, 
                   tcp_connect(address(Port, Host), RootConnection),
		   Exception = E) ->
	true
    | otherwise ->
        Exception = tcp_connect_failed
    ),
    ( var(Exception) ->
	tcp_inet_addr(Host, IPNum),
	ActualAddress = tcp(Host, Port),
	FormalActualAddress = addr(tcp(IPNum, Port)),
	
        ( memberchk(other_address(Primary), Params) ->
	    true
	| otherwise ->
	    Primary = FormalActualAddress
        ),
	% Various important info elements, such as oaa_address, get
	% filled in later, in oaa.pl.
	assert(com_connection_info(ConnectionId, tcp, client,
		[other_address(Primary),
		 connect_address(FormalActualAddress), 
		 connection(RootConnection)], 
		                   connected)),
	!
    | oaa:oaa_ResolveVariables([
             [cmd('-on_connect_exception', Response)],
             [env('ON_CONNECT_EXCEPTION', Response)],
             [setup(_, on_connect_exception, Response)]
             ]) ->
        NewParams = [resolve_vars(false) | Params],
	format('Currently unable to connect to ~w port ~w.~n',
	           [Host, Port]),
        ( Response == try_again ->
	    format('Will try again after 5 seconds ...~n', []),
	    com_sleep(5),
	    fail
        | Response = try_again(NumSeconds) ->
	    format('Will try again after ~w seconds ...~n', [NumSeconds]),
	    com_sleep(NumSeconds),
	    fail
	| Response == next_highest ->
	     NewNumAttempts is NumAttempts + 1,
	    ( NewNumAttempts > 100 ->
	        halt
	    | otherwise ->
	        NewPort is Port + 1,
		com_Connect(ConnectionId, Params, tcp(Host,NewPort), NewNumAttempts, tcp(ActualHost, ActualPort))
            ),
	    !
	| Response = next_highest(MaxAttempts) ->
            NewNumAttempts is NumAttempts + 1,
	    ( NewNumAttempts > MaxAttempts ->
	        halt
	    | otherwise ->
	        NewPort is Port + 1,
		com_Connect(ConnectionId, Params, tcp(Host,NewPort), NewNumAttempts, tcp(ActualHost, ActualPort))
            ),
	    !
	| Response == change_port ->
	    com_get_new_port(Port, NewPort),
	    com_Connect(ConnectionId, Params, tcp(Host,NewPort), tcp(ActualHost, ActualPort)),
	    !
	| otherwise ->
            format('Exiting~n', []),
	    halt
	)
    | otherwise ->
        NewParams = [resolve_vars(false) | Params],
	com_ask_about_connect_exception(Exception, Port, Host, Response),
        ( Response == try_again ->
	    fail
	| Response == next_highest ->
	    NewPort is Port + 1,
	    com_Connect(ConnectionId, Params, tcp(Host,NewPort), tcp(ActualHost, ActualPort)),
	    !
	| Response == change_port ->
	    com_get_new_port(Port, NewPort),
	    com_Connect(ConnectionId, Params, tcp(Host,NewPort), tcp(ActualHost, ActualPort)),
	    !
	| otherwise ->
	    halt
	)
    ).


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% name:    com_Connected(?ConnectionId, ?Protocol, ?Type, ?Status)
% purpose: Reports on current connections
% remarks:
%   - BACKTRACKS over database of current connections
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
com_Connected(ConnectionId, Protocol, Type, Status) :-
    com_connection_info(ConnectionId, Protocol, Type, _InfoList, Status).


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% name:    com_Disconnect(+ConnectionId)
% purpose: Given a connection ID of type 'client', shuts down the connection.
% remarks: 
%   - Succeeds silently if there is not an open connection having the
%          given id.
%   - ConnectionId may be either the symbolic name (e.g. parent) or the numeric
%          connection Identifier.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
com_Disconnect(Id) :-
	ground(Id),
	((com_connection_info(Id, tcp, client, _Info, connected),
	  ConnectionId = Id)
	 ; 
	 (com_connection_info(ConnectionId, tcp, client, _Info, connected), 
	  Connection = Id)
	),
	com_GetInfo(ConnectionId, connection(Connection)), 
	tcp_shutdown(Connection),
	retract(com_connection_info(ConnectionId,tcp,client,_Info,connected)),
	!.
com_Disconnect(_ConnectionId).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% name:    com_ShutdownAll
% purpose: Shut down all connections.  Normally called just before an
%          agent is going to halt.
% remarks: 
%   - Succeeds silently, regardless of how many connections there are.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
com_ShutdownAll :-
    findall(
	ConnectionId,
        ( com_connection_info(ConnectionId, _, Type, _, _),
          Type \== server ),
	NonServerIds),
    shutdown_each(NonServerIds),
    findall(
	ConnectionId,
        com_connection_info(ConnectionId, _, server, _, _),
	ServerIds),
    destroy_each(ServerIds).

shutdown_each([]).
shutdown_each([Id | Rest]) :-
    ( com_GetInfo(Id, connection(Connection)) ->
      ( tcp_shutdown(Connection) -> true ; true )
    | otherwise ->
      true
    ),
    retract(com_connection_info(Id,_,_,__,_)),
    shutdown_each(Rest).

destroy_each([]).
destroy_each([Id | Rest]) :-
    ( com_GetInfo(Id, connection(Connection)) ->
      ( tcp_destroy_listener(Connection) -> true ; true )
    | otherwise ->
      true
    ),
    retract(com_connection_info(Id,_,_,__,_)),
    destroy_each(Rest).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% name:    com_ReportConnections(+FilePath)
% purpose: Write info about all current connections into the given file.
% remarks: 
%   - Succeeds silently if there is not an open connection having the
%          given id.
%   - ConnectionId may be either the symbolic name (e.g. parent) or the numeric
%          connection Identifier.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

com_ReportConnections(File) :-
    telling(CurrentOut),
    on_exception(_, tell(File), fail),
    com_write_connection_info,
    told,
    tell(CurrentOut),
    !.
com_ReportConnections(File) :-
    format('~w: Unable to write connection info to file: ~w~n',
	   ['WARNING', File]).

com_write_connection_info :-
    com_connection_info(ConnectionId, Protocol, Type, InfoList, Status),
    ( Type = server, memberchk(oaa_address(A), InfoList) ->
	Address = A
    | memberchk(other_address(A), InfoList) ->
	Address = A
    | otherwise ->
	% This shouldn't ever happen
	Address = unknown
    ),
    portray_clause(connection(ConnectionId,Protocol,Type,Address,Status)),
    fail.
com_write_connection_info.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?