cyphesis/server/server.cpp
Al Riddoch 4e1527c238 * all files: Re-worked the way debugging is handled to that it no
longer gives warnings.

Al
2001-01-25  Al Riddoch  <ajr@ecs.soton.ac.uk>
2001-02-04 07:08:07 +00:00

360 lines
9.5 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) 2000 Alistair Riddoch
#include <Atlas/Message/Object.h>
#include <Atlas/Net/Stream.h>
#include <Atlas/Objects/Root.h>
#include <Atlas/Objects/Encoder.h>
#include <Atlas/Objects/Decoder.h>
#include <varconf/Config.h>
#include <iostream.h>
#include <fstream.h>
#include <Python.h>
extern "C" {
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
}
#include <common/config.h>
#include <common/const.h>
#include <common/log.h>
#include <common/debug.h>
#include <fstream>
#include "ServerRouting.h"
#include "Connection.h"
#include "server.h"
#include "CommClient.h"
#include "CommServer.h"
int profile_flag=0;
static const bool debug_flag = false;
string install_directory = string(INSTALLDIR);
using namespace Atlas;
void init_python_api();
CommClient::~CommClient() {
if (connection != NULL) {
connection->destroy();
delete connection;
}
}
int CommClient::setup()
{
Atlas::Net::StreamAccept accept("cyphesis", client_ios, this);
debug(cout << "Negotiating... " << flush;);
while (accept.GetState() == Negotiate<iostream>::IN_PROGRESS) {
accept.Poll();
}
debug(cout << "done" << endl;);
if (accept.GetState() == Negotiate<iostream>::FAILED) {
cerr << "Failed to negotiate" << endl;
return(0);
}
// Negotiation was successful
// Get the codec that negotiation established
codec = accept.GetCodec();
// This should always be sent at the beginning of a session
encoder = new Objects::Encoder(codec);
codec->StreamBegin();
connection=new Connection(this);
return(1);
}
void CommClient::message(const Objects::Operation::RootOperation & op)
{
oplist reply = connection->message(op);
while (reply.size() != 0) {
Objects::Operation::RootOperation * rep_op = reply.front();
debug(cout << "sending reply" << endl << flush;);
send(rep_op);
delete rep_op;
reply.pop_front();
}
}
void CommClient::UnknownObjectArrived(const Atlas::Message::Object& o)
{
#if 0
debug(cout << "An unknown has arrived." << endl << flush;);
if (o.IsMap()) {
for(Message::Object::MapType::const_iterator I = o.AsMap().begin();
I != o.AsMap().end();
I++) {
debug(cout << I->first << endl << flush;);
if (I->second.IsString()) {
debug(cout << I->second.AsString() << endl << flush;);
}
}
} else {
debug(cout << "Its not a map." << endl << flush;);
}
#endif
}
void CommClient::ObjectArrived(const Objects::Operation::Login & op)
{
debug(cout << "A login operation thingy here!" << endl << flush;);
message(op);
}
void CommClient::ObjectArrived(const Objects::Operation::Create & op)
{
debug(cout << "A create operation thingy here!" << endl << flush;);
message(op);
}
void CommClient::ObjectArrived(const Objects::Operation::Move & op)
{
debug(cout << "A move operation thingy here!" << endl << flush;);
message(op);
}
void CommClient::ObjectArrived(const Objects::Operation::Set & op)
{
debug(cout << "A set operation thingy here!" << endl << flush;);
message(op);
}
void CommClient::ObjectArrived(const Objects::Operation::Touch & op)
{
debug(cout << "A touch operation thingy here!" << endl << flush;);
message(op);
}
void CommClient::ObjectArrived(const Objects::Operation::Look & op)
{
debug(cout << "A look operation thingy here!" << endl << flush;);
message(op);
}
void CommClient::ObjectArrived(const Objects::Operation::Talk & op)
{
debug(cout << "A talk operation thingy here!" << endl << flush;);
message(op);
}
int CommServer::setup(int port)
{
struct sockaddr_in sin;
server_port = port;
server_fd = socket(PF_INET, SOCK_STREAM, 0);
if (server_fd < 0) {
return(-1);
}
int flag=1;
setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
sin.sin_addr.s_addr = 0L;
if (bind(server_fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
close(server_fd);
return(-1);
}
listen(server_fd, 5);
server=new ServerRouting(this,"server");
return(0);
}
int CommServer::accept() {
struct sockaddr_in sin;
unsigned int addr_len = sizeof(sin);
sin.sin_family = AF_INET;
sin.sin_port = htons(server_port);
sin.sin_addr.s_addr = 0L;
debug(cout << "Accepting.." << endl << flush;);
int asockfd = ::accept(server_fd, (struct sockaddr *)&sin, &addr_len);
if (asockfd < 0) {
return(-1);
}
debug(cout << "Accepted" << endl << flush;);
CommClient * newcli = new CommClient(this, asockfd, sin.sin_port);
if (newcli->setup()) {
clients.insert(std::pair<int, CommClient *>(asockfd, newcli));
}
return(0);
}
inline void CommServer::idle() {
server->idle();
}
void CommServer::loop() {
fd_set sock_fds;
int highest = server_fd;
int client_fd;
CommClient * client;
struct timeval tv;
tv.tv_sec=0;
tv.tv_usec=100000;
FD_ZERO(&sock_fds);
FD_SET(server_fd, &sock_fds);
client_map_t::const_iterator I;
for(I = clients.begin(); I != clients.end(); I++) {
client_fd = I->first;
FD_SET(client_fd, &sock_fds);
if (client_fd > highest) {
highest=client_fd;
}
}
highest++;
int rval = select(highest, &sock_fds, NULL, NULL, &tv);
if (rval < 0) {
return;
}
for(I = clients.begin(); I != clients.end(); I++) {
client_fd = I->first;
if (FD_ISSET(client_fd, &sock_fds)) {
client = I->second;
if (client->peek() != -1) {
client->read();
} else if (client->eof()) {
remove_client(client);
break;
} else {
cerr << "FATAL THIS SHOULD NEVER HAPPEN" << endl << flush;
remove_client(client);
break;
}
}
}
if (FD_ISSET(server_fd, &sock_fds)) {
debug(cout << "selected on server" << endl << flush;);
accept();
}
idle();
}
inline void CommServer::remove_client(CommClient * client, char * error_msg)
{
Message::Object::MapType err;
err["message"] = Message::Object(error_msg);
Message::Object::ListType eargs(1,Message::Object(err));
Error * e = new Error();
*e = Error::Instantiate();
e->SetArgs(eargs);
// Need to deal with cleanly sending the error op, without hanging
// if the client has already gone. FIXME
if (client) {
client->send(e);
clients.erase(client->get_fd());
}
delete e;
delete client;
}
void CommServer::remove_client(CommClient * client)
{
remove_client(client,"You caused exception. Connection closed");
}
varconf::Config * global_conf = varconf::Config::inst();
list<string> rulesets;
#include <rulesets/ThingFactory.h>
int main(int argc, char ** argv)
{
if (install_directory=="NONE") {
install_directory = "/usr/local";
}
// See if the user has set the install directory on the command line
char * home;
if ((home = getenv("HOME")) != NULL) {
global_conf->readFromFile(string(home) + "/.cyphesis.vconf");
}
global_conf->getCmdline(argc, argv);
if (global_conf->findItem("cyphesis", "directory")) {
install_directory = global_conf->getItem("cyphesis", "directory");
if (home != NULL) {
global_conf->writeToFile(string(home) + "/.cyphesis.vconf");
}
}
global_conf->readFromFile(install_directory + "/share/cyphesis/cyphesis.vconf");
if ((home = getenv("HOME")) != NULL) {
global_conf->readFromFile(string(home) + "/.cyphesis.vconf");
}
global_conf->getCmdline(argc, argv);
string ruleset;
while (global_conf->findItem("cyphesis", "ruleset")) {
ruleset = global_conf->getItem("cyphesis", "ruleset");
global_conf->erase("cyphesis", "ruleset");
cout << "Reading in " << ruleset << endl << flush;
thing_factory.readRuleset(install_directory + "/share/cyphesis/" + ruleset);
rulesets.push_back(ruleset);
};
init_python_api();
cout << Py_GetPath() << endl << flush;
if (consts::debug_level>=1) {
cout << "consts::debug_level>=1, logging to cyphesis_server*.log files" << endl << flush;
//ofstream log_stream("cyphesis_server.log",ios::out);
common::log::inform_fp.open("cyphesis_server.log",ios::out);
common::log::debug_fp.open("cyphesis_server_debug.log",ios::out);
}
if (consts::debug_thinking>=1) {
char * log_name="thinking.log";
cout << "consts::debug_thinking>=1:, logging to" << log_name << endl;
common::log::thinking_fp.open(log_name,ios::out);
}
CommServer s;
if (s.setup(6767)) {
cerr << "Could not create listen socket." << endl << flush;
exit(1);
}
if (consts::debug_level>=1) {
char * log_name="cyphesis_world.log";
cout << "consts::debug_level>=1:, logging to" << log_name << endl;
//s.server.world.queue_fp.open(log_name,ios::out);
}
int exit_flag=0;
while (!exit_flag) {
try {
s.loop();
}
catch (...) {
cerr << "*********** EMERGENCY ***********" << endl;
cerr << "EXCEPTION: Caught in main()" << endl;
cerr << " : Continuing..." << endl;
}
}
}