begin abstraction of Agent communication to shared classes

This commit is contained in:
Stephen Birarda 2013-02-19 16:38:57 -08:00
parent 6c70d264ac
commit 9d5a800c6f
10 changed files with 295 additions and 271 deletions

View file

@ -1,206 +0,0 @@
//
// Agent.cpp
// interface
//
// Created by Philip Rosedale on 11/20/12.
// Copyright (c) 2012 High Fidelity, Inc. All rights reserved.
//
#include <iostream>
#include "Agent.h"
#include "Head.h"
#include "Util.h"
// Structure to hold references to other agents that are nearby
const int MAX_AGENTS = 100;
struct AgentList {
char public_address[255];
unsigned short public_port;
char private_address[255];
unsigned short private_port;
char *goodAddress;
unsigned short goodPort;
timeval pingStarted;
int pingMsecs;
char agentType;
bool isSelf;
Head head;
} agents[MAX_AGENTS];
int num_agents = 0;
char * getAgentAddress(int agentNumber) {
if (agentNumber < getAgentCount()) return agents[agentNumber].public_address;
else return NULL;
}
int getAgentCount() {
return num_agents;
}
int getAgentPing(int agentNumber) {
if (agentNumber < getAgentCount()) return agents[agentNumber].pingMsecs;
else return -1;
}
//
// Process an incoming domainserver packet telling you about other nearby agents,
// and returns the number of agents that were reported.
//
int update_agents(char * data, int length) {
int numAgents = 0;
std::string packet(data, length);
size_t spot;
size_t start_spot = 0;
char *public_address = new char[255];
char *private_address = new char[255];
char agentType;
unsigned short public_port, private_port;
spot = packet.find_first_of (",", 0);
while (spot != std::string::npos) {
std::string thisAgent = packet.substr(start_spot, spot-start_spot);
sscanf(thisAgent.c_str(), "%c %s %hd %s %hd", &agentType, public_address, &public_port, private_address, &private_port);
add_agent(public_address, public_port, private_address, private_port, agentType);
numAgents++;
start_spot = spot + 1;
if (start_spot < packet.length())
spot = packet.find_first_of (",", start_spot);
else spot = std::string::npos;
}
return numAgents;
}
// Render the heads of the agents
void render_agents(int renderSelf, float * myLocation) {
for (int i = 0; i < num_agents; i++) {
glm::vec3 pos = agents[i].head.getPos();
glPushMatrix();
if (!agents[i].isSelf || renderSelf) {
glTranslatef(-pos.x, -pos.y, -pos.z);
agents[i].head.render(0, myLocation);
}
glPopMatrix();
}
}
//
// Update a single agent with data received from that agent's IP address
//
void update_agent(char * address, unsigned short port, char * data, int length)
{
//printf("%s:%d\n", address, port);
for (int i = 0; i < num_agents; i++) {
if ((strcmp(address, agents[i].public_address) == 0) && (agents[i].public_port == port)) {
// Update the agent
agents[i].head.recvBroadcastData(data, length);
if ((strcmp(address, "127.0.0.1") == 0) && (port == AGENT_UDP_PORT)) {
agents[i].isSelf = true;
} else agents[i].isSelf = false;
}
}
}
//
// Look for an agent by it's IP number, add if it does not exist in local list
//
int add_agent(char * address, unsigned short port, char *private_address, unsigned short private_port, char agentType) {
//std::cout << "Checking for " << IP->c_str() << " ";
for (int i = 0; i < num_agents; i++) {
if ((strcmp(address, agents[i].public_address) == 0) && (agents[i].public_port == port)) {
//std::cout << "Found agent!\n";
return 0;
}
}
if (num_agents < MAX_AGENTS) {
strcpy(agents[num_agents].public_address, address);
agents[num_agents].public_port = port;
agents[num_agents].agentType = agentType;
strcpy(agents[num_agents].private_address, private_address);
agents[num_agents].private_port = private_port;
agents[num_agents].goodAddress = NULL;
std::cout << "Added Agent # " << num_agents << " with Address " <<
agents[num_agents].public_address << ":" << agents[num_agents].public_port << " T: " <<
agentType << " (" << agents[num_agents].private_address << ":" << agents[num_agents].private_port << ")\n";
num_agents++;
return 1;
} else {
std::cout << "Max agents reached fail!\n";
return 0;
}
}
//
// Broadcast data to all the other agents you are aware of, returns 1 if success
//
int broadcastToAgents(UDPSocket *handle, char * data, int length, int sendToSelf) {
int sent_bytes;
//printf("broadcasting to %d agents\n", num_agents);
for (int i = 0; i < num_agents; i++) {
if (agents[i].agentType != 'M' && agents[i].goodAddress != NULL) {
// std::cout << "broadcasting my agent data to: " << agents[i].goodAddress << " : " << agents[i].goodPort << "\n";
sent_bytes = handle->send(agents[i].goodAddress, agents[i].goodPort, data, length);
if (sent_bytes != length) {
std::cout << "Broadcast to agents FAILED\n";
return 0;
}
}
}
return 1;
}
// Ping other agents to see how fast we are running
void pingAgents(UDPSocket *handle) {
char payload[] = "P";
for (int i = 0; i < num_agents; i++) {
if (agents[i].agentType != 'M') {
gettimeofday(&agents[i].pingStarted, NULL);
if (agents[i].goodAddress == NULL) {
handle->send(agents[i].public_address, agents[i].public_port, payload, 1);
handle->send(agents[i].private_address, agents[i].private_port, payload, 1);
} else {
handle->send(agents[i].goodAddress, agents[i].goodPort, payload, 1);
}
//printf("\nSent Ping at %d usecs\n", agents[i].pingStarted.tv_usec);
}
}
}
// On receiving a ping reply, save that with the agent record
void setAgentPing(char * address, unsigned short port) {
for (int i = 0; i < num_agents; i++) {
bool isLocal = false;
bool isPublic = false;
if ((strcmp(address, agents[i].public_address) == 0) && (agents[i].public_port == port)) {
isPublic = true;
agents[i].goodAddress = agents[i].public_address;
agents[i].goodPort = agents[i].public_port;
} else if ((strcmp(address, agents[i].private_address) == 0) && (agents[i].private_port == port)) {
isLocal = true;
agents[i].goodAddress = agents[i].private_address;
agents[i].goodPort = agents[i].private_port;
}
if (isPublic || isLocal) {
timeval pingReceived;
gettimeofday(&pingReceived, NULL);
float pingMsecs = diffclock(&agents[i].pingStarted, &pingReceived);
//printf("Received ping at %d usecs, Agent ping = %3.1f\n", pingReceived.tv_usec, pingMsecs);
agents[i].pingMsecs = pingMsecs;
}
}
}
void kludgyMixerUpdate(Audio audio) {
for (int i = 0; i < num_agents; i++) {
if (agents[i].agentType == 'M') {
audio.updateMixerParams(agents[i].private_address, agents[i].private_port);
}
}
}

