[asterisk-scf-commits] asterisk-scf/integration/servicelocatormdns.git branch "master" created.

Commits to the Asterisk SCF project code repositories asterisk-scf-commits at lists.digium.com
Mon Jun 20 08:12:56 CDT 2011


branch "master" has been created
        at  601635f2f988733179708d63fb3159cd9a700502 (commit)

- Log -----------------------------------------------------------------
commit 601635f2f988733179708d63fb3159cd9a700502
Author: Joshua Colp <jcolp at digium.com>
Date:   Sun Jun 12 13:05:57 2011 -0300

    Add README.txt file.

diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000..8a21070
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,43 @@
+ServiceLocatorMDNS is a set of python scripts which use multicast DNS to provide location
+information for the service locator. This allows you to use the service locator without
+having to configure your Asterisk SCF components with the IP address and port of it. It
+will be automatically found using multicast DNS.
+
+1. Pre-requisites
+
+The pybonjour module is used as the interface between multicast DNS and python. It must be
+installed for the ServiceLocatorMDNS python scripts to operate. It can be found at
+http://code.google.com/p/pybonjour/
+
+2. Installation on server side
+
+The machine running the service locator must also be running the ServiceLocatorPublisher.py
+python script. This publishes the location information using multicast DNS. There is no
+configuration required for this script.
+
+3. Installation on client side
+
+Each machine running an Asterisk SCF component must also be running the ServiceLocatorAgent.py
+python script. This finds the service locator using multicast DNS and makes it available using
+an Ice locator implementation. There is no configuration required for this script.
+
+4. Asterisk SCF component configuration
+
+Each running component must have the following Ice configuration properties:
+
+Ice.Default.Locator=AsteriskSCF/Locator:default -p 4433 -h localhost
+ServiceLocatorProxy=AsteriskSCF/LocatorService
+ServiceLocatorManagementProxy=AsteriskSCF/LocatorServiceManagement
+
+These tell the Ice client where it can find the locally running ServiceLocatorAgent.py python
+script and how to request the service locator from it.
+
+* Note that while it is possible to run a single ServiceLocatorAgent.py python script for a group
+of machines this defeats the purpose of using multicast DNS since the IP address and port of the
+machine running the python script would have to be put into the configuration file.
+
+5. Done!
+
+This is all that is required to use multicast DNS for finding the service locator. While there is
+some initial configuration required there are no hardcoded IP addresses or ports for the service
+locator.

commit 1ae5d2948731eb9631fe729e639fa07a3934ce4c
Author: Joshua Colp <jcolp at digium.com>
Date:   Sat Jun 11 20:08:15 2011 -0300

    Turn TODO list into a future improvement list after some research.

diff --git a/ServiceLocatorAgent.py b/ServiceLocatorAgent.py
index 86f24c4..3f8c231 100644
--- a/ServiceLocatorAgent.py
+++ b/ServiceLocatorAgent.py
@@ -20,8 +20,9 @@
 
 import select, sys, traceback, Ice, socket, pybonjour
 
-# TODO:
-# 1. Remove addresses from proxy when service goes away
+# Future improvements:
+# 1. When a service goes away remove any endpoints, for now we rely on the client failing to connect and trying
+#    a different one. Since this is TCP it happens quick enough.
 
 # Ice communicator used for Ice stuff
 communicator = None
