1 /***************************************************************************
2        introspect.cpp  --  lists information about available methods
3 
4     copyright            : (C) 2002-2007 by Ewald Arnold
5     email                : ulxmlrpcpp@ewald-arnold.de
6 
7     $Id: introspect.cpp 1151 2009-08-12 15:12:01Z ewald-arnold $
8 
9  ***************************************************************************/
10 
11 /**************************************************************************
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU Lesser General Public License as
15  * published by the Free Software Foundation; either version 2 of the License,
16  * or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU Lesser General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26  *
27  ***************************************************************************/
28 
29 #include <ulxmlrpcpp/ulxmlrpcpp.h>  // always first header
30 
31 #include <cstdlib>
32 #include <cstdio>
33 
34 #include <ulxmlrpcpp/ulxr_tcpip_connection.h> // first, don't move: important msvc #include bug
35 #include <ulxmlrpcpp/ulxr_requester.h>
36 #include <ulxmlrpcpp/ulxr_value.h>
37 #include <ulxmlrpcpp/ulxr_except.h>
38 #include <ulxmlrpcpp/ulxr_http_protocol.h>
39 #include <ulxmlrpcpp/ulxr_log4j.h>
40 
41 using namespace ulxr;
42 
43 #include <iostream>
44 
splitUrl(const std::string & url,ulxr::CppString & server,ulxr::CppString & resource,unsigned & port)45 bool splitUrl(const std::string &url,
46               ulxr::CppString &server,
47               ulxr::CppString &resource,
48               unsigned &port)
49 {
50   server = ULXR_GET_STRING(url);
51   std::size_t pos;
52 
53   if ((pos = server.find('/') ) != ulxr::CppString::npos)
54   {
55       resource = server.substr(pos);
56       server.erase(pos);
57   }
58 
59   if ((pos = server.find(':')) != ulxr::CppString::npos)
60   {
61       ulxr::CppString ps = server.substr(pos+1);
62       char *endp;
63       std::string s = getLatin1(ps);
64       port = strtol(s.c_str(), &endp, 10);
65       if (endp != 0 && *endp != '\0')
66       {
67         ULXR_CERR << ULXR_PCHAR( "Error in port number: ")
68                   << ULXR_GET_STRING(endp) << ULXR_PCHAR("\n\n");
69         return false;
70       }
71       server.erase(pos);
72   }
73 
74   return true;
75 }
76 
77 
usage()78 void usage()
79 {
80   ULXR_CERR << ULXR_PCHAR("usage:\n")
81             << ULXR_PCHAR(" --host=server:port/resource \n")
82             << ULXR_PCHAR("   [--use-proxy=host:port]\n")
83             << ULXR_PCHAR("   [--cpp-decl=filename]\n")
84             << ULXR_PCHAR("   [--cpp-impl=filename]\n")
85             << ULXR_PCHAR(" example: introspect --host=myhost.com:80/rpc/server.php --use-proxy=host:8080\n")
86             << ULXR_PCHAR("\n");
87 }
88 
89 
main(int argc,char ** argv)90 int main(int argc, char **argv)
91 {
92   try
93   {
94     ulxr::intializeLog4J(argv[0]);
95     ulxr::getLogger4J()->send(ULXR_PCHAR("DEBUG"),
96                               ULXR_PCHAR("introspect started"),
97                               ULXR_GET_STRING(__FILE__),
98                               __LINE__);
99     if (argc < 2)
100     {
101       usage();
102       return 1;
103     }
104 
105     unsigned proxyport = 0;
106     ulxr::CppString proxyname;
107 
108     unsigned port = 80;
109     ulxr::CppString resource = ULXR_PCHAR("/");
110     ulxr::CppString server;
111     bool have_host = false;
112 
113     std::string declfile;
114     std::string implfile;
115 
116     for (int i = 1; i < argc; ++i)
117     {
118       std::string arg = argv[i];
119       if (arg.substr(0, 12) == "--use-proxy=")
120       {
121         proxyport = 8080;
122         ulxr::CppString rsc;
123         if (!splitUrl(arg.substr(12), proxyname, rsc, proxyport))
124         {
125           usage();
126           return 1;
127         }
128       }
129 
130       else if (arg.substr(0, 7) == "--host=")
131       {
132         have_host = true;
133         if (!splitUrl(arg.substr(7), server, resource, port))
134         {
135           usage();
136           return 1;
137         }
138       }
139 
140       else if (arg.substr(0, 11) == "--cpp-decl=")
141         declfile = arg.substr(11);
142 
143       else if (arg.substr(0, 11) == "--cpp-impl=")
144         implfile = arg.substr(11);
145 
146       else
147       {
148         std::cerr << "Unknown option: " << arg << std::endl;
149         {
150           usage();
151           return 1;
152         }
153       }
154     }
155 
156     if (!have_host)
157     {
158       std::cerr << "No target host given\n";
159       usage();
160       return 1;
161     }
162 
163     ULXR_COUT << ULXR_PCHAR("Connecting to ")
164               << server << ULXR_PCHAR(":") << port << resource
165               << ULXR_PCHAR("\n");
166 
167     Integer i(1);
168     TcpIpConnection conn (false, server, port);
169 
170     if (proxyport != 0 && proxyname.length() != 0)
171     {
172       ULXR_COUT << ULXR_PCHAR("using http proxy ")
173                 << proxyname << ULXR_PCHAR(":") << proxyport
174                 << ULXR_PCHAR("\n");
175       conn.setProxy(proxyname, proxyport);
176     }
177     HttpProtocol prot(&conn);
178     Requester client(&prot);
179     MethodResponse resp;
180 
181     MethodCall list_methods (ULXR_PCHAR("system.listMethods"));
182     MethodCall method_help (ULXR_PCHAR("system.methodHelp"));
183     MethodCall method_sig (ULXR_PCHAR("system.methodSignature"));
184     MethodCall get_capabilities (ULXR_PCHAR("system.getCapabilities"));
185 
186     resp = client.call(list_methods, resource);
187     Array meth = resp.getResult();
188 
189     bool have_capabilities = false;
190     ULXR_COUT << ULXR_PCHAR("Found ") << meth.size() <<  ULXR_PCHAR(" methods:\n\n");
191 
192     std::FILE *decl_fs = 0;
193     if (declfile.length() != 0)
194       decl_fs = std::fopen(declfile.c_str(), "w");
195 
196     std::FILE *impl_fs = 0;
197     if (implfile.length() != 0)
198       impl_fs = std::fopen(implfile.c_str(), "w");
199 
200     for (unsigned m = 0; m < meth.size(); ++m)
201     {
202       RpcString name = meth.getItem(m);
203       if (name.getString() == get_capabilities.getMethodName() )
204         have_capabilities = true;
205 
206       ULXR_COUT << m+1 << ULXR_PCHAR(") ") << name.getString() << std::endl;
207       method_sig.clear();
208       method_sig.addParam(name);
209       resp = client.call(method_sig, resource);
210       ulxr::CppString signature;
211       ulxr::CppString purpose;
212       if (resp.getResult().getType() == RpcArray)
213       {
214         Array meths = resp.getResult();
215         for (unsigned ms = 0; ms < meths.size(); ++ms)
216         {
217           Array sign = meths.getItem(ms);
218           signature.clear();
219           for (unsigned is = 0; is < sign.size(); ++is)
220           {
221              if (signature.length() != 0)
222                signature += ULXR_PCHAR(", ");
223              signature +=RpcString(sign.getItem(is)).getString();
224           }
225           ULXR_COUT << ULXR_PCHAR(" Signature: ") << signature << ULXR_PCHAR("\n");
226         }
227         ULXR_COUT << ULXR_PCHAR("\n");
228       }
229       else
230       {
231         signature = ULXR_PCHAR("not available");
232         ULXR_COUT << ULXR_PCHAR(" Signature: none available\n\n");
233       }
234 
235       method_help.clear();
236       method_help.addParam(name);
237       resp = client.call(method_help, resource);
238       purpose = RpcString(resp.getResult()).getString();
239       ulxr::CppString cpurpose = purpose;
240 
241       unsigned pos = 0;
242       bool multi = false;
243       while ((pos = cpurpose.find(L'\n', pos)) != ulxr::CppString::npos)
244       {
245         multi = true;
246          cpurpose.insert(pos+1, ULXR_PCHAR("  // "));
247          pos += 1;   // 2 spaces indentation
248       }
249       if (multi)
250         cpurpose.insert(0, ULXR_PCHAR("\n  // "));
251 
252       pos = 0;
253       while ((pos = purpose.find('\n', pos)) != ulxr::CppString::npos)
254       {
255          purpose.insert (pos+1, ULXR_PCHAR("  "));
256          pos += 3;   // 2 spaces indentation
257       }
258 
259       ULXR_COUT << ULXR_PCHAR(" Documentation: \n")
260                << ULXR_PCHAR("  ") << purpose << ULXR_PCHAR("\n\n");
261 
262       std::string s = ulxr::getLatin1(name.getString());
263       std::string cname = s;
264       while((pos = cname.find(".")) != std::string::npos)
265         cname[pos] = '_';
266 
267       if (decl_fs != 0)
268       {
269         if (m == 0)
270           std::fprintf(decl_fs, "\n///////////////////////////////////////////////////////\n"
271                                 "// XMLRPC Methods imported from %s\n\n", ulxr::getLatin1(server+resource).c_str());
272 
273         std::fprintf(decl_fs, "  // signature: %s\n", ulxr::getLatin1(signature).c_str() );
274         std::fprintf(decl_fs, "  // purpose:   %s\n", ulxr::getLatin1(cpurpose).c_str() );
275         std::fprintf(decl_fs, "  ulxr::MethodCall %s;\n\n", cname.c_str());
276       }
277 
278       if (impl_fs != 0)
279         std::fprintf(impl_fs, "  , %s (ULXR_PCHAR(\"%s\"))\n", cname.c_str(), s.c_str() );
280     }
281 
282     if (decl_fs != 0)
283       std::fprintf(decl_fs, "///////////////////////////////////////////////////////\n\n");
284 
285     if (impl_fs != 0)
286       std::fclose(impl_fs);
287 
288     if (decl_fs != 0)
289       std::fclose(decl_fs);
290 
291     ULXR_COUT << ULXR_PCHAR("Checking for well known system capabilities:\n");
292     if (have_capabilities)
293     {
294       resp = client.call(get_capabilities, resource);
295       Struct cap = resp.getResult();
296       if (cap.hasMember(ULXR_PCHAR("faults_interop")))
297       {
298         Struct inter = cap.getMember(ULXR_PCHAR("faults_interop"));
299         RpcString url = inter.getMember(ULXR_PCHAR("specUrl"));
300         Integer vers = inter.getMember(ULXR_PCHAR("specVersion"));
301 
302        ULXR_COUT << ULXR_PCHAR(" Server supports interoperational fault codes as defined at:\n ")
303                  << url.getString() << ULXR_PCHAR(" with version ")
304                  << vers.getInteger() << std::endl;
305       }
306     }
307     else
308      ULXR_COUT << ULXR_PCHAR(" None avaliable.\n");
309   }
310 
311   catch(XmlException &ex)
312   {
313     ULXR_COUT << ULXR_PCHAR("Xml Error occured: ") << ex.why()
314               << ULXR_PCHAR(" (") << ex.getErrorString() << ULXR_PCHAR(") ")
315               << ULXR_PCHAR(" in line ") << ex.getErrorLine() << std::endl;
316   }
317   catch(Exception &ex)
318   {
319     ULXR_COUT << ULXR_PCHAR("Error occured: ") << ex.why() << std::endl;
320     return 1;
321   }
322   catch(std::exception &ex)
323   {
324      ULXR_COUT << ULXR_PCHAR("Error occured: ") << ULXR_GET_STRING(ex.what()) << std::endl;
325      return 1;
326   }
327   catch(...)
328   {
329      ULXR_COUT << ULXR_PCHAR("unknown Error occured.\n");
330      return 1;
331   }
332 
333   return 0;
334 }
335