View file

@ -1,36 +0,0 @@
//
// Agent.h
// interface
//
// Created by Philip Rosedale on 11/20/12.
// Copyright (c) 2012 High Fidelity, Inc. All rights reserved.
//
#ifndef __interface__Agent__
#define __interface__Agent__
#include <glm/glm.hpp>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <fcntl.h>
#include <string.h>
#include "UDPSocket.h"
#include "Audio.h"
const unsigned short AGENT_UDP_PORT = 40103;
int update_agents(char * data, int length);
int add_agent(char * address, unsigned short port, char *private_address, unsigned short private_port, char agentType);
int broadcastToAgents(UDPSocket * handle, char * data, int length, int sendToSelf);
void pingAgents(UDPSocket *handle);
void setAgentPing(char * address, unsigned short port);
void update_agent(char * address, unsigned short port, char * data, int length);
void render_agents(int renderSelf, float * myLocation);
void kludgyMixerUpdate(Audio audio);
int getAgentPing(int agentNumber);
int getAgentCount();
char * getAgentAddress(int agentNumber);
#endif

View file

@ -25,13 +25,8 @@
#include <sys/time.h>
#include <pthread.h>
#include <ifaddrs.h>
// These includes are for the serial port reading/writing
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <glm/glm.hpp>
#include <arpa/inet.h>
#include "SerialInterface.h"
#include "Field.h"
#include "world.h"
@ -42,7 +37,7 @@
#include "Particle.h"
#include "Texture.h"
#include "Cloud.h"
#include "Agent.h"
#include "AgentList.h"
#include "Cube.h"
#include "Lattice.h"
#include "Finger.h"
@ -62,7 +57,8 @@ const int MAX_PACKET_SIZE = 1500;
char DOMAIN_HOSTNAME[] = "highfidelity.below92.com";
char DOMAIN_IP[100] = ""; // IP Address will be used first if not empty string
const int DOMAINSERVER_PORT = 40102;
UDPSocket agentSocket(AGENT_UDP_PORT);
UDPSocket agentSocket(AGENT_SOCKET_LISTEN_PORT);
AgentList agentList;
// For testing, add milliseconds of delay for received UDP packets
char* incomingPacket;
@ -227,13 +223,13 @@ void Timer(int extra)
// Send a message to the domainserver telling it we are ALIVE
//
char output[100];
sprintf(output, "%c %f,%f,%f,%s %hd", 'I', location[0], location[1], location[2], localAddressBuffer, AGENT_UDP_PORT);
sprintf(output, "%c %f,%f,%f,%s %hd", 'I', location[0], location[1], location[2], localAddressBuffer, AGENT_SOCKET_LISTEN_PORT);
std::cout << "sending " << output << " to domain server\n";
int packet_size = strlen(output);
agentSocket.send(DOMAIN_IP, DOMAINSERVER_PORT, output, packet_size);
// Ping the agents we can see
pingAgents(&agentSocket);
// pingAgents(&agentSocket);
if (0) {
// Massive send packet speed test
@ -243,7 +239,7 @@ void Timer(int extra)
junk[0] = 'J';
for (int i = 0; i < 10000; i++)
{
agentSocket.send((char *)"192.168.1.38", AGENT_UDP_PORT, junk, 1000);
// agentSocket.send((char *)"192.168.1.38", AGENT_UDP_PORT, junk, 1000);
}
gettimeofday(&endtest, NULL);
float sendTime = diffclock(&starttest, &endtest);
@ -273,12 +269,12 @@ void display_stats(void)
}
// Output the ping times to the various agents
std::stringstream pingTimes;
pingTimes << "Agent Pings, msecs:";
for (int i = 0; i < getAgentCount(); i++) {
pingTimes << " " << getAgentAddress(i) << ": " << getAgentPing(i);
}
drawtext(10,50,0.10, 0, 1.0, 0, (char *)pingTimes.str().c_str());
// std::stringstream pingTimes;
// pingTimes << "Agent Pings, msecs:";
// for (int i = 0; i < getAgentCount(); i++) {
// pingTimes << " " << getAgentAddress(i) << ": " << getAgentPing(i);
// }
// drawtext(10,50,0.10, 0, 1.0, 0, (char *)pingTimes.str().c_str());
std::stringstream angles;
@ -518,7 +514,7 @@ void update_pos(float frametime)
const int MAX_BROADCAST_STRING = 200;
char broadcast_string[MAX_BROADCAST_STRING];
int broadcast_bytes = myHead.getBroadcastData(broadcast_string);
broadcastToAgents(&agentSocket, broadcast_string, broadcast_bytes, sendToSelf);
// broadcastToAgents(&agentSocket, broadcast_string, broadcast_bytes, sendToSelf);
}
int render_test_spot = WIDTH/2;
@ -567,8 +563,8 @@ void display(void)
if (display_field) field.render();
// Render heads of other agents
render_agents(sendToSelf, &location[0]);
// render_agents(sendToSelf, &location[0]);
if (display_hand) myHand.render();
if (!display_head) balls.render();
@ -780,12 +776,12 @@ void *networkReceive(void *args)
//
//printf("Replying to ping!\n");
char reply[] = "R";
agentSocket.send(inet_ntoa(senderAddress.sin_addr), ntohs(senderAddress.sin_port), reply, 1);
// agentSocket.send(inet_ntoa(senderAddress.sin_addr), ntohs(senderAddress.sin_port), reply, 1);
} else if (incomingPacket[0] == 'R') {
//
// Got Reply, record as appropriate
//
setAgentPing(inet_ntoa(senderAddress.sin_addr), ntohs(senderAddress.sin_port));
// setAgentPing(inet_ntoa(senderAddress.sin_addr), ntohs(senderAddress.sin_port));
} else if (incomingPacket[0] == 'M') {
//
@ -799,19 +795,20 @@ void *networkReceive(void *args)
// Message from domainserver
//
//printf("agent list received!\n");
nearbyAgents = update_agents(&incomingPacket[1], bytesReceived - 1);
kludgyMixerUpdate(audio);
nearbyAgents = agentList.updateList(&incomingPacket[1]);
std::cout << "Received " << nearbyAgents << " from DS!\n";
// kludgyMixerUpdate(audio);
} else if (incomingPacket[0] == 'H') {
//
// Broadcast packet from another agent
//
//printf("broadcast received");
update_agent(inet_ntoa(senderAddress.sin_addr), ntohs(senderAddress.sin_port), &incomingPacket[1], bytesReceived - 1);
// update_agent(inet_ntoa(senderAddress.sin_addr), ntohs(senderAddress.sin_port), &incomingPacket[1], bytesReceived - 1);
} else if (incomingPacket[0] == 'T') {
// Received a self-test packet (to get one's own IP), copy it to local variable!
printf("My Address: %s:%u\n",
inet_ntoa(senderAddress.sin_addr),
senderAddress.sin_port);
// printf("My Address: %s:%u\n",
// inet_ntoa(senderAddress.sin_addr),
// senderAddress.sin_port);
}
}
}
@ -939,7 +936,7 @@ int main(int argc, char** argv)
if (ifa ->ifa_addr->sa_family==AF_INET) { // check it is IP4
// is a valid IP4 Address
tmpAddrPtr=&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
inet_ntop(AF_INET, tmpAddrPtr, localAddressBuffer, INET_ADDRSTRLEN);
// inet_ntop(AF_INET, tmpAddrPtr, localAddressBuffer, INET_ADDRSTRLEN);
}
}

