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-2026, 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.
@arg 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.
@arg NameSeqAddress the name_seq/3 address of the service to be monitored.
@arg PortId the port-id of the socket that is bound to the service
@arg Timeout an integer that specifies the duration of the subscription in milliseconds. A duration of -1, specifies a subscription of infinite duration. @arg Filter the event filter bit map.
@arg UserHandle an eight-byte code that is passed transparently to the user with each event notification.
cluster1, or node1. 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(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.
high1, or critical1.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(S, 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.
385:- multifile 386 prolog:message/3. 387 388prologmessage(error(socket_error(_Code, Message), _)) --> 389 [ 'Socket error: ~w'-[Message] ].
400integerAsU32(In, Out) :- 401 nonvar(In), 402 ( In < 0 403 -> Out is In + 0x100000000 404 ; Out is In 405 ). 406integerAsU32(In, Out) :- 407 nonvar(Out), 408 ( Out > 0x7fffffff 409 -> In is Out - 0x100000000 410 ; In is Out 411 ). 412 413tipc_canonical_address(tipc_address(Z,C,N, Ref1), port_id(Ref, Node)) :- 414 integerAsU32(Ref, Ref1), 415 integerAsU32(Node, X), 416 Z is (X >> 24) /\ 0xFF, 417 C is (X >> 12) /\ 0xFFF, 418 N is X /\ 0xFFF. 419 420user:portray(port_id(Ref, Node)) :- 421 tipc_canonical_address(tipc_address(Z,C,N, Ref1), port_id(Ref, Node)), 422 format('port_id(''<~w.~w.~w:~w>'')', [Z,C,N, Ref1]).
445tipc_address(name(T, I, 0), name_seq(T, I, I)). 446tipc_address(name_seq(T, L, U), name_seq(T, L, U)). 447tipc_address(mcast(T, L, U), name_seq(T, L, U)). 448% 449% 450 451tipc_service_exists(Address) :- 452 tipc_service_exists(Address, 0.0). 453 454tipc_service_exists(Address, Timeout) :- 455 tipc_address(Address, NameSeq), 456 !, 457 ITime is integer(Timeout * 1000), 458 try_finally(tipc_socket(S, seqpacket), 459 tipc_close_socket(S)), 460 tipc_connect(S, name(1,1,0)), % connect to the topology server 461 tipc_subscribe(S, NameSeq, ITime, 2, "swipl"), 462 repeat, 463 tipc_receive_subscr_event(S, Data), 464 ( Data == subscr_timeout 465 -> !, fail 466 ; Data = tipc_event(published, NameSeq, _FoundSeq, _Port_id) 467 ), 468 !.
482try_finally(Setup, Cleanup) :- 483 setup_call_cleanup(Setup, ( Solution = yes ; Solution = no ), Cleanup), 484 Solution = yes. 485 486tipc_service_probe(Address) :- 487 tipc_address(Address, name_seq(Type, Lower, Upper)), 488 integer(Type), 489 NameSeq = name_seq(Type, Lower, Upper), 490 try_finally(tipc_socket(S, seqpacket), tipc_close_socket(S)), 491 tipc_connect(S, name(1,1,0)), % connect to the topology server 492 tipc_subscribe(S, name_seq(Type, 0, 4294967295), 0, 2, "swipl"), % look for everything 493 sp_collect(S, Members), 494 !, 495 member([NameSeq, _], Members). 496 497tipc_service_probe(Address, PortId) :- 498 tipc_address(Address, name_seq(Type, Lower, Upper)), 499 integer(Type), 500 NameSeq = name_seq(Type, Lower, Upper), 501 try_finally(tipc_socket(S, seqpacket), tipc_close_socket(S)), 502 tipc_connect(S, name(1,1,0)), % connect to the topology server 503 tipc_subscribe(S, name_seq(Type, 0, 4294967295), 0, 1, "swipl"), % look for everything 504 sp_collect(S, Members), 505 !, 506 member([NameSeq, PortId], Members). 507 508sp_collect(S, Members) :- 509 findall([NameSeq, PortId], 510 ( repeat, 511 tipc_receive_subscr_event(S, Data), 512 ( Data == subscr_timeout 513 -> !, fail 514 ; Data = tipc_event(published, _Service, NameSeq, PortId) 515 ) 516 ), Members).
559spm_dispatch(_Goal, subscr_timeout) :- !. 560spm_dispatch(Goal, tipc_event(Action, _Subscr, NameSeq, PortId)) :- 561 Event =.. [Action, NameSeq, PortId], 562 once(call(Goal, Event)), fail. 563 564:- meta_predicate 565 tipc_service_port_monitor(, ), 566 tipc_service_port_monitor(, , ). 567 568tipc_service_port_monitor(Address, Goal) :- 569 tipc_service_port_monitor(Address, Goal, 0.0), 570 !. 571 572tipc_service_port_monitor(Address, Goal, detached(ThreadId)) :- 573 !, 574 thread_create(tipc_service_port_monitor(Address, Goal, infinite), 575 ThreadId, [detached(true)]). 576tipc_service_port_monitor(Address, Goal, infinite) :- 577 tipc_service_port_monitor(Address, Goal, -0.001), 578 !. 579 580tipc_service_port_monitor(Addresses, Goal, Timeout) :- 581 maplist(tipc_address,Addresses, NameSeqs), 582 !, 583 ITime is integer(Timeout * 1000), 584 try_finally(tipc_socket(S, seqpacket), tipc_close_socket(S)), 585 tipc_connect(S, name(1,1,0)), % connect to the topology server 586 forall(member(NameSeq, NameSeqs), 587 tipc_subscribe(S, NameSeq, ITime, 1, "swipl")), 588 repeat, 589 tipc_receive_subscr_event(S, Data), 590 spm_dispatch(Goal, Data), 591 !.
600tipc_initialize :- 601 with_mutex(tipc_mutex, 602 forall(tipc_stack_initialize, true)). 603 604tipc_stack_initialize :- 605 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.