cyphesis/client/ClientConnection.cpp
Al Riddoch d8ffe97f6d * server/CommServer.cpp: Remove non-fatal "FATAL..." message when
client closes connection.

	* rulesets/Thing.cpp: If object to be created has no loc, set loc
	  to be the same as creator before passing to the factory.

	* rulesets/Entity.cpp: Clarify debug output when determining location
	  of new entities.

	* client/CommClient.cpp: Push output into debug mecanism. Switch
	  order of Create/Login for admin account so ordinary operation
	  does not issue an error. Admin account is created at startup,
	  so there is no need for the client to create it.

Al Riddoch  <alriddoch@zepler.org>
2001-10-03 10:51:43 +00:00

407 lines
9.1 KiB
C++

// This file may be redistributed and modified only under the terms of
// the GNU Lesser General Public License (See COPYING for details).
// Copyright (C) 2001 Alistair Riddoch
#include <Atlas/Codec.h>
#include <Atlas/Codecs/XML.h>
#include <Atlas/Message/Object.h>
#include <Atlas/Net/Stream.h>
#include <Atlas/Objects/Decoder.h>
#include <Atlas/Objects/Encoder.h>
#include <varconf/Config.h>
#include <skstream.h>
#include <fstream>
extern "C" {
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <unistd.h>
#include <netdb.h>
}
#include "ClientConnection.h"
#include "common/debug.h"
#include "config.h"
static bool debug_flag = false;
using Atlas::Message::Object;
ClientConnection::ClientConnection() :
client_fd(-1), encoder(NULL), serialNo(512)
{
}
ClientConnection::~ClientConnection()
{
if (encoder != NULL) {
delete encoder;
}
}
void ClientConnection::operation(const RootOperation & op)
{
#if 0
const std::string & from = op.GetFrom();
if (from.empty()) {
cerr << "ERROR: Operation with no destination" << endl << flush;
return;
}
dict_t::iterator I = objects.find(from);
if (I == objects.end()) {
cerr << "ERROR: Operation with invalid destination" << endl << flush;
return;
}
oplist res = I->second->message(op);
oplist::iterator J = res.begin();
for(J = res.begin(); J != res.end(); ++J) {
(*J)->SetFrom(I->first);
send(*(*J));
}
#endif
}
void ClientConnection::ObjectArrived(const Error&op)
{
debug(cout << "ERROR" << endl << flush;);
push(op);
error_flag = true;
}
void ClientConnection::ObjectArrived(const Info & op)
{
debug(cout << "INFO" << endl << flush;);
const std::string & from = op.GetFrom();
if (from.empty()) {
reply_flag = true;
error_flag = false;
try {
Object ac = op.GetArgs().front();
reply = ac.AsMap();
// const std::string & acid = reply["id"].AsString();
// objects[acid] = new ClientAccount(acid, *this);
}
catch (...) {
cerr << "WARNING: Malformed account from server" << endl << flush;
}
} else {
operation(op);
}
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Action& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Appearance& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Combine& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Communicate& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Create& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Delete& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Disappearance& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Divide& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Feel& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Get& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Imaginary& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Listen& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Login& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Logout& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Look& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Move& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Perceive& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Perception& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::RootOperation& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Set& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Sight& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Smell& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Sniff& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Sound& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Talk& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Touch& op)
{
push(op);
}
int ClientConnection::read() {
if (ios.is_open()) {
codec->Poll();
return 0;
} else {
return -1;
}
}
bool ClientConnection::connect(const std::string & server)
{
struct sockaddr_in serv_sa;
debug(cout << "Connecting to " << server << endl << flush;);
memset(&serv_sa, 0, sizeof(serv_sa));
serv_sa.sin_family = AF_INET;
serv_sa.sin_port = htons(6767);
struct hostent * serv_addr = gethostbyname(server.c_str());
if (serv_addr == NULL) {
cerr << "ERROR: Lookup failed for " << server << endl;
return false;
}
memcpy(&serv_sa.sin_addr, serv_addr->h_addr_list[0], serv_addr->h_length);
client_fd = socket(AF_INET, SOCK_STREAM, 0);
if (client_fd < 0) {
cerr << "ERROR: Could not create server connection" <<endl<<flush;
perror("socket");
return false;
}
int ret;
ret = ::connect(client_fd, (struct sockaddr *)&serv_sa, sizeof(serv_sa));
if (ret < 0) {
cerr << "ERROR: Could not connect to " << server<<"." << endl << flush;
perror("connect");
return false;
}
ios.attach(client_fd);
Atlas::Net::StreamConnect conn("cyphesis_aiclient", ios, this);
debug(cout << "Negotiating... " << flush;);
while (conn.GetState() == Atlas::Net::StreamConnect::IN_PROGRESS) {
conn.Poll();
}
debug(cout << "done" << endl;);
if (conn.GetState() == Atlas::Net::StreamConnect::FAILED) {
cerr << "Failed to negotiate" << endl;
return false;
}
codec = conn.GetCodec();
encoder = new Atlas::Objects::Encoder(codec);
codec->StreamBegin();
return true;
}
bool ClientConnection::login(const std::string & account,
const std::string & password)
{
Atlas::Objects::Operation::Login l = Atlas::Objects::Operation::Login::Instantiate();
Object::MapType acmap;
acmap["id"] = account;
acmap["password"] = password;
l.SetArgs(Object::ListType(1,Object(acmap)));
reply_flag = false;
error_flag = false;
send(l);
return true;
}
bool ClientConnection::create(const std::string & account,
const std::string & password)
{
Atlas::Objects::Operation::Create c = Atlas::Objects::Operation::Create::Instantiate();
Object::MapType acmap;
acmap["id"] = account;
acmap["password"] = password;
c.SetArgs(Object::ListType(1,Object(acmap)));
reply_flag = false;
error_flag = false;
send(c);
return true;
}
bool ClientConnection::wait()
// Waits for response from server. Used when we are expecting a login response
// Return whether or not an error occured
{
error_flag = false;
reply_flag = false;
while (!reply_flag) {
codec->Poll();
}
return error_flag;
}
void ClientConnection::send(Atlas::Objects::Operation::RootOperation & op)
{
debug(std::fstream f(1);
Atlas::Codecs::XML c(f, (Atlas::Bridge*)this);
Atlas::Objects::Encoder enc(&c);
enc.StreamMessage(&op);
std::cout << std::endl << flush;);
op.SetSerialno(++serialNo);
encoder->StreamMessage(&op);
ios << flush;
}
void ClientConnection::error(const std::string & message) {
// FIXME Need operation based error function
}
void ClientConnection::poll()
{
fd_set infds;
struct timeval tv;
FD_ZERO(&infds);
FD_SET(client_fd, &infds);
tv.tv_sec = 0;
tv.tv_usec = 0;
int retval = select(client_fd+1, &infds, NULL, NULL, &tv);
if (retval && (FD_ISSET(client_fd, &infds))) {
if (ios.peek() == -1) {
std::cerr << "Server disconnected" << std::endl << std::flush;
return;
}
codec->Poll();
return;
}
return;
}
RootOperation * ClientConnection::pop()
{
poll();
if (operationQueue.empty()) {
return NULL;
}
RootOperation * op = operationQueue.front();
operationQueue.pop_front();
return op;
}
bool ClientConnection::pending()
{
return !operationQueue.empty();
}
template<class O>
void ClientConnection::push(const O & op)
{
reply_flag = true;
RootOperation * new_op = new O(op);
operationQueue.push_back(new_op);
}