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

ArNetServer.cpp

00001 /*
00002 MobileRobots Advanced Robotics Interface for Applications (ARIA)
00003 Copyright (C) 2004, 2005 ActivMedia Robotics LLC
00004 Copyright (C) 2006, 2007 MobileRobots Inc.
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 MobileRobots for information about a commercial version of ARIA at 
00022 robots@mobilerobots.com or 
00023 MobileRobots Inc, 19 Columbia Drive, Amherst, NH 03031; 800-639-9481
00024 */
00025 
00026 #include <ctype.h>
00027 #include "ArExport.h"
00028 #include "ariaOSDef.h"
00029 #include "ArNetServer.h"
00030 #include "ArRobot.h"
00031 #include "ArLog.h"
00032 #include "ariaUtil.h"
00033 #include "ArSyncTask.h"
00034 #include "ArArgumentBuilder.h"
00035 #include "ariaInternal.h"
00036 
00037 ArNetServer::ArNetServer(bool addAriaExitCB) :
00038   myTaskCB(this, &ArNetServer::runOnce),
00039   myHelpCB(this, &ArNetServer::internalHelp),
00040   myEchoCB(this, &ArNetServer::internalEcho),
00041   myQuitCB(this, &ArNetServer::internalQuit),
00042   myShutdownServerCB(this, &ArNetServer::internalShutdownServer),
00043   myAriaExitCB(this, &ArNetServer::close)
00044 {
00045   myRobot = NULL;
00046   myPort = 0;
00047   myMultipleClients = false;
00048   myOpened = false;
00049   myWantToClose = false;
00050   myLoggingDataSent = false;
00051   myLoggingDataReceived = false;
00052   mySquelchNormal = false;
00053   addCommand("help", &myHelpCB, "gives the listing of available commands");
00054   addCommand("echo", &myEchoCB, "with no args gets echo, with args sets echo");
00055   addCommand("quit", &myQuitCB, "closes this connection to the server");
00056   addCommand("shutdownServer", &myShutdownServerCB, "shuts down the server");
00057 
00058   myAriaExitCB.setName("ArNetServerExit");
00059   if (addAriaExitCB)
00060     Aria::addExitCallback(&myAriaExitCB, 40);
00061 }
00062 
00063 ArNetServer::~ArNetServer()
00064 {
00065   ArSyncTask *rootTask = NULL;
00066   ArSyncTask *proc = NULL;
00067   // get rid of us running on the robot task
00068   if (myRobot != NULL && (rootTask = myRobot->getSyncTaskRoot()) != NULL)
00069   {
00070     proc = rootTask->findNonRecursive(&myTaskCB);
00071     if (proc != NULL)
00072       delete proc;
00073   }
00074   close();
00075 }
00076 
00095 AREXPORT bool ArNetServer::open(ArRobot *robot, unsigned int port, 
00096                 const char *password, bool multipleClients,
00097                 const char *openOnIP)
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, openOnIP))
00115   {
00116     myServerSocket.setLinger(0);
00117     myServerSocket.setNonBlock();
00118     if (openOnIP != NULL)
00119       ArLog::log(ArLog::Normal, "ArNetServer opened on port %d on ip %s.", 
00120          myPort, openOnIP);
00121     else
00122       ArLog::log(ArLog::Normal, "ArNetServer opened on port %d.", myPort);
00123     myOpened = true;
00124   }
00125   else
00126   {
00127     ArLog::log(ArLog::Terse, "ArNetServer failed to open: %s", 
00128            myServerSocket.getErrorStr().c_str());
00129     myOpened = false;
00130     return false;
00131   }
00132 
00133   // add ourselves to the robot if we aren't already there
00134   if (myRobot != NULL && (rootTask = myRobot->getSyncTaskRoot()) != NULL)
00135   {    
00136     proc = rootTask->findNonRecursive(&myTaskCB);
00137     if (proc == NULL)
00138     {
00139       // toss in a netserver
00140       taskName = "Net Servers ";
00141       taskName += myPort;
00142       rootTask->addNewLeaf(taskName.c_str(), 60, &myTaskCB, NULL);
00143     }
00144   }
00145   return true;
00146   
00147 }
00148 
00154 AREXPORT bool ArNetServer::addCommand(const char *command, 
00155                   ArFunctor3<char **, int, ArSocket *> *functor,
00156                       const char *help)
00157 {
00158   std::map<std::string, ArFunctor3<char **, int, ArSocket *> *, ArStrCaseCmpOp>::iterator it;
00159 
00160   if ((it = myFunctorMap.find(command)) != myFunctorMap.end())
00161   {
00162     ArLog::log(ArLog::Normal, "ArNetServer::addCommand: Already a command for %s", command);
00163     return false;
00164   }
00165 
00166   myFunctorMap[command] = functor;
00167   myHelpMap[command] = help;
00168   return true;
00169 }
00170 
00175 AREXPORT bool ArNetServer::remCommand(const char *command)
00176 {
00177   if (myFunctorMap.find(command) == myFunctorMap.end())
00178   {
00179     return false;
00180   }
00181   myFunctorMap.erase(command);
00182   myHelpMap.erase(command);
00183   return true;  
00184 }
00185 
00186 
00187 AREXPORT void ArNetServer::sendToAllClientsPlain(const char *str)
00188 {
00189   std::list<ArSocket *>::iterator it;
00190 
00191   if (myLoggingDataSent)
00192     ArLog::log(ArLog::Terse, "ArNetServer::sendToAllClients: Sending %s", str);
00193   for (it = myConns.begin(); it != myConns.end(); ++it)
00194   {
00195     (*it)->setLogWriteStrings(false);
00196     (*it)->writeString(str);
00197     (*it)->setLogWriteStrings(myLoggingDataSent);
00198   }
00199 }
00200 
00205 AREXPORT void ArNetServer::sendToAllClients(const char *str, ...)
00206 {
00207   char buf[2049];
00208   va_list ptr;
00209   va_start(ptr, str);
00210   vsprintf(buf, str, ptr);
00211 
00212   sendToAllClientsPlain(buf);
00213   
00214   va_end(ptr);
00215 }
00216 
00217 AREXPORT bool ArNetServer::isOpen(void)
00218 {
00219   return myOpened;
00220 }
00221 
00222 
00227 AREXPORT void ArNetServer::setLoggingDataSent(bool loggingData)
00228 {
00229   myLoggingDataSent = loggingData;
00230   std::list<ArSocket *>::iterator it;
00231   for (it = myConnectingConns.begin(); it != myConnectingConns.end(); ++it)
00232     (*it)->setLogWriteStrings(loggingData);
00233   for (it = myConns.begin(); it != myConns.end(); ++it)
00234     (*it)->setLogWriteStrings(loggingData);
00235 }
00236 
00241 AREXPORT bool ArNetServer::getLoggingDataSent(void)
00242 {
00243   return myLoggingDataSent;
00244 }
00245 
00250 AREXPORT void ArNetServer::setLoggingDataReceived(bool loggingData)
00251 {
00252   myLoggingDataReceived = loggingData;
00253 }
00254 
00259 AREXPORT bool ArNetServer::getLoggingDataReceived(void)
00260 {
00261   return myLoggingDataReceived;
00262 }
00263 
00264 
00265 AREXPORT void ArNetServer::runOnce(void)
00266 {
00267 
00268   ArSocket acceptingSocket;
00269   ArSocket *socket;
00270   char *str;
00271   std::list<ArSocket *> removeList;
00272   std::list<ArSocket *>::iterator it;
00273   ArArgumentBuilder *args = NULL;
00274   std::string command;
00275 
00276   if (!myOpened)
00277   {
00278     return;
00279   }
00280 
00281   lock();
00282   // get any new sockets that want to connect
00283   while (myServerSocket.accept(&acceptingSocket) && acceptingSocket.getFD() >= 0)
00284   {
00285     acceptingSocket.setNonBlock();
00286     // see if we want more sockets
00287     if (!myMultipleClients && (myConns.size() > 0 ||
00288                    myConnectingConns.size() > 0))
00289     {
00290       // we didn't want it, so politely tell it to go away
00291       acceptingSocket.writeString("Conn refused.");
00292       acceptingSocket.writeString(
00293           "Only client allowed and it is already connected.");
00294       acceptingSocket.close();
00295       ArLog::log(ArLog::Terse, "ArNetServer not taking multiple clients and another client tried to connect from %s.", acceptingSocket.getIPString());
00296     }
00297     else 
00298     {
00299       // we want the client so we put it in our list of connecting
00300       // sockets, which means that it is waiting to give its password
00301       socket = new ArSocket;
00302       socket->setLogWriteStrings(myLoggingDataSent);
00303       socket->transfer(&acceptingSocket);
00304       socket->writeString("Enter password:");
00305       myConnectingConns.push_front(socket);
00306       ArLog::log(ArLog::Normal, 
00307          "Client connecting from %s.",
00308          socket->getIPString());
00309     }
00310   }
00311 
00312   // now we read in data from our connecting sockets and see if
00313   // they've given us the password
00314   for (it = myConnectingConns.begin(); it != myConnectingConns.end(); ++it)
00315   {
00316     socket = (*it);
00317     // read in what the client has to say
00318     if ((str = socket->readString()) != NULL)
00319     {
00320       if (str[0] == '\0')
00321     continue;
00322       // now see if the word matchs the password
00323       if (myPassword == str)
00324       {
00325     ArLog::log(ArLog::Normal, 
00326            "Client from %s gave password and connected.",
00327            socket->getIPString());
00328     myConns.push_front(socket);
00329     removeList.push_front(socket);
00330     internalGreeting(socket);
00331       }
00332       else
00333       {
00334     socket->close();
00335     myDeleteList.push_front(socket);
00336     ArLog::log(ArLog::Terse, 
00337            "Client from %s gave wrong password and is being disconnected.", 
00338            socket->getIPString());
00339       }
00340     }
00341     // if we couldn't read a string it means we lost a connection
00342     else
00343     {
00344       ArLog::log(ArLog::Normal, 
00345          "Connection to %s lost.", socket->getIPString());
00346       socket->close();
00347       myDeleteList.push_front(socket);
00348     }
00349   }
00350   // now we clear out the ones we want to remove from our connecting
00351   // clients list
00352   while ((it = removeList.begin()) != removeList.end())
00353   {
00354     socket = (*it);
00355     myConnectingConns.remove(socket);
00356     removeList.pop_front();
00357   }
00358 
00359 
00360   // now we read in data from our connecting sockets and see if
00361   // they've given us the password
00362   for (it = myConns.begin(); it != myConns.end() && myOpened; ++it)
00363   {
00364     socket = (*it);
00365     // read in what the client has to say
00366     while ((str = socket->readString()) != NULL)
00367     {
00368       // if this is null then there wasn't anything said
00369       if (str[0] == '\0')
00370     break;
00371       // make sure we read something
00372       // set up the arguments and then call the function for the
00373       // argument
00374       args = new ArArgumentBuilder;
00375       args->addPlain(str);
00376       //args->log();
00377       parseCommandOnSocket(args, socket);
00378       delete args;
00379       args = NULL;
00380     }
00381     // if str was NULL we lost connection
00382     if (str == NULL)
00383     {
00384       ArLog::log(ArLog::Normal, 
00385          "Connection to %s lost.", socket->getIPString());
00386       socket->close();
00387       myDeleteList.push_front(socket);
00388     }
00389   }
00390 
00391   // now we delete the ones we want to delete (we could do this above
00392   // but then it wouldn't be symetrical with above)
00393   while ((it = myDeleteList.begin()) != myDeleteList.end())
00394   {
00395     socket = (*it);
00396     myConnectingConns.remove(socket);
00397     myConns.remove(socket);
00398     socket->close();
00399     delete socket;
00400     myDeleteList.pop_front();
00401   }
00402 
00403   if (myWantToClose)
00404   {
00405     close();
00406   }
00407   unlock();
00408 }
00409 
00410 AREXPORT void ArNetServer::close(void)
00411 {
00412   std::list<ArSocket *>::iterator it;
00413   ArSocket *socket;
00414   
00415   if (!myOpened)
00416     return;
00417   myWantToClose = false;
00418   ArLog::log(ArLog::Normal, "ArNetServer shutting down server.");
00419   sendToAllClients("Shutting down server");
00420   for (it = myConnectingConns.begin(); it != myConnectingConns.end(); ++it)
00421   {
00422     (*it)->writeString("Shutting down server");
00423   }
00424   myOpened = false;
00425 
00426   while ((it = myConnectingConns.begin())!= myConnectingConns.end())
00427   {
00428     socket = (*it);
00429     myConnectingConns.pop_front();
00430     socket->close();
00431     delete socket;
00432   }
00433   while ((it = myConns.begin()) != myConns.end())
00434   {
00435     socket = (*it);
00436     myConns.pop_front();
00437     socket->close();
00438     delete socket;
00439   }
00440   myServerSocket.close();
00441 }
00442 
00443 AREXPORT void ArNetServer::internalGreeting(ArSocket *socket)
00444 {
00445   if (mySquelchNormal)
00446     return;
00447   socket->writeString("Welcome to the server.");
00448   socket->writeString("You can type 'help' at any time for the following help list.");
00449   internalHelp(socket);
00450 }
00451 
00452 AREXPORT void ArNetServer::internalHelp(ArSocket *socket)
00453 {
00454  std::map<std::string, std::string, ArStrCaseCmpOp>::iterator it;
00455   
00456  socket->writeString("Commands:");
00457  for (it = myHelpMap.begin(); it != myHelpMap.end(); ++it)
00458    socket->writeString("%15s%10s%s", it->first.c_str(), "", 
00459                it->second.c_str());
00460 }
00461 
00462 AREXPORT void ArNetServer::internalHelp(char **argv, int argc, 
00463                     ArSocket *socket)
00464 {
00465   internalHelp(socket);
00466 }
00467 
00468 
00469 AREXPORT void ArNetServer::internalEcho(char **argv, int argc, 
00470                         ArSocket *socket)
00471 {
00472   // if they just typed it we tell them if its on or off
00473   if (argc == 1)
00474   {
00475     if (socket->getEcho())
00476       socket->writeString("Echo is on.");
00477     else
00478       socket->writeString("Echo is off.");
00479   }
00480   // if the have two words see if they have the right args
00481   else if (argc == 2 && strcasecmp(argv[1], "on") == 0)
00482   {
00483     socket->writeString("Echo turned on.");
00484     socket->setEcho(true);
00485   }
00486   else if (argc == 2 && strcasecmp(argv[1], "off") == 0)
00487   {
00488     socket->writeString("Echo turned off.");
00489     socket->setEcho(false);
00490   }
00491   else
00492   {
00493     socket->writeString("usage: echo <on/off>");
00494   }
00495 }
00496 
00497 AREXPORT void ArNetServer::internalQuit(char **argv, int argc, 
00498                      ArSocket *socket)
00499 {
00500   socket->writeString("Closing connection");
00501 
00502   myDeleteList.push_front(socket);
00503   ArLog::log(ArLog::Normal, "Client from %s quit.", socket->getIPString());
00504 }
00505 
00506 AREXPORT void ArNetServer::internalShutdownServer(char **argv, int argc, 
00507                           ArSocket *socket)
00508 {
00509   sendToAllClients("Shutting down server");
00510   myWantToClose = true;
00511   if (myRobot != NULL)
00512     myRobot->stopRunning();
00513   
00514 }
00515 
00516 AREXPORT void ArNetServer::parseCommandOnSocket(ArArgumentBuilder *args, 
00517                         ArSocket *socket, bool allowLog)
00518 {
00519 
00520   std::map<std::string, ArFunctor3<char **, int, ArSocket *> *, ArStrCaseCmpOp>::iterator fIt;
00521   char **argv;
00522   int argc;
00523 
00524   if (myLoggingDataReceived && !mySquelchNormal && allowLog)
00525     ArLog::log(ArLog::Normal, "Command received from %s: %s",
00526            socket->getIPString(), args->getFullString());
00527   else if (myLoggingDataReceived && mySquelchNormal && allowLog)
00528     ArLog::log(ArLog::Normal, "%s: %s",
00529            socket->getIPString(), args->getFullString());
00530   argv = args->getArgv();
00531   argc = args->getArgc();
00532   // if we have some command see if it has a functor
00533   if (argc >= 1 && 
00534       (fIt = myFunctorMap.find(argv[0])) != myFunctorMap.end())
00535   {
00536     fIt->second->invoke(argv, argc, socket);
00537   }
00538   // it didn't have a functor so we don't know it as a command
00539   else if (argc >= 1)
00540   {
00541     if (!mySquelchNormal)
00542       socket->writeString("Unknown command %s", argv[0]);
00543   }
00544 }
00545 
00546 AREXPORT void ArNetServer::internalAddSocketToList(ArSocket *socket)
00547 {
00548   myConns.push_front(socket);
00549 }
00550 
00551 
00552 AREXPORT void ArNetServer::internalAddSocketToDeleteList(ArSocket *socket)
00553 {
00554   myDeleteList.push_front(socket);
00555 }
00556 
00557 AREXPORT void ArNetServer::squelchNormal(void)
00558 {
00559   mySquelchNormal = true;
00560   remCommand("help");
00561   remCommand("echo");
00562   remCommand("quit");
00563   remCommand("shutdownServer");
00564 
00565 }
00566 
00567 AREXPORT void ArNetServer::sendToClientPlain(
00568     ArSocket *socket, const char *ipString, const char *str)
00569 {
00570   std::list<ArSocket *>::iterator it;
00571 
00572   for (it = myConns.begin(); it != myConns.end(); ++it)
00573   {
00574     if ((*it) == socket && strcmp((*it)->getIPString(), ipString) == 0)
00575     {
00576       if (myLoggingDataSent)
00577     ArLog::log(ArLog::Terse, 
00578            "ArNetServer::sendToClient: Sending '%s' to %s", str,
00579            ipString);
00580       (*it)->setLogWriteStrings(false);
00581       (*it)->writeString(str);
00582       (*it)->setLogWriteStrings(myLoggingDataSent);
00583     }
00584   }
00585 }
00586 
00591 AREXPORT void ArNetServer::sendToClient(ArSocket *socket, const char *ipString,
00592                const char *str, ...)
00593 {
00594   char buf[2049];
00595   va_list ptr;
00596   va_start(ptr, str);
00597   vsprintf(buf, str, ptr);
00598 
00599   sendToClientPlain(socket, ipString, buf);
00600   
00601   va_end(ptr);
00602 }

Generated on Tue Feb 20 10:51:40 2007 for Aria by  doxygen 1.4.0