apps/dnd.py
changeset 0 2b3e5ec03512
equal deleted inserted replaced
-1:000000000000 0:2b3e5ec03512
       
     1 #!/usr/bin/python
       
     2 
       
     3 #
       
     4 #    Copyright 2006 Intel Corporation
       
     5 # 
       
     6 #    Licensed under the Apache License, Version 2.0 (the "License");
       
     7 #    you may not use this file except in compliance with the License.
       
     8 #    You may obtain a copy of the License at
       
     9 # 
       
    10 #        http://www.apache.org/licenses/LICENSE-2.0
       
    11 # 
       
    12 #    Unless required by applicable law or agreed to in writing, software
       
    13 #    distributed under the License is distributed on an "AS IS" BASIS,
       
    14 #    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       
    15 #    See the License for the specific language governing permissions and
       
    16 #    limitations under the License.
       
    17 #
       
    18 
       
    19 
       
    20 
       
    21 # DTN Neighbor Discovery (over UDP Broadcast) -- A small python script
       
    22 # that will propagate DTN registration information via UDP broadcasts.
       
    23 #
       
    24 # Written by Keith Scott, The MITRE Corporation
       
    25 
       
    26 # I got tired of having to manually configure dtn daemons, expecially
       
    27 # since the combination of the windows operating system and MITRE's
       
    28 # dhcp/dynamic DNS caused machine names/addresses to change
       
    29 # when least convenient.
       
    30 
       
    31 # This script will populate the static routing tables of DTN daemons
       
    32 # with registrations (and optionally routes) it hears from its peers.
       
    33 # When advertising my local
       
    34 # registrations, I append "/*" to the local EID and prune anything
       
    35 # that would match on this route.  This way if I'm running something
       
    36 # like bundlePing that generates 'transient' registrations,
       
    37 # I don't end up cluttering up everybody else's tables with 'em.
       
    38 
       
    39 # This script assumes that all machines use TCP convergence layers to
       
    40 # communicate
       
    41 
       
    42 # This script transmits UDP broadcast messages to a particular port
       
    43 # (5005 by default).  You'll need to open up firewalls to let this
       
    44 # traffic through.
       
    45 
       
    46 # The UDP Messages sent are of the form:
       
    47 #
       
    48 #	my DTN local EID
       
    49 #	my TCP CL Listen Port
       
    50 #	EID1 route1 distance1 nextHopEID1
       
    51 #	EID2 route2 distance2 nextHopEID2
       
    52 #	...
       
    53 
       
    54 from socket import *
       
    55 from time import *
       
    56 import mutex
       
    57 import os
       
    58 import random
       
    59 import string
       
    60 import thread
       
    61 import re
       
    62 import getopt
       
    63 import sys
       
    64 import struct
       
    65 
       
    66 INFINITY = 100
       
    67 THE_MULTICAST_TTL = 5
       
    68 
       
    69 # The default address and port
       
    70 _DND_PORT = 5005
       
    71 _DND_ADDR = '239.0.1.99'
       
    72 
       
    73 #sendToAddresses = [_DND_ADDR]
       
    74 #sendToPort = 5005				# Port to which reg info is sent
       
    75 dtnTclConsolePort = 5050			# Port on which DTN tcl interpreter is listening
       
    76 rebroadcastRoutes = 1
       
    77 addLocalEIDWildcard = 1				# If 1, advertise a route of the form 
       
    78 						# dtn://LOCAL_EID/* in addition to any
       
    79 						# registrations.  Note that the wildcard route will
       
    80 						# probably override other registrations.
       
    81 myRIB = []					# list of entries
       
    82 myEID = ""
       
    83 myPort = ""
       
    84 verbose = 0
       
    85 
       
    86 # This mutex makes sure that the various threads for receiving / processing messages
       
    87 # and sending out messages don't step on each other.
       
    88 messageProcessingMutex = mutex.mutex()
       
    89 
       
    90 myListeningDTNTCPPort = ""
       
    91 
       
    92 # Here's a list of 'default' routes.  If we have no other way to get to a particular
       
    93 # destination EID, make sure these are instantiated.  If there's any other way to get
       
    94 # to a destination EID, make sure these are DE-instantiated so thate we don't have
       
    95 # duplicate bundles flowing over both paths.
       
    96 #
       
    97 # Right now, the link name "default" is special and is the only one that will work
       
    98 # for default routes.
       
    99 #
       
   100 defaultRoutes = [["dtn://26959-pc/*", "default"],
       
   101 		 ["dtn://otherDest/*", "default"]]
       
   102 
       
   103 #
       
   104 # These are the indices of the various elements of a RIB entry.
       
   105 # The RIB is really just an annotated copy of the forwarding table.
       
   106 #
       
   107 RIB_HOST = 0					# IP address of a the next hop to the RIB_EID
       
   108 RIB_PORT = 1					# The TCPCL port of the next hop to the RIB_EID
       
   109 RIB_EID =  2					# The EID in question (a destination EID)
       
   110 RIB_DIST = 3					# Distance to the EID in question.
       
   111 RIB_TIME = 4					# Time at which this entry was last updated
       
   112 RIB_LINKNAME = 5
       
   113 RIB_NHEID = 6					# EID of the next hop (used to implement split-horizon)
       
   114 
       
   115 ROUTE_TIMEOUT = 25
       
   116 
       
   117 
       
   118 broadcastInterval = 10 # How often to broadcast, in seconds
       
   119 
       
   120 #
       
   121 # Send a message to the dtn tcl interpreter and return results
       
   122 # Return 'None' if we couldn't talk.
       
   123 #
       
   124 def talktcl(sent):
       
   125 	received = 0
       
   126 	# print "Opening connection to dtnd tcl interpreter."
       
   127 	sock = socket(AF_INET, SOCK_STREAM)
       
   128 	try:
       
   129 			sock.connect(("localhost", dtnTclConsolePort))
       
   130 	except:
       
   131 		print "Connection failed"
       
   132 		sock.close()
       
   133 		return None
       
   134 
       
   135 	try:
       
   136 		messlen, received = sock.send(sent), 0
       
   137 		if messlen != len(sent):
       
   138 			print "Failed to send complete message to tcl interpreter"
       
   139 		else:
       
   140 			# print "Message '",sent,"' sent to tcl interpreter."
       
   141 			messlen = messlen
       
   142 
       
   143 		data = ''
       
   144 		while 1:
       
   145 			promptsSeen = 0
       
   146 			data += sock.recv(32)
       
   147 			#sys.stdout.write(data)
       
   148 			received += len(data)
       
   149 			# print "Now received:", data
       
   150 			# print "checking for '%' in received data stream [",received,"], ", len(data)
       
   151 			for i in range(len(data)):
       
   152 				if data[i]=='%':
       
   153 					promptsSeen = promptsSeen + 1
       
   154 				if promptsSeen>1:
       
   155 					break;
       
   156 			if promptsSeen>1:
       
   157 				break;
       
   158 
       
   159 		# print "talktcl received: ",data," back from tcl.\n"
       
   160 
       
   161 	except:
       
   162 		sock.close()
       
   163 		return None
       
   164 
       
   165 	# Remove up to and including the first prompt
       
   166 	firstPrompt=string.find(data, "dtn% ")
       
   167 	if firstPrompt==-1:
       
   168 		return ''
       
   169 	data = data[firstPrompt+5:]
       
   170 
       
   171 	sock.close()
       
   172 	return(data);
       
   173 		
       
   174 #
       
   175 # Return the port on which the TCP convergence layer is listening
       
   176 #
       
   177 def findListeningPort():
       
   178 	response = talktcl("interface list\n")
       
   179 	if response==None:
       
   180 		return None
       
   181 
       
   182 	lines = string.split(response, "\n")
       
   183 	for i in range(len(lines)):
       
   184 		if string.find(lines[i], "Convergence Layer: tcp")>=0:
       
   185 			words = string.split(lines[i+1])
       
   186 			return(words[3])
       
   187 	return None
       
   188 
       
   189 #
       
   190 # Munge the list 'lines' to contain only entries
       
   191 # that contain (in the re.seach sense) at least
       
   192 # one of the keys
       
   193 #
       
   194 def onlyLinesContaining(lines, keys):
       
   195 	answer = []
       
   196 	for theLine in lines:
       
   197 		for theKey in keys:
       
   198 			if re.search(theKey, theLine):
       
   199 					answer += [theLine]
       
   200 					break;
       
   201 	return answer
       
   202 
       
   203 #
       
   204 # Generate a random string containing letters and digits
       
   205 # of specified length
       
   206 #
       
   207 def generateRandom(length):
       
   208 	chars = string.ascii_letters + string.digits
       
   209 	return(''.join([random.choice(chars) for i in range(length)]))
       
   210 
       
   211 #
       
   212 # Generate a new unique link identifier of the form dnd_XXXX
       
   213 # where XXXX is a string of random letters.
       
   214 #
       
   215 def genNewLink(linkList):
       
   216 	done = False
       
   217 	print "genNewLink: ", linkList
       
   218 	while done==False:
       
   219 		test = generateRandom(4)
       
   220 		# See if the identifier is already in use
       
   221 		if len(linkList)>0:
       
   222 			for i in range(len(linkList)):
       
   223 				words = string.split(linkList[i], " ");
       
   224 				if words[4]!=test:
       
   225 					done = True
       
   226 					break;
       
   227 		else:
       
   228 			done = True
       
   229 	return "dnd_" + test
       
   230 
       
   231 
       
   232 #
       
   233 # Return a pair of lists: the current links and the current
       
   234 # routes from the DTN daemon
       
   235 #
       
   236 def getLinksRoutes():
       
   237 	myRoutes = talktcl("route dump\n")
       
   238 	if myRoutes==None:
       
   239 		print "getLinksRoutes: can't talk to dtn daemon"
       
   240 		return([[],[]])
       
   241 	#myRoutes = string.strip(myRoutes, "dtn% ")
       
   242 
       
   243 	# Split the response into lines
       
   244 	lines = string.split(myRoutes, '\n');
       
   245 	
       
   246 	theRoutes = []
       
   247 	theLinks = []
       
   248 
       
   249 	# After stripping off the header (first 5 lines), 
       
   250 	# the routes are the first few lines up to the first blank line
       
   251 	i = 0
       
   252 	for i in range(5,len(lines)):
       
   253 		# If the line has a "->" in it, it's a route.
       
   254 		if string.find(lines[i], "->")>=0:
       
   255 			theRoutes += [lines[i]]
       
   256 		if string.find(lines[i], "Long")>=0:
       
   257 			break
       
   258 		if string.find(lines[i], "Links")>=0:
       
   259 			break
       
   260 		if len(lines[i])==1:
       
   261 			break
       
   262 
       
   263 	#
       
   264 	# Fix up any Long Endpoint IDs
       
   265 	#
       
   266 	for i in range(5,len(lines)):
       
   267 		if string.find(lines[i], "Long")>=0:
       
   268 			break
       
   269 	for j in range(i+1, len(lines)):
       
   270 		if len(lines[j])==1:
       
   271 			break;
       
   272 		tokens = string.split(lines[j], ' ');
       
   273 		tokens[0] = tokens[0].lstrip()
       
   274 		tokens[0] = tokens[0].lstrip()
       
   275 		tokens[0] = tokens[0].strip(":")
       
   276 
       
   277 		for k in range(0, len(theRoutes)):
       
   278 			if theRoutes[k].find(tokens[0])>=0:
       
   279 				tokens[1] = tokens[1].strip("\r")
       
   280 				theRoutes[k] = theRoutes[k].replace(tokens[0], tokens[1])
       
   281 	
       
   282 	#
       
   283 	# Find the links
       
   284 	# Start by whipping through the lines agin looking for "Links:"
       
   285 	#
       
   286 	for i in range(5,len(lines)):
       
   287 		if string.find(lines[i], "Links:")>=0:
       
   288 			break
       
   289 
       
   290 	for j in range(i+1, len(lines)):
       
   291 		if len(lines[j])==1:
       
   292 			break;
       
   293 		theLinks += [lines[j]]
       
   294 
       
   295 	if ( verbose > 4 ):
       
   296 		print "getLinksRoutes returns: "
       
   297 		print theLinks
       
   298 		print theRoutes
       
   299 	return([theLinks, theRoutes])
       
   300 
       
   301 # Return the link name of an existing link, or None
       
   302 # format for newLink is hot:port
       
   303 # format for 'newLink is host:port'
       
   304 def alreadyHaveLink(newLink):
       
   305 	theLinks, theRoutes = getLinksRoutes()
       
   306 	for testLink in theLinks:
       
   307 		bar = string.split(newLink, ":")
       
   308 		host = bar[0]
       
   309 		port = bar[1]
       
   310 
       
   311 		# If we have a complete match (host:port), we're done
       
   312 		if string.find(testLink, newLink)>=0:
       
   313 			testLink = string.split(testLink)
       
   314 			return testLink[0]
       
   315 
       
   316 		# If we match on the host and the link is opportunistic,
       
   317 		# go ahead and call it a match
       
   318 		hostThere = string.find(testLink, host)
       
   319 		isOpportunistic = testLink.startswith("opportunistic")
       
   320 		if ( (hostThere>0) and (isOpportunistic)):
       
   321 			foo = string.split(testLink, " ")
       
   322 			return foo[0]
       
   323 	return None
       
   324 
       
   325 def myBroadcast():
       
   326 	answer = []
       
   327 	myaddrs = os.popen("/sbin/ip addr show").read()
       
   328 	myaddrs = string.split(myaddrs, "\n")
       
   329 
       
   330 	myaddrs = onlyLinesContaining(myaddrs, ["inet.*brd"])
       
   331 
       
   332 	for addr in myaddrs:
       
   333 		words = string.split(addr)
       
   334 		for i in range(len(words)):
       
   335 			if words[i]=="brd":
       
   336 				answer += [words[i+1]]
       
   337 
       
   338 	return answer
       
   339 
       
   340 #
       
   341 # Called periodically to time out routes that have not been refreshed.
       
   342 #
       
   343 def timeOutOldRoutes(RIB):
       
   344 	# print "checking RIB for timed out routes..."
       
   345 	# printRIB(myRIB)
       
   346 	# The whole 'done' thing handles the fact that the list traversal gets gorked when
       
   347 	# you yank elements out of the list
       
   348 	done = 0
       
   349 	while done == 0:
       
   350 		done = 1
       
   351 		for entry in RIB:
       
   352 			if verbose>0:
       
   353 				print "RIB entry", entry, "is ", time()-entry[RIB_TIME]," seconds old"
       
   354 			if time()-entry[RIB_TIME]>ROUTE_TIMEOUT:
       
   355 				print "RIB entry", entry, "timed out."
       
   356 				print "Using 'removeRoute "+entry[RIB_EID]
       
   357 				removeRoute(entry[RIB_EID])
       
   358 				if entry[RIB_DIST]==INFINITY:
       
   359 					RIB.remove(entry)
       
   360 				entry[RIB_TIME] = time()
       
   361 				done = 0
       
   362 
       
   363 #
       
   364 # remove a route, doing 'the right thing' by re-adding routes using the 'default'
       
   365 # link for destinations listed as being able to use the default link
       
   366 #
       
   367 def removeRoute(eid):
       
   368 	talktcl("route del "+eid+"\n")
       
   369 	for (theEID, theLink) in defaultRoutes:
       
   370 		if ( theEID==eid ):
       
   371 			talktcl("route add "+eid+" "+theLink+"\n")
       
   372 			return True
       
   373 	return False
       
   374 #
       
   375 # Return True if I have an exact routing match (no wildcards) for the given
       
   376 # EID
       
   377 #
       
   378 def exactRouteFor(eid):
       
   379 	theLinks, theRoutes = getLinksRoutes()
       
   380 	if len(theRoutes)>0:
       
   381 		for i in range(len(theRoutes)):
       
   382 			theRoutes[i] = theRoutes[i].strip()
       
   383 			nextHop = string.split(theRoutes[i])[0];
       
   384 			# print "Checking",eid," against existing route:", nextHop
       
   385 			if nextHop==eid:
       
   386 				return True
       
   387 	return False
       
   388 
       
   389 #
       
   390 # Return True if I have a current route to the destination EID, False otherwise
       
   391 # Route information is extracted from the deamon, NOT the RIB
       
   392 #
       
   393 def haveRouteFor(eid):
       
   394 	theLinks, theRoutes = getLinksRoutes()
       
   395 	if ( verbose>3 ):
       
   396 		print "haveRouteFor about to check eid "+eid+" against existing routes [",len(theRoutes),"]"
       
   397 	if len(theRoutes)>0:
       
   398 		for i in range(len(theRoutes)):
       
   399 			theRoutes[i] = theRoutes[i].strip()
       
   400 			nextHop = string.split(theRoutes[i])[0];
       
   401 			# print "Checking",eid," against existing route:", nextHop
       
   402 			foo = re.search(nextHop, eid)
       
   403 			if foo!=None:
       
   404 				return True
       
   405 	return False
       
   406 
       
   407 def haveNonDefaultRouteFor(eid):
       
   408 	theLinks, theRoutes = getLinksRoutes()
       
   409 	if ( verbose>3 ):
       
   410 		print "haveRouteFor about to check eid "+eid+" against existing routes [",len(theRoutes),"]"
       
   411 	if len(theRoutes)>0:
       
   412 		for i in range(len(theRoutes)):
       
   413 			theRoutes[i] = theRoutes[i].strip()
       
   414 			nextHop = string.split(theRoutes[i])[0];
       
   415 			theLink = string.split(theRoutes[i])[4];
       
   416 			# print "Checking",eid," against existing route:", nextHop
       
   417 			foo = re.search(nextHop, eid)
       
   418 			if ( (foo!=None) & (theLink!="default") ):
       
   419 				return True
       
   420 	return False
       
   421 
       
   422 #
       
   423 # Remove any existing route to the eid that uses a link
       
   424 # named "default"
       
   425 #
       
   426 # Return True if we did in fact remove such a route, False if we didn't
       
   427 def removeDefaultRouteFor(eid):
       
   428 	theLinks, theRoutes = getLinksRoutes()
       
   429 	if len(theRoutes)>0:
       
   430 		for i in range(len(theRoutes)):
       
   431 			theRoutes[i] = theRoutes[i].strip()
       
   432 			nextHop = string.split(theRoutes[i])[0];
       
   433 			theLink = string.split(theRoutes[i])[4];
       
   434 			print "removeDefaultRouteFor:: checking",eid," against existing route:", nextHop + "->"+theLink
       
   435 			foo = re.search(nextHop, eid)
       
   436 			if ( (foo!=None) & (theLink=="default") ) :
       
   437 				# Don't call removeRoute here, we don't ever
       
   438 				# want to add the default route back in while we're removing
       
   439 				# it.
       
   440 				print "MATCH: removing default route to EID: "+eid
       
   441 				talktcl("route del "+eid+"\n")
       
   442 				return True
       
   443 	return False
       
   444 
       
   445 #
       
   446 # Check our list of destinations that can use the 'default'
       
   447 # link and add routes for any that do not have other routes
       
   448 # already in the RIB
       
   449 #
       
   450 def addDefaultRouteFor(eid):
       
   451 	if haveRouteFor(eid):
       
   452 		return(False)
       
   453 	for (theEID, theLink) in defaultRoutes:
       
   454 		if ( eid==theEID):
       
   455 			talktcl("route add "+eid+" "+theLink+"\n")
       
   456 
       
   457 #
       
   458 # Do I have a RIB entry for this EID?
       
   459 #
       
   460 def haveRIBEntryForEID(RIB, eid):
       
   461 	for entry in RIB:
       
   462 		foo = re.search(entry[RIB_EID], eid)
       
   463 		if foo!=None:
       
   464 			return True
       
   465 	return False
       
   466 
       
   467 #
       
   468 # Return True if I have a local registration for the given EID, False otherwise
       
   469 #
       
   470 def haveRegistrationForEID(eid):
       
   471 	# myEID = myLocalEID()
       
   472 
       
   473 	if string.find(myEID+"/*", eid)>=0:
       
   474 		return True
       
   475 
       
   476 	myRegistrations = getRegistrationList()
       
   477 	if myRegistrations is None:
       
   478 		return False
       
   479 	for myReg in myRegistrations:
       
   480 		if string.find(myReg+"/*", eid)>=0:
       
   481 			return True
       
   482 	return False
       
   483 
       
   484 #
       
   485 # Try to add a route to eid via tcp CL host:port
       
   486 #
       
   487 # Adds the route and a supporting link.
       
   488 #
       
   489 # Remove any existing route that uses a link called "default"
       
   490 # and replace with a link to host:port
       
   491 #
       
   492 # Don't add if we've already got a matching route for
       
   493 # the eid
       
   494 #
       
   495 # Do refresh the update time for the route
       
   496 #
       
   497 # Return the name of the link added or None
       
   498 #
       
   499 def tryAddRoute(host, port, eid):
       
   500 	theLinks, theRoutes = getLinksRoutes()
       
   501 
       
   502 	# Remove any existing route to the eid that uses a link
       
   503 	# named "default"
       
   504 	removeDefaultRouteFor(eid)
       
   505 
       
   506 	if haveRouteFor(eid):
       
   507 		return None
       
   508 
       
   509 	# print "About to check eid "+eid+" against my registrations."
       
   510 	if haveRegistrationForEID(eid):
       
   511 		return None
       
   512 
       
   513 	# See if there's an existing link we can glom onto
       
   514 	linkName = alreadyHaveLink(host+":"+port)
       
   515 	if linkName==None:
       
   516 		linkName = genNewLink(theLinks)
       
   517 	else:
       
   518 		print "Adding route to existing link:", linkName
       
   519 
       
   520 	# link add linkName host:port ONDEMAND tcp
       
   521 	print "link add ",linkName," ",host+":"+port," ONDEMAND tcp"
       
   522 	talktcl("link add "+linkName+" "+host+":"+port+" ONDEMAND tcp\n")
       
   523 	
       
   524 	# route add EID linkName
       
   525 	print "route add",eid," ",linkName
       
   526 	talktcl("route add "+eid+" "+linkName+"\n")
       
   527 	return linkName
       
   528 
       
   529 #
       
   530 # Server Thread
       
   531 #
       
   532 # This will set up a server listening on a particular interface (bindInterface)
       
   533 # for messages to a particular address (listenAddress, possibly different from
       
   534 # bindInterface to support multicast), and port
       
   535 #
       
   536 # On message receipt this calls processMessage, so that we can have multiple
       
   537 # servers if need be.
       
   538 #
       
   539 def doServer(bindInterface, listenAddress, port):
       
   540 	# Set the socket parameters
       
   541 	buf = 1024
       
   542 	# addr = (listenAddress,port)
       
   543 	# list = []	# My persistent list of routes (RIB)
       
   544 
       
   545 	if bindInterface is None:
       
   546 		#intf = gethostbyname(gethostname())
       
   547 		bindInterface = INADDR_ANY
       
   548 	
       
   549 	if listenAddress is None:
       
   550 		listenAddress = _DND_ADDR
       
   551 
       
   552 	if port is None:
       
   553 		port = _DND_PORT
       
   554 	
       
   555 	print "doServer started on interface:", bindInterface, "address: ", listenAddress, "port: ", port
       
   556 
       
   557 	# Create socket
       
   558 	try:
       
   559 		UDPSock = socket(AF_INET,SOCK_DGRAM)
       
   560 	except:
       
   561 		print "Can't create UDP socket."
       
   562 		sys.exit(0)
       
   563 
       
   564 	#
       
   565 	# Figure out if listenAddress is multicast or not
       
   566 	#
       
   567 	if listenAddress.startswith("239."):
       
   568 		#
       
   569 		# ListenAddress IS Multicast
       
   570 		#
       
   571 		group = ('', port)
       
   572 
       
   573 		try:
       
   574 			UDPSock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
       
   575 			UDPSock.setsockopt(SOL_SOCKET, SO_REUSEPORT, 1)
       
   576 		except:
       
   577 			print "Can't setsockopt SO_REUSEADDR / SO_REUSEPORT in server."
       
   578 			pass
       
   579 			# sys.exit(0)
       
   580 
       
   581 		UDPSock.setsockopt(SOL_IP, IP_MULTICAST_TTL, THE_MULTICAST_TTL)
       
   582 		UDPSock.setsockopt(SOL_IP, IP_MULTICAST_LOOP, 1)
       
   583 
       
   584 
       
   585 		try:
       
   586 			UDPSock.bind(group)
       
   587 		except:
       
   588 			# Some versions of linux raise an exception even though
       
   589 			# SO_REUSE* options have been set, so ignore it
       
   590 			print "Bind to: ", group, " failed."
       
   591 			pass
       
   592 
       
   593 		try:
       
   594 			UDPSock.setsockopt(SOL_IP, IP_MULTICAST_IF, inet_aton(bindInterface)+inet_aton('0.0.0.0'))
       
   595 		except:
       
   596 			print "Can't set IP_MULTICAST_IF on:", bindInterface
       
   597 			sys.exit(0)
       
   598 
       
   599 		try:
       
   600 			UDPSock.setsockopt(SOL_IP, IP_ADD_MEMBERSHIP, inet_aton(listenAddress) + inet_aton(bindInterface))
       
   601 		except:
       
   602 			print "Can't set IP_ADD_MEMBERSHIP for ", listenAddress
       
   603 			sys.exit(0)
       
   604 	else:
       
   605 		#
       
   606 		# ListenAddress is NOT multicast
       
   607 		#
       
   608 		#try:
       
   609 		#	UDPSock.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
       
   610 		#except:
       
   611 		#	print "Can't set UDP socket for broadcast."
       
   612 		#	sys.exit(0)
       
   613 
       
   614 		UDPSock.bind((listenAddress, listenPort))
       
   615 
       
   616 	#
       
   617 	# General Processing
       
   618 	#
       
   619 	#myEID = myLocalEID()
       
   620 
       
   621 	# Receive messages
       
   622 	while 1:
       
   623 		try:
       
   624 			data,addr = UDPSock.recvfrom(buf)
       
   625 		except:
       
   626 			"UDP recvfrom failed."
       
   627 
       
   628 		print "Got a message from: ", addr
       
   629 
       
   630 		if not data:
       
   631 			print "Client has exited!"
       
   632 			break
       
   633 		else:
       
   634 			processMessage(data, addr)
       
   635 
       
   636 	# Close socket
       
   637 	UDPSock.close()
       
   638 
       
   639 def processMessage(data, addr):
       
   640 
       
   641 	# Returns True if we got the lock, False if we didn't
       
   642 	while messageProcessingMutex.testandset() == False:
       
   643 		print "ProcessMessage is sleeping waiting on mutex..."
       
   644 		sleep(1)
       
   645 
       
   646 	#
       
   647 	# This try is here to give us an out if something causes this thread
       
   648 	# to core, so that we don't end up holding the mutex.
       
   649 	# 
       
   650 	try:
       
   651 		SenderAddress = addr[0]
       
   652 		things = string.split(data, '\n')
       
   653 		SenderEID = things[0]
       
   654 		SenderListenPort = things[1]
       
   655 
       
   656 		# myEID = myLocalEID()
       
   657 
       
   658 		# Am I the sender of this message?
       
   659 		if things[0] == myEID:
       
   660 			# print "I don't process my own messages (",SenderEID,",",gethostname(),")"
       
   661 			messageProcessingMutex.unlock()
       
   662 			return
       
   663 
       
   664 		if (verbose>0):
       
   665 			print "Received message."
       
   666 
       
   667 		if (verbose>1):
       
   668 			print data,"' from addr:", addr, "\n"
       
   669 
       
   670 		if (verbose>3):
       
   671 			print "Before message processing, RIB is:"
       
   672 			printRIB(myRIB)
       
   673 
       
   674 		# For each destination EID in the message, see if I've
       
   675 		# already got a route to it or if my route is longer than
       
   676 		# the one in the message.  If either of these hold, add a route
       
   677 		# via the next hop of the message.
       
   678 		# Also update RIB with entry info
       
   679 		for i in range(2, len(things)-1):
       
   680 			if (verbose>0):
       
   681 				print "Processing message element:", things[i]
       
   682 			[destEID, distance, NHEID] = string.split(things[i], " ");
       
   683 			distance = string.atoi(distance)+1
       
   684 			if (verbose>3):
       
   685 				print "Received route entry for", destEID, "from", SenderEID," ",addr[0]," ",SenderListenPort
       
   686 
       
   687 			#
       
   688 			# Split-horizon means that I shouldn't be getting advertisements of routes
       
   689 			# for which I am the next hop.  We do this filtering at the receiver so that
       
   690 			# we can broadcase / multicast updates
       
   691 			#
       
   692 			if (NHEID==myEID):
       
   693 				if (verbose > 2 ):
       
   694 					print "Not processing route entry due to split horizon."
       
   695 				continue
       
   696 
       
   697 			#
       
   698 			# Check my RIB to see what my current distance to this destination EID is
       
   699 			# Also make sure that the daemon agrees that the route exists
       
   700 			#
       
   701 			myDist = currentDistanceTo(myRIB, destEID)
       
   702 			daemonHasRoute = haveNonDefaultRouteFor(destEID)
       
   703 			if (daemonHasRoute and (myDist!=None) and (myDist<=distance)):
       
   704 				# My current route is better or equal
       
   705 				if (verbose>3):
       
   706 					print "current distance", myDist," is better or equal to received distance:", distance
       
   707 
       
   708 				# If the EIDs match exactly, update the RIB entry, otherwise don't
       
   709 				# This could happen, for example, if we have a RIB entry and route to dtn://xxxxx/* and this
       
   710 				# entry is for dtn://xxxxx/ping
       
   711 				if haveExactRIBEIDMatch(myRIB, destEID):
       
   712 					refreshInternalRouteList(myRIB, SenderAddress, SenderListenPort, destEID, distance, SenderEID)
       
   713 			else:
       
   714 				# My current route entry has a higher metric or I have no current entry
       
   715 				if (myDist<99999):
       
   716 					removeRoute(destEID)
       
   717 					#talktcl("route del "+destEID+"\n")
       
   718 					removeRIBEntry(myRIB, destEID) # In case I had an entry.
       
   719 				newLinkName = tryAddRoute(SenderAddress, SenderListenPort, destEID)
       
   720 				refreshInternalRouteList(myRIB, SenderAddress, SenderListenPort, destEID, distance, SenderEID)
       
   721 
       
   722 			# Make or update a RIB entry for this route.
       
   723 
       
   724 			if (verbose>1):
       
   725 				print "After refresh RIB is:"
       
   726 				printRIB(myRIB)
       
   727 	except:
       
   728 		print "WARNING: something went wrong in processMessage..."
       
   729 		messageProcessingMutex.unlock()
       
   730 
       
   731 	messageProcessingMutex.unlock()
       
   732 
       
   733 
       
   734 def haveExactRIBEIDMatch(RIB, eid):
       
   735 	for elem in RIB:
       
   736 		if elem[RIB_EID]==eid:
       
   737 			return True
       
   738 	return False
       
   739 
       
   740 #
       
   741 # Return the current best known distance to a destination EID
       
   742 #
       
   743 def currentDistanceTo(RIB, destEID):
       
   744 	for elem in RIB:
       
   745 		if haveRIBEntryForEID(RIB, destEID):
       
   746 				return elem[RIB_DIST]
       
   747 		print "I don't have a RIB entry for:", destEID
       
   748 		return(99999)
       
   749 
       
   750 #
       
   751 # Remove an entry from the RIB table
       
   752 #
       
   753 def removeRIBEntry(RIB, destEID):
       
   754 	for elem in RIB:
       
   755 		if (elem[RIB_EID]==destEID):
       
   756 			print "Removing elem: '", elem, "' from RIB"
       
   757 			RIB.remove(elem)
       
   758 
       
   759 #
       
   760 # RIB element format described above.
       
   761 #
       
   762 # host: the IP address from which this entry was received
       
   763 # port: the port on which the sending TCPCL is listening
       
   764 # EID:  A destination EID
       
   765 # distance: Distance from the sender of the update to the destination EID
       
   766 # NHEID: the EID of the node that sent the update
       
   767 #
       
   768 #
       
   769 def refreshInternalRouteList(RIB, host, port, EID, distance, NHEID):
       
   770 	found = 0;
       
   771 	if verbose>2:
       
   772 			print "Processing entry:", host," ",port," ",EID," ",distance
       
   773 
       
   774 	# If the NHEID is us, we need to NOT process this entry
       
   775 	# (split-horizon)
       
   776 	if (NHEID == myEID):
       
   777 		return RIB
       
   778 
       
   779 	for elem in RIB:
       
   780 		if ( verbose>3):
       
   781 			print "refreshInternalRouteList: checking", elem[RIB_EID]," against new entry", EID,"\n"
       
   782 		#foo = re.search(EID, elem[RIB_EID])
       
   783 		#if foo==None:
       
   784 		#	continue
       
   785 		if (elem[RIB_EID]==EID):
       
   786 			elem[RIB_DIST] = distance
       
   787 			elem[RIB_TIME] = time()
       
   788 			found = 1
       
   789 
       
   790 	# If we didn't update an existing RIB entry for this destination EID
       
   791 	# make a new entry.
       
   792 	if (found == 0):
       
   793 		linkName = alreadyHaveLink(host+":"+port)
       
   794 		print "Making new RIB entry"
       
   795 		RIB += [[host, port, EID, distance, time(), linkName, NHEID]]
       
   796 
       
   797 	return RIB
       
   798 
       
   799 #
       
   800 # printRIB
       
   801 #
       
   802 def printRIB(RIB):
       
   803 	print "HOST      PORT      DESTEID    DIST    TIME    LINKNAME     NHEID"
       
   804 	for elem in RIB:
       
   805 		print elem[RIB_HOST]," ",elem[RIB_PORT]," ",elem[RIB_EID]," ",elem[RIB_DIST]," ",elem[RIB_TIME]," ",elem[RIB_LINKNAME]," ",elem[RIB_NHEID]
       
   806 
       
   807 #
       
   808 # Return a list of strings that are the current
       
   809 # registrations
       
   810 #
       
   811 # Return None if we can't talk to the daemon
       
   812 #
       
   813 def getRegistrationList():
       
   814 	response = talktcl("registration list\n")
       
   815 	if response==None:
       
   816 		return(None)
       
   817 	#response = string.strip(response, "dtn% registration list")
       
   818 	response = string.strip(response, "registration list")
       
   819 
       
   820 	# Split the response into lines
       
   821 	lines = string.split(response, '\n');
       
   822 
       
   823 	# Throw away the first line
       
   824 	lines = lines[1:]
       
   825 
       
   826 	# Throw away things that are not registrations
       
   827 	lines = onlyLinesContaining(lines, ["id "])
       
   828 	answer = []
       
   829 	for i in range(len(lines)):
       
   830 			temp = string.split(lines[i], " ")
       
   831 			answer += [temp[3]]
       
   832 	return answer
       
   833 
       
   834 #
       
   835 # return my local EID
       
   836 #
       
   837 def myLocalEID():
       
   838 	foo = talktcl("registration dump\n");
       
   839 	if foo==None:
       
   840 		return None
       
   841 
       
   842 	foo = string.split(foo, "\n");
       
   843 	foo = onlyLinesContaining(foo, "id 0:")
       
   844 	bar = foo[0].find('%')
       
   845 	foo = foo[0][bar+1:]
       
   846 	foo = string.split(foo)
       
   847 	return foo[3]
       
   848 
       
   849 # Figure out if the given newItem (and EID) is covered by an existing one
       
   850 # from the 'list'.  The format of list is very specific to the sending client
       
   851 # (that is, list items are assumed to be (destEID, dist nheid)
       
   852 def alreadyCovered(list, newItem):
       
   853 	for listItem in list:
       
   854 		bar = string.split(listItem, " ")
       
   855 		foo = string.replace(bar[0], "?*", "\?*")
       
   856 		if re.search(foo, newItem):
       
   857 			if verbose>4:
       
   858 				print newItem, " already covered by ", bar[0]
       
   859 			return(True)
       
   860 	return False
       
   861 
       
   862 #
       
   863 # destinations is a list of ['addr', port] pairs to send messages to
       
   864 #
       
   865 # multicastInterfaces is a list of interfaces on which multicast packets will be sent
       
   866 #
       
   867 def doClient(destinations, multicastInterfaces):
       
   868 	print "doClient started with destinations:        ", destinations
       
   869 	print "doClient started with multicastInterfaces: ", multicastInterfaces
       
   870 
       
   871 	group = ('', _DND_PORT)
       
   872 
       
   873 	# Create socket
       
   874 	try:
       
   875 		UDPSock = socket(AF_INET,SOCK_DGRAM)
       
   876 	except:
       
   877 		print "Can't create UDP socket."
       
   878 		sys.exit(0)
       
   879 
       
   880 	try:
       
   881 		UDPSock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
       
   882 		UDPSock.setsockopt(SOL_SOCKET, SO_REUSEPORT, 1)
       
   883 	except:
       
   884 		print "Can't set UDP socket for REUSEADDR / REUSEPORT in client."
       
   885 		pass
       
   886 
       
   887 	#
       
   888 	# Need to set the socket to SO_BROADCAST in case one of the destinations
       
   889 	# is a broadcast address.
       
   890 	#
       
   891 	try:
       
   892 		UDPSock.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
       
   893 	except:
       
   894 		print "Can't set UDP socket for BROADCAST."
       
   895 		sys.exit(0)
       
   896 
       
   897 	for interface in multicastInterfaces:
       
   898 		#
       
   899 		# Do these in case one of the destination addresses is multicast.
       
   900 		# IP_MULTICAST_LOOP seems to mean that I get copies of things I
       
   901 		# send.
       
   902 		#
       
   903 		try:
       
   904 			UDPSock.setsockopt(SOL_IP, IP_MULTICAST_TTL, THE_MULTICAST_TTL)
       
   905 			UDPSock.setsockopt(SOL_IP, IP_MULTICAST_LOOP, 1)
       
   906 		except:
       
   907 			print "Can't set UDP socket for IP_MULITCAST_TTL or IP_MULTICAST_LOOP."
       
   908 
       
   909 		#
       
   910 		# If the destination is multicast, I need to do this
       
   911 		#
       
   912 		try:
       
   913 			UDPSock.setsockopt(SOL_IP, IP_MULTICAST_IF, inet_aton(interface) + inet_aton('0.0.0.0'))
       
   914 		except:
       
   915 			print "Can't setsockopt SOL_MULTICAST_IF on interface: ", interface
       
   916 			pass
       
   917 
       
   918 		print "Interface: ", interface, " set for MULTICAST."
       
   919 
       
   920 	#
       
   921 	# Send messages
       
   922 	#
       
   923 	while (1):
       
   924 		# It's slightly simpler if we sleep at the top of the loop;
       
   925 		# continue's work out easier
       
   926 		sleep(broadcastInterval)
       
   927 
       
   928 		# Returns True if I got the mutex
       
   929 		while messageProcessingMutex.testandset()==False:
       
   930 			print "Client is sleeping waiting on mutex..."
       
   931 			sleep(1)
       
   932 
       
   933 		thingsSent = []
       
   934 		theList = getRegistrationList();
       
   935 		if verbose > 2:
       
   936 			print "getRegistrationList() returned:", theList
       
   937 		if theList is None:
       
   938 			# Probably couldn't talk to DTN daemon
       
   939 			messageProcessingMutex.unlock()
       
   940 			continue	
       
   941 
       
   942 		if addLocalEIDWildcard==1:
       
   943 			# Build a message that contains my IP address and port,
       
   944 			# plus the list of registrations
       
   945 			thingsSent += [myEID+"/* 0 "+myEID]
       
   946 
       
   947 		#
       
   948 		# Remove any duplication in building thingsSent list
       
   949 		#
       
   950 		isAlreadyThere = 0
       
   951 		# For each registration
       
   952 		for listEntry in theList:
       
   953 			# Check against each entry already in the 'to be sent' list
       
   954 			tempEntry = string.replace(listEntry, "?*", "\?*")
       
   955 
       
   956 			if alreadyCovered(thingsSent, tempEntry):
       
   957 				continue
       
   958 			# OK, need to send this
       
   959 			# Local registrations are at distance 0
       
   960 			thingsSent += [listEntry+" 0 "+myEID]
       
   961 
       
   962 		#
       
   963 		#
       
   964 		#
       
   965 		if rebroadcastRoutes:
       
   966 			for entry in myRIB:
       
   967 				thingsSent += [entry[RIB_EID]+" "+str(entry[RIB_DIST])+" "+entry[RIB_NHEID]]
       
   968 
       
   969 		#
       
   970 		# Now build the text string to send
       
   971 		#
       
   972 		msg = myEID+'\n'
       
   973 		msg += myListeningDTNTCPPort
       
   974 		msg += '\n'
       
   975 		for entry in thingsSent:
       
   976 				msg += entry
       
   977 				msg += "\n"
       
   978 		if ( verbose>0 ):
       
   979 			print "msg to send is:"
       
   980 			print msg
       
   981 
       
   982 		# Send to desired addresses
       
   983 		for addr,port in destinations:
       
   984 			print "Sending msg to: ", addr,":", port
       
   985 			try:
       
   986 				if(UDPSock.sendto(msg,(addr, port))):
       
   987 					msg = msg
       
   988 			except:
       
   989 				print "Error sending message to:", addr
       
   990 				print os.strerror("Error sending message to")
       
   991 
       
   992 		timeOutOldRoutes(myRIB)
       
   993 
       
   994 		#
       
   995 		# Unlock the mutex
       
   996 		#
       
   997 		messageProcessingMutex.unlock()
       
   998 
       
   999 	# Close socket
       
  1000 	UDPSock.close()
       
  1001 
       
  1002 def installDefaultRoutes():
       
  1003 	for (eid,linkName) in defaultRoutes:
       
  1004 		if ( haveRouteFor(eid)==False ):
       
  1005 			talktcl("route add "+eid+" "+linkName+"\n")
       
  1006 	
       
  1007 def removeExistingRoutes():
       
  1008 	theLinks, theRoutes = getLinksRoutes()
       
  1009 	for route in theRoutes:
       
  1010 		tokens = string.split(route)
       
  1011 		talktcl("route del "+tokens[0]+"\n")
       
  1012 	return
       
  1013 
       
  1014 
       
  1015 def usage():
       
  1016 	print "dnd.py [-h] [-s] [-c] [-b PORT] [-t PORT] [-L seeBelow] [-d] [-r] [addr,[port]] [addr...]"
       
  1017 	print "  -h:       Print usage information (this)"
       
  1018 	print "  -s:       Only perform server (receiving) actions"
       
  1019 	print "  -c:       Only perform client (transmitting) actions"
       
  1020 	print "  -t #:     Set the DTN Tcl Console Port ("+str(dtnTclConsolePort)+")"
       
  1021 	print "  -L intf,addr:port  Add a listening socket on the given address and"
       
  1022 	print "            port.  If the address is multicast, then the interface "
       
  1023 	print "            needs to be given as well.  Possible syntaxes for the"
       
  1024 	print "            argument of '-L' are:"
       
  1025 	print "                  '-L port'     -- Use INADDR_ANY as the listen address"
       
  1026 	print "                  '-L intf,addr:port' -- Bind to the given interface,"
       
  1027 	print "				listening on a particular address/port --"
       
  1028 	print "		                This is useful for multicast."
       
  1029 	print "                  If you insist on binding to a particular interface"
       
  1030 	print "                  without using multicast, use the interface address"
       
  1031 	print "                  for both the intf and addr parts."
       
  1032 	print "  -d MDIST  Set the MULTICAST_TTL to MDIST (default ",THE_MULTICAST_TTL,")"
       
  1033 	print "  -m intf:  Add interface to the list of multicast SENDING"
       
  1034 	print "            interfaces."
       
  1035 	print "  -r:       Include route information in addition to (local) registration"
       
  1036 	print "            information.  This makes neighbor discovery into a"
       
  1037 	print "            really stupid routing algorithm, but possibly suitable"
       
  1038 	print "            for small lab setups (like several dtn routes in a"
       
  1039 	print "            linear topology)."
       
  1040 	print "  addrs are addresses to which UDP packets should be sent"
       
  1041 	print "            default:", myBroadcast()
       
  1042 	print "  ports are the destination ports for the addresses."
       
  1043 	print "            default:", _DND_PORT
       
  1044 	print "  -R    Remove existing routes and exit."
       
  1045 	print " "
       
  1046 	print " "
       
  1047 	print "Examples:"
       
  1048 	print "These examples assume that 10.9.1.1/24 is a local interface."
       
  1049 	print ""
       
  1050 	print "=================="
       
  1051 	print "Start dnd.py listening on port 5005 and sending to a broadcast address"
       
  1052 	print ""
       
  1053 	print "dnd.py -L 5005 10.9.1.255"
       
  1054 	print ""
       
  1055 	print "=================="
       
  1056 	print "Start dnd.py listening on port 5005 and sending to a remote subnet broadcast address"
       
  1057 	print "(10.10.4.255) and a remote unicast address (10.10.5.17)"
       
  1058 	print ""
       
  1059 	print "dnd.py -L 5005 10.10.4.255 10.10.5.17"
       
  1060 	print ""
       
  1061 	print "=================="
       
  1062 	print "Start dnd.py listening for multicast packets and transmitting to a multicast address"
       
  1063 	print ""
       
  1064 	print "./dnd.py -L 10.9.1.1:239.0.1.99:5005 -m 10.9.1.1 239.0.1.99:5005"
       
  1065 	print ""
       
  1066 	print "=================="
       
  1067 	print "Start dnd.py listening for multicast packets to group 239.0.1.99 on interface 10.9.1.1 and for"
       
  1068 	print "regular packets on port 5001.  Interface 10.9.3.2 is a multicast sendint interface, and we're "
       
  1069 	print "going to send to the multicast group 239.0.1.99 as well as to 10.9.2.255 port 5001"
       
  1070 	print ""
       
  1071 	print "dnd.py -L 10.9.1.1,239.0.1.99:5005 -L 5001 -m 10.9.3.2 239.0.1.99 10.9.2.255:5001"
       
  1072 	print ""
       
  1073 
       
  1074 
       
  1075 if __name__ == '__main__':
       
  1076 	print "argv is:", sys.argv, "[", len(sys.argv), "]"
       
  1077 	serverOn = True
       
  1078 	clientOn = True
       
  1079 	listenAddress = _DND_ADDR
       
  1080 	bindInterface = INADDR_ANY
       
  1081 	destinations = []  # list of [addr, port] pairs
       
  1082 	multicastSendInterfaces = []  # interfaces on which I may want to SEND MC packets
       
  1083 	listenThings = []   # where I listen for messages
       
  1084 	
       
  1085 	print "This is dnd.py version 1.0"
       
  1086 
       
  1087 	#
       
  1088 	# Read DTND configuration information
       
  1089 	#
       
  1090 	myEID = myLocalEID()
       
  1091 	print "myEID is: ",myEID
       
  1092 	if myEID==None:
       
  1093 		print "Can't get local EID.  exiting"
       
  1094 		sys.exit(-1)
       
  1095 
       
  1096 	myListeningDTNTCPPort = findListeningPort()
       
  1097 	if myListeningDTNTCPPort == None:
       
  1098 		print "Can't find listening port for TCP CL, client exiting."
       
  1099 		sys.exit(-1)
       
  1100 
       
  1101 	sendToPort = _DND_PORT
       
  1102 
       
  1103 	try:
       
  1104 		opts, args = getopt.getopt(sys.argv[1:], "L:m:l:b:rd:t:hI:scvR", ["help", "server", "client"])
       
  1105 	except getopt.GetoptError:
       
  1106 		usage()
       
  1107 		sys.exit(2)
       
  1108 
       
  1109 	for o, a in opts:
       
  1110 		if o == "-h":
       
  1111 			usage();
       
  1112 			sys.exit(2)
       
  1113 		if o == "-v":
       
  1114 			verbose += 1
       
  1115 		if o == "-s":
       
  1116 			clientOn = False
       
  1117 		if o == "-c":
       
  1118 			serverOn = False
       
  1119 		if o == '-d':
       
  1120 			THE_MULTICAST_TTL = string.atoi(a)
       
  1121 		if o == "-L":
       
  1122 			# Possible syntaxes:
       
  1123 			# 	bindInterface,address:port   -- Multicast
       
  1124 			#	bindInterface,address        -- Multicast
       
  1125 			#	port
       
  1126 			print "-L is working on :", a
       
  1127 			foo = string.split(a, ':')
       
  1128 			if len(foo)==2:
       
  1129 				listenPort = foo[1]
       
  1130 
       
  1131 			# foo[0] is empty,, intf, addr,,  or just a port
       
  1132 
       
  1133 			bar = string.split(foo[0], ',')
       
  1134 			if len(bar)==1:
       
  1135 				# just a port
       
  1136 				listenPort = bar[0]
       
  1137 				bindInterface = '0.0.0.0'
       
  1138 				listenAddress = '0.0.0.0'
       
  1139 			else:
       
  1140 				# Assuming bindInterface,address syntax at this point
       
  1141 				bindInterface = bar[0]
       
  1142 				listenAddress = bar[1]
       
  1143 			
       
  1144 			listenThings += [[bindInterface, listenAddress, string.atoi(listenPort)]]
       
  1145 		if o == "-b":
       
  1146 			sendToPort = a
       
  1147 		if o == "-m":
       
  1148 			multicastSendInterfaces += [a]
       
  1149 		if o == "-r":
       
  1150 			rebroadcastRoutes = 1
       
  1151 		if o == "-t":
       
  1152 			dtnTclConsolePort = a
       
  1153 		if o == "-R":
       
  1154 			removeExistingRoutes()
       
  1155 			sys.exit(2)
       
  1156 
       
  1157 	print "rest of args is now:", args
       
  1158 
       
  1159 	#
       
  1160 	# Process destination addresses (where I send to)
       
  1161 	#
       
  1162 	for item in args:
       
  1163 		foo = string.split(item, ':')
       
  1164 		if len(foo)==1:
       
  1165 			# No port information given, use default
       
  1166 			theAddr = foo[0]
       
  1167 			thePort = str(sendToPort)
       
  1168 		else:
       
  1169 			theAddr = foo[0]
       
  1170 			thePort = foo[1]
       
  1171 
       
  1172 		destinations += [[theAddr, string.atoi(thePort)]]
       
  1173 		print "Destinations now: ", destinations
       
  1174 
       
  1175 	if len(destinations)==0:
       
  1176 		sendToAddress = myBroadcast()
       
  1177 		destinations = [[sendToAddress[0], sendToPort]]
       
  1178 
       
  1179 	if len(listenThings)==0:
       
  1180 		listenThings = [['0.0.0.0', '0.0.0.0', sendToPort]]
       
  1181 
       
  1182 	print " "
       
  1183 	print "================================"
       
  1184 	print " "
       
  1185 	print "Destinations now: ", destinations
       
  1186 	print " "
       
  1187 	print "ListenThings now: ", listenThings
       
  1188 
       
  1189 	removeExistingRoutes()
       
  1190 
       
  1191 	installDefaultRoutes()
       
  1192 
       
  1193 	if clientOn:
       
  1194 		thread.start_new(doClient, (destinations, multicastSendInterfaces))
       
  1195 	if serverOn:
       
  1196 		for bindInterface, listenAddress, listenPort in listenThings:
       
  1197 			thread.start_new(doServer, (bindInterface, listenAddress, listenPort))
       
  1198 
       
  1199 	# Now I just sort of hang out...
       
  1200 	while 1:
       
  1201 		sleep(10)
       
  1202