Hello,

I'm using a monitoring software called shinken which rely on Pyro 3 for
the communication between the many servers it contains. But, in my case,
some parts of the network between these servers are IPv6 only.

So, I created a patch against Pyro 3 to add the IPv6 support. I'm not a
python developper and I tested it only whith shinken, but I hope a
python developer could improve it so it can be included in Pyro 3
repository.

Is some intereted in this patch ?
I can help to explain what I intended to do with it.

Once the patch OK, is it possible to add IPv6 support to Pyro 3 ? 

Best regards,

Vincent Leloup
vincent.lel...@ker-is.net
Index: Pyro/core.py
===================================================================
--- Pyro/core.py	(révision 507)
+++ Pyro/core.py	(copie de travail)
@@ -282,7 +282,7 @@
 		else:
 			self.address=Pyro.protocol.getIPAddress(host)
 			if not self.address:
-				raise URIError('unknown host')
+				raise URIError('unknown host or more than one IPv4 and IPv6 address')
 		if port:
 			if type(port)==type(1):
 				self.port=port
@@ -320,12 +320,14 @@
 #
 def processStringURI(URI):
 	# PYRONAME(SSL)://[hostname[:port]/]objectname
-	x=re.match(r'(?P<protocol>PYRONAME|PYRONAMESSL)://(((?P<hostname>[^\s:]+):(?P<port>\d+)/)|((?P<onlyhostname>[^\s:]+)/))?(?P<name>\S*)',URI)
+	x=re.match(r'(?P<protocol>PYRONAME|PYRONAMESSL)://(((?P<hostname>\[[0-9a-fA-F:]+]|[^\s:[]+):(?P<port>\d+)/)|((?P<onlyhostname>\[[0-9a-fA-F:]+]|[^\s:[]+)/))?(?P<name>\S*)',URI)
 	if x:
 		protocol=x.group('protocol')
 		if protocol=="PYRONAMESSL":
 			raise ProtocolError("NOT SUPPORTED YET: "+protocol) # XXX obviously, this should be implemented
 		hostname=x.group('hostname') or x.group('onlyhostname')
+		if hostname.startswith( "[" ):
+			hostname = hostname.lstrip("[").rstrip("]")
 		port=x.group('port')
 		name=x.group('name')
 		import Pyro.naming
@@ -335,10 +337,12 @@
 		NS=loc.getNS(host=hostname,port=port)
 		return NS.resolve(name)
 	# PYROLOC(SSL)://hostname[:port]/objectname
-	x=re.match(r'(?P<protocol>PYROLOC|PYROLOCSSL)://(?P<hostname>[^\s:]+):?(?P<port>\d+)?/(?P<name>\S*)',URI)
+	x=re.match(r'(?P<protocol>PYROLOC|PYROLOCSSL)://(?P<hostname>\[[0-9a-fA-F:]+]|[^\s:[]+):?(?P<port>\d+)?/(?P<name>\S*)',URI)
 	if x:
 		protocol=x.group('protocol')
 		hostname=x.group('hostname')
+		if hostname.startswith( "[" ):
+			hostname = hostname.lstrip("[").rstrip("]")
 		port=x.group('port')
 		if port:
 			port=int(port)
@@ -622,12 +626,12 @@
 		if self.hostname!="localhost":
 			ip = Pyro.protocol.getIPAddress(self.hostname)
 			if ip is None:
-				Log.error("Daemon","no IP address known")
-				raise socket.error("no IP address known for daemon")
-			if not ip.startswith("127.0."):
+				Log.error("Daemon","no or more than one IPv4 and IPv6 address known")
+				raise socket.error("no or more than one IPv4 and IPv6 address known for daemon")
+			if not ( ip.startswith("127.0.") or ip == "::1" ):
 				return None  # this is good!
 		# 127.0.x.x or 'localhost' is a warning situation!
-		msg="daemon bound on hostname that resolves to loopback address 127.0.x.x"
+		msg="daemon bound on hostname that resolves to loopback address 127.0.x.x or ::1"
 		Log.warn("Daemon",msg)
 		Log.warn("Daemon","hostname="+self.hostname)
 		return msg
