PLearn 0.1
ServerCommand.cc
Go to the documentation of this file.
00001 // -*- C++ -*-
00002 
00003 // ServerCommand.cc
00004 //
00005 // Copyright (C) 2005 Pascal Vincent 
00006 // 
00007 // Redistribution and use in source and binary forms, with or without
00008 // modification, are permitted provided that the following conditions are met:
00009 // 
00010 //  1. Redistributions of source code must retain the above copyright
00011 //     notice, this list of conditions and the following disclaimer.
00012 // 
00013 //  2. Redistributions in binary form must reproduce the above copyright
00014 //     notice, this list of conditions and the following disclaimer in the
00015 //     documentation and/or other materials provided with the distribution.
00016 // 
00017 //  3. The name of the authors may not be used to endorse or promote
00018 //     products derived from this software without specific prior written
00019 //     permission.
00020 // 
00021 // THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
00022 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00023 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
00024 // NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00025 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
00026 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00027 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00028 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00029 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00030 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00031 // 
00032 // This file is part of the PLearn library. For more information on the PLearn
00033 // library, go to the PLearn Web site at www.plearn.org
00034 
00035 /* *******************************************************      
00036  * $Id: ServerCommand.cc 7471 2007-05-31 19:03:35Z plearner $ 
00037  ******************************************************* */
00038 
00039 // Authors: Pascal Vincent
00040 
00044 #include "ServerCommand.h"
00045 #include <plearn/misc/PLearnServer.h>
00046 #include <plearn/io/PStream.h>
00047 // #include <plearn/io/StdPStreamBuf.h>
00048 // #include <plearn/io/FdPStreamBuf.h>
00049 #include <plearn/io/pl_log.h>
00050 #include <plearn/io/PrPStreamBuf.h>
00051 #include <plearn/io/openFile.h>
00052 #include <plearn/base/tostring.h>
00053 #include <plearn/base/PrUtils.h>
00054 #include <nspr/prio.h>
00055 #include <nspr/prerror.h>
00056 #include <nspr/prnetdb.h>
00057 
00058 #ifndef WIN32
00059 // POSIX includes for getpid() and gethostname()
00060 #include <sys/types.h>
00061 #include <unistd.h>
00062 #endif 
00063 
00064 
00065 namespace PLearn {
00066 using namespace std;
00067 
00069 PLearnCommandRegistry ServerCommand::reg_(new ServerCommand);
00070 
00071 ServerCommand::ServerCommand():
00072     PLearnCommand("server",
00073 
00074                   "Launches plearn in computation server mode",
00075 
00076                   "server\n"
00077                   "  Launches plearn in stdin/stdout server mode, \n"
00078                   "  listening for commands on standard in \n"
00079                   "  and outputing results on standard out. \n"
00080                   " \n"
00081                   "server <tcp_port> [<outfile>] [-singleuse]\n"
00082                   "  Launches plearn in TCP server mode \n"
00083                   "  Will then print a line to outfile or to stdout (if no outfile is specified) of the form: \n"
00084                   "    PLEARN_SERVER_TCP hostname port pid\n"
00085                   "  Will then wait for a connection on the given TCP port. \n"
00086                   "  All i/o for commands are then done through that connection. \n"
00087                   "  If you specify -singleuse, then the server will exit when the conneciton \n"
00088                   "  with its first client is closed or lost."
00089         )
00090 {}
00091 
00093 void ServerCommand::run(const vector<string>& args)
00094 {
00095     if(args.size()>0) // Start TCP server on given port
00096     {
00097         PRStatus st;
00098         char buf[256];
00099         int port = toint(args[0]);
00100 
00101         bool singleuse=false;
00102         string outfile;
00103         if(args.size()>1)
00104         {
00105             if(args[1]=="-singleuse")
00106                 singleuse = true;
00107             else
00108                 outfile = args[1];
00109             if(args.size()>2 && args[2]=="-singleuse")
00110                 singleuse = true;
00111         }
00112 
00113         PRFileDesc* sock = PR_NewTCPSocket();
00114         if (!sock)
00115             PLERROR("Servercommand: socket creation failed! (Maybe you ran out of file descriptors?)");
00116         PRNetAddr server_address;
00117         PR_InitializeNetAddr(PR_IpAddrAny, port, &server_address);
00118         if (PR_Bind(sock, &server_address) != PR_SUCCESS)
00119             PLERROR("ServerCommand: could not bind to port %d!", port);
00120 
00121         // Allow reuse of the socket immediately after the server shuts down
00122         PRSocketOptionData socket_option_data;
00123         socket_option_data.option = PR_SockOpt_Reuseaddr;
00124         socket_option_data.value.reuse_addr = PR_TRUE;
00125         PR_SetSocketOption(sock, &socket_option_data);
00126 
00127         string myhostname = "UNKNOWN_HOSTNAME";
00128         string mypid = "UNKNOWN_PID";      
00129 #ifndef WIN32
00130         mypid = tostring(getpid());
00131         if(gethostname(buf, sizeof(buf))==0)
00132             myhostname = buf;
00133 #endif
00134 
00135         PRNetAddr assigned_addr;
00136         PR_InitializeNetAddr(PR_IpAddrAny, PR_htons(0), &assigned_addr);
00137         st= PR_GetSockName(sock, &assigned_addr);
00138         if(port==0 && st==PR_SUCCESS)
00139             port= PR_ntohs(assigned_addr.inet.port);
00140         
00141         if(outfile.size()>0)
00142         {
00143             string tmpoutfile =outfile+".tmp";
00144             PStream out = openFile(tmpoutfile, PStream::raw_ascii, "w");
00145             out << "PLEARN_SERVER_TCP " << myhostname << " " << port << " " << mypid << endl;            
00146             out = 0; // close it
00147             PR_Rename(tmpoutfile.c_str(), outfile.c_str());
00148         }
00149         else
00150             pout << "PLEARN_SERVER_TCP " << myhostname << " " << port << " " << mypid << endl;
00151 
00152         NORMAL_LOG << "PLEARN_SERVER STARTING IN TCP MODE ON "  << myhostname << ", PORT " << port << ", PID " << mypid << endl;
00153         NORMAL_LOG << "singleuse = " << singleuse << endl;
00154 
00155         bool running = true;
00156         do  {
00157             NORMAL_LOG << "\nPLEARN_SERVER WAITING FOR CONNECTION"  << endl;
00158             
00160             pout << " JBL " << endl;
00162 
00163             st = PR_Listen(sock,0);
00164             if(st!=PR_SUCCESS)
00165                 PLERROR("serverCommand: listen on socket failed");
00166             PRNetAddr addr;
00167             PRFileDesc* fd = PR_Accept(sock, &addr, PR_INTERVAL_NO_TIMEOUT);
00168             if(fd==0)
00169                 PLERROR("ServerCommand: accept returned 0, error code is: %d : %s",
00170                         PR_GetError(), getPrErrorString().c_str());
00171             st = PR_NetAddrToString(&addr, buf, sizeof(buf));
00172             NORMAL_LOG << "PLEARN_SERVER CONNECTION_FROM "  << buf << endl;
00173             PStream io(new PrPStreamBuf(fd,fd,true,true));
00174 
00175             PLearnServer server(io);
00176             running = server.run();
00177             io.flush();
00178             if (PR_Close(fd) != PR_SUCCESS)
00179                 PLERROR("ServerCommand: couldn't close client socket from %s!", buf);
00180 
00181         } while(running && !singleuse);
00182 
00183         NORMAL_LOG << "PLEARN_SERVER CLOSING SOCKET" << endl;
00184         if (PR_Shutdown(sock, PR_SHUTDOWN_BOTH) != PR_SUCCESS)
00185             PLERROR("ServerCommand: couldn't shutdown socket %d!", port);
00186         if (PR_Close(sock) != PR_SUCCESS)
00187             PLERROR("ServerCommand: couldn't close port %d!", port);
00188     }
00189     else // Start stdin/stdout server
00190     {
00191         perr << "Type !? to get some help." << endl;
00192         // PStream io(&std::cin, &std::cout);
00193         // PStream io(new StdPStreamBuf(&std::cin,&std::cout));
00194         // PStream io(new FdPStreamBuf(0,1));
00195         PStream io = get_pio();
00196         io.setMode(PStream::plearn_ascii);
00197         PLearnServer server(io);
00198         server.run();
00199     }
00200 }
00201 
00202 } // end of namespace PLearn
00203 
00204 
00205 /*
00206   Local Variables:
00207   mode:c++
00208   c-basic-offset:4
00209   c-file-style:"stroustrup"
00210   c-file-offsets:((innamespace . 0)(inline-open . 0))
00211   indent-tabs-mode:nil
00212   fill-column:79
00213   End:
00214 */
00215 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=79 :
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines