git » pytipc » master » tree

[master] / tipc.py

"""
TIPC python wrapper
Alberto Bertogli (albertito@gmail.com)


Addresses are expressed as (addr_type, v1, v2, v3 [, scope]);
where addr_type can be one of:
	TIPC_ADDR_NAMESEQ, TIPC_ADDR_NAME, and TIPC_ADDR_ID;
and scope can be one of:
	TIPC_ZONE_SCOPE, TIPC_CLUSTER_SCOPE, and TIPC_NODE_SCOPE.


The meaning of v1, v2 and v3 depend on the value of addr_type:

	if addr_type is TIPC_ADDR_NAME:
		v1 is the server type
		v2 is the port identifier
		v3 is ignored
	if addr_type is TIPC_ADDR_NAMESEQ:
		v1 is the server type
		v2 is the lower port number
		v3 is the upper port number
	if addr_type is TIPC_ADDR_ID:
		v1 is the node
		v2 is the ref
		v3 is ignored

Even when ignored, v3 must be present and be an integer.
"""

import os
import socket as socketmodule
import tipc_ll

# Exported constants
from tipc_ll import AF_TIPC, SOL_TIPC, \
	TIPC_ADDR_NAMESEQ, TIPC_ADDR_NAME, TIPC_ADDR_ID, \
	TIPC_ZONE_SCOPE, TIPC_CLUSTER_SCOPE, TIPC_NODE_SCOPE, \
	TIPC_IMPORTANCE, \
	TIPC_SRC_DROPPABLE, TIPC_DEST_DROPPABLE, \
	TIPC_CONN_TIMEOUT, \
	TIPC_LOW_IMPORTANCE, TIPC_MEDIUM_IMPORTANCE, \
	TIPC_HIGH_IMPORTANCE, TIPC_CRITICAL_IMPORTANCE, \
	TIPC_SUB_PORTS, TIPC_SUB_SERVICE, TIPC_SUB_CANCEL, \
	TIPC_WAIT_FOREVER, \
	TIPC_PUBLISHED, TIPC_WITHDRAWN, TIPC_SUBSCR_TIMEOUT, \
	TIPC_CFG_SRV, TIPC_TOP_SRV


