PLearn 0.1
|
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 :