The Winamp Remote Control suite
a remote control client and plugin for Winamp 2.x, 5.x
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
RPCExecutor.cpp
Go to the documentation of this file.
1 /*
2  * RPCServer.cpp
3  *
4  * Created on: 4 Nov 2012
5  * Author: Patrick
6  */
7 
8 
9 #include "RPCExecutor.h"
10 #include "RPCErrors.h"
11 
12 // problem with definition of __try - this gets round out with no problems
13 #define __try try
14 
15 #include "winampinterface.h" // header file generated by MIDL compiler
16 
17 // winamp interface
18 #include "waint.h"
19 
20 //RPC errors
21 #include "RPCErrors.h"
22 
23 #include "RPCExecutor.h"
24 
25 #include <sstream>
26 
27 using namespace std;
28 
29 
30 void * __stdcall MIDL_user_allocate(size_t size)
31 {
32  return malloc(size);
33 }
34 
35 void __stdcall MIDL_user_free(void * mem)
36 {
37  free(mem);
38 }
39 
40 
41 namespace WinampRemote
42 {
43 namespace Server
44 {
45 
46 RPCExecutor::RPCExecutor() : m_callObserver(), m_winamp(),
47  m_protocolSequence("ncacn_np"),
48  m_endPoint("\\pipe\\winampremote"),
49  m_executionStatus(waInactive)
50 {
51 
52 }
53 
55 {
56  // as Execute blocks, given destruction happens on the same thread
57  // no need to ensure shutdown was happened
58 }
59 
61 {
62  return m_protocolSequence;
63 }
64 
65 void RPCExecutor::setProtocolSequence(const std::string value)
66 {
67  m_protocolSequence = value;
68 }
69 
70 std::string RPCExecutor::getEndpoint() const
71 {
72  return m_protocolSequence;
73 }
74 
75 void RPCExecutor::setEndpoint(const std::string value)
76 {
77  m_protocolSequence = value;
78 }
79 
81 {
82  static RPCExecutor instance;
83 
84  return instance;
85 }
86 
88 {
89  return m_winamp;
90 }
91 
92 
94 {
95  m_winamp = winampServer;
96 }
97 
99 {
100  return m_callObserver;
101 }
102 
104 {
105  m_callObserver = callObserver;
106 }
107 
109 {
110  // tempting to throw an exception here
111  if (!m_callObserver)
112  {
114  return;
115  }
116  if (!m_winamp)
117  {
118  m_callObserver->notifyException("winamp implementation is not set");
120  return;
121  }
122 
123  std::string str;
124  RPC_STATUS status;
125  // "ncacn_np" for named pip
126  // "ncacn_ip_tcp" for tcpip
127 
128  m_callObserver->notifyStatus("initialising...");
129 
130  m_callObserver->notifyMessage(m_winamp->WinampVersion().c_str());
131 
133  status = RpcServerUseProtseqEp((unsigned char *) m_protocolSequence.c_str(),
134  20,
135  (unsigned char *) m_endPoint.c_str(),
136  NULL);
137 
138  if (status == RPC_S_OK){
139  status = RpcServerRegisterIf(winamp_v1_0_s_ifspec, NULL, NULL);
140  if (status == RPC_S_OK){
141  m_callObserver->notifyMessage("listening...");
143  status = RpcServerListen(1, 20, FALSE);
144  if (status != RPC_S_OK){
146  m_callObserver->notifyException("error in listening");
147  m_callObserver->notifyException(RPCError(status));
148  }
149  }
150  else{
152  m_callObserver->notifyException("failed to register interface");
153  m_callObserver->notifyException(RPCError(status));
154  m_callObserver->notifyException("initialise failed");
155  }
156  }
157  else{
159  m_callObserver->notifyException("failed to create protocol sequence");
160  m_callObserver->notifyException(RPCError(status));
161  m_callObserver->notifyException("initialise failed");
162  }
164 
165 }
166 
168 {
169  m_executionStatus = status;
170 }
171 
173 {
174  return m_executionStatus;
175 }
176 
177 
178 } /* namespace Server */
179 } /* namespace WinampRemote */
180 
181 
182 static void inline MainMessage(const char * msgString)
183 {
185 }
186 
187 static void inline MainStatus(const char * msgString)
188 {
190 }
191 
193 {
195 }
196 
197 string queryLogFormat(const char * strSender, long command, long data)
198 {
199 
200  stringstream sstr;
201  sstr.str() = strSender;
202  sstr << " sent - query : " << WinampCommand(command) << " - data : " << data;
203  return sstr.str();
204 
205 }
206 
207 string commandLogFormat(const char * strSender, long command, const char * strParam = NULL)
208 {
209  stringstream sstr;
210  sstr.str() = (char *) strSender;
211  sstr << " sent - command : " << WinampCommand(command);
212  if (strParam)
213  sstr << " - parameter : " << strParam;
214  return sstr.str();
215 }
216 
217 
218 /*note __RPC_FAR is literally nothing, but is left in for consistency
219 - none of the MIDL generated code should need direct modification*/
220 
226  /* [string][in] */ unsigned char __RPC_FAR *pszString)
227 {
228 
229  std::string str = (char *) pszString;
230  str += " sent hello";
231  MainMessage(str.c_str());
232  MainStatus("listening...");
233 
234 }
235 
242  /* [string][in] */ unsigned char __RPC_FAR *pszString,
243  /* [in] */ long command)
244 {
245 
246  MainMessage( commandLogFormat( (const char *) pszString, command).c_str());
248  MainStatus("listening...");
249 
250 }
251 
252 
260  /* [string][in] */ unsigned char __RPC_FAR *pszString,
261  /* [string][in] */ unsigned char __RPC_FAR *pszParam,
262  /* [in] */ long command)
263 {
264 
265  MainMessage( commandLogFormat( (const char *) pszString, command, (const char *) pszParam).c_str());
266  winampServer()->ExecuteStringCommand((const char *) pszParam, WinampCommand(command) );
267  MainStatus("listening...");
268 
269 }
270 
278  /* [string][in] */ unsigned char __RPC_FAR *pszString,
279  /* [in] */ long command,
280  /* [in] */ long data)
281 {
282 
283  MainMessage( queryLogFormat( (const char *) pszString, command, data).c_str());
284 
285  long retval = winampServer()->QueryInt( (WinampCommand) command, data);
286  MainStatus("listening");
287  return retval;
288 
289 }
290 
298  /* [string][out][in] */ unsigned char __RPC_FAR pszString[ 260 ],
299  /* [in] */ long command,
300  /* [in] */ long data)
301 {
302 
303  MainMessage( queryLogFormat( (const char *) pszString, command, data).c_str());
304 
305  std::string str = winampServer()->QueryString( static_cast<WinampCommand>(command), data).c_str();
306 
307  strcpy((char *) pszString, str.c_str());
308  MainStatus("listening...");
309 
310  // TODO: return non-zero when error handling is implemented
311  return 0;
312 
313 }
314 
318 void WAShutdown(void)
319 {
320  RpcMgmtStopServerListening(NULL);
321  RpcServerUnregisterIf(NULL, NULL, FALSE);
322  MainStatus("not listening");
323  MainMessage("asked to close");
324  // TODO: need to implement WAExecutionStatus report status
325 
326 }
327 
336  /* [string][in] */ unsigned char __RPC_FAR *pszString,
337  /* [in][size_is] */ byte __RPC_FAR Buffer[ ],
338  /* [in] */ unsigned long BufferLength,
339  /* [in] */ long command)
340 {
341 
342  // TODO: implement logging
343  stringstream sstr (string( (char *) Buffer));
344  string line;
346 
347  while (std::getline(sstr, line))
348  {
349  winampServer()->ExecuteStringCommand(line.c_str(), static_cast<WinampCommand>(command));
350  }
351  MainStatus("listening...");
352 
353  // TODO: notification for exceptions
354 
355 }
356 
357 
358 inline static void populateBuffer(BUFFER * pBuffer, std::string& buffer)
359 {
360 
361  pBuffer->BufferLength = 0;
362  int strlen = buffer.size();
363  // FIXME check this results in the RPC RT returning the memory
364  pBuffer->Buffer = (byte *) MIDL_user_allocate(strlen + 1);
365  if (pBuffer->Buffer)
366  {
367  pBuffer->BufferLength = strlen + 1;
368  memcpy(pBuffer->Buffer, buffer.c_str(), pBuffer->BufferLength);
369  }
370 
371 }
372 
380  /* [string][in] */ unsigned char __RPC_FAR *pszString,
381  /* [out] */ BUFFER __RPC_FAR *pBuffer,
382  /* [in] */ long command)
383 {
384 
385 
386  std::stringstream list;
387 
388  int listLength = winampServer()->QueryInt(IPC_GETLISTLENGTH, 0);
389  for (int i = 0 ; i < listLength ; i++)
390  {
391  if (i)
392  list << std::endl;
393  list << winampServer()->QueryString(static_cast<WinampCommand>(command), i);
394  }
395 
396  populateBuffer(pBuffer, list.str());
397  // TODO: no logging at all here
398  MainStatus("listening...");
399 
400  // TODO: notification for exceptions
401 
402 }
403 
413  /* [string][in] */ unsigned char __RPC_FAR *pszString,
414  /* [out] */ BUFFER __RPC_FAR *pBuffer,
415  /* [in] */ long stringcommand,
416  /* [in] */ long datacommand,
417  /* [in] */ long datadata)
418 {
419 
420  // TODO: no test coverage exists for this function
421  std::stringstream list;
422  for (int i = 0 ; i < 20; i++ )
423  {
424  if (i)
425  list << std::endl;
426  list << "string #" << i << std::endl;
427  list << "value #" << i;
428  }
429 
430  populateBuffer(pBuffer, list.str());
431  MainStatus("listening...");
432 
433  // TODO: notification for exceptions
434 
435 }