class TIPCSocket:
	def __init__(self, stype, fd = None):
		if not fd:
			self.fd = tipc_ll.socket(stype)
		else:
			self.fd = fd

		self.closed = 0
		self.psock = socketmodule.fromfd(self.fd, AF_TIPC, stype)

		self.family = AF_TIPC
		self.type = stype
		self.proto = 0

	def __del__(self):
		self.close()


	# Friendly functions for the ones implemented in tipc_ll

	def connect(self, addr):
		"Connects to the given server."
		return tipc_ll.connect(self.fd, addr)

	def bind(self, addr):
		"Binds to the given address."
		return tipc_ll.bind(self.fd, addr)

	def accept(self):
		"Accepts a new connection, returns (conn, addr)."
		newfd, addr = tipc_ll.accept(self.fd)
		return (TIPCSocket(self.type, fd = newfd), addr)

	def sendto(self, buf, addr):
		"Sends a message/buffer to the given address."
		return tipc_ll.sendto(self.fd, buf, addr)

	def recvfrom(self, maxlen = 64 * 1024):
		"Receives a message/buffer, returns (buffer, address)."
		return tipc_ll.recvfrom(self.fd, maxlen)

	def close(self):
		"Closes the socket."
		if not self.closed:
			self.closed = 1
			return os.close(self.fd)

	def getsockname(self):
		return tipc_ll.getsockname(self.fd)


	# Other useful functions, some of them based on socketmodule

	def fileno(self):
		"Returns the file descriptor number."
		return self.fd

	def send(self, buf):
		"Sends a message/buffer."
		return self.psock.send(buf)

	def recv(self, bufsize):
		"Receives a message/buffer."
		b, a = self.recvfrom(bufsize)
		return b

	def listen(self, backlog):
		"Listen for connections made to the socket."
		return self.psock.listen(backlog)

	def setblocking(self, flag):
		"Set blocking or non-blocking mode for the socket."
		return self.psock.setblocking(flag)

	def getsockopt(self, level, optname, buflen = None):
		"""Return the value of the given socket option (see the Unix
		man page getsockopt(2))."""
		if not buflen:
			return self.psock.getsockopt(level, optname)
		return self.psock.getsockopt(level, optname, buflen)

	def setsockopt(self, level, optname, value):
		"""Set the value of the given socket option (see the Unix
		manual page setsockopt(2))"""
		return self.psock.setsockopt(level, optname, value)

	def shutdown(self, how):
		"Shut down one or both halves of the connection."
		return self.psock.shutdown(how)


	# Subscription handling

	def send_subscr(self, addr, timeout = None, filter = TIPC_SUB_SERVICE):
		"""
		Sends a subscription message to the server (the socket must
		be connected to TIPC_ADDR_NAME, TIPC_TOP_SRV, TIPC_TOP_SRV, 0)
		for this to work).
		 - addr: specifies the address to wait for (can be a name or a
		   nameseq).
		 - timeout: timeout in milliseconds (use None to wait
		   forever), defaults to None.
		 - filter: Either TIPC_SUB_SERVICE or TIPC_SUB_PORTS, see TIPC
		   documentation for details. Defaults to TIPC_SUB_SERVICE.
		"""

		if not timeout:
			timeout = TIPC_WAIT_FOREVER

		atype, stype, lower, upper = addr[:4]

		if atype == TIPC_ADDR_NAME:
			upper = lower

		subs = tipc_ll.build_subscr(stype, lower, upper,
				timeout, filter)
		self.send(subs)

	def recv_subscr_event(self):
		"""
		Receives a subscription event from the socket.

		It returns None if there was an error receiving the
		subscription, or the tuple:
		 ( event, found_lower, found_upper,
		   (srv_type, lower, upper, timeout, filter) )

		- event: one of TIPC_SUBSCR_TIMEOUT, TIPC_PUBLISHED or
		  TIPC_WITHDRAWN.
		- found_lower, found_upper: the lower and upper ports found.
		- (srv_type, lower, upper, timeout, filter): information on
		  the subscription that generated the event (see send_subscr()
		  for details).
		"""
		buf = self.recv(4092)
		return tipc_ll.parse_event(buf)


def socket(stype):
	"""
	Creates and returns a socket object of the given type.

	The type can be one of SOCK_RDM, SOCK_SEQPACKET, SOCK_STREAM and
	SOCK_DGRAM, see TIPC documentation for more information.
	"""
	return TIPCSocket(stype)


def wait_for(addr, timeout = None, filter = None):
	"""
	Waits for a server to appear on the given address.

	If a timeout is specified and no server came up after that number of
	milliseconds, returns None.
	The optional filter parameter can be either TIPC_SUB_SERVICE or
	TIPC_SUB_PORTS, see TIPC documentation for more details; it defaults
	to TIPC_SUB_SERVICE.

	If there are any errors, return None; otherwise return an event tuple
	composed of:
	 ( event, found_lower, found_upper,
	   (srv_type, lower, upper, timeout, filter) )

	- event: one of TIPC_SUBSCR_TIMEOUT, TIPC_PUBLISHED or
	  TIPC_WITHDRAWN.
	- found_lower, found_upper: the lower and upper ports found.
	- (srv_type, lower, upper, timeout, filter): information on
	  the subscription that generated the event (see send_subscr()
	  for details).
	"""

	fd = socket(socketmodule.SOCK_SEQPACKET)

	if not timeout:
		timeout = TIPC_WAIT_FOREVER
	if not filter:
		filter = TIPC_SUB_SERVICE

	topsrv_addr = (TIPC_ADDR_NAME, TIPC_TOP_SRV,
			TIPC_TOP_SRV, TIPC_TOP_SRV)
	fd.connect(topsrv_addr)

	fd.send_subscr(addr, timeout, filter)
	return fd.recv_subscr_event()