Index: Pyro/protocol.py
===================================================================
--- Pyro/protocol.py	(révision 507)
+++ Pyro/protocol.py	(copie de travail)
@@ -56,14 +56,30 @@
 	except socket.error:
 		return None
 
-#------ Get IP address (return None on error)
+#------ Get IP address (return None when no or many IPv4 and IPv6 addresses found)
 def getIPAddress(host=None):
 	try:
-		return socket.gethostbyname(host or getHostname())
+		addresses = socket.getaddrinfo(host or getHostname(), None, 0, socket.SOCK_STREAM)
+		if len( addresses ) == 1:
+			return addresses[0][4][0]
+		else:
+			return None
 	except socket.error:
 		return None
 
-	
+#------ Get version of an IP address from its format
+def getIPVersion(host=None):
+	IPaddress = getIPAddress(host)
+	if IPaddress == None:
+		return None
+	elif "." in IPaddress:
+		return 4
+	elif ":" in IPaddress:
+		return 6
+	else:
+		return None
+
+
 #------ Socket helper functions for sending and receiving data correctly.
 
 
@@ -260,8 +276,14 @@
 		with self.lock:   # only 1 thread at a time can bind the URI
 			try:
 				self.URI=URI
-				sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-				sock.connect((URI.address, URI.port))
+				if getIPVersion(URI.address) == 4:
+					sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+					sock.connect((URI.address, URI.port))
+				elif getIPVersion(URI.address) == 6:
+					sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
+					sock.connect((URI.address, URI.port,0,0))
+				else:
+					raise ProtocolError("unkown IP address format: " + URI.address)
 				conn=TCPConnection(sock,sock.getpeername())
 				# receive the authentication challenge string, and use that to build the actual identification string.
 				try:
@@ -859,10 +881,20 @@
 		with self.lock:   # only 1 thread at a time can bind the URI
 			try:
 				self.URI=URI
-				sock = SSL.Connection(self.ctx,socket.socket(socket.AF_INET, socket.SOCK_STREAM))
+				if getIPVersion(URI.address) == 4:
+					sock = SSL.Connection(self.ctx,socket.socket(socket.AF_INET, socket.SOCK_STREAM))
+				elif getIPVersion(URI.address) == 6:
+					sock = SSL.Connection(self.ctx,socket.socket(socket.AF_INET6, socket.SOCK_STREAM))
+				else:
+					raise ProtocolError("unkown IP address format: " + URI.address)
 				if not Pyro.config.PYROSSL_POSTCONNCHECK:
 					sock.postConnectionCheck=None
-				sock.connect((URI.address, URI.port))
+				if getIPVersion(URI.address) == 4:
+					sock.connect((URI.address, URI.port))
+				elif getIPVersion(URI.address) == 6:
+					sock.connect((URI.address, URI.port,0,0))
+				else:   
+					raise ProtocolError("unkown IP address format: " + URI.address)
 				conn=TCPConnection(sock, sock.getpeername())
 				# receive the authentication challenge string, and use that to build the actual identification string.
 				authChallenge=self.recvAuthChallenge(conn)
@@ -1001,7 +1033,7 @@
 		self.connections = []  # connection threads
 		self.initTLS=lambda tls: None  # default do-nothing func
 		if host:
-			socket.gethostbyname(host)  # validate hostname
+			socket.getaddrinfo(host, None)  # validate hostname
 		try:
 			if prtcol=='PYROSSL':
 				try:
@@ -1029,10 +1061,18 @@
 				self.setNewConnectionValidator(DefaultConnValidator())
 				
 			# create server socket for new connections
-			self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-			set_reuse_addr(self.sock)
-			set_sock_no_inherit(self.sock)
-			self.sock.bind((host,port))
+			if getIPVersion( host ) == 4:
+				self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+				set_reuse_addr(self.sock)
+				set_sock_no_inherit(self.sock)
+				self.sock.bind((host,port))
+			elif getIPVersion( host ) == 6:
+				self.sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
+				set_reuse_addr(self.sock)
+				set_sock_no_inherit(self.sock)
+				self.sock.bind((host,port,0,0))
+			else:
+				raise ProtocolError("Unkown IP address format: " + host)
 			self.sock.listen(Pyro.config.PYRO_TCP_LISTEN_BACKLOG)
 			if self._ssl_server:
 				self.sock = SSL.Connection(self.ctx,self.sock)   # wrap server socket as SSL socket