77
shared/src/Agent.cpp Normal file
View file

@ -0,0 +1,77 @@
//
// Agent.cpp
// hifi
//
// Created by Stephen Birarda on 2/15/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#include "Agent.h"
Agent::Agent() {
}
Agent::Agent(AgentSocket *agentPublicSocket, AgentSocket *agentLocalSocket, char agentType) {
publicSocket = new AgentSocket(*agentPublicSocket);
localSocket = new AgentSocket(*agentLocalSocket);
activeSocket = NULL;
type = agentType;
linkedData = 0;
}
Agent::Agent(const Agent &otherAgent) {
publicSocket = new AgentSocket(*otherAgent.publicSocket);
localSocket = new AgentSocket(*otherAgent.localSocket);
if (otherAgent.activeSocket == otherAgent.publicSocket) {
activeSocket = publicSocket;
} else if (otherAgent.activeSocket == otherAgent.localSocket) {
activeSocket = localSocket;
} else {
activeSocket = NULL;
}
type = otherAgent.type;
// copy over linkedData
}
Agent& Agent::operator=(const Agent &otherAgent) {
if (this != &otherAgent) {
// deallocate old memory
delete publicSocket;
delete localSocket;
delete linkedData;
publicSocket = new AgentSocket(*otherAgent.publicSocket);
localSocket = new AgentSocket(*otherAgent.localSocket);
if (otherAgent.activeSocket == otherAgent.publicSocket) {
activeSocket = publicSocket;
} else if (otherAgent.activeSocket == otherAgent.localSocket) {
activeSocket = localSocket;
} else {
activeSocket = NULL;
}
type = otherAgent.type;
}
return *this;
}
Agent::~Agent() {
delete publicSocket;
delete localSocket;
delete linkedData;
}
bool Agent::matches(AgentSocket *otherPublicSocket, AgentSocket *otherLocalSocket, char otherAgentType) {
return publicSocket->port == otherPublicSocket->port
&& localSocket->port == otherLocalSocket->port
&& type == otherAgentType
&& strcmp(publicSocket->address, otherPublicSocket->address) == 0
&& strcmp(localSocket->address, otherLocalSocket->address) == 0;
}

