Index: Wireless/Wireless.cc
===================================================================
--- Wireless/Wireless.cc	(revision 1)
+++ Wireless/Wireless.cc	(revision 130)
@@ -3,6 +3,8 @@
 #include <cstring>
 #include "Shared/ProjectInterface.h"
 
+#include "SocketListener.h"
+
 Wireless *wireless=NULL;
 
 #ifdef PLATFORM_APERIOS
@@ -382,6 +384,13 @@
 	sockets[sock]->rcvcbckfn=rcvcbckfn;
 }
 
+void Wireless::setReceiver(int sock, SocketListener *listener) {
+	if (sock <= 0 || sock >= WIRELESS_MAX_SOCKETS || sockets[sock] == NULL)
+		return;
+	
+	sockets[sock]->sckListener = listener;
+}
+
 void
 Wireless::receive(int sock)
 {
@@ -454,8 +463,15 @@
 				}
 
 			sockets[sock]->recvSize = receiveMsg->sizeMin;
-			if ( sockets[sock]->rcvcbckfn != NULL )
-				sockets[sock]->rcvcbckfn( ( char * ) sockets[sock]->recvData, sockets[sock]->recvSize );
+			
+			if (sockets[sock]->sckListener != NULL) {
+				sockets[sock]->sckListener->processData((char *)sockets[sock]->recvData,
+														sockets[sock]->recvSize);
+				
+			} else if (sockets[sock]->rcvcbckfn != NULL) {
+				sockets[sock]->rcvcbckfn((char *)sockets[sock]->recvData,
+										 sockets[sock]->recvSize);
+			}
 			sockets[sock]->recvSize = 0;
 
 		}
@@ -475,22 +491,25 @@
 
 					sockets[sock]->peer_addr=receiveMsg->address.Address();
 					sockets[sock]->peer_port=receiveMsg->port;
-					if ( !strncmp( "connection request", ( char * ) sockets[sock]->recvData, 18 ) )
-						{
-							// clear this message from the receiving buffer
-							sockets[sock]->recvData += sockets[sock]->recvSize;
-
-							if ( sockets[sock]->state != CONNECTION_CONNECTED )
-								{
-									char caller[14];
-									receiveMsg->address.GetAsString( caller );
-									connect( sock, caller, receiveMsg->port );
-								}
-						}
-
-					else if ( sockets[sock]->rcvcbckfn != NULL )
-						sockets[sock]->rcvcbckfn( ( char * ) sockets[sock]->recvData, sockets[sock]->recvSize );
-
+					if ( !strncmp( "connection request", ( char * ) sockets[sock]->recvData, 18 ) ) {
+						// clear this message from the receiving buffer
+						sockets[sock]->recvData += sockets[sock]->recvSize;
+						
+						if ( sockets[sock]->state != CONNECTION_CONNECTED )
+							{
+								char caller[14];
+								receiveMsg->address.GetAsString( caller );
+								connect( sock, caller, receiveMsg->port );
+							}
+						
+					} else if (sockets[sock]->sckListener != NULL) {
+						sockets[sock]->sckListener->processData((char *)sockets[sock]->recvData,
+																sockets[sock]->recvSize);
+						
+					} else if (sockets[sock]->rcvcbckfn != NULL) {
+						sockets[sock]->rcvcbckfn((char *)sockets[sock]->recvData,
+												 sockets[sock]->recvSize);
+					}
 				}
 
 			sockets[sock]->recvSize = 0;
@@ -663,6 +682,10 @@
 	sockets[sock]->rcvcbckfn=rcvcbckfn;
 }
 
