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