Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | Related Pages

ArNetServer.cpp

00001 /*
00002 ActivMedia Robotics Interface for Applications (ARIA)
00003 Copyright (C) 2004,2005 ActivMedia Robotics, LLC
00004 
00005 
00006      This program is free software; you can redistribute it and/or modify
00007      it under the terms of the GNU General Public License as published by
00008      the Free Software Foundation; either version 2 of the License, or
00009      (at your option) any later version.
00010 
00011      This program is distributed in the hope that it will be useful,
00012      but WITHOUT ANY WARRANTY; without even the implied warranty of
00013      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014      GNU General Public License for more details.
00015 
00016      You should have received a copy of the GNU General Public License
00017      along with this program; if not, write to the Free Software
00018      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 
00020 If you wish to redistribute ARIA under different terms, contact 
00021 ActivMedia Robotics for information about a commercial version of ARIA at 
00022 robots@activmedia.com or 
00023 ActivMedia Robotics, 19 Columbia Drive, Amherst, NH 03031; 800-639-9481
00024 
00025 */
00026 
00027 #include <ctype.h>
00028 #include "ArExport.h"
00029 #include "ariaOSDef.h"
00030 #include "ArNetServer.h"
00031 #include "ArRobot.h"
00032 #include "ArLog.h"
00033 #include "ariaUtil.h"
00034 #include "ArSyncTask.h"
00035 #include "ArArgumentBuilder.h"
00036 #include "ariaInternal.h"
00037 
00038 ArNetServer::ArNetServer(bool addAriaExitCB) :
00039   myTaskCB(this, &ArNetServer::runOnce),
00040   myHelpCB(this, &ArNetServer::internalHelp),
00041   myEchoCB(this, &ArNetServer::internalEcho),
00042   myQuitCB(this, &ArNetServer::internalQuit),
00043   myShutdownServerCB(this, &ArNetServer::internalShutdownServer),
00044   myAriaExitCB(this, &ArNetServer::close)
00045 {
00046   myRobot = NULL;
00047   myPort = 0;
00048   myMultipleClients = false;
00049   myOpened = false;
00050   myWantToClose = false;
00051   myLoggingDataSent = false;
00052   myLoggingDataReceived = false;
00053   mySquelchNormal = false;
00054   addCommand("help", &myHelpCB, "gives the listing of available commands");
00055   addCommand("echo", &myEchoCB, "with no args gets echo, with args sets echo");
00056   addCommand("quit", &myQuitCB, "closes this connection to the server");
00057   addCommand("shutdownServer", &myShutdownServerCB, "shuts down the server");
00058 
00059   myAriaExitCB.setName("ArNetServerExit");
00060   if (addAriaExitCB)
00061     Aria::addExitCallback(&myAriaExitCB, 40);
00062 }
00063 
00064 ArNetServer::~ArNetServer()
00065 {
00066   ArSyncTask *rootTask = NULL;
00067   ArSyncTask *proc = NULL;
00068   // get rid of us running on the robot task
00069   if (myRobot != NULL && (rootTask = myRobot->getSyncTaskRoot()) != NULL)
00070   {
00071     proc = rootTask->findNonRecursive(&myTaskCB);
00072     if (proc != NULL)
00073       delete proc;
00074   }
00075   close();
00076 }
00077 
00096 bool ArNetServer::open(ArRobot *robot, unsigned int port, 
00097                                 const char *password, bool multipleClients)
00098 {
00099   ArSyncTask *rootTask = NULL;
00100   ArSyncTask *proc = NULL;
00101   std::string taskName;
00102 
00103   if (myOpened)
00104   {
00105     ArLog::log(ArLog::Terse, "ArNetServer already inited, cannot reinit");
00106     return false;
00107   }
00108 
00109   myRobot = robot;
00110   myPort = port;
00111   myPassword = password;
00112   myMultipleClients = multipleClients;
00113   
00114   if (myServerSocket.open(myPort, ArSocket::TCP))
00115   {
00116     myServerSocket.setLinger(0);
00117     myServerSocket.setNonBlock();
00118     ArLog::log(ArLog::Normal, "ArNetServer opened on port %d.", myPort);
00119     myOpened = true;
00120   }
00121   else
00122   {
00123     ArLog::log(ArLog::Terse, "ArNetServer failed to open: %s", 
00124                myServerSocket.getErrorStr().c_str());
00125     myOpened = false;
00126     return false;
00127   }
00128 
00129   // add ourselves to the robot if we aren't already there
00130   if (myRobot != NULL && (rootTask = myRobot->getSyncTaskRoot()) != NULL)
00131   {    
00132     proc = rootTask->findNonRecursive(&myTaskCB);
00133     if (proc == NULL)
00134     {
00135       // toss in a netserver
00136       taskName = "Net Servers ";
00137       taskName += myPort;
00138       rootTask->addNewLeaf(taskName.c_str(), 60, &myTaskCB, NULL);
00139     }
00140   }
00141   return true;
00142   
00143 }
00144 
00150 bool ArNetServer::addCommand(const char *command, 
00151                               ArFunctor3<char **, int, ArSocket *> *functor,
00152                                       const char *help)
00153 {
00154   std::map<std::string, ArFunctor3<char **, int, ArSocket *> *, ArStrCaseCmpOp>::iterator it;
00155 
00156   if ((it = myFunctorMap.find(command)) != myFunctorMap.end())
00157   {
00158     ArLog::log(ArLog::Normal, "ArNetServer::addCommand: Already a command for %s", command);
00159     return false;
00160   }
00161 
00162   myFunctorMap[command] = functor;
00163   myHelpMap[command] = help;
00164   return true;
00165 }
00166 
00171 bool ArNetServer::remCommand(const char *command)
00172 {
00173   if (myFunctorMap.find(command) == myFunctorMap.end())
00174   {
00175     return false;
00176   }
00177   myFunctorMap.erase(command);
00178   myHelpMap.erase(command);
00179   return true;  
00180 }
00181 
00182 
00183 void ArNetServer::sendToAllClientsPlain(const char *str)
00184 {
00185   std::list<ArSocket *>::iterator it;
00186 
00187   if (myLoggingDataSent)
00188     ArLog::log(ArLog::Terse, "ArNetServer::sendToAllClients: Sending %s", str);
00189   for (it = myConns.begin(); it != myConns.end(); ++it)
00190   {
00191     (*it)->setLogWriteStrings(false);
00192     (*it)->writeString(str);
00193     (*it)->setLogWriteStrings(myLoggingDataSent);
00194   }
00195 }
00196 
00201 void ArNetServer::sendToAllClients(const char *str, ...)
00202 {
00203   char buf[2049];
00204   va_list ptr;
00205   va_start(ptr, str);
00206   vsprintf(buf, str, ptr);
00207 
00208   sendToAllClientsPlain(buf);
00209   
00210   va_end(ptr);
00211 }
00212 
00213 bool ArNetServer::isOpen(void)
00214 {
00215   return myOpened;
00216 }
00217 
00218 
00223 void ArNetServer::setLoggingDataSent(bool loggingData)
00224 {
00225   myLoggingDataSent = loggingData;
00226   std::list<ArSocket *>::iterator it;
00227   for (it = myConnectingConns.begin(); it != myConnectingConns.end(); ++it)
00228     (*it)->setLogWriteStrings(loggingData);
00229   for (it = myConns.begin(); it != myConns.end(); ++it)
00230     (*it)->setLogWriteStrings(loggingData);
00231 }
00232 
00237 bool ArNetServer::getLoggingDataSent(void)
00238 {
00239   return myLoggingDataSent;
00240 }
00241 
00246 void ArNetServer::setLoggingDataReceived(bool loggingData)
00247 {
00248   myLoggingDataReceived = loggingData;
00249 }
00250 
00255 bool ArNetServer::getLoggingDataReceived(void)
00256 {
00257   return myLoggingDataReceived;
00258 }
00259 
00260 
00261 void ArNetServer::runOnce(void)
00262 {
00263 
00264   ArSocket acceptingSocket;
00265   ArSocket *socket;
00266   char *str;
00267   std::list<ArSocket *> removeList;
00268   std::list<ArSocket *>::iterator it;
00269   ArArgumentBuilder *args = NULL;
00270   std::string command;
00271 
00272   if (!myOpened)
00273   {
00274     return;
00275   }
00276 
00277   lock();
00278   // get any new sockets that want to connect
00279   while (myServerSocket.accept(&acceptingSocket) && acceptingSocket.getFD() >= 0)
00280   {
00281     acceptingSocket.setNonBlock();
00282     // see if we want more sockets
00283     if (!myMultipleClients && (myConns.size() > 0 ||
00284                                myConnectingConns.size() > 0))
00285     {
00286       // we didn't want it, so politely tell it to go away
00287       acceptingSocket.writeString("Conn refused.");
00288       acceptingSocket.writeString(
00289               "Only client allowed and it is already connected.");
00290       acceptingSocket.close();
00291       ArLog::log(ArLog::Terse, "ArNetServer not taking multiple clients and another client tried to connect from %s.", acceptingSocket.getIPString());
00292     }
00293     else 
00294     {
00295       // we want the client so we put it in our list of connecting
00296       // sockets, which means that it is waiting to give its password
00297       socket = new ArSocket;
00298       socket->setLogWriteStrings(myLoggingDataSent);
00299       socket->transfer(&acceptingSocket);
00300       socket->writeString("Enter password:");
00301       myConnectingConns.push_front(socket);
00302       ArLog::log(ArLog::Normal, 
00303                  "Client connecting from %s.",
00304                  socket->getIPString());
00305     }
00306   }
00307 
00308   // now we read in data from our connecting sockets and see if
00309   // they've given us the password
00310   for (it = myConnectingConns.begin(); it != myConnectingConns.end(); ++it)
00311   {
00312     socket = (*it);
00313     // read in what the client has to say
00314     if ((str = socket->readString()) != NULL)
00315     {
00316       if (str[0] == '\0')
00317         continue;
00318       // now see if the word matchs the password
00319       if (myPassword == str)
00320       {
00321         ArLog::log(ArLog::Normal, 
00322                    "Client from %s gave password and connected.",
00323                    socket->getIPString());
00324         myConns.push_front(socket);
00325         removeList.push_front(socket);
00326         internalGreeting(socket);
00327       }
00328       else
00329       {
00330         socket->close();
00331         myDeleteList.push_front(socket);
00332         ArLog::log(ArLog::Terse, 
00333                    "Client from %s gave wrong password and is being disconnected.", 
00334                    socket->getIPString());
00335       }
00336     }
00337     // if we couldn't read a string it means we lost a connection
00338     else
00339     {
00340       ArLog::log(ArLog::Normal, 
00341                  "Connection to %s lost.", socket->getIPString());
00342       socket->close();
00343       myDeleteList.push_front(socket);
00344     }
00345   }
00346   // now we clear out the ones we want to remove from our connecting
00347   // clients list
00348   while ((it = removeList.begin()) != removeList.end())
00349   {
00350     socket = (*it);
00351     myConnectingConns.remove(socket);
00352     removeList.pop_front();
00353   }
00354 
00355 
00356   // now we read in data from our connecting sockets and see if
00357   // they've given us the password
00358   for (it = myConns.begin(); it != myConns.end() && myOpened; ++it)
00359   {
00360     socket = (*it);
00361     // read in what the client has to say
00362     while ((str = socket->readString()) != NULL)
00363     {
00364       // if this is null then there wasn't anything said
00365       if (str[0] == '\0')
00366         break;
00367       // make sure we read something
00368       // set up the arguments and then call the function for the
00369       // argument
00370       args = new ArArgumentBuilder;
00371       args->addPlain(str);
00372       //args->log();
00373       parseCommandOnSocket(args, socket);
00374       delete args;
00375       args = NULL;
00376     }
00377     // if str was NULL we lost connection
00378     if (str == NULL)
00379     {
00380       ArLog::log(ArLog::Normal, 
00381                  "Connection to %s lost.", socket->getIPString());
00382       socket->close();
00383       myDeleteList.push_front(socket);
00384     }
00385   }
00386 
00387   // now we delete the ones we want to delete (we could do this above
00388   // but then it wouldn't be symetrical with above)
00389   while ((it = myDeleteList.begin()) != myDeleteList.end())
00390   {
00391     socket = (*it);
00392     myConnectingConns.remove(socket);
00393     myConns.remove(socket);
00394     socket->close();
00395     delete socket;
00396     myDeleteList.pop_front();
00397   }
00398 
00399   if (myWantToClose)
00400   {
00401     close();
00402   }
00403   unlock();
00404 }
00405 
00406 void ArNetServer::close(void)
00407 {
00408   std::list<ArSocket *>::iterator it;
00409   ArSocket *socket;
00410   
00411   if (!myOpened)
00412     return;
00413   myWantToClose = false;
00414   ArLog::log(ArLog::Normal, "ArNetServer shutting down server.");
00415   sendToAllClients("Shutting down server");
00416   for (it = myConnectingConns.begin(); it != myConnectingConns.end(); ++it)
00417   {
00418     (*it)->writeString("Shutting down server");
00419   }
00420   myOpened = false;
00421 
00422   while ((it = myConnectingConns.begin())!= myConnectingConns.end())
00423   {
00424     socket = (*it);
00425     myConnectingConns.pop_front();
00426     socket->close();
00427     delete socket;
00428   }
00429   while ((it = myConns.begin()) != myConns.end())
00430   {
00431     socket = (*it);
00432     myConns.pop_front();
00433     socket->close();
00434     delete socket;
00435   }
00436   myServerSocket.close();
00437 }
00438 
00439 void ArNetServer::internalGreeting(ArSocket *socket)
00440 {
00441   if (mySquelchNormal)
00442     return;
00443   socket->writeString("Welcome to the server.");
00444   socket->writeString("You can type 'help' at any time for the following help list.");
00445   internalHelp(socket);
00446 }
00447 
00448 void ArNetServer::internalHelp(ArSocket *socket)
00449 {
00450  std::map<std::string, std::string, ArStrCaseCmpOp>::iterator it;
00451   
00452  socket->writeString("Commands:");
00453  for (it = myHelpMap.begin(); it != myHelpMap.end(); ++it)
00454    socket->writeString("%15s%10s%s", it->first.c_str(), "", 
00455                        it->second.c_str());
00456 }
00457 
00458 void ArNetServer::internalHelp(char **argv, int argc, 
00459                                         ArSocket *socket)
00460 {
00461   internalHelp(socket);
00462 }
00463 
00464 
00465 void ArNetServer::internalEcho(char **argv, int argc, 
00466                                             ArSocket *socket)
00467 {
00468   // if they just typed it we tell them if its on or off
00469   if (argc == 1)
00470   {
00471     if (socket->getEcho())
00472       socket->writeString("Echo is on.");
00473     else
00474       socket->writeString("Echo is off.");
00475   }
00476   // if the have two words see if they have the right args
00477   else if (argc == 2 && strcasecmp(argv[1], "on") == 0)
00478   {
00479     socket->writeString("Echo turned on.");
00480     socket->setEcho(true);
00481   }
00482   else if (argc == 2 && strcasecmp(argv[1], "off") == 0)
00483   {
00484     socket->writeString("Echo turned off.");
00485     socket->setEcho(false);
00486   }
00487   else
00488   {
00489     socket->writeString("usage: echo <on/off>");
00490   }
00491 }
00492 
00493 void ArNetServer::internalQuit(char **argv, int argc, 
00494                                          ArSocket *socket)
00495 {
00496   socket->writeString("Closing connection");
00497 
00498   myDeleteList.push_front(socket);
00499   ArLog::log(ArLog::Normal, "Client from %s quit.", socket->getIPString());
00500 }
00501 
00502 void ArNetServer::internalShutdownServer(char **argv, int argc, 
00503                                                   ArSocket *socket)
00504 {
00505   sendToAllClients("Shutting down server");
00506   myWantToClose = true;
00507   if (myRobot != NULL)
00508     myRobot->stopRunning();
00509   
00510 }
00511 
00512 void ArNetServer::parseCommandOnSocket(ArArgumentBuilder *args, 
00513                                                 ArSocket *socket, bool allowLog)
00514 {
00515 
00516   std::map<std::string, ArFunctor3<char **, int, ArSocket *> *, ArStrCaseCmpOp>::iterator fIt;
00517   char **argv;
00518   int argc;
00519 
00520   if (myLoggingDataReceived && !mySquelchNormal && allowLog)
00521     ArLog::log(ArLog::Normal, "Command received from %s: %s",
00522                socket->getIPString(), args->getFullString());
00523   else if (myLoggingDataReceived && mySquelchNormal && allowLog)
00524     ArLog::log(ArLog::Normal, "%s: %s",
00525                socket->getIPString(), args->getFullString());
00526   argv = args->getArgv();
00527   argc = args->getArgc();
00528   // if we have some command see if it has a functor
00529   if (argc >= 1 && 
00530       (fIt = myFunctorMap.find(argv[0])) != myFunctorMap.end())
00531   {
00532     fIt->second->invoke(argv, argc, socket);
00533   }
00534   // it didn't have a functor so we don't know it as a command
00535   else if (argc >= 1)
00536   {
00537     if (!mySquelchNormal)
00538       socket->writeString("Unknown command %s", argv[0]);
00539   }
00540 }
00541 
00542 void ArNetServer::internalAddSocketToList(ArSocket *socket)
00543 {
00544   myConns.push_front(socket);
00545 }
00546 
00547 
00548 void ArNetServer::internalAddSocketToDeleteList(ArSocket *socket)
00549 {
00550   myDeleteList.push_front(socket);
00551 }
00552 
00553 void ArNetServer::squelchNormal(void)
00554 {
00555   mySquelchNormal = true;
00556   remCommand("help");
00557   remCommand("echo");
00558   remCommand("quit");
00559   remCommand("shutdownServer");
00560 
00561 }
00562 
00563 
00564 

Generated on Wed Oct 19 12:56:36 2005 for Aria by  doxygen 1.4.0