33
shared/src/Agent.h Normal file
View file

@ -0,0 +1,33 @@
//
// Agent.h
// hifi
//
// Created by Stephen Birarda on 2/15/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#ifndef __hifi__Agent__
#define __hifi__Agent__
#include <iostream>
#include "AgentSocket.h"
#include "AgentData.h"
class Agent {
public:
Agent();
Agent(AgentSocket *agentPublicSocket, AgentSocket *agentLocalSocket, char agentType);
Agent(const Agent &otherAgent);
Agent& operator=(const Agent &otherAgent);
~Agent();
bool matches(AgentSocket *otherPublicSocket, AgentSocket *otherLocalSocket, char otherAgentType);
AgentSocket *publicSocket, *localSocket, *activeSocket;
char type;
timeval pingStarted;
int pingMsecs;
bool isSelf;
AgentData *linkedData;
};
#endif /* defined(__hifi__Agent__) */

17
shared/src/AgentData.h Normal file
View file

@ -0,0 +1,17 @@
//
// AgentData.h
// hifi
//
// Created by Stephen Birarda on 2/19/13.
//
//
#ifndef hifi_AgentData_h
#define hifi_AgentData_h
class AgentData {
public:
virtual ~AgentData();
};
#endif

49
shared/src/AgentList.cpp Normal file
View file

