// -*- c++ -*- // Generated by assa-genesis //------------------------------------------------------------------------------ // $Id: daytime.cpp,v 1.8 2006/07/20 02:30:55 vlg Exp $ //------------------------------------------------------------------------------ // DayTime_Server.cpp //------------------------------------------------------------------------------ // Copyright (c) 2002,2005 by Vladislav Grinchenko // // Permission to use, copy, modify, and distribute this software // and its documentation for any purpose and without fee is hereby // granted, provided that the above copyright notice appear in all // copies. The author makes no representations about the suitability // of this software for any purpose. It is provided "as is" without // express or implied warranty. //------------------------------------------------------------------------------ // // Date : Fri Oct 18 23:32:23 2002 // //------------------------------------------------------------------------------ static const char help_msg[]= " \n" " NAME: \n" " \n" " daytime - a daytime server \n" " \n" " DESCRIPTION: \n" " \n" " Provides caller with local date. Server ignores any requests, \n" " writes the date out to the client, discards any requests received, \n" " and closes connection. \n" " \n" " By default, it listens on $ASSAPORT/tcp socket for service requests. \n" " This can be overwritten with {-p, --port=PORT } option. \n" " \n" " USAGE: \n" " \n" " shell> daytime [OPTIONS] \n" " \n" " OPTIONS: \n" " \n" " --one-shot - Serve exactly one request and exit afterwards. \n" " --with-timestamp - Log messages with timestamp \n" " -b, --daemon - Run process as true UNIX daemon \n" " -l, --pidfile PATH - The process ID is written to the lockfile PATH \n" " instead of default ~/.{procname}.pid \n" " -L, --no-pidfile - Do not create PID lockfile \n" " \n" " -D, --log-file NAME - Write debug to NAME file \n" " -d, --log-stdout - Write debug to standard output \n" " -z, --log-size NUM - Maximum size debug file can reach (dfl: is 10Mb) \n" " \n" " -m, --mask MASK - Mask (default: ALL = 0x7fffffff) \n" " -p, --port NAME - The tcp/ip port NAME (default - procname) \n" " -n, --instance NUM - Process instance NUM (default - none) \n" " \n" " -h, --help - Print this messag \n" " -v, --version - Print version number \n"; //------------------------------------------------------------------------------ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include using std::string; #include #include #include #include #include #include #include using namespace ASSA; /******************************************************************************* Class Responder *******************************************************************************/ class Responder : public ServiceHandler { public: Responder (IPv4Socket* stream_); virtual int open (void); virtual int handle_read (int fd_); virtual int handle_close (int fd_); }; /******************************************************************************* Class DayTime_Server *******************************************************************************/ class DayTime_Server : public GenServer, public Singleton { public: DayTime_Server (); virtual void init_service (); virtual void process_events (); int get_exit_value () const { return m_exit_value; } void set_exit_value (int v_) { m_exit_value = v_; } bool one_shot () const { return m_one_shot; } private: Acceptor* m_listener; int m_exit_value; // Return status of the process bool m_one_shot; bool m_with_timestamp; }; /******************************************************************************* Useful definitions *******************************************************************************/ #define DAYTIME_SERVER DayTime_Server::get_instance() #define REACTOR DAYTIME_SERVER->get_reactor() // Static declarations mandated by Singleton class ASSA_DECL_SINGLETON(DayTime_Server); /******************************************************************************* Class Responder member functions *******************************************************************************/ Responder:: Responder (IPv4Socket* stream_) : ServiceHandler (stream_) { trace("Responder::Responder"); // no-op } int Responder:: open (void) { trace("Responder::open"); IPv4Socket& stream = get_stream (); REACTOR->registerIOHandler (this, stream.getHandler (), READ_EVENT); /* * Return date in readable format: "Sat Oct 19 23:00:57 EDT 2002" */ string response (TimeVal::gettimeofday ().fmtString ("%c")); response += "\n"; size_t len = response.length (); DL((APP,"Sending response: \"%s\" (%d bytes)\n",response.c_str (), len)); Assure_exit (stream.write (response.c_str (), len) == len); stream << flush; /* By closing stream here we let Reactor detect 'BAD FD' in its * select() loop and clean up afterwards. */ stream.close (); if (DAYTIME_SERVER->one_shot ()) { DAYTIME_SERVER->stop_service (); } return -1; } int Responder:: handle_read (int fd_) { trace("Responder::handle_read"); /* Discard whatever I read from a client - required by RFC, but * never called. */ IPv4Socket& s = get_stream (); s.ignore (); return BYTES_LEFT_IN_SOCKBUF(s); } int Responder:: handle_close (int fd_) { trace("Responder::handle_close"); delete this; return 0; } /******************************************************************************* Class DayTime_Server Member Functions *******************************************************************************/ DayTime_Server:: DayTime_Server () : m_listener (NULL), m_exit_value (0), m_one_shot (false), m_with_timestamp (false) { add_flag_opt (0, "one-shot", &m_one_shot); add_flag_opt (0, "with-timestamp", &m_with_timestamp); // ---Configuration--- rm_opt ('f', "config-file" ); /*--- * Disable all debugging *---*/ m_mask = 0x0; } void DayTime_Server:: init_service () { trace("DayTime_Server::init_service"); if (m_with_timestamp) { Log::enable_timestamp (); LOGGER->set_timezone (1); } /* We overwrite default m_port value which would be otherwise set to the process' name - "daytime". */ char* assaport = ::getenv("ASSAPORT"); m_port = assaport != NULL ? assaport : "10000"; DL((APP,"m_port = %s\n", m_port.c_str ())); m_listener = new Acceptor (get_reactor ()); INETAddress addr (get_port ().c_str ()); addr.dump (); if (addr.bad ()) { EL((ASSA::ASSAERR,"Bad listening address!\n")); set_exit_value (1); stop_service (); return; } Assure_exit (m_listener->open (addr) == 0); DL((APP,"Service has been initialized\n")); } void DayTime_Server:: process_events () { trace("DayTime_Server::process_events"); while (service_is_active ()) { m_reactor.waitForEvents (); } m_reactor.stopReactor (); DL((APP,"Service stopped!\n")); } int main (int argc, char* argv[]) { static const char release[] = "VERSION"; int patch_level = 0; DAYTIME_SERVER->set_version (release, patch_level); DAYTIME_SERVER->set_author ("Vladislav Grinchenko"); DAYTIME_SERVER->set_flags (GenServer::RMLOG); DAYTIME_SERVER->init (&argc, argv, help_msg); DAYTIME_SERVER->init_service (); DAYTIME_SERVER->process_events (); return DAYTIME_SERVER->get_exit_value (); }