1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: samples/ipc/baseserver.cpp
3 // Purpose: IPC sample: console server
4 // Author: Anders Larsen
5 // Most of the code was stolen from: samples/ipc/server.cpp
6 // (c) Julian Smart, Jurgen Doornik
7 // Created: 2007-11-08
8 // Copyright: (c) 2007 Anders Larsen
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23
24 #ifndef WX_PRECOMP
25 #include "wx/wx.h"
26 #endif
27
28 // Settings common to both executables: determines whether
29 // we're using TCP/IP or real DDE.
30 #include "ipcsetup.h"
31
32 #include "connection.h"
33
34 #include "wx/timer.h"
35 #include "wx/datetime.h"
36
37 // ----------------------------------------------------------------------------
38 // local classes
39 // ----------------------------------------------------------------------------
40
41 // a simple connection class testing and logging various operations
42 class MyConnection : public MyConnectionBase, public wxTimer
43 {
44 public:
Disconnect()45 virtual bool Disconnect() wxOVERRIDE { return wxConnection::Disconnect(); }
46 virtual bool OnExecute(const wxString& topic,
47 const void *data,
48 size_t size,
49 wxIPCFormat format) wxOVERRIDE;
50 virtual const void *OnRequest(const wxString& topic,
51 const wxString& item,
52 size_t *size,
53 wxIPCFormat format) wxOVERRIDE;
54 virtual bool OnPoke(const wxString& topic,
55 const wxString& item,
56 const void *data,
57 size_t size,
58 wxIPCFormat format) wxOVERRIDE;
59 virtual bool OnStartAdvise(const wxString& topic, const wxString& item) wxOVERRIDE;
60 virtual bool OnStopAdvise(const wxString& topic, const wxString& item) wxOVERRIDE;
61 virtual bool DoAdvise(const wxString& item,
62 const void *data,
63 size_t size,
64 wxIPCFormat format) wxOVERRIDE;
65 virtual bool OnDisconnect() wxOVERRIDE;
66 virtual void Notify() wxOVERRIDE;
67
68 private:
69 wxString m_sAdvise;
70
71 wxString m_sRequestDate;
72 char m_achRequestBytes[3];
73 };
74
75 // a connection used for benchmarking some IPC operations by
76 // tests/benchmarks/ipcclient.cpp
77 class BenchConnection : public wxConnection
78 {
79 public:
BenchConnection()80 BenchConnection() { m_advise = false; }
81
82 virtual bool OnPoke(const wxString& topic,
83 const wxString& item,
84 const void *data,
85 size_t size,
86 wxIPCFormat format) wxOVERRIDE;
87 virtual bool OnStartAdvise(const wxString& topic, const wxString& item) wxOVERRIDE;
88 virtual bool OnStopAdvise(const wxString& topic, const wxString& item) wxOVERRIDE;
89
90 private:
91 // return true if this is the supported topic+item combination, log an
92 // error message otherwise
93 bool IsSupportedTopicAndItem(const wxString& operation,
94 const wxString& topic,
95 const wxString& item) const;
96
97 // the item which can be manipulated by the client via Poke() calls
98 wxString m_item;
99
100 // should we notify the client about changes to m_item?
101 bool m_advise;
102
103 wxDECLARE_NO_COPY_CLASS(BenchConnection);
104 };
105
106 // a simple server accepting connections to IPC_TOPIC and IPC_BENCHMARK_TOPIC
107 class MyServer : public wxServer
108 {
109 public:
110 MyServer();
111 virtual ~MyServer();
112 void Disconnect();
IsConnected()113 bool IsConnected() { return m_connection != NULL; }
114
115 virtual wxConnectionBase *OnAcceptConnection(const wxString& topic) wxOVERRIDE;
116
117 private:
118 wxConnection *m_connection;
119 };
120
121 // Define a new application
122 class MyApp : public wxApp
123 {
124 public:
125 virtual bool OnInit() wxOVERRIDE;
126
127 protected:
128 MyServer m_server;
129 };
130
131 wxDECLARE_APP(MyApp);
132
133 // ============================================================================
134 // implementation
135 // ============================================================================
136
137 wxIMPLEMENT_APP_CONSOLE(MyApp);
138
139 // ----------------------------------------------------------------------------
140 // MyApp
141 // ----------------------------------------------------------------------------
142
OnInit()143 bool MyApp::OnInit()
144 {
145 if ( !wxApp::OnInit() )
146 return false;
147
148 delete wxLog::SetActiveTarget(new wxLogStderr);
149
150 const char * const kind =
151 #if wxUSE_DDE_FOR_IPC
152 "DDE"
153 #else
154 "TCP"
155 #endif
156 ;
157
158 // Create a new server
159 if ( !m_server.Create(IPC_SERVICE) )
160 {
161 wxLogMessage("%s server failed to start on %s", kind, IPC_SERVICE);
162 return false;
163 }
164
165 wxLogMessage("%s server started on %s", kind, IPC_SERVICE);
166 return true;
167 }
168
169 // ----------------------------------------------------------------------------
170 // MyServer
171 // ----------------------------------------------------------------------------
172
MyServer()173 MyServer::MyServer()
174 {
175 m_connection = NULL;
176 }
177
~MyServer()178 MyServer::~MyServer()
179 {
180 Disconnect();
181 }
182
OnAcceptConnection(const wxString & topic)183 wxConnectionBase *MyServer::OnAcceptConnection(const wxString& topic)
184 {
185 wxLogMessage("OnAcceptConnection(\"%s\")", topic);
186
187 if ( topic == IPC_TOPIC )
188 {
189 m_connection = new MyConnection;
190 }
191 else if ( topic == IPC_BENCHMARK_TOPIC )
192 {
193 m_connection = new BenchConnection;
194 }
195 else // unknown topic
196 {
197 wxLogMessage("Unknown topic");
198 return NULL;
199 }
200
201 wxLogMessage("Connection accepted");
202 return m_connection;
203 }
204
Disconnect()205 void MyServer::Disconnect()
206 {
207 if ( m_connection )
208 {
209 m_connection->Disconnect();
210 wxDELETE(m_connection);
211 wxLogMessage("Disconnected client");
212 }
213 }
214
215 // ----------------------------------------------------------------------------
216 // MyConnection
217 // ----------------------------------------------------------------------------
218
219 bool
OnExecute(const wxString & topic,const void * data,size_t size,wxIPCFormat format)220 MyConnection::OnExecute(const wxString& topic,
221 const void *data,
222 size_t size,
223 wxIPCFormat format)
224 {
225 Log("OnExecute", topic, "", data, size, format);
226 return true;
227 }
228
229 bool
OnPoke(const wxString & topic,const wxString & item,const void * data,size_t size,wxIPCFormat format)230 MyConnection::OnPoke(const wxString& topic,
231 const wxString& item,
232 const void *data,
233 size_t size,
234 wxIPCFormat format)
235 {
236 Log("OnPoke", topic, item, data, size, format);
237 return wxConnection::OnPoke(topic, item, data, size, format);
238 }
239
240 const void *
OnRequest(const wxString & topic,const wxString & item,size_t * size,wxIPCFormat format)241 MyConnection::OnRequest(const wxString& topic,
242 const wxString& item,
243 size_t *size,
244 wxIPCFormat format)
245 {
246 const void *data;
247 if (item == "Date")
248 {
249 m_sRequestDate = wxDateTime::Now().Format();
250 data = m_sRequestDate.c_str();
251 *size = wxNO_LEN;
252 }
253 else if (item == "Date+len")
254 {
255 m_sRequestDate = wxDateTime::Now().FormatTime() +
256 " " + wxDateTime::Now().FormatDate();
257 data = m_sRequestDate.c_str();
258 *size = m_sRequestDate.Length() + 1;
259 }
260 else if (item == "bytes[3]")
261 {
262 data = m_achRequestBytes;
263 m_achRequestBytes[0] = '1';
264 m_achRequestBytes[1] = '2';
265 m_achRequestBytes[2] = '3';
266 *size = 3;
267 }
268 else
269 {
270 data = NULL;
271 *size = 0;
272 }
273 Log("OnRequest", topic, item, data, *size, format);
274 return data;
275 }
276
OnStartAdvise(const wxString & topic,const wxString & item)277 bool MyConnection::OnStartAdvise(const wxString& topic, const wxString& item)
278 {
279 wxLogMessage("OnStartAdvise(\"%s\",\"%s\")", topic, item);
280 wxLogMessage("Returning true");
281 m_sAdvise = item;
282 Start(3000); // schedule our Notify() to be called in 3 seconds
283 return true;
284 }
285
OnStopAdvise(const wxString & topic,const wxString & item)286 bool MyConnection::OnStopAdvise(const wxString& topic, const wxString& item)
287 {
288 wxLogMessage("OnStopAdvise(\"%s\",\"%s\")", topic, item);
289 wxLogMessage("Returning true");
290 m_sAdvise.clear();
291 Stop();
292 return true;
293 }
294
Notify()295 void MyConnection::Notify()
296 {
297 if (!m_sAdvise.empty())
298 {
299 wxString s = wxDateTime::Now().Format();
300 Advise(m_sAdvise, s);
301 s = wxDateTime::Now().FormatTime() + " "
302 + wxDateTime::Now().FormatDate();
303 Advise(m_sAdvise, s.mb_str(), s.length() + 1);
304
305 #if wxUSE_DDE_FOR_IPC
306 wxLogMessage("DDE Advise type argument cannot be wxIPC_PRIVATE. "
307 "The client will receive it as wxIPC_TEXT, "
308 "and receive the correct no of bytes, "
309 "but not print a correct log entry.");
310 #endif // DDE
311
312 char bytes[3];
313 bytes[0] = '1'; bytes[1] = '2'; bytes[2] = '3';
314 Advise(m_sAdvise, bytes, 3, wxIPC_PRIVATE);
315 // this works, but the log treats it as a string now
316 // m_connection->Advise(m_connection->m_sAdvise, bytes, 3, wxIPC_TEXT );
317 }
318 }
319
DoAdvise(const wxString & item,const void * data,size_t size,wxIPCFormat format)320 bool MyConnection::DoAdvise(const wxString& item,
321 const void *data,
322 size_t size,
323 wxIPCFormat format)
324 {
325 Log("Advise", "", item, data, size, format);
326 return wxConnection::DoAdvise(item, data, size, format);
327 }
328
OnDisconnect()329 bool MyConnection::OnDisconnect()
330 {
331 wxLogMessage("OnDisconnect()");
332 return true;
333 }
334
335 // ----------------------------------------------------------------------------
336 // BenchConnection
337 // ----------------------------------------------------------------------------
338
IsSupportedTopicAndItem(const wxString & operation,const wxString & topic,const wxString & item) const339 bool BenchConnection::IsSupportedTopicAndItem(const wxString& operation,
340 const wxString& topic,
341 const wxString& item) const
342 {
343 if ( topic != IPC_BENCHMARK_TOPIC ||
344 item != IPC_BENCHMARK_ITEM )
345 {
346 wxLogMessage("Unexpected %s(\"%s\", \"%s\") call.",
347 operation, topic, item);
348 return false;
349 }
350
351 return true;
352 }
353
OnPoke(const wxString & topic,const wxString & item,const void * data,size_t size,wxIPCFormat format)354 bool BenchConnection::OnPoke(const wxString& topic,
355 const wxString& item,
356 const void *data,
357 size_t size,
358 wxIPCFormat format)
359 {
360 if ( !IsSupportedTopicAndItem("OnPoke", topic, item) )
361 return false;
362
363 if ( !IsTextFormat(format) )
364 {
365 wxLogMessage("Unexpected format %d in OnPoke().", format);
366 return false;
367 }
368
369 m_item = GetTextFromData(data, size, format);
370
371 if ( m_advise )
372 {
373 if ( !Advise(item, m_item) )
374 {
375 wxLogMessage("Failed to advise client about the change.");
376 }
377 }
378
379 return true;
380 }
381
OnStartAdvise(const wxString & topic,const wxString & item)382 bool BenchConnection::OnStartAdvise(const wxString& topic, const wxString& item)
383 {
384 if ( !IsSupportedTopicAndItem("OnStartAdvise", topic, item) )
385 return false;
386
387 m_advise = true;
388
389 return true;
390 }
391
OnStopAdvise(const wxString & topic,const wxString & item)392 bool BenchConnection::OnStopAdvise(const wxString& topic, const wxString& item)
393 {
394 if ( !IsSupportedTopicAndItem("OnStopAdvise", topic, item) )
395 return false;
396
397 m_advise = false;
398
399 return true;
400 }
401
402