@@ -202,7 +203,8 @@ def BonjourBrowseCallback(sdRef, flags, interfaceIndex, errorCode, serviceName,
     if errorCode != pybonjour.kDNSServiceErr_NoError:
         return
 
-    # If a service was removed we should take away their endpoints
+    # If a service was removed we should take away their endpoints, but for now just rely on the client
+    # trying a different endpoint
     if not (flags & pybonjour.kDNSServiceFlagsAdd):
         return
 

commit 3a07d00317ab891c19dd9827e522ac845a44fb82
Author: Joshua Colp <jcolp at digium.com>
Date:   Sat Jun 11 20:03:30 2011 -0300

    Fix a bug where the port would be the value received for the last service for all, and not just the last service.

diff --git a/ServiceLocatorAgent.py b/ServiceLocatorAgent.py
index 86105fb..86f24c4 100644
--- a/ServiceLocatorAgent.py
+++ b/ServiceLocatorAgent.py
@@ -21,8 +21,7 @@
 import select, sys, traceback, Ice, socket, pybonjour
 
 # TODO:
-# 1. Remove proxies when a publisher gets shutdown
-# 2. Determine if other transports should be supported other than TCP
+# 1. Remove addresses from proxy when service goes away
 
 # Ice communicator used for Ice stuff
 communicator = None
@@ -45,6 +44,12 @@ BonjourServiceName = None
 # Addresses for the current service, used internally by callbacks
 BonjourAddresses = [ ]
 
+# Endpoints for service locator proxy
+BonjourLocatorEndpoints = [ ]
+
+# Endpoints for service locator management proxy
+BonjourManagementEndpoints = [ ]
+
 # Whether a DNS request has completed or not, used internally by callbacks
 BonjourDNSRequestCompleted = False
 
@@ -108,6 +113,8 @@ def BonjourResolveCallback(sdRef, flags, interfaceIndex, errorCode, fullname,
                                hosttarget, port, txtRecord):
     global communicator
     global BonjourAddresses
+    global BonjourLocatorEndpoints
+    global BonjourManagementEndpoints
     global BonjourServiceName
     global BonjourDNSRecordCompleted
     global ServiceLocatorProxy
@@ -118,6 +125,9 @@ def BonjourResolveCallback(sdRef, flags, interfaceIndex, errorCode, fullname,
     if errorCode != pybonjour.kDNSServiceErr_NoError:
         return
 
+    # Clear any existing addresses
+    BonjourAddresses = [ ]
+
     # Query for A records
     BonjourDNSRecordCompleted = False
     query = pybonjour.DNSServiceQueryRecord(interfaceIndex = interfaceIndex,
@@ -154,15 +164,25 @@ def BonjourResolveCallback(sdRef, flags, interfaceIndex, errorCode, fullname,
     # Remove duplicates from addresses
     BonjourAddresses = list(set(BonjourAddresses))
 
-    # But if we have any addresses we need to create the proper proxy
-    if BonjourAddresses:
-        # We only support TCP transport right now
-        transport = 'tcp'
+    # We only support TCP transport right now
+    transport = 'tcp'
 
-        # Construct portion for endpoints
-        endpoints = ''.join([':{0} -h {1} -p {2}'.format(transport, address, port) for address in BonjourAddresses])
+    # Add new addresses to all addresses
+    for address in BonjourAddresses:
+        endpoint = ':{0} -h {1} -p {2}'.format(transport, address, port)
+        if BonjourServiceName == 'ServiceLocator':
+            BonjourLocatorEndpoints.append(endpoint)
+            BonjourLocatorEndpoints = list(set(BonjourLocatorEndpoints))
+            BonjourAllAddresses = BonjourLocatorEndpoints
+        elif BonjourServiceName == 'ServiceLocatorManagement':
+            BonjourManagementEndpoints.append(endpoint)
+            BonjourManagementEndpoints = list(set(BonjourManagementEndpoints))
+            BonjourAllAddresses = BonjourManagementEndpoints
 
+    # But if we have any addresses we need to create the proper proxy
+    if BonjourAllAddresses:
         proxy = None
+        endpoints = ''.join(['{0}'.format(address) for address in BonjourAllAddresses])
         if BonjourServiceName == 'ServiceLocator':
             proxy = communicator.stringToProxy('LocatorService{0}'.format(endpoints))
             ServiceLocatorProxy = proxy

commit bf40f4fc6f749256467f9effd773f74aa5a73b60
Author: Joshua Colp <jcolp at digium.com>
Date:   Sat Jun 11 19:48:17 2011 -0300

    Support multiple services by returning a proxy with multiple endpoints.

diff --git a/ServiceLocatorAgent.py b/ServiceLocatorAgent.py
index 7d5c8e4..86105fb 100644
--- a/ServiceLocatorAgent.py
+++ b/ServiceLocatorAgent.py
@@ -21,9 +21,8 @@
 import select, sys, traceback, Ice, socket, pybonjour
 
 # TODO:
-# 2. Remove proxies when a publisher gets shutdown
-# 4. Determine if other transports should be supported other than TCP
-# 5. Determine how to handle multiple responses
+# 1. Remove proxies when a publisher gets shutdown
+# 2. Determine if other transports should be supported other than TCP
 
 # Ice communicator used for Ice stuff
 communicator = None
@@ -119,9 +118,6 @@ def BonjourResolveCallback(sdRef, flags, interfaceIndex, errorCode, fullname,
     if errorCode != pybonjour.kDNSServiceErr_NoError:
         return
 
-    # Clear out any old addresses
-    BonjourAddresses = [ ]
-
     # Query for A records
     BonjourDNSRecordCompleted = False
     query = pybonjour.DNSServiceQueryRecord(interfaceIndex = interfaceIndex,
@@ -155,6 +151,9 @@ def BonjourResolveCallback(sdRef, flags, interfaceIndex, errorCode, fullname,
     # Yeah request completed
     BonjourDNSRequestCompleted = True
 
+    # Remove duplicates from addresses
+    BonjourAddresses = list(set(BonjourAddresses))
+
     # But if we have any addresses we need to create the proper proxy
     if BonjourAddresses:
         # We only support TCP transport right now

commit 0109bc69cb5c09dbd5881846ddbed339c82f9b03
Author: Joshua Colp <jcolp at digium.com>
Date:   Sat Jun 11 19:47:35 2011 -0300

    Fix port for service locator management.

diff --git a/ServiceLocatorPublisher.py b/ServiceLocatorPublisher.py
index b5ca659..4ef95ac 100644
--- a/ServiceLocatorPublisher.py
+++ b/ServiceLocatorPublisher.py
@@ -28,7 +28,7 @@ bonjourServiceLocator = pybonjour.DNSServiceRegister(name = 'ServiceLocator',
 # Register the service locator management interface with Bonjour
 bonjourServiceLocatorManagement = pybonjour.DNSServiceRegister(name = 'ServiceLocatorManagement',
                                                                regtype = '_asteriskscf._tcp',
-                                                               port = 4411)
+                                                               port = 4422)
 
 # Go into a loop processing results that may come in
 while True:

commit ef0b4112e78b182f9285962ba19be7ff6adb2025
Author: Joshua Colp <jcolp at digium.com>
Date:   Tue Jun 7 09:55:58 2011 -0300

    Add python scripts that provide a mechanism for automatic service locator discovery using Bonjour.

diff --git a/ServiceLocatorAgent.py b/ServiceLocatorAgent.py
new file mode 100644
index 0000000..7d5c8e4
--- /dev/null
+++ b/ServiceLocatorAgent.py
@@ -0,0 +1,262 @@
+#!/usr/bin/env python
+
+#
+# Asterisk SCF -- An open-source communications framework.
+#
+# Copyright (C) 2011, Digium, Inc.
+#
+# See http://www.asterisk.org for more information about
+# the Asterisk SCF project. Please do not directly contact
+# any of the maintainers of this project for assistance;
+# the project provides a web site, mailing lists and IRC
+# channels for your use.
+#
+# This program is free software, distributed under the terms of
+# the GNU General Public License Version 2. See the LICENSE.txt file
+# at the top of the source tree.
+#
+
+# Service Locator Bonjour Receiver
+
+import select, sys, traceback, Ice, socket, pybonjour
+
+# TODO:
+# 2. Remove proxies when a publisher gets shutdown
+# 4. Determine if other transports should be supported other than TCP
+# 5. Determine how to handle multiple responses
+
+# Ice communicator used for Ice stuff
+communicator = None
+
+# Proxy to the service locator interface, may contain multiple endpoints
+ServiceLocatorProxy = None
+
+# Proxy to the service locator management interface, may contain multiple endpoints
+ServiceLocatorManagementProxy = None
+
+# Timeout used for Bonjour requests
+BonjourTimeout = 5
+
+# Timeout used for DNS record queries
+BonjourDNSTimeout = 5
+
+# Service name currently returned, used internally by callbacks
+BonjourServiceName = None
+
+# Addresses for the current service, used internally by callbacks
+BonjourAddresses = [ ]
+
+# Whether a DNS request has completed or not, used internally by callbacks
+BonjourDNSRequestCompleted = False
+
+# Whether a DNS record lookup has completed or not, used internally by callbacks
+BonjourDNSRecordCompleted = False
+
+# We provide an implementation of the locator interface so anyone can ask us to do a lookup
+# for the service locator and service locator management proxy.
+class LocatorI(Ice.Locator):
+    def findObjectById_async(self, cb, id, current):
+        # If this is not for the AsteriskSCF category we certainly know nothing
+        if id.category != 'AsteriskSCF':
+            cb.ice_response(None)
+
+        # Determine which proxy to return
+        if id.name == 'LocatorService':
+            cb.ice_response(ServiceLocatorProxy)
+        elif id.name == 'LocatorServiceManagement':
+            cb.ice_response(ServiceLocatorManagementProxy)
+
+        # Anything else we don't know anything about
+        cb.ice_response(None)
+
+    def findAdapterById_async(self, cb, id, current):
+        # We do not support anything to do with object adapters
+        cb.ice_response(None)
+
+    def getRegistry_async(self, cb, current):
+        # We do not support the registry
+        cb.ice_response(None)
+
+# Callback called when we have an A record for a service
+def BonjourARecordCallback(sdRef, flags, interfaceIndex, errorCode, fullname,
+                           rrtype, rrclass, rdata, ttl):
+    global BonjourAddresses
+    global BonjourDNSRecordCompleted
+
+    # If an error occurred just go on our way
+    if errorCode != pybonjour.kDNSServiceErr_NoError:
+        return
+
+    BonjourAddresses.append(socket.inet_ntop(socket.AF_INET, rdata))
+    BonjourDNSRecordCompleted = True
+
+# Callback called when we have an AAAA record for a service
+def BonjourAAAARecordCallback(sdRef, flags, interfaceIndex, errorCode, fullname,
+                              rrtype, rrclass, rdata, ttl):
+    global BonjourAddresses
+    global BonjourDNSRecordCompleted
+
+    # If an error occurred just go on our way
+    if errorCode != pybonjour.kDNSServiceErr_NoError:
+        return
+
+    BonjourAddresses.append('\"{0}\"'.format(socket.inet_ntop(socket.AF_INET6, rdata)))
+    BonjourDNSRecordCompleted = True
+
+
+# Callback called when a resolve request on a browse response is completed
+def BonjourResolveCallback(sdRef, flags, interfaceIndex, errorCode, fullname,
+                               hosttarget, port, txtRecord):
+    global communicator
+    global BonjourAddresses
+    global BonjourServiceName
+    global BonjourDNSRecordCompleted
+    global ServiceLocatorProxy
+    global ServiceLocatorManagementProxy
+    global BonjourDNSRequestCompleted
+
+    # If an error occurred just go on our way
+    if errorCode != pybonjour.kDNSServiceErr_NoError:
+        return
+
+    # Clear out any old addresses
+    BonjourAddresses = [ ]
+
+    # Query for A records
+    BonjourDNSRecordCompleted = False
+    query = pybonjour.DNSServiceQueryRecord(interfaceIndex = interfaceIndex,
+                                            fullname = hosttarget,
+                                            rrtype = pybonjour.kDNSServiceType_A,
+                                            callBack = BonjourARecordCallback)
+
+    while BonjourDNSRecordCompleted == False:
+        ready = select.select([query], [], [], BonjourDNSTimeout)
+        if query not in ready[0]:
+            break
+        pybonjour.DNSServiceProcessResult(query)
+
+    query.close()
+
+    # Query for AAAA records
+    BonjourDNSRecordCompleted = False
+    query = pybonjour.DNSServiceQueryRecord(interfaceIndex = interfaceIndex,
+                                            fullname = hosttarget,
+                                            rrtype = pybonjour.kDNSServiceType_AAAA,
+                                            callBack = BonjourAAAARecordCallback)
+
+    while BonjourDNSRecordCompleted == False:
+        ready = select.select([query], [], [], BonjourDNSTimeout)
+        if query not in ready[0]:
+            break
+        pybonjour.DNSServiceProcessResult(query)
+
+    query.close()
+
+    # Yeah request completed
+    BonjourDNSRequestCompleted = True
+
+    # But if we have any addresses we need to create the proper proxy
+    if BonjourAddresses:
+        # We only support TCP transport right now
+        transport = 'tcp'
+
+        # Construct portion for endpoints
+        endpoints = ''.join([':{0} -h {1} -p {2}'.format(transport, address, port) for address in BonjourAddresses])
+
+        proxy = None
+        if BonjourServiceName == 'ServiceLocator':
+            proxy = communicator.stringToProxy('LocatorService{0}'.format(endpoints))
+            ServiceLocatorProxy = proxy
+        elif BonjourServiceName == 'ServiceLocatorManagement':
+            proxy = communicator.stringToProxy('LocatorServiceManagement{0}'.format(endpoints))
+            ServiceLocatorManagementProxy = proxy
+
+        print 'Discovered and created proxy: ', proxy
+
+# Callback called when we have a browse response for an Asterisk SCF publisher
+def BonjourBrowseCallback(sdRef, flags, interfaceIndex, errorCode, serviceName,
+                    regtype, replyDomain):
+    global BonjourServiceName
+    global BonjourDNSRequestCompleted
+
+    # If an error occurred just go on our way
+    if errorCode != pybonjour.kDNSServiceErr_NoError:
+        return
+
+    # If a service was removed we should take away their endpoints
+    if not (flags & pybonjour.kDNSServiceFlagsAdd):
+        return
+
+    # If this is an unsupported service ignore it
+    if serviceName != 'ServiceLocator':
+        if serviceName != 'ServiceLocatorManagement':
+            return
+
+    BonjourServiceName = serviceName
+
+    # If a service was added we need to resolve, get their records, and construct a proxy
+    resolve = pybonjour.DNSServiceResolve(0,
+                                          interfaceIndex,
+                                          serviceName,
+                                          regtype,
+                                          replyDomain,
+                                          BonjourResolveCallback)
+
+    BonjourDNSRequestCompleted = False
+
+    while BonjourDNSRequestCompleted == False:
+        ready = select.select([resolve], [], [], BonjourDNSTimeout)
+
+        # If the resolve attempt timed out abort entirely
+        if resolve not in ready[0]:
+            break
+
+        # Otherwise process the result
+        pybonjour.DNSServiceProcessResult(resolve)
+
+    # Now that we have completed resolving we can move on to the next service
+    resolve.close()
+
+# Ensure some values are properly initialized
+browse = None
+status = 0
+adapter = None
+
+try:
+    # Before we start making ourselves available at all go ahead and start trying
+    # to find the service locator information using Bonjour
+    browse = pybonjour.DNSServiceBrowse(regtype = "_asteriskscf._tcp",
+                                        callBack = BonjourBrowseCallback)
+
+    # Now initialize Ice
+    communicator = Ice.initialize(sys.argv)
+
+    # Port 4433 has been set aside by us for this purpose, thus why it is hardcoded
+    adapter = communicator.createObjectAdapterWithEndpoints(
+        "LocatorAdapter", "default -h localhost -p 4433")
+
+    # Create an instance of our locator implementation and make it available
+    object = LocatorI()
+    adapter.add(object, communicator.stringToIdentity("AsteriskSCF/Locator"))
+    adapter.activate()
+
+    # Now that the Ice portion is done start processing Bonjour results
+    while True:
+        ready = select.select([browse], [], [], BonjourTimeout)
+        if browse in ready[0]:
+            pybonjour.DNSServiceProcessResult(browse)
+except:
+    status = 1
+
+if browse:
+    browse.close()
+
+if communicator:
+    # Clean up
+    try:
+        communicator.destroy()
+    except:
+        traceback.print_exc()
+        status = 1
+
+sys.exit(status)
diff --git a/ServiceLocatorPublisher.py b/ServiceLocatorPublisher.py
new file mode 100644
index 0000000..b5ca659
--- /dev/null
+++ b/ServiceLocatorPublisher.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+
+#
+# Asterisk SCF -- An open-source communications framework.
+#
+# Copyright (C) 2011, Digium, Inc.
+#
+# See http://www.asterisk.org for more information about
+# the Asterisk SCF project. Please do not directly contact
+# any of the maintainers of this project for assistance;
+# the project provides a web site, mailing lists and IRC
+# channels for your use.
+#
+# This program is free software, distributed under the terms of
+# the GNU General Public License Version 2. See the LICENSE.txt file
+# at the top of the source tree.
+#
+
+# Service Locator Bonjour Publisher
+
+import select, sys, pybonjour
+
+# Register the service locator interface with Bonjour
+bonjourServiceLocator = pybonjour.DNSServiceRegister(name = 'ServiceLocator',
+                                                     regtype = '_asteriskscf._tcp',
+                                                     port = 4411)
+
+# Register the service locator management interface with Bonjour
+bonjourServiceLocatorManagement = pybonjour.DNSServiceRegister(name = 'ServiceLocatorManagement',
+                                                               regtype = '_asteriskscf._tcp',
+                                                               port = 4411)
+
+# Go into a loop processing results that may come in
+while True:
+    ready = select.select([bonjourServiceLocator, bonjourServiceLocatorManagement], [], [])
+    if bonjourServiceLocator in ready[0]:
+        pybonjour.DNSServiceProcessResult(bonjourServiceLocator)
+    elif bonjourServiceLocatorManagement in ready[0]:
+        pybonjour.DNSServiceProcessResult(bonjourServiceLocatorManagement)
+
+# Close both registrations
+bonjourServiceLocator.close()
+bonjourServiceLocatorManagement.close()

-----------------------------------------------------------------------


-- 
asterisk-scf/integration/servicelocatormdns.git



More information about the asterisk-scf-commits mailing list