1 /***************************************************************************
2         val1_server.cpp  --  server for userland validator tests
3 
4     copyright            : (C) 2002-2007 by Ewald Arnold
5     email                : ulxmlrpcpp@ewald-arnold.de
6 
7     These validator functions are taken from the specs
8     on http://validator.xmlrpc.com/ and should also run from
9     their online validator website.
10 
11     $Id: val1_server.cpp 1151 2009-08-12 15:12:01Z ewald-arnold $
12 
13  ***************************************************************************/
14 
15 /**************************************************************************
16  *
17  * This program is free software; you can redistribute it and/or modify
18  * it under the terms of the GNU Lesser General Public License as
19  * published by the Free Software Foundation; either version 2 of the License,
20  * or (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU Lesser General Public License
28  * along with this program; if not, write to the Free Software
29  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
30  *
31  ***************************************************************************/
32 
33 #include <ulxmlrpcpp/ulxmlrpcpp.h>  // always first header
34 
35 #include <cstdlib>
36 #include <iostream>
37 #include <cstring>
38 #include <memory>
39 
40 #include <ulxmlrpcpp/ulxr_except.h>
41 #include <ulxmlrpcpp/ulxr_signature.h>
42 #include <ulxmlrpcpp/ulxr_dispatcher.h>
43 #include <ulxmlrpcpp/ulxr_http_protocol.h>
44 #include <ulxmlrpcpp/ulxr_tcpip_connection.h>
45 #include <ulxmlrpcpp/ulxr_ssl_connection.h>
46 
47 #include "util.c"
main(int argc,char ** argv)48 
49 using namespace ulxr;
50 
51 bool terminate_server = false;
52 
53 MethodResponse arrayOfStructs (const MethodCall &calldata)
54 {
55   if (calldata.numParams() != 1)
56     throw ParameterException(InvalidMethodParameterError,
57                              ULXR_PCHAR("Exactly 1 parameter allowed for \"")
58                              +calldata.getMethodName() + ULXR_PCHAR("\""));
59 
60   Array arr = calldata.getParam(0);
61   unsigned long sum = 0;
62   for (unsigned i = 0; i < arr.size(); ++i)
63   {
64      Struct str = arr.getItem(i);
65      Integer num = str.getMember(ULXR_PCHAR("curly"));
66      sum += num.getInteger();
67   }
68 
69   return MethodResponse (Integer(sum));;
70 }
71 
72 
73 MethodResponse countTheEntities (const MethodCall &calldata)
74 {
75   if (calldata.numParams() != 1)
76     throw ParameterException(InvalidMethodParameterError,
77                              ULXR_PCHAR("Exactly 1 parameter allowed for \"")
78                              +calldata.getMethodName() + ULXR_PCHAR("\""));
79 
80   CppString s = RpcString(calldata.getParam(0)).getString();
81   int leftangs = 0;
82   int rightangs = 0;
83   int ampers = 0;
84   int apos = 0;
85   int quotes = 0;
86   for (unsigned i = 0; i < s.length(); ++i)
87   {
88      switch(s[i])
89      {
90        case ULXR_CHAR('<'): ++leftangs;
91        break;
92 
93        case ULXR_CHAR('>'): ++rightangs;
94        break;
95 
96        case ULXR_CHAR('&'): ++ampers;
97        break;
98 
99        case ULXR_CHAR('\"'): ++quotes;
100        break;
101 
102        case ULXR_CHAR('\''): ++apos;
103        break;
104      }
105   }
106 
107   Struct str;
108   str.addMember(ULXR_PCHAR("ctLeftAngleBrackets"), Integer(leftangs));
109   str.addMember(ULXR_PCHAR("ctRightAngleBrackets"), Integer(rightangs));
110   str.addMember(ULXR_PCHAR("ctAmpersands"), Integer(ampers));
111   str.addMember(ULXR_PCHAR("ctApostrophes"), Integer(apos));
112   str.addMember(ULXR_PCHAR("ctQuotes"), Integer(quotes));
113 
114   return MethodResponse (str);
115 }
116 
117 
118 MethodResponse easyStructTest (const MethodCall &calldata)
119 {
120   if (calldata.numParams() != 1)
121     throw ParameterException(InvalidMethodParameterError,
122                              ULXR_PCHAR("Exactly 1 parameter allowed for \"")
123                              +calldata.getMethodName() + ULXR_CHAR("\""));
124 
125   Struct str = Struct(calldata.getParam(0));
126 
127   int sum = 0;
128 
129   Integer num = str.getMember(ULXR_CHAR("moe"));
130   sum += num.getInteger();
131 
132   num = str.getMember(ULXR_CHAR("larry"));
133   sum += num.getInteger();
134 
135   num = str.getMember(ULXR_CHAR("curly"));
136   sum += num.getInteger();
137 
138   return MethodResponse (Integer(sum));
139 }
140 
141 
142 MethodResponse echoStructTest (const MethodCall &calldata)
143 {
144   if (calldata.numParams() != 1)
145     throw ParameterException(InvalidMethodParameterError,
146                              ULXR_PCHAR("Exactly 1 parameter allowed for \"")
147                              +calldata.getMethodName() + ULXR_PCHAR("\""));
148 
149   Struct str = Struct(calldata.getParam(0));
150 
151 //   if (str.hasMember(ULXR_CHAR("mickey")) )
152 //   {
153 //     ULXR_COUT << ULXR_PCHAR("mickey ") << Base64(str.getMember(ULXR_PCHAR("mickey"))).getString() << std::endl;
154 //     ULXR_COUT << ULXR_PCHAR("mickey ") << Base64(str.getMember(ULXR_PCHAR("mickey"))).getBase64() << std::endl;
155 //   }
156 
157   return MethodResponse (str);
158 }
159 
160 
161 MethodResponse manyTypesTest(const MethodCall &calldata)
162 {
163   if (calldata.numParams() != 6)
164     throw ParameterException(InvalidMethodParameterError,
165                              ULXR_PCHAR("Exactly 6 parameter allowed for \"")
166                              +calldata.getMethodName() + ULXR_PCHAR("\""));
167 
168   Array arr;
169 
170   arr.addItem(Integer(calldata.getParam(0)));
171   arr.addItem(Boolean(calldata.getParam(1)));
172   arr.addItem(RpcString(calldata.getParam(2)));
173   arr.addItem(Double(calldata.getParam(3)));
174   arr.addItem(DateTime(calldata.getParam(4)));
175   arr.addItem(Base64(calldata.getParam(5)));
176 
177   return MethodResponse (arr);
178 }
179 
180 
181 MethodResponse moderateSizeArrayCheck(const MethodCall &calldata)
182 {
183   if (calldata.numParams() != 1)
184     throw ParameterException(InvalidMethodParameterError,
185                              ULXR_PCHAR("Exactly 1 parameter allowed for \"")
186                              +calldata.getMethodName() + ULXR_PCHAR("\""));
187 
188   Array arr = calldata.getParam(0);
189 
190   if (arr.size() < 2)
191     throw ParameterException(InvalidMethodParameterError,
192                              ULXR_PCHAR("Need at least 2 elements in the array parameter for \"")
193                              +calldata.getMethodName() + ULXR_PCHAR("\""));
194 
195  RpcString first =RpcString(arr.getItem(0)).getString();
196  RpcString last =RpcString(arr.getItem(arr.size()-1)).getString();
197 
198   return MethodResponse (RpcString(first.getString() + last.getString()));
199 }
200 
201 
202 MethodResponse nestedStructTest(const MethodCall &calldata)
203 {
204   if (calldata.numParams() != 1)
205     throw ParameterException(InvalidMethodParameterError,
206                              ULXR_PCHAR("Exactly 1 parameter allowed for \"")
207                              +calldata.getMethodName() + ULXR_PCHAR("\""));
208 
209   Struct years = Struct(calldata.getParam(0));
210   Struct months = years.getMember(ULXR_CHAR("2000"));
211   Struct days = months.getMember(ULXR_CHAR("04"));
212   Struct data = days.getMember(ULXR_CHAR("01"));
213 
214   int moe = Integer(data.getMember(ULXR_CHAR("moe"))).getInteger();
215   int larry = Integer(data.getMember(ULXR_CHAR("larry"))).getInteger();
216   int curly = Integer(data.getMember(ULXR_CHAR("curly"))).getInteger();
217 
218   return MethodResponse (Integer(moe+larry+curly));
219 }
220 
221 
222 MethodResponse simpleStructReturnTest(const MethodCall &calldata)
223 
224 {
225 
226   if (calldata.numParams() != 1)
227     throw ParameterException(InvalidMethodParameterError,
228                              ULXR_PCHAR("Exactly 1 parameter allowed for \"")
229                              +calldata.getMethodName() + ULXR_PCHAR("\""));
230 
231   int i = Integer(calldata.getParam(0)).getInteger();
232 
233   Struct str;
234   str.addMember(ULXR_CHAR("times10"), Integer(i * 10));
235   str.addMember(ULXR_CHAR("times100"), Integer(i * 100));
236   str.addMember(ULXR_CHAR("times1000"), Integer(i * 1000));
237 
238   return MethodResponse (str);
239 }
240 
241 
242 ulxr::MethodResponse shutdown (const ulxr::MethodCall &/*calldata*/)
243 {
244   ULXR_COUT << ULXR_PCHAR("got signal to shut down\n");
245   terminate_server = true;
246   return ulxr::MethodResponse(ulxr::Boolean(true));
247 }
248 
249 
250 int main(int argc, char **argv)
251 {
252   ulxr::intializeLog4J(argv[0]);
253 
254   ulxr::CppString host = ULXR_PCHAR("localhost");
255   if (argc > 1)
256     host = ULXR_GET_STRING(argv[1]);
257 
258   unsigned port = 32002;
259   if (argc > 2)
260     port = ulxr_atoi(argv[2]);
261 
262   bool persistent = haveOption(argc, argv, "persistent");
263   bool chunked = haveOption(argc, argv, "chunked");
264   bool wbxml = haveOption(argc, argv, "wbxml");
265   bool secure = haveOption(argc, argv, "ssl");
266 
267   ulxr::CppString sec = ULXR_PCHAR("unsecured");
268   if (secure)
269     sec = ULXR_PCHAR("secured");
270 
271   ULXR_COUT << ULXR_PCHAR("Serving ") << sec << ULXR_PCHAR(" rpc requests at ") << host << ULXR_PCHAR(":") << port << std::endl;
272   ULXR_COUT << ULXR_PCHAR("Chunked transfer: ") << chunked << std::endl;
273   ULXR_COUT << ULXR_PCHAR("WBXML: ") << wbxml << std::endl;
274 
275   std::auto_ptr<ulxr::TcpIpConnection> conn;
276 #ifdef ULXR_INCLUDE_SSL_STUFF
277   if (secure)
278   {
279     ulxr::SSLConnection *ssl = new ulxr::SSLConnection (true, host, port);
280     ssl->setCryptographyData("password", "foo-cert.pem", "foo-cert.pem");
281     conn.reset(ssl);
282   }
283   else
284 #endif
285 #ifdef _MSC_VER
286   {
287     std::auto_ptr<ulxr::TcpIpConnection> temp(new ulxr::TcpIpConnection (true, host, port));
288     conn = temp;
289   }
290 #else
291     conn.reset(new ulxr::TcpIpConnection (true, host, port));
292 #endif
293 
294   ulxr::HttpProtocol prot(conn.get());
295   ulxr::Dispatcher server(&prot, wbxml);
296   int res = 0;
297 
298   prot.setPersistent(persistent);
299   if (persistent)
300     conn->setTcpNoDelay(true);
301 
302   if (prot.isPersistent())
303      ULXR_COUT << ULXR_PCHAR("Using persistent connections\n") ;
304   else
305      ULXR_COUT << ULXR_PCHAR("Using non-persistent connections\n") ;
306 
307   prot.setChunkedTransfer(chunked);
308 
309   try
310   {
311     server.addMethod(&arrayOfStructs,
312                      Integer::getValueName(),
313                      ULXR_PCHAR("validator1.arrayOfStructs"),
314                      Array::getValueName(),
315                      ULXR_PCHAR("Validator function to tot up elements in a Struct"));
316 
317     server.addMethod(&countTheEntities,
318                      Struct::getValueName(),
319                      ULXR_PCHAR("validator1.countTheEntities"),
320                      RpcString::getValueName(),
321                      ULXR_PCHAR("Validator function to count some characters in a string"));
322 
323     server.addMethod(&easyStructTest,
324                      Integer::getValueName(),
325                      ULXR_PCHAR("validator1.easyStructTest"),
326                      Struct::getValueName(),
327                      ULXR_PCHAR("Validator function to tot up some Struct members"));
328 
329     server.addMethod(&echoStructTest,
330                      Struct::getValueName(),
331                      ULXR_PCHAR("validator1.echoStructTest"),
332                      Struct::getValueName(),
333                      ULXR_PCHAR("Validator function echoing a Struct completely back"));
334 
335     server.addMethod(&manyTypesTest,
336                      Array::getValueName(),
337                      ULXR_PCHAR("validator1.manyTypesTest"),
338                      Integer::getValueName()
339                      +ULXR_PCHAR(",") + Boolean::getValueName()
340                      +ULXR_PCHAR(",") + RpcString::getValueName()
341                      +ULXR_PCHAR(",") + Double::getValueName()
342                      +ULXR_PCHAR(",") + DateTime::getValueName()
343                      +ULXR_PCHAR(",") + Base64::getValueName(),
344                      ULXR_PCHAR("Validator function return all input parameters back as array"));
345 
346     server.addMethod(&moderateSizeArrayCheck,
347                      RpcString::getValueName(),
348                      ULXR_PCHAR("validator1.moderateSizeArrayCheck"),
349                      Array::getValueName(),
350                      ULXR_PCHAR("Validator function returns the first + the last elements of a string array"));
351 
352     server.addMethod(&nestedStructTest,
353                      Integer::getValueName(),
354                      ULXR_PCHAR("validator1.nestedStructTest"),
355                      Struct::getValueName(),
356                      ULXR_PCHAR("Validator function returns sum of nested elements"));
357 
358     server.addMethod(&simpleStructReturnTest,
359                      Struct::getValueName(),
360                      ULXR_PCHAR("validator1.simpleStructReturnTest"),
361                      Integer::getValueName(),
362                      ULXR_PCHAR("Validator function returns calculation with some nested elements"));
363 
364     server.addMethod(&shutdown,
365                      ulxr::Signature(),
366                      ULXR_PCHAR("shutdown"),
367                      ulxr::Signature(),
368                      ULXR_PCHAR("Shut down Worker"));
369 
370     for (unsigned i = 0; terminate_server == false /* i < 100 */; ++i)
371     {
372       ULXR_COUT << ULXR_PCHAR("Run ") << i << std::endl;
373       MethodCall call = server.waitForCall();
374       MethodResponse resp = server.dispatchCall(call);
375       if (!prot.isTransmitOnly())
376         server.sendResponse(resp);
377       if (!prot.isPersistent())
378         prot.close();
379     }
380 
381     if (prot.isPersistent())
382       ULXR_COUT << ULXR_PCHAR("Used persistent connections\n") ;
383     else
384       ULXR_COUT << ULXR_PCHAR("Used non-persistent connections\n") ;
385   }
386 
387   catch(XmlException& xmlex)
388   {
389      res = 1;
390      ULXR_COUT << ULXR_PCHAR("Xml Error occured: ") << ULXR_GET_STRING(xmlex.why()) << std::endl;
391      ULXR_COUT << ULXR_PCHAR("  in line ") << xmlex.getErrorLine()
392                << ULXR_PCHAR(". Reason: ") << ULXR_GET_STRING(xmlex.getErrorString()) << std::endl;
393 
394      if (prot.isOpen())
395      {
396        try{
397          MethodResponse resp(1, xmlex.why() );
398          if (!prot.isTransmitOnly())
399            server.sendResponse(resp);
400        }
401        catch(...)
402        {
403          ULXR_COUT << ULXR_PCHAR("error within exception occured\n");
404        }
405        prot.close();
406      }
407   }
408 
409   catch(Exception& ex)
410   {
411      res = 1;
412      ULXR_COUT << ULXR_PCHAR("Error occured: ") << ULXR_GET_STRING(ex.why()) << std::endl;
413      if (prot.isOpen())
414      {
415        try{
416          MethodResponse resp(1, ex.why() );
417          if (!prot.isTransmitOnly())
418            server.sendResponse(resp);
419        }
420        catch(...)
421        {
422          ULXR_COUT << ULXR_PCHAR("error within exception occured\n");
423        }
424        prot.close();
425      }
426   }
427 
428   ULXR_COUT << ULXR_PCHAR("Terminating.\n");
429   return res;
430 }
431