@ -0,0 +1,49 @@
//
// AgentList.cpp
// hifi
//
// Created by Stephen Birarda on 2/15/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#include "AgentList.h"
int AgentList::updateList(char *packetData) {
int readAgents = 0;
int scannedItems = 0;
char agentType;
AgentSocket agentPublicSocket = AgentSocket();
AgentSocket agentLocalSocket = AgentSocket();
Agent newAgent;
while((scannedItems = sscanf(packetData,
"%c %s %hd %s %hd,",
&agentType,
agentPublicSocket.address,
&agentPublicSocket.port,
agentLocalSocket.address,
&agentLocalSocket.port
))) {
std::vector<Agent>::iterator it;
for(it = agents.begin(); it != agents.end(); ++it) {
if (it->matches(&agentPublicSocket, &agentLocalSocket, agentType)) {
// we already have this agent, stop checking
break;
}
}
if (it == agents.end()) {
// we didn't have this agent, so add them
newAgent = Agent(&agentPublicSocket, &agentLocalSocket, agentType);
agents.push_back(newAgent);
} else {
// we had this agent already, don't do anything
}
readAgents++;
}
return readAgents;
}

32
shared/src/AgentList.h Normal file
View file

@ -0,0 +1,32 @@
//
// AgentList.h
// hifi
//
// Created by Stephen Birarda on 2/15/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#ifndef __hifi__AgentList__
#define __hifi__AgentList__
#include <iostream>
#include <vector>
#include "Agent.h"
const unsigned short AGENT_SOCKET_LISTEN_PORT = 40103;
class AgentList {
public:
std::vector<Agent> agents;
int updateList(char *packetData);
int processAgentData(char *address, unsigned short port, char *packetData, size_t dataBytes);
int broadcastToAgents(char *broadcastData, size_t dataBytes, bool sendToSelf);
void pingAgents();
private:
int addAgent(AgentSocket *publicSocket, AgentSocket *localSocket, char agentType);
int indexOfMatchingAgent(AgentSocket *publicSocket, AgentSocket *privateSocket, char agentType);
};
#endif /* defined(__hifi__AgentList__) */

View file

@ -0,0 +1,37 @@
//
// AgentSocket.cpp
// hifi
//
// Created by Stephen Birarda on 2/19/13.
//
//
#include "AgentSocket.h"
#define MAX_ADDRESS_SIZE 255
AgentSocket::AgentSocket() {
address = new char[MAX_ADDRESS_SIZE];
}
AgentSocket::AgentSocket(const AgentSocket &otherAgentSocket) {
address = new char[MAX_ADDRESS_SIZE];
strcpy(address, otherAgentSocket.address);
port = otherAgentSocket.port;
}
AgentSocket& AgentSocket::operator=(const AgentSocket &otherAgentSocket) {
if (this != &otherAgentSocket) {
delete address;
address = new char[MAX_ADDRESS_SIZE];
strcpy(address, otherAgentSocket.address);
port = otherAgentSocket.port;
}
return *this;
}
AgentSocket::~AgentSocket() {
delete address;
}

24
shared/src/AgentSocket.h Normal file
View file

@ -0,0 +1,24 @@
//
// AgentSocket.h
// hifi
//
// Created by Stephen Birarda on 2/19/13.
//
//
#ifndef __hifi__AgentSocket__
#define __hifi__AgentSocket__
#include <iostream>
class AgentSocket {
public:
AgentSocket();
AgentSocket(const AgentSocket &otherAgentSocket);
AgentSocket& operator=(const AgentSocket &otherAgentSocket);
~AgentSocket();
char *address;
unsigned short port;
};
#endif /* defined(__hifi__AgentSocket__) */