1//
2// TimeServer.cpp
3//
4// This sample demonstrates the TCPServer and ServerSocket classes.
5//
6// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
7// and Contributors.
8//
9// SPDX-License-Identifier: BSL-1.0
10//
11
12
13#include "Poco/Net/TCPServer.h"
14#include "Poco/Net/TCPServerConnection.h"
15#include "Poco/Net/TCPServerConnectionFactory.h"
16#include "Poco/Net/TCPServerParams.h"
17#include "Poco/Net/StreamSocket.h"
18#include "Poco/Net/ServerSocket.h"
19#include "Poco/Timestamp.h"
20#include "Poco/DateTimeFormatter.h"
21#include "Poco/DateTimeFormat.h"
22#include "Poco/Exception.h"
23#include "Poco/Util/ServerApplication.h"
24#include "Poco/Util/Option.h"
25#include "Poco/Util/OptionSet.h"
26#include "Poco/Util/HelpFormatter.h"
27#include <iostream>
28
29
30using Poco::Net::ServerSocket;
31using Poco::Net::StreamSocket;
32using Poco::Net::TCPServerConnection;
33using Poco::Net::TCPServerConnectionFactory;
34using Poco::Net::TCPServer;
35using Poco::Timestamp;
36using Poco::DateTimeFormatter;
37using Poco::DateTimeFormat;
38using Poco::Util::ServerApplication;
39using Poco::Util::Application;
40using Poco::Util::Option;
41using Poco::Util::OptionSet;
42using Poco::Util::HelpFormatter;
43
44
45class TimeServerConnection: public TCPServerConnection
46 /// This class handles all client connections.
47 ///
48 /// A string with the current date and time is sent back to the client.
49{
50public:
51 TimeServerConnection(const StreamSocket& s, const std::string& format):
52 TCPServerConnection(s),
53 _format(format)
54 {
55 }
56
57 void run()
58 {
59 Application& app = Application::instance();
60 app.logger().information("Request from " + this->socket().peerAddress().toString());
61 try
62 {
63 Timestamp now;
64 std::string dt(DateTimeFormatter::format(now, _format));
65 dt.append("\r\n");
66 socket().sendBytes(dt.data(), (int) dt.length());
67 }
68 catch (Poco::Exception& exc)
69 {
70 app.logger().log(exc);
71 }
72 }
73
74private:
75 std::string _format;
76};
77
78
79class TimeServerConnectionFactory: public TCPServerConnectionFactory
80 /// A factory for TimeServerConnection.
81{
82public:
83 TimeServerConnectionFactory(const std::string& format):
84 _format(format)
85 {
86 }
87
88 TCPServerConnection* createConnection(const StreamSocket& socket)
89 {
90 return new TimeServerConnection(socket, _format);
91 }
92
93private:
94 std::string _format;
95};
96
97
98class TimeServer: public Poco::Util::ServerApplication
99 /// The main application class.
100 ///
101 /// This class handles command-line arguments and
102 /// configuration files.
103 /// Start the TimeServer executable with the help
104 /// option (/help on Windows, --help on Unix) for
105 /// the available command line options.
106 ///
107 /// To use the sample configuration file (TimeServer.properties),
108 /// copy the file to the directory where the TimeServer executable
109 /// resides. If you start the debug version of the TimeServer
110 /// (TimeServerd[.exe]), you must also create a copy of the configuration
111 /// file named TimeServerd.properties. In the configuration file, you
112 /// can specify the port on which the server is listening (default
113 /// 9911) and the format of the date/time string sent back to the client.
114 ///
115 /// To test the TimeServer you can use any telnet client (telnet localhost 9911).
116{
117public:
118 TimeServer(): _helpRequested(false)
119 {
120 }
121
122 ~TimeServer()
123 {
124 }
125
126protected:
127 void initialize(Application& self)
128 {
129 loadConfiguration(); // load default configuration files, if present
130 ServerApplication::initialize(self);
131 }
132
133 void uninitialize()
134 {
135 ServerApplication::uninitialize();
136 }
137
138 void defineOptions(OptionSet& options)
139 {
140 ServerApplication::defineOptions(options);
141
142 options.addOption(
143 Option("help", "h", "display help information on command line arguments")
144 .required(false)
145 .repeatable(false));
146 }
147
148 void handleOption(const std::string& name, const std::string& value)
149 {
150 ServerApplication::handleOption(name, value);
151
152 if (name == "help")
153 _helpRequested = true;
154 }
155
156 void displayHelp()
157 {
158 HelpFormatter helpFormatter(options());
159 helpFormatter.setCommand(commandName());
160 helpFormatter.setUsage("OPTIONS");
161 helpFormatter.setHeader("A server application that serves the current date and time.");
162 helpFormatter.format(std::cout);
163 }
164
165 int main(const std::vector<std::string>& args)
166 {
167 if (_helpRequested)
168 {
169 displayHelp();
170 }
171 else
172 {
173 // get parameters from configuration file
174 unsigned short port = (unsigned short) config().getInt("TimeServer.port", 9911);
175 std::string format(config().getString("TimeServer.format", DateTimeFormat::ISO8601_FORMAT));
176
177 // set-up a server socket
178 ServerSocket svs(port);
179 // set-up a TCPServer instance
180 TCPServer srv(new TimeServerConnectionFactory(format), svs);
181 // start the TCPServer
182 srv.start();
183 // wait for CTRL-C or kill
184 waitForTerminationRequest();
185 // Stop the TCPServer
186 srv.stop();
187 }
188 return Application::EXIT_OK;
189 }
190
191private:
192 bool _helpRequested;
193};
194
195
196int main(int argc, char** argv)
197{
198 TimeServer app;
199 return app.run(argc, argv);
200}
201