Index: Pyro/ext/NS_NtService.py
===================================================================
--- Pyro/ext/NS_NtService.py	(révision 507)
+++ Pyro/ext/NS_NtService.py	(copie de travail)
@@ -51,7 +51,7 @@
 		PyroDaemon.useNameServer(ns)
 		NS_URI=PyroDaemon.connect(ns,Pyro.constants.NAMESERVER_NAME)
 	
-	BcServerObject = BroadcastServer((hstn or '',bcport),bcRequestHandler)
+	BcServerObject = BroadcastServer(hstn or '',bcport,bcRequestHandler)
 	if Guards[1]:
 		BcServerObject.setRequestValidator(Guards[1])
 	BcServerObject.keepRunning(keep)
Index: Pyro/naming.py
===================================================================
--- Pyro/naming.py	(révision 507)
+++ Pyro/naming.py	(copie de travail)
@@ -119,18 +119,35 @@
 				raise Pyro.errors.PyroError(msg)
 			if bcaddr:
 				try:
-					socket.gethostbyname(bcaddr)
+					socket.getaddrinfo(bcaddr, None)
 				except socket.error:
 					msg="invalid broadcast address '%s'" % bcaddr
 					if trace:
 						print msg
 					raise ValueError(msg)
-				destination1 = (bcaddr, port1)
-				destination2 = (bcaddr, port2)
+				if protocol.getIPAddress( bcaddr ) == 4:
+					destination1 = (bcaddr, port1)
+					destination2 = (bcaddr, port2)
+				elif protocol.getIPAddress( bcaddr ) == 6:
+					destination1 = (bcaddr, port1, 0, 0)
+					destination2 = (bcaddr, port2, 0, 0)
+				else:
+					raise ValueError("unkown IP address format: " + bcaddr)
 			else:
-				destination1 = (Pyro.config.PYRO_NS_BC_ADDR or '<broadcast>', port1)
-				destination2 = (Pyro.config.PYRO_NS2_BC_ADDR or '<broadcast>', port2)
-			s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+				if protocol.getIPAddress( bcaddr ) == 4:
+					destination1 = (Pyro.config.PYRO_NS_BC_ADDR or '<broadcast>', port1)
+					destination2 = (Pyro.config.PYRO_NS2_BC_ADDR or '<broadcast>', port2)
+				elif protocol.getIPAddress( bcaddr ) == 6:
+					destination1 = (Pyro.config.PYRO_NS_BC_ADDR or '<broadcast>', port1, 0, 0)
+					destination2 = (Pyro.config.PYRO_NS2_BC_ADDR or '<broadcast>', port2, 0, 0)
+				else:
+					raise ValueError("unkown IP address format: " + bcaddr)
+			if protocol.getIPAddress( bcaddr ) == 4:
+				s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+			elif protocol.getIPAddress( bcaddr ) == 6:
+				s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
+			else:
+				raise ValueError("unkown IP address format: " + bcaddr)
 			if hasattr(socket,'SO_BROADCAST'):
 				s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
 			
@@ -1023,15 +1040,19 @@
 
 	nameServerURI = ''	# the Pyro URI of the Name Server
 
-	def __init__(self, addr, bcRequestHandler,norange=0):
+	def __init__(self, location, port, bcRequestHandler,norange=0):
 		if norange:
 			portrange=1
 		else:
 			portrange=Pyro.config.PYRO_PORT_RANGE
-		(location,port)=addr
 		for port in range(port, port+portrange):
 			try:
-				SocketServer.UDPServer.__init__(self, (location,port), bcRequestHandler)
+				if protocol.getIPAddress( location ) == 4:
+					SocketServer.UDPServer.__init__(self, (location,port), bcRequestHandler)
+				elif protocol.getIPAddress( location ) == 6:
+					SocketServer.UDPServer.__init__(self, (location,port,0,0), bcRequestHandler)
+				else:
+					raise ValueError("unknown IP address format: " + location)
 				return			# got it!
 			except socket.error:
 				continue		# try the next port in the list
@@ -1225,7 +1246,7 @@
 					broadcastAddresses=["<broadcast>", "", "255.255.255.255"]
 				for bc_bind in broadcastAddresses:
 					try:
-						self.bcserver = BroadcastServer((bc_bind,bcport),bcRequestHandler,norange=1)
+						self.bcserver = BroadcastServer(bc_bind,bcport,bcRequestHandler,norange=1)
 						break
 					except socket.error,x:
 						notStartedError += str(x)+" "
Index: Pyro/util.py
===================================================================
--- Pyro/util.py	(révision 507)
+++ Pyro/util.py	(copie de travail)
@@ -9,8 +9,8 @@
 
 from __future__ import with_statement
 import os, sys, traceback
-import time, random, linecache
-import socket, binascii
+import time, linecache
+import uuid
 import Pyro.constants
 from Pyro.util2 import *	# bring in 'missing' util functions
 
@@ -292,70 +292,9 @@
 			print
 
 
-_getGUID_counter=0		# extra safeguard against double numbers
-_getGUID_lock=getLockObject()
+def getGUID():
+	return uuid.uuid1().hex
 
-if os.name=='java':
-	# define jython specific stuff
-	# first, the guid stuff. try java5 uuid first.
-	try:
-		from java.util import UUID
-		def getGUID():
-			return str(UUID.randomUUID())
-	except ImportError:
-		# older java, use rmi's vmid instead
-		from java.rmi.dgc import VMID
-		def getGUID():
-			return str(VMID().toString().replace(':','-').replace('--','-'))
-	import imp
-	if not hasattr(imp,"acquire_lock"):
-		# simulate missing imp.acquire_lock() from jython 2.2 (fixed in jython 2.5)
-		imp_lock=getLockObject()
-		def imp_acquire_lock():
-			return imp_lock.acquire()
-		def imp_release_lock():
-			return imp_lock.release()
-		imp.acquire_lock=imp_acquire_lock
-		imp.release_lock=imp_release_lock
-		
-elif sys.platform=='cli':
-	import System
-	def getGUID():
-		# IronPython uses .NET guid call
-		return System.Guid.NewGuid().ToString()
-else:	
-	def getGUID():
-		# Generate readable GUID string.
-		# The GUID is constructed as follows: hexlified string of
-		# AAAAAAAA-AAAABBBB-BBBBBBBB-BBCCCCCC  (a 128-bit number in hex)
-		# where A=network address, B=timestamp, C=random. 
-		# The 128 bit number is returned as a string of 16 8-bits characters.
-		# For A: should use the machine's MAC ethernet address, but there is no
-		# portable way to get it... use the IP address + 2 bytes process id.
-		try:
-			ip=socket.gethostbyname(socket.gethostname())
-			networkAddrStr=binascii.hexlify(socket.inet_aton(ip))+"%04x" % os.getpid()
-		except socket.error:
-			# can't get IP address... use another value, like our Python id() and PID
-			Log.warn('getGUID','Can\'t get IP address')
-			try:
-				ip=os.getpid()
-			except:
-				ip=0
-			ip += id(getGUID)
-			networkAddrStr = "%08lx%04x" % (ip, os.getpid())
-	
-		with _getGUID_lock:  # cannot generate multiple GUIDs at once
-			global _getGUID_counter
-			t1=time.time()*100 +_getGUID_counter
-			_getGUID_counter+=1 
-		t2=int((t1*time.clock())%sys.maxint) & 0xffffff
-		t1=int(t1%sys.maxint) 
-		timestamp = (long(t1) << 24) | t2 
-		r2=(random.randint(0,sys.maxint//2)>>4) & 0xffff
-		r3=(random.randint(0,sys.maxint//2)>>5) & 0xff
-		return networkAddrStr+'%014x%06x' % (timestamp, (r2<<8)|r3 )
-
 def genguid_scripthelper(argv):
 	p=ArgParser()
 	p.parse(argv,'')

Attachment: signature.asc
Description: This is a digitally signed message part

------------------------------------------------------------------------------
All of the data generated in your IT infrastructure is seriously valuable.
Why? It contains a definitive record of application performance, security 
threats, fraudulent activity, and more. Splunk takes this data and makes 
sense of it. IT sense. And common sense.
http://p.sf.net/sfu/splunk-d2d-c2
_______________________________________________
Shinken-devel mailing list
Shinken-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/shinken-devel

Reply via email to