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