+void Wireless::setReceiver(int sock, SocketListener *listener) {
+	sockets[sock]->sckListener = listener;
+}
+
 void Wireless::close(int sock) {
 	MarkScope l(getLock());
 	if ( sock <= 0 || sock >= WIRELESS_MAX_SOCKETS || sockets[sock] == NULL)
@@ -1005,6 +1028,17 @@
 							// clear this message from the receiving buffer
 							if ( sockets[*it]->state != CONNECTION_CONNECTED )
 								connect( *it, sockets[*it]->getPeerAddressAsString().c_str(), sockets[*it]->getPeerPort() );
+						} else if (sockets[*it]->sckListener != NULL) {
+							try {
+								sockets[*it]->sckListener->processData((char *)sockets[*it]->recvData,
+																	   sockets[*it]->recvSize);
+							} catch(const std::exception& ex) {
+								if(!ProjectInterface::uncaughtException(__FILE__,__LINE__,"Occurred during networking received data callback",&ex))
+									throw;
+							} catch(...) {
+								if(!ProjectInterface::uncaughtException(__FILE__,__LINE__,"Occurred during networking received data callback",NULL))
+									throw;
+							}
 						} else if ( sockets[*it]->rcvcbckfn != NULL ) {
 							try {
 								sockets[*it]->rcvcbckfn( ( char * ) sockets[*it]->recvData, sockets[*it]->recvSize );
@@ -1041,8 +1075,19 @@
 					continue;
 				} else {
 					//cout << "Read " << sockets[*it]->recvSize << " bytes " << sockets[*it]->rcvcbckfn << endl;
-					if ( sockets[*it]->rcvcbckfn != NULL ) {
+					if (sockets[*it]->sckListener != NULL) {
 						try {
+							sockets[*it]->sckListener->processData((char *)sockets[*it]->recvData,
+																	   sockets[*it]->recvSize);
+						} catch(const std::exception& ex) {
+							if(!ProjectInterface::uncaughtException(__FILE__,__LINE__,"Occurred during networking received data callback",&ex))
+								throw;
+						} catch(...) {
+							if(!ProjectInterface::uncaughtException(__FILE__,__LINE__,"Occurred during networking received data callback",NULL))
+								throw;
+						}
+					} else if ( sockets[*it]->rcvcbckfn != NULL ) {
+						try {
 							sockets[*it]->rcvcbckfn( ( char * ) sockets[*it]->recvData, sockets[*it]->recvSize );
 						} catch(const std::exception& ex) {
 							if(!ProjectInterface::uncaughtException(__FILE__,__LINE__,"Occurred during networking received data callback",&ex))
Index: Wireless/Wireless.h
===================================================================
--- Wireless/Wireless.h	(revision 1)
+++ Wireless/Wireless.h	(revision 130)
@@ -19,6 +19,8 @@
 using namespace SocketNS;
 using namespace __gnu_cxx;
 
+class SocketListener;
+
 //! Tekkotsu wireless class
 /*!
  * For more information on using wireless, please read the following tutorials:
@@ -73,8 +75,12 @@
 
   //! The socket tries to connect to a specific
   int connect(int sock, const char* ipaddr, int port);
+	
 	//! sets receiver callback for a socket
-  void setReceiver(int sock, int (*rcvcbckfn) (char*, int) );
+	void setReceiver(int sock, int (*rcvcbckfn) (char*, int) );
+	
+	void setReceiver(int sock, SocketListener *listener);
+	
   //! sets the socket to be a daemon (recycles on close)
   void setDaemon(int sock, bool val=true) { sockets[sock]->daemon=val; }
   //! sets the socket to be a daemon (recycles on close)
@@ -104,6 +110,10 @@
     { setReceiver(sobj.sock, rcvcbckfn); }
   void setReceiver(Socket *sobj, int (*rcvcbckfn) (char*, int) )
     { setReceiver(sobj->sock, rcvcbckfn); }
+	void setReceiver(Socket &sobj, SocketListener *listener)
+	{ setReceiver(sobj.sock, listener); }
+	void setReceiver(Socket *sobj, SocketListener *listener)
+	{ setReceiver(sobj->sock, listener); }
   void setDaemon(Socket &sobj, bool val=true) { setDaemon(sobj.sock, val); }
   void setDaemon(Socket *sobj, bool val=true) { setDaemon(sobj->sock, val); }
   bool getDaemon(Socket &sobj) { return getDaemon(sobj.sock); }
Index: Wireless/SocketListener.h
===================================================================
--- Wireless/SocketListener.h	(revision 0)
+++ Wireless/SocketListener.h	(revision 130)
@@ -0,0 +1,12 @@
+#ifndef SOCKETLISTENER_H_
+#define SOCKETLISTENER_H_
+
+class SocketListener {
+	public:
+
+	virtual ~SocketListener() {}
+	
+	virtual int processData(char *data, int bytes) = 0;
+};
+
+#endif

Property changes on: Wireless/SocketListener.h
___________________________________________________________________
Name: svn:executable
   + *

Index: Wireless/Socket.h
===================================================================
--- Wireless/Socket.h	(revision 1)
+++ Wireless/Socket.h	(revision 130)
@@ -13,6 +13,8 @@
 #include <stdlib.h>
 #include <string>
 
+class SocketListener;
+
 //! holds socket enumerations and constants
 namespace SocketNS {
 	
@@ -89,7 +91,7 @@
 			tx(false), rx(false), sendBuffer(), sendData(NULL), writeData(NULL), 
 			recvBuffer(), recvData(NULL), readData(NULL), server_port(0), 
       rcvcbckfn(NULL), peer_addr(-1), peer_port(-1), textForward(false), textForwardBuf(NULL),
-      forwardSock(NULL), daemon(false)
+		  forwardSock(NULL), daemon(false), sckListener(NULL)
 	{
 #ifndef PLATFORM_APERIOS
 		endpoint=-1;
@@ -268,7 +270,8 @@
   Socket * forwardSock; //!< if non-NULL, output will be sent to this socket if the current socket is not otherwise connected (overrides #textForward)
 
   bool daemon; //!< if true, the socket will automatically be reopened after any closure (manual or otherwise)
- 
+
+	SocketListener *sckListener;
 protected:
   Socket(const Socket&); //!< copy constructor, don't call
   Socket& operator= (const Socket&); //!< assignment operator, don't call
Index: aperios/MMCombo/MMCombo.cc
===================================================================
--- aperios/MMCombo/MMCombo.cc	(revision 1)
+++ aperios/MMCombo/MMCombo.cc	(revision 130)
@@ -131,7 +131,7 @@
 	}
 	
 	erouter = new EventRouter;
-
+	
 	if(strcmp(objectName,"MainObj")==0) {
 		bool isSlowOutput[NumOutputs];
 		for(unsigned int i=0; i<NumOutputs; i++)
@@ -159,6 +159,10 @@
 		sout->setTextForward();
 		serr->setForward(sout);
 		
+		//Have erouter listen for incoming stuff
+		cout << "Telling erouter to serve remote event requests" << endl;
+		erouter->serveRemoteEventRequests();
+		
 		//worldStatePoolMemRgn -> state setup
 		worldStatePoolMemRgn = InitRegion(sizeof(WorldStatePool));
 		wspool=new ((WorldStatePool*)worldStatePoolMemRgn->Base()) WorldStatePool;
Index: Events/RemoteRouter.cc
===================================================================
--- Events/RemoteRouter.cc	(revision 0)
+++ Events/RemoteRouter.cc	(revision 130)
@@ -0,0 +1,281 @@
+#include "Events/RemoteRouter.h"
+#include "Events/EventRouter.h"
+
+#include "Events/TextMsgEvent.h"
+#include "Events/TimerEvent.h"
+#include "Events/FilterBankEvent.h"
+#include "Events/LocomotionEvent.h"
+#include "Events/LookoutEvents.h"
+#include "Events/PitchEvent.h"
+#include "Events/VisionObjectEvent.h"
+
+RemoteRouter::RemoteRouter(int host) : RemoteEvents(),
+									   rstate(NULL), waitingForPort(true),
+									   requestQueue(),
+									   timerActive(false), waitTime(0),
+									   remoteHost(0) {
+	rstate = new RemoteState(this);
+	
+	remoteHost = host;
+	
+	connect(EventRouter::defaultPort);
+	erouter->addTimer(this, 1, 500, true);
+}
+
+RemoteRouter::~RemoteRouter() {
+	delete rstate;
+	
+	wireless->close(sck);
+}
+
+void RemoteRouter::forwardEvent(std::vector<char> &evec) {
+	//Decode the event from the buffer and send it
+
+	unsigned int size = evec.size();
+	char *buf = &evec[0];
+	EventBase etest, *event = NULL;
+	
+	if (!etest.checkInc((int)etest.loadBinaryBuffer(buf, size), buf, size)) {
+		cout << "Error: Received event is not a subclass of EventBase" << endl;
+		return;
+	}
+
+	
+	//If there are bytes left, it's not just an EventBase
+	if (size) {
+
+		if (etest.checkCreator("EventBase::TextMsgEvent",
+							   buf, size, false)) {
+			event = new TextMsgEvent();
+		} else if (etest.checkCreator("EventBase::TimerEvent",
+									  buf, size, false)) {
+			event = new TimerEvent();
+		} else if (etest.checkCreator("EventBase::LocomotionEvent",
+									  buf, size, false)) {
+			event = new LocomotionEvent();
+		} else if (etest.checkCreator("EventBase::VisionObjectEvent",
+									  buf, size, false)) {
+			event = new VisionObjectEvent();
+		} else {
+			cout << "Buffer isn't a recognized event type. " << endl;
+		}
+		
+	} else {
+		event = new EventBase();
+	}
+
+	//Load the buffer
+	if (event) {
+		if (!event->loadBinaryBuffer(&evec[0], evec.size())) {
+			cout << "Error loading from buffer" << endl;
+		} else {
+ 			cout << "Created event object successfully. Posting event from host "
+ 				 << EventRouter::intToStringIP(remoteHost) << endl;
+
+			event->setHostID(remoteHost);
+			erouter->postEvent(*event);
+
+			delete event;
+		}
+	}
+}
+
+void RemoteRouter::connect(int port) {
+	std::string ip = EventRouter::intToStringIP(remoteHost);
+	cout << "RemoteRouter: Connecting to " << ip << " on port "
+		 << port << endl;
+	sck = wireless->socket(SocketNS::SOCK_STREAM);
+	wireless->setReceiver(sck, this);
+	if (wireless->connect(sck, ip.c_str(), port)) {
+		cout << "RemoteRouter: error connecting to remote host" << endl;
+	}
+}
+
+int RemoteRouter::processData(char *data, int bytes) {
+	if (waitingForPort) {
+		if (bytes != sizeof(int)) {
+			cout << "RemoteRouter: unexpected data" << endl;
+			return -1;
+		}
+
+		wireless->close(sck);
+		int port = *(int *)data;
+		connect(port);
+		waitingForPort = false;
+		return 0;
+	}
+	
+	while (bytes) {
+		if (bufType == Invalid) {
+			//Get the buffer type
+			if (!readType(data, bytes))
+				cout << "Error reading buffer type" << endl;
+
+		} else if (!sizeLeft) {
+			//Get the size
+			if (!readSize(data, bytes))
+				cout << "Error reading buffer size" << endl;
+				
+		} else {
+			//Read some data
+			if (readData(data, bytes)) {
+				//Dispatch the chunk of data
+				switch(bufType) {
+				case EventData:
+					forwardEvent(vecbuf);
+					break;
+				case StateData:
+					rstate->update(&vecbuf[0]);
+					break;
+				case Invalid:
+					cout << "Error: invalid data. This should never happen." << endl;
+					return -1;
+				default:
+					cout << "Error: data came in that wasn't expected" << endl;
+					return -1;
+				}
+				bufType = Invalid;
+			}
+		}
+		
+	}
+
+	return 0;
+}
+
+void RemoteRouter::requestStateUpdates(RemoteState::StateType type,
+											 unsigned int interval) {
+	RemoteRequest info;
+	info.type = StateUpdateRequest;
+	info.sType = type;
+	info.interval = interval;
+	sendRemoteRequest(info);
+}
+
+void RemoteRouter::stopStateUpdates(RemoteState::StateType type) {
+	RemoteRequest info;
+	info.type = StopStateUpdateRequest;
+	info.sType = type;
+	sendRemoteRequest(info);
+}
+
+void RemoteRouter::addListener(EventBase::EventGeneratorID_t egid) {
+	RemoteRequest info;
+	info.type = EventListenerRequest;
+	info.numElements = 1;
+	info.egid = egid;
+	sendRemoteRequest(info);
+}
+
+void RemoteRouter::addListener(EventBase::EventGeneratorID_t egid,
+							   unsigned int sid) {
+	RemoteRequest info;
+	info.type = EventListenerRequest;
+	info.numElements = 2;
+	info.egid = egid;
+	info.sid = sid;
+	sendRemoteRequest(info);
+}
+
+void RemoteRouter::addListener(EventBase::EventGeneratorID_t egid,
+							   unsigned int sid,
+							   EventBase::EventTypeID_t etid) {
+	RemoteRequest info;
+	info.type = EventListenerRequest;
+	info.numElements = 3;
+	info.egid = egid;
+	info.sid = sid;
+	info.etid = etid;
+	sendRemoteRequest(info);
+}
+
+void RemoteRouter::removeListener(EventBase::EventGeneratorID_t egid) {
+	RemoteRequest info;
+	info.type = RemoveEventListenerRequest;
+	info.numElements = 1;
+	info.egid = egid;
+	sendRemoteRequest(info);
+}
+
+void RemoteRouter::removeListener(EventBase::EventGeneratorID_t egid,
+								  unsigned int sid) {
+	RemoteRequest info;
+	info.type = RemoveEventListenerRequest;
+	info.numElements = 2;
+	info.egid = egid;
+	info.sid = sid;
+	sendRemoteRequest(info);
+}
+
+void RemoteRouter::removeListener(EventBase::EventGeneratorID_t egid,
+								  unsigned int sid,
+								  EventBase::EventTypeID_t etid) {
+	RemoteRequest info;
+	info.type = RemoveEventListenerRequest;
+	info.numElements = 3;
+	info.egid = egid;
+	info.sid = sid;
+	info.etid = etid;
+	sendRemoteRequest(info);
+}
+
+void RemoteRouter::processEvent(const EventBase& event) {
+	if (event.getGeneratorID() == EventBase::timerEGID ) {
+		switch(event.getSourceID()) {
+		case 0:
+			if (isReady()) {
+				cout << "Connected! Sending queue of requests" << endl;
+				while (requestQueue.size()) {
+					sendRemoteRequest(requestQueue.front());
+					requestQueue.pop_front();
+				}
+				
+				erouter->removeTimer(this, 0);
+				timerActive = false;
+			} else {
+				waitTime += 500;
+				if (waitTime == 5000) {
+					cout << "RemoteRouter has been waiting for 5 seconds to connect, "
+						 << "are you sure you specified the right host?" << endl;
+				}
+			}
+			break;
+
+		case 1:
+			if (isConnected()) {
+				int foo = 0;
+				sck->write((byte *)&foo, sizeof(int));
+				erouter->removeTimer(this, 1);
+			}
+			break;
+
+		default:
+			cout << "RemoteRouter got unknown timer event" << endl;
+		}
+	}
+}
+
+void RemoteRouter::sendRemoteRequest(RemoteRequest &info) {
+	if (!isReady()) {
+		cout << "Tried to send remote request but not connected! Queuing RemoteRequest..." << endl;
+
+		requestQueue.push_back(info);
+		if (!timerActive) {
+			erouter->addTimer(this, 0, 500, true);
+			timerActive = true;
+			waitTime = 0;
+		}
+		return;
+	}
+
+	NetworkBuffer nBuf;
+
+	nBuf.addItem(RequestData);
+	nBuf.addItem(sizeof(RemoteRequest));
+	nBuf.addItem(info);
+
+	if (!nBuf.send(sck)) {
+		cout << "Error sending remote request" << endl;
+		return;
+	}	
+}
Index: Events/RemoteDogs.h
===================================================================
--- Events/RemoteDogs.h	(revision 0)
+++ Events/RemoteDogs.h	(revision 130)
@@ -0,0 +1,11 @@
+#ifndef _REMOTEDOGS_H_
+#define _REMOTEDOGS_H_
+
+#define COGROB1 "128.237.255.183"
+#define COGROB2 "128.237.255.184"
+#define COGROB3 "128.237.255.185"
+#define COGROB4 "128.237.255.186"
+#define COGROB5 "128.237.255.187"
+#define COGROB6 "128.237.255.188"
+
+#endif
Index: Events/EventBase.cc
===================================================================
--- Events/EventBase.cc	(revision 1)
+++ Events/EventBase.cc	(revision 130)
@@ -1,8 +1,10 @@
 #include "EventBase.h"
+#include "EventRouter.h"
 #include <stdio.h>
 #include <sstream>
 #include <libxml/tree.h>
 #include "Shared/debuget.h"
+#include "Events/RemoteRouter.h"
 
 const char* const EventBase::EventGeneratorNames[numEGIDs] = {
 	"unknownEGID",
@@ -38,6 +40,7 @@
 	"visObjEGID",
 	"wmVarEGID",
 	"worldModelEGID",
+	"remoteStateEGID"
 };
 
 const char* const EventBase::EventTypeNames[numETIDs] = {
@@ -49,13 +52,15 @@
 const char* const EventBase::EventTypeAbbr[numETIDs] = { "A", "S", "D" };
 
 EventBase::EventBase()
-	: XMLLoadSave(), stim_id(), magnitude(0), timestamp(get_time()), saveFormat(XML), nameisgen(true), genID(unknownEGID), typeID(statusETID), sourceID((unsigned int)-1), duration(0)
+	: XMLLoadSave(), stim_id(), magnitude(0), timestamp(get_time()), saveFormat(XML),
+	  nameisgen(true), genID(unknownEGID), typeID(statusETID), sourceID((unsigned int)-1),
+	  hostID(-1), duration(0)
 {
 	genName();
 }
 
 EventBase::EventBase(EventGeneratorID_t gid, unsigned int sid, EventTypeID_t tid, unsigned int dur)
-	: XMLLoadSave(), stim_id(), magnitude(0), timestamp(get_time()), saveFormat(XML), nameisgen(true), genID(gid), typeID(tid), sourceID(sid), duration(dur)
+	: XMLLoadSave(), stim_id(), magnitude(0), timestamp(get_time()), saveFormat(XML), nameisgen(true), genID(gid), typeID(tid), sourceID(sid), hostID(-1), duration(dur)
 {
 	genName();
 	if(tid==deactivateETID)
@@ -65,7 +70,7 @@
 }
 
 EventBase::EventBase(EventGeneratorID_t gid, unsigned int sid, EventTypeID_t tid, unsigned int dur, const std::string& n)
-	: XMLLoadSave(), stim_id(), magnitude(0), timestamp(get_time()), saveFormat(XML), nameisgen(true), genID(gid), typeID(tid), sourceID(sid), duration(dur)
+	: XMLLoadSave(), stim_id(), magnitude(0), timestamp(get_time()), saveFormat(XML), nameisgen(true), genID(gid), typeID(tid), sourceID(sid), hostID(-1), duration(dur)
 {
 	setName(n);
 	if(tid==deactivateETID)
@@ -75,7 +80,7 @@
 }
 
 EventBase::EventBase(EventGeneratorID_t gid, unsigned int sid, EventTypeID_t tid, unsigned int dur, const std::string& n, float mag)
-	: XMLLoadSave(), stim_id(), magnitude(mag), timestamp(get_time()), saveFormat(XML), nameisgen(true), genID(gid), typeID(tid), sourceID(sid), duration(dur)
+	: XMLLoadSave(), stim_id(), magnitude(mag), timestamp(get_time()), saveFormat(XML), nameisgen(true), genID(gid), typeID(tid), sourceID(sid), hostID(-1), duration(dur)
 {
 	setName(n);
 }
@@ -95,6 +100,12 @@
 	stim_id+=sourcename;
 	stim_id+=',';
 	stim_id+=EventTypeAbbr[getTypeID()];
+
+	if (hostID != -1) {
+		stim_id += ',';
+		stim_id += EventRouter::intToStringIP(hostID);
+	}
+	
 	stim_id+=')';
 	nameisgen=false;
 	return *this;
@@ -126,6 +137,7 @@
 	used+=getSerializedSize<char>(); //genID is an enum, override to char
 	used+=getSerializedSize<char>(); //typeID is an enum, override to char
 	used+=getSerializedSize(sourceID);
+	used+=getSerializedSize(hostID);
 	used+=getSerializedSize(duration);
 	return used;
 }
@@ -144,7 +156,12 @@
 	if(!decodeInc(tmp,buf,len)) return 0;
 	typeID=(EventTypeID_t)tmp;
 	if(!decodeInc(sourceID,buf,len)) return 0;
+
+	if(!decodeInc(hostID,buf,len)) return 0;
+	
 	if(!decodeInc(duration,buf,len)) return 0;
+
+	genName();
 	return origlen-len;	
 }
 
@@ -159,6 +176,9 @@
 	if(!encodeInc((char)genID,buf,len)) return 0;
 	if(!encodeInc((char)typeID,buf,len)) return 0;
 	if(!encodeInc(sourceID,buf,len)) return 0;
+	
+	if(!encodeInc(hostID,buf,len)) return 0;
+	
 	if(!encodeInc(duration,buf,len)) return 0;
 	return origlen-len;
 }
@@ -178,11 +198,19 @@
 	if(i==numEGIDs)
 		throw bad_format(node,"bad event generator name");
 	genID=static_cast<EventGeneratorID_t>(i);
+	
 	str = xmlGetProp(node,(const xmlChar*)"sid");
 	if(str==NULL)
 		throw bad_format(node,"missing source id");
 	sourceID=atoi((const char*)str);
 	xmlFree(str);
+
+	str = xmlGetProp(node,(const xmlChar*)"hid");
+	if(str==NULL)
+		throw bad_format(node,"missing host id");
+	hostID=atoi((const char*)str);
+	xmlFree(str);
+	
 	str = xmlGetProp(node,(const xmlChar*)"etid");
 	if(str==NULL)
 		throw bad_format(node,"missing type id");
@@ -222,8 +250,13 @@
 	xmlNodeSetName(node,(const xmlChar*)"event");
 	xmlSetProp(node,(const xmlChar*)"egid",(const xmlChar*)EventGeneratorNames[genID]);
 	char buf[20];
+	
 	snprintf(buf,20,"%lu",static_cast<unsigned long>(sourceID));
 	xmlSetProp(node,(const xmlChar*)"sid",(const xmlChar*)buf);
+
+	snprintf(buf,20,"%lu",static_cast<long>(hostID));
+	xmlSetProp(node,(const xmlChar*)"hid",(const xmlChar*)buf);
+	
 	xmlSetProp(node,(const xmlChar*)"etid",(const xmlChar*)EventTypeAbbr[typeID]);
 	snprintf(buf,20,"%u",timestamp);
 	xmlSetProp(node,(const xmlChar*)"time",(const xmlChar*)buf);
Index: Events/RemoteEvents.h
===================================================================
--- Events/RemoteEvents.h	(revision 0)
+++ Events/RemoteEvents.h	(revision 130)
@@ -0,0 +1,89 @@
+#ifndef _REMOTEEVENTS_H_
+#define _REMOTEEVENTS_H_
+
+#include "Wireless/Socket.h"
+#include "Wireless/Wireless.h"
+#include "Wireless/SocketListener.h"
+#include "Events/EventBase.h"
+#include "Events/NetworkBuffer.h"
+#include "Shared/RemoteState.h"
+#include <vector>
+#include <string>
+
+
+/*! This class contains the network code common between RemoteRouter
+ *  and EventProxy. It contains methods for sending and receiving
+ *  events, state updates, and requests to recieve the former two
+ *  things. */
+class RemoteEvents : public SocketListener {
+    public:
+
+	//! This is sent in the header of any data sent over the wireless,
+	//it indicates what type of data it is
+    enum BufferType {
+        Invalid,
+        StateData,
+        EventData,
+        RequestData
+    };
+
+	//! This is sent in the header of any requests for remote events
+	//or state updates
+	enum RequestType {
+		EventListenerRequest,
+		StateUpdateRequest,
+		RemoveEventListenerRequest,
+		StopStateUpdateRequest
+	};
+	
+	//! Returns true of the socket is connected
+    bool isConnected();
+
+	//! Returns the remote IP address as a string
+	std::string remoteIPString();
+
+	//! Returns the remote IP address as an int
+	int remoteIPInt();
+
+	
+	static const int defaultBufferSize = 1024;
+	
+    protected:
+
+    //This is so the class can't be instantiated by itself
+    RemoteEvents();
+    virtual ~RemoteEvents();
+    
+    Socket *sck;
+    
+    //Methods and variables for receiving data------------------
+    int sizeLeft;
+    std::vector<char> vecbuf;
+    BufferType bufType;
+    
+    bool readSize(char* &data, int &bytes);
+    bool readType(char* &data, int &bytes);
+    bool readData(char* &data, int &bytes);
+    //-------------------------------------------------------
+	
+    RemoteEvents(RemoteEvents&);
+    RemoteEvents &operator=(const RemoteEvents&);
+};
+
+/*! This struct holds the information required for a request to a
+ *  server robot for events for state updates.  */
+struct RemoteRequest {
+	RemoteEvents::RequestType type;
+
+	//Event subscription
+	int numElements;
+	EventBase::EventGeneratorID_t egid;
+	unsigned int sid;
+	EventBase::EventTypeID_t etid;
+
+	//State updates
+	RemoteState::StateType sType;
+	unsigned int interval;
+};
+
+#endif
Index: Events/EventRouter.h
===================================================================
--- Events/EventRouter.h	(revision 1)
+++ Events/EventRouter.h	(revision 130)
@@ -2,9 +2,11 @@
 #ifndef INCLUDED_EventRouter_h
 #define INCLUDED_EventRouter_h
 
+#include <string>
 #include <vector>
 #include <queue>
 #include <map>
+#include <list>
 #include <algorithm>
 #include "EventListener.h"
 #include "EventTrapper.h"
@@ -13,8 +15,14 @@
 #include "Shared/attributes.h"
 #include "IPC/ProcessID.h"
 #include <iostream>
+#include "Shared/RemoteState.h"
 
+#include "Wireless/SocketListener.h"
+#include "Wireless/Socket.h"
+
+class RemoteRouter;
 class EventTranslator;
+class EventProxy;
 
 //! This class will handle distribution of events as well as management of timers
 /*! Classes must inherit from EventListener and/or EventTrapper in order to
@@ -92,7 +100,7 @@
  *  <h3>Event processing examples:</h3>
  *
  *  Posting events:
- *  @code
+ *  @codeEventProxy
  *  //method A: basic event posting (EventBase instance is sent)
  *  erouter->postEvent(EventBase::aiEGID, 1234, EventBase::statusETID);
  *
@@ -111,7 +119,24 @@
  *    virtual void processEvent(const EventBase& e) {
  *      std::cout << "Got: " << e.getName() << std::endl;
  *    }
- *  };
+ *  };		erouter->addRemoteListener(this,
+							 remoteDog,
+							 EventBase::buttonEGID,
+							 RobotInfo::FrontBackButOffset,
+							 EventBase::activateETID);
+
+		erouter->addRemoteListener(this,
+							 remoteDog,
+							 EventBase::buttonEGID,
+							 RobotInfo::MiddleBackButOffset,
+							 EventBase::activateETID);
+
+		erouter->addRemoteListener(this,
+							 remoteDog,
+							 EventBase::buttonEGID,
+							 RobotInfo::RearBackButOffset,
+							 EventBase::activateETID);
+
  *
  *  YourListener yourList;
  *
@@ -151,11 +176,11 @@
  *    - <a href="http://www.cs.cmu.edu/~dst/Tekkotsu/Tutorial/events.shtml">David Touretzky's Events Chapter</a>
  *    - <a href="http://www.cs.cmu.edu/afs/cs/academic/class/15494-s06/www/lectures/behaviors.pdf">CMU's Cognitive Robotics course slides</a>
  */
-class EventRouter : public EventListener {
+class EventRouter : public EventListener, public SocketListener {
  public:
 	EventRouter(); //!< Constructs the router
 	virtual ~EventRouter(); //!< just calls reset and removeAllTimers()
-	
+
 	void reset() { listeners.clear(); trappers.clear(); removeAllTimers(); } //!< erases all listeners, trappers and timers, resets EventRouter
 	
 	
@@ -246,6 +271,55 @@
 	void addListener(EventListener* el, EventBase::EventGeneratorID_t egid, unsigned int sid, EventBase::EventTypeID_t etid); //!< Adds a listener for a specific source id and type from a given event generator
 	void addListener(EventListener* el, const EventBase& e); //!< Uses the generator, source, and type fields of @a e to add a listener for that specific tuple
 
+	
+	//!@name Remote Event/State code
+
+	//! Converts a int representation of an IP to a string
+	static std::string intToStringIP(int ip);
+	//! Converts a string representation of an IP to an int
+	static int stringToIntIP(std::string ip);
+
+	//! Request remote events to be sent to this dog, works like the regular addListeners
+    void addRemoteListener(EventListener* el, int host, EventBase::EventGeneratorID_t egid);
+    void addRemoteListener(EventListener* el, int host, EventBase::EventGeneratorID_t egid, unsigned int sid);
+    void addRemoteListener(EventListener* el, int host, const EventBase& e);
+    void addRemoteListener(EventListener* el, int host, EventBase::EventGeneratorID_t egid, unsigned int sid, EventBase::EventTypeID_t etid);
+
+	//! Stop getting remote events from the given dog
+    void removeRemoteListener(EventListener* el, int host, EventBase::EventGeneratorID_t egid);
+    void removeRemoteListener(EventListener* el, int host, EventBase::EventGeneratorID_t egid, unsigned int sid);
+    void removeRemoteListener(EventListener* el, int host, const EventBase& e);
+    void removeRemoteListener(EventListener* el, int host, EventBase::EventGeneratorID_t egid, unsigned int sid, EventBase::EventTypeID_t etid);
+
+
+	//! Request remote state updates from the remote dog, every interval ms
+	void requestRemoteStateUpdates(int host, RemoteState::StateType type, unsigned int interval = 500);
+
+	//! Stop getting remote state updates
+	void stopRemoteStateUpdates(int host, RemoteState::StateType type);
+
+	//! This is called once on startup; it tells the EventRouter to listen for incoming requests
+	bool serveRemoteEventRequests();
+
+	//! This handles incomiung connection requests by starting a new EventProxy
+	int processData(char *data, int bytes);
+
+	static const int defaultPort = 2424;
+	
+	protected:
+
+	RemoteRouter &remoteRouterForHost(int host);
+
+	std::list<EventProxy *> proxies;
+
+	std::map<int, RemoteRouter *> rrouters;
+	Socket *sck;
+	int nextProxyPort;
+
+	//!}
+	public:
+
+	
 	//! stops sending ALL events to the listener -- does not remove pending timers however (may need to call removeTimer(el) as well); see remove()
 	void removeListener(EventListener* el); 
 	//! stops sending specified events from the generator to the listener.
@@ -258,6 +332,7 @@
 	void remove(EventListener* el) { removeListener(el); removeTimer(el); }
 
 	//@}
+	
 
 	//!@name Trapper Management
 	
@@ -280,6 +355,7 @@
 	//@}
 
  protected:
+
 	//! Contains all the information needed to maintain a timer by the EventRouter
 	struct TimerEntry {
 		//! constructs an entry using the given value for next - useful for with TimerEntryPtrCmp
Index: Events/RemoteRouter.h
===================================================================
--- Events/RemoteRouter.h	(revision 0)
+++ Events/RemoteRouter.h	(revision 130)
@@ -0,0 +1,95 @@
+#ifndef REMOTEROUTER_H_
+#define REMOTEROUTER_H_
+
+#include <string>
+#include "Wireless/Socket.h"
+#include "Wireless/Wireless.h"
+#include "Events/RemoteEvents.h"
+#include "Events/EventProxy.h"
+#include "Events/EventListener.h"
+#include "Shared/RemoteState.h"
+
+#include <vector>
+#include <list>
+
+class RemoteState;
+
+/* ! This class allows a client robot to subscribe to events and state updates on a remote robot. It receives events and state from EventProxy on the 
+  * remote server robot. It is started automatically. Subscribe to events on remote robots using EventRouter::addRemoteListener() and state updates using
+  * EventRouter::requestRemoteStateUpdates()
+  */
+class RemoteRouter : public RemoteEvents, public EventListener {
+	public:
+
+	//! constructor
+	RemoteRouter(int host);
+	
+	//! destructor
+	virtual ~RemoteRouter();
+
+	//! Request state data from a remote robot every 'interval' amount of time. Use EventRouter::requestRemoteStateUpdates() rather than calling this directly.
+	void requestStateUpdates(RemoteState::StateType type, unsigned int interval);
+	
+	//! Cancels state data updates from a remote dog for the given StateType. Use EventRouter::stopRemoteStateUpdates() rather than calling this directly.
+	void stopStateUpdates(RemoteState::StateType type);
+
+	//! Add remote listener by EGID. Use EventRouter::addRemoteListener() rather than calling this directly.
+	void addListener(EventBase::EventGeneratorID_t egid);
+
+	//! Add remote listener by EGID and SID. Use EventRouter::addRemoteListener() rather than calling this directly.
+	void addListener(EventBase::EventGeneratorID_t egid,
+					 unsigned int sid);
+
+	//! Add remote listener by EGID, SID, and ETID. Use EventRouter::addRemoteListener() rather than calling this directly.
+	void addListener(EventBase::EventGeneratorID_t egid,
+					 unsigned int sid,
+					 EventBase::EventTypeID_t etid);
+
+	//! Remove remote listener by EGID. Use EventRouter::removeRemoteListener() rather than calling this directly.
+	void removeListener(EventBase::EventGeneratorID_t egid);
+
+	//! Remove remote listener by EGID and SID. Use EventRouter::removeRemoteListener() rather than calling this directly.
+	void removeListener(EventBase::EventGeneratorID_t egid,
+						unsigned int sid);
+
+	//! Remove remote listener by EGID, SID, and ETID. Use EventRouter::removeRemoteListener() rather than calling this directly.
+	void removeListener(EventBase::EventGeneratorID_t egid,
+						unsigned int sid,
+						EventBase::EventTypeID_t etid);
+
+	RemoteState *rstate;
+
+	//! Processes timer events which wait for connections to remote EventProxy.
+	void processEvent(const EventBase& event);
+	
+	//! Receives data from remote EventProxy and forwards it to the correct function according to the data type (Event or State)
+	int processData(char *data, int bytes);
+
+	protected:
+
+	//! Returns true when robot is connected to remote robot
+	bool isReady() {
+		return !waitingForPort && isConnected();
+	}
+
+	//! Connect robot on specified port
+	void connect(int port);
+
+	bool waitingForPort;
+	list<RemoteRequest> requestQueue;
+	bool timerActive;
+	int waitTime;
+	
+	int remoteHost;
+	
+	//! Add a remote request to the request queue
+	void sendRemoteRequest(RemoteRequest& info);
+	
+	//! Decode the event from the buffer and post it locally
+	void forwardEvent(std::vector<char>& event);
+	
+	RemoteRouter(RemoteRouter&);
+	RemoteRouter &operator=(const RemoteRouter&);
+};
+
+#endif /*REMOTEROUTER_H_*/
Index: Events/EventBase.h
===================================================================
--- Events/EventBase.h	(revision 1)
+++ Events/EventBase.h	(revision 130)
@@ -111,6 +111,7 @@
 		visObjEGID,       //!< Sends VisionObjectEvents for objects detected in camera images; SID is whatever value you gave during setup (typically in StartupBehavior_SetupVision.cc), duration is always 0
 		wmVarEGID,        //!< Sends an event when a watched memory is changed; source id is pointer to WMEntry
 		worldModelEGID,   //!< not being used, yet (for when objects are detected/lost?)
+                remoteStateEGID,  //!< Sent when remote state is updated
 		numEGIDs          //!< the number of generators available
 	};
 
@@ -169,6 +170,10 @@
 	virtual EventTypeID_t getTypeID() const { return typeID; } /*!< @brief gets the type ID @see EventTypeID_t */
 	virtual EventBase& setTypeID(EventTypeID_t tid) { typeID=tid; unsigned int n=strlen(EventTypeAbbr[typeID]); stim_id.replace(stim_id.size()-n-1,n,EventTypeAbbr[typeID]); return *this; } /*!< @brief sets the type ID @see EventTypeID_t */
 
+
+	virtual int getHostID() const { return hostID; }
+	virtual EventBase& setHostID(int host) { hostID = host; genName(); return *this; }
+	
 	virtual unsigned int getDuration() const { return duration; } /*!< @brief gets the time since the beginning of this sequence (the timestamp of the activate event) @see duration */
 	virtual EventBase& setDuration(unsigned int d) { duration = d; return *this; }/*!< @brief sets the time since the beginning of this sequence (the timestamp of the activate event) @see duration */
 
@@ -276,6 +281,7 @@
 													* Source IDs are defined by the generator that made it.  This should
 													* give authors flexibility to design their modules without having to
 													* worry about ID space collision */
+	int hostID;
 	unsigned int duration; /*!< @brief the time since this sequence started (like, how long the
 													*   button has been pressed); not all generators will set this;
 													*   Typically, this would be 0 for activate,
Index: Events/RemoteEvents.cc
===================================================================
--- Events/RemoteEvents.cc	(revision 0)
+++ Events/RemoteEvents.cc	(revision 130)
@@ -0,0 +1,72 @@
+#include "Events/RemoteEvents.h"
+#include "Events/EventRouter.h"
+
+RemoteEvents::RemoteEvents() : sck(NULL),
+                               sizeLeft(0), vecbuf(), bufType(Invalid) {
+
+}
+
+RemoteEvents::~RemoteEvents() {
+
+}
+
+std::string RemoteEvents::remoteIPString() {
+	return EventRouter::intToStringIP(remoteIPInt());
+}
+
+int RemoteEvents::remoteIPInt() {
+	return sck->getPeerAddress();
+}
+
+//Receiving data-------------------------------------------
+
+/* Reads in the buffer type header */
+bool RemoteEvents::readType(char* &data, int &bytes) {
+	//printf("Got pointer: %x, %d bytes\n", data, bytes);
+    if ((unsigned)bytes < sizeof(BufferType))
+        return false;
+
+    bufType = *(BufferType *)data;
+    data += sizeof(BufferType);
+    bytes -= sizeof(BufferType);
+    return true;
+}
+
+/* Reads in a size header from the data pointer. */
+bool  RemoteEvents::readSize(char* &data, int &bytes) {
+    //Return an error if there's not enough data there
+    if ((unsigned)bytes < sizeof(int))
+        return false;
+
+    //Reset the buffer
+    vecbuf.clear();
+
+    //Read the size and increment/decrement things as appropriate
+    sizeLeft = *(int *)data;
+    data += sizeof(int);
+    bytes -= sizeof(int);
+    return true;
+}
+
+/* Reads in data from the given pointer until the target size is
+ * reached, or bytes becomes zero. Return true if the whole desired
+ * chunk was read, false otherwise. */
+bool RemoteEvents::readData(char* &data, int &bytes) {
+    while (bytes) {
+        //If sizeLeft is zero it's done reading the data
+        if (!sizeLeft)
+            return true;
+        
+        //Read a byte
+        vecbuf.push_back(*data++);
+        bytes--;
+        sizeLeft--;
+    }
+    //Return whether or not the whole chunk was read
+    return !sizeLeft;
+}
+//------------------------------------------------------
+
+bool RemoteEvents::isConnected() {
+    return wireless->isConnected(sck->sock);
+}
Index: Events/EventRouter.cc
===================================================================
--- Events/EventRouter.cc	(revision 1)
+++ Events/EventRouter.cc	(revision 130)
@@ -5,7 +5,11 @@
 #include <algorithm>
 #include "Events/TimerEvent.h"
 #include "EventTranslator.h"
+#include "Events/RemoteRouter.h"
+#include "Events/EventProxy.h"
 
+#include <sstream>
+
 #ifndef PLATFORM_APERIOS
 #  include "IPC/Thread.h"
 #  include "Shared/MarkScope.h"
@@ -14,11 +18,13 @@
 EventRouter * erouter=NULL;
 
 EventRouter::EventRouter()
-	: timers(), trappers(), listeners(), postings()
+	: proxies(), rrouters(), sck(NULL), nextProxyPort(defaultPort+1),
+	  timers(), trappers(), listeners(), postings()
 {
 	for(unsigned int i=0; i<ProcessID::NumProcesses; ++i) {
 		forwards[i]=NULL;
 	}
+
 }
 
 EventRouter::~EventRouter() {
@@ -28,6 +34,16 @@
 		delete forwards[i];
 		forwards[i]=NULL;
 	}
+
+	//Delete all the event proxies
+	printf("Deleting %d EventProxies and %d RemoteRouters\n", proxies.size(), rrouters.size());
+	for (list<EventProxy *>::iterator pi = proxies.begin(); pi != proxies.end(); pi++)
+		delete *pi;
+	
+	//Delete the remote routers
+	for (map<int, RemoteRouter *>::iterator mi = rrouters.begin(); mi != rrouters.end(); mi++)
+		delete (*mi).second;
+	
 }
 
 void EventRouter::postEvent(EventBase* e) { processEvent(*e); delete e; }
@@ -169,6 +185,146 @@
 		postEvent(EventBase(EventBase::erouterEGID,e.getGeneratorID(),EventBase::statusETID,0,EventBase::EventGeneratorNames[e.getGeneratorID()],1));
 }
 
+//Start of remote event code------------------
+void EventRouter::addRemoteListener(EventListener* el, int host,
+									EventBase::EventGeneratorID_t egid) {
+	RemoteRouter &rr = remoteRouterForHost(host);
+	addListener(el, egid);
+	rr.addListener(egid);
+}
+
+void EventRouter::addRemoteListener(EventListener* el, int host,
+									EventBase::EventGeneratorID_t egid, unsigned int sid) {
+	RemoteRouter &rr = remoteRouterForHost(host);
+	addListener(el, egid, sid);
+	rr.addListener(egid, sid);
+}
+
+void EventRouter::addRemoteListener(EventListener* el, int host, const EventBase& e){
+	addRemoteListener(el, host, e.getGeneratorID(), e.getSourceID(), e.getTypeID());
+}
+
+void EventRouter::addRemoteListener(EventListener* el, int host,
+									EventBase::EventGeneratorID_t egid, unsigned int sid,
+									EventBase::EventTypeID_t etid) {
+	RemoteRouter &rr = remoteRouterForHost(host);
+	addListener(el, egid, sid, etid);
+	rr.addListener(egid, sid, etid);
+}
+
+
+void EventRouter::removeRemoteListener(EventListener* el, int host,
+									   EventBase::EventGeneratorID_t egid) {
+	RemoteRouter &rr = remoteRouterForHost(host);
+	removeListener(el, egid);
+	rr.removeListener(egid);
+}
+
+void EventRouter::removeRemoteListener(EventListener* el, int host,
+									   EventBase::EventGeneratorID_t egid, unsigned int sid) {
+	RemoteRouter &rr = remoteRouterForHost(host);
+	removeListener(el, egid, sid);
+	rr.removeListener(egid, sid);	
+}
+    
+void EventRouter::removeRemoteListener(EventListener* el, int host,
+									   const EventBase& e) {
+	removeRemoteListener(el, host, e.getGeneratorID(), e.getSourceID(), e.getTypeID());	
+}
+
+void EventRouter::removeRemoteListener(EventListener* el, int host,
+									   EventBase::EventGeneratorID_t egid, unsigned int sid,
+									   EventBase::EventTypeID_t etid) {
+	RemoteRouter &rr = remoteRouterForHost(host);
+	removeListener(el, egid, sid, etid);
+	rr.removeListener(egid, sid, etid);
+}
+
+
+void EventRouter::requestRemoteStateUpdates(int host, RemoteState::StateType type,
+											unsigned int interval) {
+	RemoteRouter &rr = remoteRouterForHost(host);
+	rr.requestStateUpdates(type, interval);
+}
+
+void EventRouter::stopRemoteStateUpdates(int host, RemoteState::StateType type) {
+	RemoteRouter &rr = remoteRouterForHost(host);
+	rr.stopStateUpdates(type);
+}
+
+RemoteRouter &EventRouter::remoteRouterForHost(int host) {
+	RemoteRouter *rr = rrouters[host];
+	if (rr) {
+		printf("Returning existing remote router for host %s", intToStringIP(host).c_str());
+		return *rr;
+	} else {
+		rrouters[host] = rr = new RemoteRouter(host);
+		printf("Returning new remote router for host %s", intToStringIP(host).c_str());
+		return *rr;
+	}
+}
+
+std::string EventRouter::intToStringIP(int ip) {
+	std::stringstream ret;
+	ret << (ip >> 24 & 0xff) << '.' << (ip >> 16 & 0xff) << '.'
+		<< (ip >> 8 & 0xff) << '.' << (ip >> 0 & 0xff);
+	return ret.str();
+}
+
+int EventRouter::stringToIntIP(std::string ip_str) {
+	std::istringstream sstr;
+	sstr.str(ip_str);
+	int ip = 0, b;
+	char c;
+
+	sstr >> b >> c;
+	ip |= b << 24;
+
+	sstr >> b >> c;
+	ip |= b << 16;
+
+	sstr >> b >> c;
+	ip |= b << 8;
+
+	sstr >> b;
+	ip |= b << 0;
+
+	return ip;
+}
+
+/* This is called in MMCombo.cc on startup. */
+bool EventRouter::serveRemoteEventRequests() {
+	if (sck)
+		return false;
+	sck = wireless->socket(SocketNS::SOCK_STREAM);
+	wireless->setReceiver(sck, this);
+	wireless->setDaemon(sck, true);
+	wireless->listen(sck, EventRouter::defaultPort);
+	return true;
+}
+
+int EventRouter::processData(char* /* data*/, int bytes) {
+	if (bytes != sizeof(int)) {
+		cout << "Unknown data received" << endl;
+		return -1;
+	}
+	
+	int nextPort = nextProxyPort++;
+	cout << "Starting EventProxy on port " << nextPort
+		 << " for host " << intToStringIP(sck->getPeerAddress()) << endl;
+	proxies.push_back(new EventProxy(nextPort));
+
+	//Send the port to the RemoteRouter
+	sck->write((byte *)&nextPort, sizeof(int));
+
+	//Start listening again
+	wireless->close(sck);
+	
+	return 0;
+}
+
+//End of remote event code
+
 void EventRouter::removeListener(EventListener* el) {
 	for(unsigned int eg=0; eg<EventBase::numEGIDs; eg++) {
 		EventBase::EventGeneratorID_t egid=(EventBase::EventGeneratorID_t)eg;
Index: Events/EventProxy.cc
===================================================================
--- Events/EventProxy.cc	(revision 0)
+++ Events/EventProxy.cc	(revision 130)
@@ -0,0 +1,202 @@
+#include "Events/EventProxy.h"
+#include "Shared/WorldState.h"
+#include "Events/RemoteRouter.h"
+#include "Events/EventRouter.h"
+
+EventProxy::EventProxy(int port) : RemoteEvents(), listening(true) {
+	sck = wireless->socket(SocketNS::SOCK_STREAM, 4096, 4096);
+	wireless->setReceiver(sck, this);
+	wireless->setDaemon(sck, true);
+	wireless->listen(sck, port);
+
+	cout << "Adding timer" << endl;
+}
+
+EventProxy::~EventProxy() {
+	//For some reason this causes a crash, so it's commented out for now
+	
+	if (isConnected())
+		wireless->close(sck);
+}
+
+bool EventProxy::isActive() {
+	return listening || isConnected();
+}
+
+int EventProxy::processData(char *data, int bytes) {
+	listening = false;
+	while (bytes) {
+		if (bufType == Invalid) {
+			//Get the buffer type
+			if (!readType(data, bytes)) {
+				cout << "Error reading buffer type" << endl;
+			}
+		} else if (!sizeLeft) {
+			//Get the size
+			if (!readSize(data, bytes)) {
+				cout << "Error reading buffer size" << endl;
+			}
+		} else {
+			//Read some data
+			if (readData(data, bytes)) {
+				//Dispatch the chunk of data
+				switch(bufType) {
+				case RequestData:
+					//Dispatch the data
+					handleRemoteRequest((RemoteRequest *)&vecbuf[0]);
+					break;
+				case Invalid:
+					cout << "Error: invalid data. This should never happen." << endl;
+					return -1;
+				default:
+					cout << "Error: data came in that wasn't expected" << endl;
+					return -1;
+				}
+				bufType = Invalid;
+			}
+		}
+	}
+
+	return 0;
+}
+
+/* Encodes and sends the received event */
+void EventProxy::processEvent(const EventBase &event) {
+	
+	if (event.getGeneratorID() != EventBase::timerEGID) {
+		if (!isConnected()) {
+			cout << "Got an event but not connected!" << endl;
+			return;
+		}
+	
+		//Send Event to connected robot
+	
+		int esize = 0;
+		byte *ebuf = new byte[defaultBufferSize];
+		
+		if ( (esize = event.saveBinaryBuffer((char *)ebuf, defaultBufferSize)) ) {
+			NetworkBuffer nBuf;
+			nBuf.addItem(EventData);
+			nBuf.addBuffer(ebuf, esize);
+			
+			if (!nBuf.send(sck)) {
+				cout << "Error sending event to remote dog" << endl;
+				return;
+			}
+		} else {
+			cout << "Unable to save event to a buffer, aborting transmission" << endl;
+		}
+		
+		delete[] ebuf;
+	} else {
+		//Send state information
+		sendState((RemoteState::StateType)event.getSourceID());
+	}
+}
+
+void EventProxy::handleRemoteRequest(RemoteRequest *info) {
+	switch (info->type) {
+	case EventListenerRequest:
+ 		cout << "Adding remote event listener request: " << info->numElements
+			 << " for host " << remoteIPString() << endl;
+		
+		switch (info->numElements) {
+		case 1:
+			erouter->addListener(this, info->egid);
+			break;
+			
+		case 2:
+			erouter->addListener(this, info->egid, info->sid);
+			break;
+			
+		case 3:
+			erouter->addListener(this, info->egid, info->sid, info->etid);
+			break;
+			
+		default:
+			cout << "Invalid number of elements in event listener request." << endl;
+			break;
+		}
+		break;
+
+		
+	case RemoveEventListenerRequest:
+		cout << "Removing remote event listener: " << info->numElements
+			 << " for host " << remoteIPString() << endl;
+
+		switch (info->numElements) {
+		case 1:
+			erouter->removeListener(this, info->egid);
+			break;
+			
+		case 2:
+			erouter->removeListener(this, info->egid, info->sid);
+			break;
+			
+		case 3:
+			erouter->removeListener(this, info->egid, info->sid, info->etid);
+			break;
+			
+		default:
+			cout << "Invalid number of elements in event listener removal request."
+				 << endl;
+			break;
+		}
+		break;
+
+		
+	case StateUpdateRequest:
+ 		cout << "Adding remote state update request for host "
+			 << remoteIPString() << endl;
+
+		erouter->addTimer(this, info->sType, info->interval, true);
+		break;
+
+	case StopStateUpdateRequest:
+		cout << "Removing remote state update request" << endl;
+		
+		erouter->removeTimer(this, info->sType);
+		break;
+		
+	}
+}
+
+/* Encodes and sends the requested state info */
+void EventProxy::sendState(RemoteState::StateType stype) {
+	if (!isConnected()) {
+		cout << "Got a request to send state data but not connected!" << endl;
+		return;
+	}
+	
+	float *src = NULL;
+	int size = RemoteState::sizes[stype];
+
+	/* Get the source of the data */
+	switch (stype) {
+	case RemoteState::OutputState:
+		src = state->outputs;
+		break;
+		
+	case RemoteState::ButtonState:
+		src = state->buttons;
+		break;
+		
+	case RemoteState::SensorState:
+		src = state->sensors;
+		break;
+		
+	default:
+		cout << "Unrecognized state type, aborting" << endl;
+		return;
+	}
+	
+	NetworkBuffer nBuf;
+	nBuf.addItem(StateData);
+	nBuf.addItem(size + 2*sizeof(int));
+	nBuf.addItem(stype);
+	nBuf.addBuffer((byte *)src, size);
+	
+	if (!nBuf.send(sck)) {
+		cout << "Error sending state buffer" << endl;
+	}
+}

Property changes on: Events/EventProxy.cc
___________________________________________________________________
Name: svn:executable
   + *

Index: Events/NetworkBuffer.h
===================================================================
--- Events/NetworkBuffer.h	(revision 0)
+++ Events/NetworkBuffer.h	(revision 130)
@@ -0,0 +1,66 @@
+#ifndef NETWORK_BUFFER_H_
+#define NETWORK_BUFFER_H_
+
+/*! This is used to incrementally build up a buffer to be sent over
+ *  the network , so that only one call to the socket write function
+ *  needs to be made. */
+class NetworkBuffer {
+	public:
+	
+	NetworkBuffer() : buf(NULL), offset(0),
+					  bufSize(1024) {
+		
+		buf = new byte[bufSize];
+	}
+
+	virtual ~NetworkBuffer() {
+		delete[] buf;
+	}
+
+	//! Template for adding a single item to the buffer, such as a
+	//struct or an int
+	template <class T> bool addItem(T item) {
+		if (offset+sizeof(T) > (unsigned int)bufSize)
+			return false;
+		
+		*(T *)(buf+offset) = item;
+		offset += sizeof(T);
+		return true;
+	}
+
+	//! Template for adding a buffer such with a size to the network
+	//buffer
+	bool addBuffer(byte *src, int size) {
+		if (!addItem(size) || (offset+size > bufSize))
+			return false;
+
+		memcpy(buf+offset, src, size);
+		offset += size;
+		return true;
+	}
+
+	//! Returns the current size of the buffer
+	int getSize() {
+		return offset;
+	}
+
+	//! Sends the buffer over the given socket
+	bool send(Socket *sck) {
+		if (sck->write(buf, offset) != offset) {
+			cout << "Error sending buffer" << endl;
+			return false;
+		}
+		
+		return true;
+	}
+	
+	private:
+
+	byte *buf;
+	int offset, bufSize;
+
+	NetworkBuffer(NetworkBuffer&);
+	NetworkBuffer &operator=(const NetworkBuffer&);
+};
+
+#endif
Index: Events/EventProxy.h
===================================================================
--- Events/EventProxy.h	(revision 0)
+++ Events/EventProxy.h	(revision 130)
@@ -0,0 +1,42 @@
+#ifndef EVENTPROXY_H_
+#define EVENTPROXY_H_
+#include "Wireless/Socket.h"
+#include "Wireless/Wireless.h"
+#include "Events/EventListener.h"
+#include "Shared/RemoteState.h"
+#include "Events/RemoteEvents.h"
+
+/*! This class serves as the host for subscribing to remote events. It
+ *  should never be directly manipulated by the user; all interaction
+ *  with this class is handled by EventRouter
+ */
+class EventProxy : public EventListener, public RemoteEvents {
+	public:
+	EventProxy(int port); //!< EventProxy constructor, takes a port to listen on
+	virtual ~EventProxy(); //!< EventProxy destructor
+
+	//! Returns true if the EventProxy is still waiting for a connection or is connected
+	bool isActive();
+
+	//! Sends the requested state information to the client robot
+	void sendState(RemoteState::StateType dtype);
+
+	//! Forwards any recieved events on to the client robot
+	void processEvent(const EventBase& event);
+
+	//! Handles any incoming requests from the client robot
+	int processData(char *data, int bytes);
+
+	protected:
+
+	//! Called by processData, handles an oncoming data request packet
+	void handleRemoteRequest(RemoteRequest *info);
+	
+	
+	bool listening;
+	
+	EventProxy(EventProxy&);
+	EventProxy &operator=(const EventProxy&);
+};
+
+#endif /*EVENTPROXY_H_*/

Property changes on: Events/EventProxy.h
___________________________________________________________________
Name: svn:executable
   + *

Index: Shared/RemoteState.h
===================================================================
--- Shared/RemoteState.h	(revision 0)
+++ Shared/RemoteState.h	(revision 130)
@@ -0,0 +1,37 @@
+#ifndef REMOTESTATE_H_
+#define REMOTESTATE_H_
+
+#include "Shared/RobotInfo.h"
+#include <vector>
+
+class RemoteRouter;
+
+/*! This class represents remote state information recieved from a
+ *  remote dog, and can be treated like a WorldState object */
+class RemoteState {
+    public:
+    RemoteState(const RemoteRouter *p);
+    virtual ~RemoteState();
+    float outputs[NumOutputs];
+	float buttons[NumButtons];
+	float sensors[NumSensors];
+
+    void update(char *data);
+    
+    enum StateType {
+        OutputState,
+		ButtonState,
+		SensorState,
+    };
+
+    static const int sizes[];
+    
+    private:
+    const RemoteRouter *parent;
+
+    
+    RemoteState(RemoteState&);
+    RemoteState &operator=(const RemoteState&);
+};
+
+#endif /* REMOTESTATE_H_ */
Index: Shared/RemoteState.cc
===================================================================
--- Shared/RemoteState.cc	(revision 0)
+++ Shared/RemoteState.cc	(revision 130)
@@ -0,0 +1,53 @@
+#include "Shared/RemoteState.h"
+#include "Events/RemoteRouter.h"
+#include "Events/EventRouter.h"
+#include "Events/DataEvent.h"
+
+const int RemoteState::sizes[] = {
+    NumOutputs*sizeof(float),
+	NumButtons*sizeof(float),
+	NumSensors*sizeof(float),
+};
+
+RemoteState::RemoteState(const RemoteRouter *p) : parent(p) {
+    unsigned int i = 0;
+    for (i = 0; i < NumOutputs; i++)
+        outputs[i] = 0.0;
+}
+
+RemoteState::~RemoteState() {
+
+}
+
+void RemoteState::update(char *data) {
+    //Get the type of the data, a StateType
+    StateType t = *(StateType *)data;
+    data += sizeof(StateType);
+
+    //Get the size of the data, an int
+    int size = *(int *)data / sizeof(float);
+    data += sizeof(int);
+
+    //Set up the source and destination arrays
+    float *src = (float *)data;
+    float *dest;
+    
+    switch (t) {
+    case OutputState:
+        dest = outputs;
+        break;
+    default:
+        return;
+    }
+
+    //Copy the values
+    int i;
+    for (i = 0; i < size; i++)
+        dest[i] = src[i];
+
+    //Post the event
+	DataEvent<const RemoteState *> event(this, EventBase::remoteStateEGID,
+										 t, EventBase::statusETID);
+	
+    erouter->postEvent(event);
+}
