1/* Part of SWI-Prolog 2 3 Author: Jeffrey Rosenwald 4 E-mail: jeffrose@acm.org 5 WWW: http://www.swi-prolog.org 6 Copyright (c) 2009-2020, Jeffrey Rosenwald 7 All rights reserved. 8 9 Redistribution and use in source and binary forms, with or without 10 modification, are permitted provided that the following conditions 11 are met: 12 13 1. Redistributions of source code must retain the above copyright 14 notice, this list of conditions and the following disclaimer. 15 16 2. Redistributions in binary form must reproduce the above copyright 17 notice, this list of conditions and the following disclaimer in 18 the documentation and/or other materials provided with the 19 distribution. 20 21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 POSSIBILITY OF SUCH DAMAGE. 33*/ 34 35:- module(tipc, 36 [ tipc_socket/2, % -Socket +Type 37 tipc_close_socket/1, % +Socket 38 tipc_setopt/2, % +Socket, +Option 39 tipc_bind/3, % +Socket, +Address +Scope 40 tipc_listen/2, % +Socket, +BackLog 41 tipc_accept/3, % +Master, -Slave, -PeerName 42 tipc_open_socket/3, % +Socket, -Read, -Write 43 tipc_get_name/2, % +Socket, -Address 44 tipc_get_peer_name/2, % +Socket, -Address 45 tipc_connect/2, % +Socket, +Address 46 tipc_receive/4, % +Socket, -Data, -Sender, +Options 47 tipc_send/4, % +Socket, +Data, +Receiver, +Options 48% tipc_subscribe/5, % +Socket, +Address, +Timeout, +Filter, 49% +Usr_handle 50 51% tipc_receive_subscr_event/2, % +Socket, -Event 52 tipc_canonical_address/2, % -Address, +port_id/2 53 tipc_service_probe/1, % ?Address 54 tipc_service_probe/2, % ?Address, ?PortId 55 tipc_service_port_monitor/2, % +Address, :Goal 56 tipc_service_port_monitor/3, % +Address, :Goal, +Timeout 57 tipc_service_exists/1, % +Address 58 tipc_service_exists/2, % +Address +Timeout 59 tipc_initialize/0 % 60 ]). 61:- autoload(library(apply),[maplist/3]). 62:- autoload(library(lists),[member/2]). 63 64:- use_foreign_library(foreign(tipc)). 65 66:- multifile tipc_stack_initialize/0.
Timeout specifies the duration of the subscription in milliseconds. Specifying a Timeout of -1, provides for a subscription of infinite duration. Filter specifies the events of interest to the subscriber. It is an integer bit field where:
It is possible to have multiple subscriptions active on the same socket any one time, making periodic subscription renewal easy.
This predicate is valid only on connections to the topology
server: name(1,1,0)
.
Please note that this predicate should be considered private. It has been removed from the Prolog public API. Its use in user programs is strongly discouraged. See the "tipc_service" predicates for equivalent functionality.
@param SocketId the socket identifier that was provided by
tipc_socket/2, and is connected to the topology server,
name(1,1,0)
, via tipc_connect/2.
@param NameSeqAddress the name_seq/3 address of the service to be monitored.
@param PortId the port-id of the socket that is bound to the service
@param Timeout an integer that specifies the duration of the subscription in milliseconds. A duration of -1, specifies a subscription of infinite duration. @param Filter the event filter bit map.
@param UserHandle an eight-byte code that is passed transparently to the user with each event notification.
scope(Scope)
zone
, cluster
, or
node
. Servers may bind to more than one address by making
successive calls to tipc_bind/3, one for each address that it
wishes to advertise. The server will receive traffic for all
of them. A server may, for example, register one address with
node scope, another with cluster scope, and a third with zone
scope. A client may then limit the scope of its transmission
by specifying the appropriate address.no_scope(Scope)
no_scope(all)
, may be used to
unbind the socket from all of its registered addresses. This
feature allows an application to gracefully exit from service.
Because the socket remains open, the application may continue
to service current transactions to completion. TIPC however,
will not schedule any new work for the server instance. If no
other servers are available, the work will be rejected or
dropped according to the socket options specified by the
client.Connection-oriented, byte-stream services are implemented with this predicate combined with tipc_listen/2 and tipc_accept/3. Connectionless, datagram services may be implemented using tipc_receive/4.
Note that clients do not need to bind to any address. Its port-id is sufficient for this role. And server sockets (e.g. those that are bound to name/3 or name_seq/3, addresses) may not act as clients. That is, they may not originate connections from the socket using tipc_connect/2. Servers however, may originate datagrams from bound sockets using tipc_send/4. Please see the TIPC programmers's guide for other restrictions.
importance(+Priority)
low
(default), medium
, high
, or critical
.src_droppable(+Boolean)
dest_droppable(+Boolean)
conn_timeout(+Seconds)
Defined options are:
error(socket_error(eagain, Message), _)
, will be thrown. Users
are cautioned not to "spin" unnecessarily on non-blocking
receives as they may prevent the system from servicing other
background activities such as XPCE event dispatching.The typical sequence to receive a connectionless TIPC datagram is:
receive :- tipc_socket(S, dgram), tipc_bind(S, name(18888, 10, 0), scope(zone)), repeat, tipc_receive(Socket, Data, From, [as(atom)]), format('Got ~q from ~q~n', [Data, From]), Data == quit, !, tipc_close_socket(S).
tipc_overview.txt
, for more information
on TIPC Address Structures. Options is currently unused.
A simple example to send a connectionless TIPC datagram is:
send(Message) :- tipc_socket(S, dgram), tipc_send(S, Message, name(18888, 10,0), []), tipc_close_socket(S).
Messages are delivered silently unless some form of congestion
was encountered and the dest_droppable(false)
option was
issued on the sender's socket. In this case, the send succeeds
but a notification in the form of an empty message is returned
to the sender from the receiver, indicating some kind of
delivery failure. The port-id of the receiver is returned in
congestion conditions. A port_id(0,0)
, is returned if the
destination address was invalid. Senders and receivers should
beware of this possibility.
Please note that this predicate is considered private. Its use in user programs is strongly discouraged. See the tipc-service predicates for alternatives.
386:- multifile 387 prolog:message/3. 388 389prologmessage(error(socket_error(_Code, Message), _)) --> 390 [ 'Socket error: ~w'-[Message] ].
401integerAsU32(In, Out) :- 402 nonvar(In), 403 ( In < 0 404 -> Out is In + 0x100000000 405 ; Out is In 406 ). 407integerAsU32(In, Out) :- 408 nonvar(Out), 409 ( Out > 0x7fffffff 410 -> In is Out - 0x100000000 411 ; In is Out 412 ). 413 414tipc_canonical_address(tipc_address(Z,C,N, Ref1), port_id(Ref, Node)) :- 415 integerAsU32(Ref, Ref1), 416 integerAsU32(Node, X), 417 Z is (X >> 24) /\ 0xFF, 418 C is (X >> 12) /\ 0xFFF, 419 N is X /\ 0xFFF. 420 421user:portray(port_id(Ref, Node)) :- 422 tipc_canonical_address(tipc_address(Z,C,N, Ref1), port_id(Ref, Node)), 423 format('port_id(''<~w.~w.~w:~w>'')', [Z,C,N, Ref1]).
446tipc_address(name(T, I, 0), name_seq(T, I, I)). 447tipc_address(name_seq(T, L, U), name_seq(T, L, U)). 448tipc_address(mcast(T, L, U), name_seq(T, L, U)). 449% 450% 451 452tipc_service_exists(Address) :- 453 tipc_service_exists(Address, 0.0). 454 455tipc_service_exists(Address, Timeout) :- 456 tipc_address(Address, NameSeq), 457 !, 458 ITime is integer(Timeout * 1000), 459 try_finally(tipc_socket(S, seqpacket), 460 tipc_close_socket(S)), 461 tipc_connect(S, name(1,1,0)), % connect to the topology server 462 tipc_subscribe(S, NameSeq, ITime, 2, "swipl"), 463 repeat, 464 tipc_receive_subscr_event(S, Data), 465 ( Data == subscr_timeout 466 -> !, fail 467 ; Data = tipc_event(published, NameSeq, _FoundSeq, _Port_id) 468 ), 469 !.
483try_finally(Setup, Cleanup) :- 484 setup_call_cleanup(Setup, ( Solution = yes ; Solution = no ), Cleanup), 485 Solution = yes. 486 487tipc_service_probe(Address) :- 488 tipc_address(Address, name_seq(Type, Lower, Upper)), 489 integer(Type), 490 NameSeq = name_seq(Type, Lower, Upper), 491 try_finally(tipc_socket(S, seqpacket), tipc_close_socket(S)), 492 tipc_connect(S, name(1,1,0)), % connect to the topology server 493 tipc_subscribe(S, name_seq(Type, 0, 4294967295), 0, 2, "swipl"), % look for everything 494 sp_collect(S, Members), 495 !, 496 member([NameSeq, _], Members). 497 498tipc_service_probe(Address, PortId) :- 499 tipc_address(Address, name_seq(Type, Lower, Upper)), 500 integer(Type), 501 NameSeq = name_seq(Type, Lower, Upper), 502 try_finally(tipc_socket(S, seqpacket), tipc_close_socket(S)), 503 tipc_connect(S, name(1,1,0)), % connect to the topology server 504 tipc_subscribe(S, name_seq(Type, 0, 4294967295), 0, 1, "swipl"), % look for everything 505 sp_collect(S, Members), 506 !, 507 member([NameSeq, PortId], Members). 508 509sp_collect(S, Members) :- 510 findall([NameSeq, PortId], 511 ( repeat, 512 tipc_receive_subscr_event(S, Data), 513 ( Data == subscr_timeout 514 -> !, fail 515 ; Data = tipc_event(published, _Service, NameSeq, PortId) 516 ) 517 ), Members).
560spm_dispatch(_Goal, subscr_timeout) :- !. 561spm_dispatch(Goal, tipc_event(Action, _Subscr, NameSeq, PortId)) :- 562 Event =.. [Action, NameSeq, PortId], 563 once(call(Goal, Event)), fail. 564 565:- meta_predicate 566 tipc_service_port_monitor( , ), 567 tipc_service_port_monitor( , , ). 568 569tipc_service_port_monitor(Address, Goal) :- 570 tipc_service_port_monitor(Address, Goal, 0.0), 571 !. 572 573tipc_service_port_monitor(Address, Goal, detached(ThreadId)) :- 574 !, 575 thread_create(tipc_service_port_monitor(Address, Goal, infinite), 576 ThreadId, [detached(true)]). 577tipc_service_port_monitor(Address, Goal, infinite) :- 578 tipc_service_port_monitor(Address, Goal, -0.001), 579 !. 580 581tipc_service_port_monitor(Addresses, Goal, Timeout) :- 582 maplist(tipc_address,Addresses, NameSeqs), 583 !, 584 ITime is integer(Timeout * 1000), 585 try_finally(tipc_socket(S, seqpacket), tipc_close_socket(S)), 586 tipc_connect(S, name(1,1,0)), % connect to the topology server 587 forall(member(NameSeq, NameSeqs), 588 tipc_subscribe(S, NameSeq, ITime, 1, "swipl")), 589 repeat, 590 tipc_receive_subscr_event(S, Data), 591 spm_dispatch(Goal, Data), 592 !.
601tipc_initialize :- 602 with_mutex(tipc_mutex, 603 forall(tipc_stack_initialize, true)). 604 605tipc_stack_initialize :- 606 tipc_service_exists(name(1,1,0))
TIPC Sockets
Transparent Inter-Process Communication (TIPC) provides a flexible, reliable, fault-tolerant, high-speed, and low-overhead framework for inter-process communication between federations of trusted peers, operating as a unit. It was developed by Ericsson AB, as a means to provide for communications between Common Control Systems processes and Network Element peers in telephone switching systems, sometimes operating at arm's length on different line cards or mainframes. Delegation of responsibility in this way is one of the fundamental precepts of the Erlang programming system, also developed at Ericsson. TIPC represents a more generalized version of the same behavioral design pattern. For an overview, please see:
tipc_overview.md
.Errors
The TIPC module uses the error handling functions from library(socket) and therefore all the functions below may throw
error(socket_error(Code, Message))
where Code is the lowercase version of the C-macro error code and Message is an atom describing the error in a human friendly format, depending on the current locale. See the socket library for details.