Cerebro: Difference between revisions
No edit summary |
|||
(15 intermediate revisions by 5 users not shown) | |||
Line 1: | Line 1: | ||
[[image:Meshnetwork.png|right|250px|thumb|Layout information]] |
[[image:Meshnetwork.png|right|250px|thumb|Layout information]] |
||
[[image:Comparison1.png|right|250px|thumb|Scaling properties]] |
[[image:Comparison1.png|right|250px|thumb|Scaling properties]] |
||
[[image:65-arr-1.png|right|250px|thumb|Presence arrivals]] |
|||
[[image:65-cdf-1.png|right|250px|thumb|CDF of presence arrivals]] |
|||
[[Image:Bandwidth-presence-info-1.png|right|250px|thumb|Bandwidth usage on 65-node testbed]] |
|||
==What is Cerebro?== |
==What is Cerebro?== |
||
Cerebro <ref>http://cerebro.mit.edu</ref> is a scalable, light-weight platform that provides presence information, efficient file sharing and an easy collaboration mechanism for activities. |
Cerebro <ref>http://cerebro.mit.edu</ref> is a scalable, light-weight platform that provides presence information, efficient file sharing and an easy collaboration mechanism for activities. |
||
==Features== |
==Features== |
||
Line 17: | Line 21: | ||
* internet connection even '''without a valid IP address''' (*) |
* internet connection even '''without a valid IP address''' (*) |
||
* '''programming API''' based on dbus (see examples) |
* '''programming API''' based on dbus (see examples) |
||
==Experimental results== |
|||
Two experiments were carried out with [http://cerebro.mit.edu/index.php/Experimental_results 27 nodes] and [[Simple mesh test (Cerebro)|65 nodes]] respectively. |
|||
==Download== |
|||
http://lyme.media.mit.edu/cerebro/index.php/Download |
|||
==Presence Information== |
==Presence Information== |
||
Line 41: | Line 54: | ||
==== register (method) ==== |
==== register (method) ==== |
||
Input : |
Input : activity_id, activity_type |
||
Output: A unique activity ID (aid) |
Output: A unique activity ID (aid) |
||
Description: Register a new activity instance in order to access the services and events offered by Cerebro. This method does not share with the activity with neighborhood. |
|||
Description: Share current activity or join an activity shared by someone else. |
|||
---- |
---- |
||
Line 49: | Line 64: | ||
==== unregister (method) ==== |
==== unregister (method) ==== |
||
Input: aid |
Input: aid |
||
Description: Unregister an activity instance (identified by "aid"). |
Description: Unregister an activity instance (identified by "aid"). |
||
Line 55: | Line 71: | ||
==== on_node_arrival (signal) ==== |
==== on_node_arrival (signal) ==== |
||
Output: Array of node IDs that joined the network |
Output: Array of node IDs that joined the network |
||
Description: Receive notification when a new node joins the netowrk, The activity may choose to act on this. |
Description: Receive notification when a new node joins the netowrk, The activity may choose to act on this. |
||
Line 61: | Line 78: | ||
==== on_node_departure (signal) ==== |
==== on_node_departure (signal) ==== |
||
Output: Array of node IDs that left the network |
Output: Array of node IDs that left the network |
||
Description: Receive notification when a new node leaves the netowrk. The activity may choose to act on this. |
Description: Receive notification when a new node leaves the netowrk. The activity may choose to act on this. |
||
Line 67: | Line 85: | ||
==== get_personal_info (method) ==== |
==== get_personal_info (method) ==== |
||
Output: A buddy dictionary containing current user information |
Output: A buddy dictionary containing current user information |
||
Description: Retrieves user personal information. |
Description: Retrieves user personal information. |
||
Line 73: | Line 92: | ||
==== set_personal_info (method) ==== |
==== set_personal_info (method) ==== |
||
Input: A buddy dictionary containing new user information |
Input: A buddy dictionary containing new user information |
||
Description: Updates user personal information. |
Description: Updates user personal information. |
||
Line 79: | Line 99: | ||
==== received_data (signal) ==== |
==== received_data (signal) ==== |
||
Output: data, buddy, src, port, aid |
Output: data, buddy, src, port, aid |
||
Description: A signal that gets emitted whenever "data" is received from "buddy" (who has the unique ID "src"), for activity instance "aid" which is of type "port" (eg Chat). |
Description: A signal that gets emitted whenever "data" is received from "buddy" (who has the unique ID "src"), for activity instance "aid" which is of type "port" (eg Chat). |
||
Line 85: | Line 106: | ||
==== push_data (method) ==== |
==== push_data (method) ==== |
||
Input: aid, data, port |
Input: aid, data, port |
||
Description: Sends "data" to all users participating in the shared activity identified by "aid" which is of type "port". |
Description: Sends "data" to all users participating in the shared activity identified by "aid" which is of type "port". |
||
Line 91: | Line 113: | ||
==== exec_command (method) ==== |
==== exec_command (method) ==== |
||
Input: A command string |
Input: A command string |
||
Description: Executes "command" on the local machine. This method is provided for debugging and may be removed. |
Description: Executes "command" on the local machine. This method is provided for debugging and may be removed. |
||
Line 97: | Line 120: | ||
==== list_shared_activities (method) ==== |
==== list_shared_activities (method) ==== |
||
Output: Returns a list of tuples, each containing 3 fields: nickname, aid, activity_type |
Output: Returns a list of tuples, each containing 3 fields: nickname, aid, activity_type |
||
Description: This method returns a list of all activities currently shared in the network and the nicknames of the users that are participating. The activity ID "aid" provides the unique identifier for each of the shared activities and "activity_type" provides the type of the activity. |
Description: This method returns a list of all activities currently shared in the network and the nicknames of the users that are participating. The activity ID "aid" provides the unique identifier for each of the shared activities and "activity_type" provides the type of the activity. |
||
Line 103: | Line 127: | ||
==== show_mst (method) ==== |
==== show_mst (method) ==== |
||
Output: A list of nicknames (or user ID, if we have not received profile information yet), the corresponding distance to each user, and the path (consisting of other nicknames) that needs to be followed to reach the remote nickname. |
Output: A list of nicknames (or user ID, if we have not received profile information yet), the corresponding distance to each user, and the path (consisting of other nicknames) that needs to be followed to reach the remote nickname. |
||
Description: Returns the minimum distances from the current node to all other nodes present in the network. |
Description: Returns the minimum distances from the current node to all other nodes present in the network. |
||
Line 109: | Line 134: | ||
==== show_network_tree (method) ==== |
==== show_network_tree (method) ==== |
||
Output: Same as "show_mst", but includes all possible paths known from the current node to the remote destination. |
Output: Same as "show_mst", but includes all possible paths known from the current node to the remote destination. |
||
Description: Returns all known paths from the current node to all other nodes present in the network. |
Description: Returns all known paths from the current node to all other nodes present in the network. |
||
==Example== |
==Example== |
||
Line 119: | Line 144: | ||
# joining shared activities (joins by default a shared "Debugger" activity) |
# joining shared activities (joins by default a shared "Debugger" activity) |
||
# a command-based interface with Cerebro. Commands are issued by escaping the command with a forward slash "/". The following commands are implemented: |
# a command-based interface with Cerebro. Commands are issued by escaping the command with a forward slash "/". The following commands are implemented: |
||
/listactivities or /la (shows a list of all currently shared activities) |
|||
/tree (shows all paths to all known destinations) |
|||
{| |
|||
/mst (shows the minimun distances and path to all known destinations) |
|||
| '''Command''' || || '''Description''' |
|||
/sound (plays a sound. Useful for pinpointing a machine ;-) |
|||
|- |
|||
| '''/listactivities''' or '''/la''' || || shows a list of all currently shared activities |
|||
|- |
|||
| '''/share''' || || share current activity |
|||
|- |
|||
| '''/join XXXXXXXXXX''' || || join activity with unique ID XXXXXXXXXX (unique IDs can be listed using '/la') |
|||
|- |
|||
| '''/leave''' || || leave all shared instancies of current activity |
|||
|- |
|||
| '''/tree''' || || shows all paths to all known destinations |
|||
|- |
|||
| '''/mst''' || || shows the minimun distances and path to all known destinations |
|||
|- |
|||
| '''/dn''' || || shows all direct (1-hop) neighbors |
|||
|- |
|||
| '''/sound''' || || plays a sound. Useful for pinpointing a machine ;-) |
|||
|- |
|||
| '''/run COMMAND''' || || run a command locally |
|||
|} |
|||
<pre> |
<pre> |
||
Line 143: | Line 189: | ||
d = ':' |
d = ':' |
||
return d.join( |
return d.join("%02X" % ord(c) for c in m) |
||
#ATYPE = '\x0a\x00' |
#ATYPE = '\x0a\x00' |
||
Line 160: | Line 206: | ||
interface.connect_to_signal("received_data", self.receive_chat_text) |
interface.connect_to_signal("received_data", self.receive_chat_text) |
||
self.register = interface.get_dbus_method('register', 'org.olpc.cerebro') |
|||
self.unregister = interface.get_dbus_method('unregister', 'org.olpc.cerebro') |
|||
self.push_data = interface.get_dbus_method("push_data", 'org.olpc.cerebro') |
self.push_data = interface.get_dbus_method("push_data", 'org.olpc.cerebro') |
||
self.list_shared_activities = interface.get_dbus_method("list_shared_activities", 'org.olpc.cerebro') |
self.list_shared_activities = interface.get_dbus_method("list_shared_activities", 'org.olpc.cerebro') |
||
Line 165: | Line 213: | ||
self.show_mst = interface.get_dbus_method("show_mst", 'org.olpc.cerebro') |
self.show_mst = interface.get_dbus_method("show_mst", 'org.olpc.cerebro') |
||
self.send_command = interface.get_dbus_method("exec_command", 'org.olpc.cerebro') |
self.send_command = interface.get_dbus_method("exec_command", 'org.olpc.cerebro') |
||
self.get_personal_info = interface.get_dbus_method("get_personal_info", 'org.olpc.cerebro') |
|||
self.set_personal_info = interface.get_dbus_method("set_personal_info", 'org.olpc.cerebro') |
|||
self.buddyinfo = [] |
self.buddyinfo = [] |
||
self.last = {} |
self.last = {} |
||
try: |
|||
register = interface.get_dbus_method('register', 'org.olpc.cerebro') |
|||
self.aid = register(ATYPE, SERVICE, '/org/olpc/cerebro', INTERFACE, OBJECT_PATH) |
|||
print "my aid is:", self.aid, len(self.aid), bin2mac(self.aid,1) |
|||
except dbus.DBusException: |
|||
traceback.print_exc() |
|||
sys.exit() |
|||
def onNodeArrival(self, node_arr): |
def onNodeArrival(self, node_arr): |
||
Line 182: | Line 223: | ||
s = "".join(chr(b) for b in n) |
s = "".join(chr(b) for b in n) |
||
#s = "".join(ord(b) for b in n) |
#s = "".join(ord(b) for b in n) |
||
print "CHAT: Node |
print "CHAT: Node entered:", bin2mac(s) |
||
print "sending to", bin2mac(s) |
#print "sending to", bin2mac(s) |
||
self.send_chat_text('hello world') |
#self.send_chat_text('hello world') |
||
def send_chat_text(self, data): |
def send_chat_text(self, data): |
||
Line 202: | Line 243: | ||
#buddy = bin2mac(src) |
#buddy = bin2mac(src) |
||
nick = ''.join( |
nick = ''.join(chr(x) for x in buddy['nick']) |
||
sequence = data[:8] |
sequence = data[:8] |
||
text = data[8:] |
text = data[8:] |
||
sequence = unpack('q', sequence)[0] |
sequence = unpack('q', sequence)[0] |
||
if |
if src not in self.last: |
||
self.last[src] = 0 |
self.last[src] = 0 |
||
if sequence > self.last[src]: |
if sequence > self.last[src]: |
||
Line 225: | Line 266: | ||
lines = self.list_shared_activities(0) |
lines = self.list_shared_activities(0) |
||
for line in lines: |
for line in lines: |
||
print "\t".join(str(item) for item in line) |
|||
res = [] |
|||
for item in line: |
|||
print str(item), "\t", |
|||
print |
|||
if command == "tree": |
if command == "tree": |
||
for nick,path,dist,total_dist in self.show_network_tree(): |
for nick,path,dist,total_dist in self.show_network_tree(): |
||
_path = [] |
_path = [str(p) for p in path] |
||
for p in path: |
|||
_path.append(str(p)) |
|||
print nick, _path, dist, total_dist |
print nick, _path, dist, total_dist |
||
if command == "mst": |
if command == "mst": |
||
for nick,path,dist in self.show_mst(): |
for nick,path,dist in self.show_mst(): |
||
_path = [] |
_path = [str(p) for p in path] |
||
for p in path: |
|||
_path.append(str(p)) |
|||
print nick, _path, dist |
print nick, _path, dist |
||
if command == "sound": |
if command == "sound": |
||
self.send_command('aplay /usr/share/sounds/alsa/Noise.wav') |
self.send_command('aplay /usr/share/sounds/alsa/Noise.wav') |
||
if command.startswith("nick"): |
|||
newnick = command[5:] |
|||
if newnick: |
|||
myBuddyInfo = self.get_personal_info() |
|||
myBuddyInfo['nick'] = newnick |
|||
self.set_personal_info(myBuddyInfo) |
|||
if command.startswith("join"): |
|||
aid = command[5:] |
|||
print "Will try to join activity ID:", aid |
|||
try: |
|||
self.aid = self.register(aid, ATYPE) |
|||
print "my aid is:", self.aid, len(self.aid), bin2mac(self.aid,1) |
|||
except dbus.DBusException: |
|||
traceback.print_exc() |
|||
sys.exit() |
|||
if command.startswith("share"): |
|||
print "Will share current activity" |
|||
try: |
|||
self.aid = self.register('', ATYPE) |
|||
print "my aid is:", self.aid, len(self.aid), bin2mac(self.aid,1) |
|||
except dbus.DBusException: |
|||
traceback.print_exc() |
|||
sys.exit() |
|||
#self.keeper.process_command( line ) |
|||
else: |
else: |
||
self.send_chat_text(line) |
self.send_chat_text(line) |
||
Line 262: | Line 318: | ||
[[Cerebro test plan]] |
[[Cerebro test plan]] |
||
== References == |
|||
<references /> |
|||
[[Category:Network]] |
[[Category:Network]] |
Latest revision as of 01:48, 10 April 2010
What is Cerebro?
Cerebro <ref>http://cerebro.mit.edu</ref> is a scalable, light-weight platform that provides presence information, efficient file sharing and an easy collaboration mechanism for activities.
Features
The following is a list of features that Cerebro offers. Some (marked with a *) are under development.
- presence information (including distance and route) for all other users in the network
- mesh network extended to regular 802.11b/g devices
- extensible user profile including nickname, colors, keys, IP addreses, picture of arbitrary size, status message etc
- file sharing using an efficient multicast mechanism
- simple collaboration mechanism
- connect to remote mesh networks over the internet (*)
- interoperability with regular x86 machines (*)
- internet connection even without a valid IP address (*)
- programming API based on dbus (see examples)
Experimental results
Two experiments were carried out with 27 nodes and 65 nodes respectively.
Download
http://lyme.media.mit.edu/cerebro/index.php/Download
Presence Information
Presence information involves the set of users/XOs that are currently accessible over the mesh network. This information is decoupled from the user profile so as to increase the scaling properties of the presence mechanism. For example, it is possible that we know that there are 120 users in the network, but only have detailed profile information about only 100 users. Fore the rest, we have not received their profile information, yet!
A cache is used to store user profiles (so as to avoid having to retrieve all user profiles every time we join the network) and events are triggered whenever a user modifies her profile.
File sharing
Since we have a presence mechanism that provides network layout information, we can make better decisions on how to efficiently distribute files within the mesh network.
A mechanism for sharing files efficiently within the mesh network is offered. When enough file recipients are present as direct neighbors <ref>http://cerebro.mit.edu/index.php/Experimental_results</ref>, a file is simultaneously broadcasted to all of them instead of establishing sequential TCP sessions. The presence mechanism is consulted in conjunction with the set of receivers to decide whether it is worth using the broadcast mechanism or not. Experiments have shown that roughly when more than 15 recipients are direct neighbors, it is more efficient using the broadcast mechanism.
The file sharing mechanism is used by Cerebro itself to transport (potentially large) user profiles within the mesh network. Also, API calls allow activities to make use of this mechanism.
Collaboration
Since we have a means of sharing profiles and trigger events within the network, collaboration between activities is simply achieved by adding information in the user profile about what activities the user is currently sharing. Activity sharing information involves activity type and instance: Every activity is a of specific, "well-known" type and each instance being shared receives a unique identifier. This way it is possible to share new activities and join specific activities from across the network.
Again, API calls provide the primitives for sharing, joining and leaving activities.
Programming API
The API is currently under development. This means that slight changes may be done in the future to the arguments of the API interfaces and new interfaces will probably be added. Comments/suggestions/patches are most welcomed!
register (method)
Input : activity_id, activity_type
Output: A unique activity ID (aid)
Description: Share current activity or join an activity shared by someone else.
unregister (method)
Input: aid
Description: Unregister an activity instance (identified by "aid").
on_node_arrival (signal)
Output: Array of node IDs that joined the network
Description: Receive notification when a new node joins the netowrk, The activity may choose to act on this.
on_node_departure (signal)
Output: Array of node IDs that left the network
Description: Receive notification when a new node leaves the netowrk. The activity may choose to act on this.
get_personal_info (method)
Output: A buddy dictionary containing current user information
Description: Retrieves user personal information.
set_personal_info (method)
Input: A buddy dictionary containing new user information
Description: Updates user personal information.
received_data (signal)
Output: data, buddy, src, port, aid
Description: A signal that gets emitted whenever "data" is received from "buddy" (who has the unique ID "src"), for activity instance "aid" which is of type "port" (eg Chat).
push_data (method)
Input: aid, data, port
Description: Sends "data" to all users participating in the shared activity identified by "aid" which is of type "port".
exec_command (method)
Input: A command string
Description: Executes "command" on the local machine. This method is provided for debugging and may be removed.
Output: Returns a list of tuples, each containing 3 fields: nickname, aid, activity_type
Description: This method returns a list of all activities currently shared in the network and the nicknames of the users that are participating. The activity ID "aid" provides the unique identifier for each of the shared activities and "activity_type" provides the type of the activity.
show_mst (method)
Output: A list of nicknames (or user ID, if we have not received profile information yet), the corresponding distance to each user, and the path (consisting of other nicknames) that needs to be followed to reach the remote nickname.
Description: Returns the minimum distances from the current node to all other nodes present in the network.
show_network_tree (method)
Output: Same as "show_mst", but includes all possible paths known from the current node to the remote destination.
Description: Returns all known paths from the current node to all other nodes present in the network.
Example
The following example demonstrates most of the available API. You can find this file in the Cerebro bundle.
Using this example, can have access to most of Cerebro's features. The example shows the following functionality:
- a simple chat application
- joining shared activities (joins by default a shared "Debugger" activity)
- a command-based interface with Cerebro. Commands are issued by escaping the command with a forward slash "/". The following commands are implemented:
Command | Description | |
/listactivities or /la | shows a list of all currently shared activities | |
/share | share current activity | |
/join XXXXXXXXXX | join activity with unique ID XXXXXXXXXX (unique IDs can be listed using '/la') | |
/leave | leave all shared instancies of current activity | |
/tree | shows all paths to all known destinations | |
/mst | shows the minimun distances and path to all known destinations | |
/dn | shows all direct (1-hop) neighbors | |
/sound | plays a sound. Useful for pinpointing a machine ;-) | |
/run COMMAND | run a command locally |
# !/usr/bin/env python # Applications that use D-Bus to export a method to create a dictionary import dbus import dbus.service import dbus.glib import dbus.mainloop.glib import gobject, traceback, sys, time from struct import pack, unpack def bin2mac(bin, all=False): if all: m = bin # return all the bytes d = '' else: m = bin[-3:] # get the last three bytes d = ':' return d.join("%02X" % ord(c) for c in m) #ATYPE = '\x0a\x00' ATYPE = 'FF' SERVICE = 'org.olpc.cerebro' OBJECT_PATH = '/org/olpc/cerebro/chat123' INTERFACE = 'org.olpc.cerebro.chat123' class Debugger(dbus.service.Object): def __init__(self): bus = dbus.SystemBus() interface = bus.get_object('org.olpc.cerebro', '/org/olpc/cerebro') interface.connect_to_signal("on_node_arrival", self.onNodeArrival) interface.connect_to_signal("received_data", self.receive_chat_text) self.register = interface.get_dbus_method('register', 'org.olpc.cerebro') self.unregister = interface.get_dbus_method('unregister', 'org.olpc.cerebro') self.push_data = interface.get_dbus_method("push_data", 'org.olpc.cerebro') self.list_shared_activities = interface.get_dbus_method("list_shared_activities", 'org.olpc.cerebro') self.show_network_tree = interface.get_dbus_method("show_network_tree", 'org.olpc.cerebro') self.show_mst = interface.get_dbus_method("show_mst", 'org.olpc.cerebro') self.send_command = interface.get_dbus_method("exec_command", 'org.olpc.cerebro') self.get_personal_info = interface.get_dbus_method("get_personal_info", 'org.olpc.cerebro') self.set_personal_info = interface.get_dbus_method("set_personal_info", 'org.olpc.cerebro') self.buddyinfo = [] self.last = {} def onNodeArrival(self, node_arr): for n in node_arr: s = "".join(chr(b) for b in n) #s = "".join(ord(b) for b in n) print "CHAT: Node entered:", bin2mac(s) #print "sending to", bin2mac(s) #self.send_chat_text('hello world') def send_chat_text(self, data): sequence = pack('q', 1000 * time.time()) # 8 bytes print "chat: sending", data, len(self.aid) data = sequence + data self.push_data(self.aid, data, ATYPE) def receive_chat_text(self, data, buddy, src, port, aid): data = "".join(chr(b) for b in data) #fhash = "".join(chr(b) for b in fhash) src = "".join(chr(b) for b in src) port = "".join(chr(b) for b in port) if port != ATYPE or aid != self.aid: return True #buddy = bin2mac(src) nick = ''.join(chr(x) for x in buddy['nick']) sequence = data[:8] text = data[8:] sequence = unpack('q', sequence)[0] if src not in self.last: self.last[src] = 0 if sequence > self.last[src]: self.last[src] = sequence print "Chat:", nick,":", text #else: #print "Chat:", buddy,":", text, "(duplicate!)" def on_stdin_cb(self, sck, condition): line = sck.readline().strip() if line != "" and line != "\n": #print "SYS.STDIN:", line.strip() if line[0] == "/": command = line[1:] if command == "listactivities" or command == "la": lines = self.list_shared_activities(0) for line in lines: print "\t".join(str(item) for item in line) if command == "tree": for nick,path,dist,total_dist in self.show_network_tree(): _path = [str(p) for p in path] print nick, _path, dist, total_dist if command == "mst": for nick,path,dist in self.show_mst(): _path = [str(p) for p in path] print nick, _path, dist if command == "sound": self.send_command('aplay /usr/share/sounds/alsa/Noise.wav') if command.startswith("nick"): newnick = command[5:] if newnick: myBuddyInfo = self.get_personal_info() myBuddyInfo['nick'] = newnick self.set_personal_info(myBuddyInfo) if command.startswith("join"): aid = command[5:] print "Will try to join activity ID:", aid try: self.aid = self.register(aid, ATYPE) print "my aid is:", self.aid, len(self.aid), bin2mac(self.aid,1) except dbus.DBusException: traceback.print_exc() sys.exit() if command.startswith("share"): print "Will share current activity" try: self.aid = self.register('', ATYPE) print "my aid is:", self.aid, len(self.aid), bin2mac(self.aid,1) except dbus.DBusException: traceback.print_exc() sys.exit() else: self.send_chat_text(line) return True if __name__ == '__main__': dbus.mainloop.glib.DBusGMainLoop(set_as_default = True) db = Debugger() gobject.io_add_watch(sys.stdin, gobject.IO_IN, db.on_stdin_cb) mainloop = gobject.MainLoop() mainloop.run()
References
<references />