1 // -*- c++ -*-
2 // Generated by assa-genesis
3 //------------------------------------------------------------------------------
4 // $Id: daytime.cpp,v 1.8 2006/07/20 02:30:55 vlg Exp $
5 //------------------------------------------------------------------------------
6 //                            DayTime_Server.cpp
7 //------------------------------------------------------------------------------
8 //  Copyright (c) 2002,2005 by Vladislav Grinchenko
9 //
10 //  Permission to use, copy, modify, and distribute this software
11 //  and its documentation for any purpose and without fee is hereby
12 //  granted, provided that the above copyright notice appear in all
13 //  copies.  The author makes no representations about the suitability
14 //  of this software for any purpose.  It is provided "as is" without
15 //  express or implied warranty.
16 //------------------------------------------------------------------------------
17 //
18 // Date   : Fri Oct 18 23:32:23 2002
19 //
20 //------------------------------------------------------------------------------
21 
22 static const char help_msg[]=
23 "                                                                            \n"
24 " NAME:                                                                      \n"
25 "                                                                            \n"
26 "   daytime - a daytime server                                               \n"
27 "                                                                            \n"
28 " DESCRIPTION:                                                               \n"
29 "                                                                            \n"
30 "   Provides caller with local date. Server ignores any requests,            \n"
31 "   writes the date out to the client, discards any requests received,       \n"
32 "   and closes connection.                                                   \n"
33 "                                                                            \n"
34 "   By default, it listens on $ASSAPORT/tcp socket for service requests.     \n"
35 "   This can be overwritten with {-p, --port=PORT } option.                  \n"
36 "                                                                            \n"
37 " USAGE:                                                                     \n"
38 "                                                                            \n"
39 "   shell>  daytime  [OPTIONS]                                               \n"
40 "                                                                            \n"
41 " OPTIONS:                                                                   \n"
42 "                                                                            \n"
43 "     --one-shot          - Serve exactly one request and exit afterwards.   \n"
44 "     --with-timestamp    - Log messages with timestamp                      \n"
45 " -b, --daemon            - Run process as true UNIX daemon                  \n"
46 " -l, --pidfile PATH      - The process ID is written to the lockfile PATH   \n"
47 "                           instead of default ~/.{procname}.pid             \n"
48 " -L, --no-pidfile        - Do not create PID lockfile                       \n"
49 "                                                                            \n"
50 " -D, --log-file NAME     - Write debug to NAME file                         \n"
51 " -d, --log-stdout        - Write debug to standard output                   \n"
52 " -z, --log-size NUM      - Maximum size debug file can reach (dfl: is 10Mb) \n"
53 "                                                                            \n"
54 " -m, --mask MASK         - Mask (default: ALL = 0x7fffffff)                 \n"
55 " -p, --port NAME         - The tcp/ip port NAME (default - procname)        \n"
56 " -n, --instance NUM      - Process instance NUM (default - none)            \n"
57 "                                                                            \n"
58 " -h, --help              - Print this messag                                \n"
59 " -v, --version           - Print version number                            \n";
60 //------------------------------------------------------------------------------
61 
62 #ifdef HAVE_CONFIG_H
63 #    include "config.h"
64 #endif
65 #include <string>
66 using std::string;
67 
68 #include <assa/GenServer.h>
69 #include <assa/Singleton.h>
70 #include <assa/TimeVal.h>
71 #include <assa/ServiceHandler.h>
72 #include <assa/IPv4Socket.h>
73 #include <assa/INETAddress.h>
74 #include <assa/Acceptor.h>
75 
76 using namespace ASSA;
77 
78 /*******************************************************************************
79   Class Responder
80 *******************************************************************************/
81 
82 class Responder :
83 	public ServiceHandler<IPv4Socket>
84 {
85 public:
86     Responder  (IPv4Socket* stream_);
87 
88     virtual int open (void);
89 
90     virtual int handle_read (int fd_);
91     virtual int handle_close (int fd_);
92 };
93 
94 
95 /*******************************************************************************
96                        Class DayTime_Server
97 *******************************************************************************/
98 class DayTime_Server :
99     public GenServer,
100     public Singleton<DayTime_Server>
101 {
102 public:
103     DayTime_Server ();
104 
105     virtual void init_service ();
106     virtual void process_events ();
107 
get_exit_value() const108     int  get_exit_value () const { return m_exit_value; }
set_exit_value(int v_)109     void set_exit_value (int v_) { m_exit_value = v_;   }
one_shot() const110 	bool one_shot () const { return m_one_shot; }
111 
112 private:
113 	Acceptor<Responder, IPv4Socket>* m_listener;
114 
115     int  m_exit_value;     // Return status of the process
116 	bool m_one_shot;
117 	bool m_with_timestamp;
118 };
119 
120 /*******************************************************************************
121  Useful definitions
122 *******************************************************************************/
123 
124 #define DAYTIME_SERVER  DayTime_Server::get_instance()
125 #define REACTOR DAYTIME_SERVER->get_reactor()
126 
127 // Static declarations mandated by Singleton class
128 ASSA_DECL_SINGLETON(DayTime_Server);
129 
130 /*******************************************************************************
131  Class Responder member functions
132 *******************************************************************************/
133 Responder::
Responder(IPv4Socket * stream_)134 Responder (IPv4Socket* stream_)
135     : ServiceHandler<IPv4Socket> (stream_)
136 {
137 	trace("Responder::Responder");
138 	// no-op
139 }
140 
141 int
142 Responder::
open(void)143 open (void)
144 {
145 	trace("Responder::open");
146 
147 	IPv4Socket& stream = get_stream ();
148 	REACTOR->registerIOHandler (this, stream.getHandler (), READ_EVENT);
149 	/*
150 	 * Return date in readable format: "Sat Oct 19 23:00:57 EDT 2002"
151 	 */
152 	string response (TimeVal::gettimeofday ().fmtString ("%c"));
153 	response += "\n";
154 	size_t len = response.length ();
155 	DL((APP,"Sending response: \"%s\" (%d bytes)\n",response.c_str (), len));
156 	Assure_exit (stream.write (response.c_str (), len) == len);
157 	stream << flush;
158 
159 	/* By closing stream here we let Reactor detect 'BAD FD' in its
160 	 * select() loop and clean up afterwards.
161 	 */
162 	stream.close ();
163 	if (DAYTIME_SERVER->one_shot ()) {
164 		DAYTIME_SERVER->stop_service ();
165 	}
166 	return -1;
167 }
168 
169 int
170 Responder::
handle_read(int fd_)171 handle_read (int fd_)
172 {
173 	trace("Responder::handle_read");
174 	/* Discard whatever I read from a client - required by RFC, but
175 	 * never called.
176 	 */
177 	IPv4Socket& s = get_stream ();
178 	s.ignore ();
179 
180 	return BYTES_LEFT_IN_SOCKBUF(s);
181 }
182 
183 int
184 Responder::
handle_close(int fd_)185 handle_close (int fd_)
186 {
187 	trace("Responder::handle_close");
188 	delete this;
189 	return 0;
190 }
191 
192 /*******************************************************************************
193  Class DayTime_Server Member Functions
194 *******************************************************************************/
195 DayTime_Server::
DayTime_Server()196 DayTime_Server () :
197 	m_listener (NULL),
198 	m_exit_value (0),
199 	m_one_shot (false),
200 	m_with_timestamp (false)
201 {
202 	add_flag_opt (0, "one-shot", &m_one_shot);
203 	add_flag_opt (0, "with-timestamp", &m_with_timestamp);
204 
205     // ---Configuration---
206     rm_opt ('f', "config-file"  );
207 
208     /*---
209      * Disable all debugging
210      *---*/
211     m_mask = 0x0;
212 }
213 
214 void
215 DayTime_Server::
init_service()216 init_service ()
217 {
218     trace("DayTime_Server::init_service");
219 
220 	if (m_with_timestamp) {
221 		Log::enable_timestamp ();
222 		LOGGER->set_timezone (1);
223 	}
224 
225 	/* We overwrite default m_port value which would be
226 	   otherwise set to the process' name - "daytime".
227 	*/
228 	char* assaport = ::getenv("ASSAPORT");
229 	m_port = assaport != NULL ? assaport : "10000";
230 	DL((APP,"m_port = %s\n", m_port.c_str ()));
231 
232 	m_listener = new Acceptor<Responder, IPv4Socket> (get_reactor ());
233 	INETAddress addr (get_port ().c_str ());
234 	addr.dump ();
235 
236 	if (addr.bad ()) {
237         EL((ASSA::ASSAERR,"Bad listening address!\n"));
238 		set_exit_value (1);
239 		stop_service ();
240 		return;
241     }
242     Assure_exit (m_listener->open (addr) == 0);
243     DL((APP,"Service has been initialized\n"));
244 }
245 
246 void
247 DayTime_Server::
process_events()248 process_events ()
249 {
250     trace("DayTime_Server::process_events");
251 
252     while (service_is_active ()) {
253         m_reactor.waitForEvents ();
254     }
255     m_reactor.stopReactor ();
256     DL((APP,"Service stopped!\n"));
257 }
258 
259 int
main(int argc,char * argv[])260 main (int argc, char* argv[])
261 {
262     static const char release[] = "VERSION";
263     int patch_level = 0;
264 
265     DAYTIME_SERVER->set_version (release, patch_level);
266     DAYTIME_SERVER->set_author  ("Vladislav Grinchenko");
267     DAYTIME_SERVER->set_flags   (GenServer::RMLOG);
268 
269     DAYTIME_SERVER->init (&argc, argv, help_msg);
270 
271     DAYTIME_SERVER->init_service ();
272     DAYTIME_SERVER->process_events ();
273 
274     return DAYTIME_SERVER->get_exit_value ();
275 }
276 
277