xmlrpc_transport.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. /* Transport some XML to a server and get the response back, as if doing
  2. an XML-RPC call.
  3. */
  4. #define _XOPEN_SOURCE 600 /* Make sure strdup() is in <string.h> */
  5. #include <stdlib.h>
  6. #include <stdio.h>
  7. #include <string.h>
  8. #include "xmlrpc_config.h" /* information about this build environment */
  9. #include "casprintf.h"
  10. #include "mallocvar.h"
  11. #include "cmdline_parser.h"
  12. #include "xmlrpc-c/base.h"
  13. #include "xmlrpc-c/client.h"
  14. #define NAME "xmlrpc_transport command line program"
  15. #define VERSION "1.0"
  16. struct cmdlineInfo {
  17. const char * url;
  18. const char * username;
  19. const char * password;
  20. const char * transport;
  21. /* Name of XML transport he wants to use. NULL if he has no
  22. preference.
  23. */
  24. };
  25. static void
  26. die_if_fault_occurred (xmlrpc_env * const envP) {
  27. if (envP->fault_occurred) {
  28. fprintf(stderr, "Error: %s (%d)\n",
  29. envP->fault_string, envP->fault_code);
  30. exit(1);
  31. }
  32. }
  33. static void GNU_PRINTF_ATTR(2,3)
  34. setError(xmlrpc_env * const envP, const char format[], ...) {
  35. va_list args;
  36. const char * faultString;
  37. va_start(args, format);
  38. cvasprintf(&faultString, format, args);
  39. va_end(args);
  40. xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR, faultString);
  41. strfree(faultString);
  42. }
  43. static void
  44. processArguments(xmlrpc_env * const envP,
  45. cmdlineParser const cp,
  46. struct cmdlineInfo * const cmdlineP) {
  47. if (cmd_argumentCount(cp) < 1)
  48. setError(envP, "Not enough arguments. Need a URL.");
  49. else {
  50. cmdlineP->url = cmd_getArgument(cp, 0);
  51. }
  52. }
  53. static void
  54. parseCommandLine(xmlrpc_env * const envP,
  55. int const argc,
  56. const char ** const argv,
  57. struct cmdlineInfo * const cmdlineP) {
  58. cmdlineParser const cp = cmd_createOptionParser();
  59. const char * error;
  60. cmd_defineOption(cp, "transport", OPTTYPE_STRING);
  61. cmd_defineOption(cp, "username", OPTTYPE_STRING);
  62. cmd_defineOption(cp, "password", OPTTYPE_STRING);
  63. cmd_processOptions(cp, argc, argv, &error);
  64. if (error) {
  65. setError(envP, "Command syntax error. %s", error);
  66. strfree(error);
  67. } else {
  68. cmdlineP->username = cmd_getOptionValueString(cp, "username");
  69. cmdlineP->password = cmd_getOptionValueString(cp, "password");
  70. if (cmdlineP->username && !cmdlineP->password)
  71. setError(envP, "When you specify -username, you must also "
  72. "specify -password.");
  73. else {
  74. cmdlineP->transport = cmd_getOptionValueString(cp, "transport");
  75. processArguments(envP, cp, cmdlineP);
  76. }
  77. }
  78. cmd_destroyOptionParser(cp);
  79. }
  80. static void
  81. freeCmdline(struct cmdlineInfo const cmdline) {
  82. strfree(cmdline.url);
  83. if (cmdline.username)
  84. strfree(cmdline.username);
  85. if (cmdline.password)
  86. strfree(cmdline.password);
  87. if (cmdline.transport)
  88. strfree(cmdline.transport);
  89. }
  90. static void
  91. computeUrl(const char * const urlArg,
  92. const char ** const urlP) {
  93. if (strstr(urlArg, "://") != 0) {
  94. *urlP = strdup(urlArg);
  95. } else {
  96. casprintf(urlP, "http://%s/RPC2", urlArg);
  97. }
  98. }
  99. static void
  100. doCall(xmlrpc_env * const envP,
  101. const char * const transport,
  102. const xmlrpc_server_info * const serverInfoP,
  103. xmlrpc_mem_block * const callXmlP,
  104. xmlrpc_mem_block ** const respXmlPP) {
  105. struct xmlrpc_clientparms clientparms;
  106. clientparms.transport = transport;
  107. clientparms.transportparmsP = NULL;
  108. clientparms.transportparm_size = 0;
  109. xmlrpc_client_init2(envP, XMLRPC_CLIENT_NO_FLAGS, NAME, VERSION,
  110. &clientparms, XMLRPC_CPSIZE(transportparm_size));
  111. if (!envP->fault_occurred) {
  112. xmlrpc_client_transport_call(envP, NULL, serverInfoP,
  113. callXmlP, respXmlPP);
  114. xmlrpc_client_cleanup();
  115. }
  116. }
  117. static void
  118. createServerInfo(xmlrpc_env * const envP,
  119. const char * const serverUrl,
  120. const char * const userName,
  121. const char * const password,
  122. xmlrpc_server_info ** const serverInfoPP) {
  123. xmlrpc_server_info * serverInfoP;
  124. serverInfoP = xmlrpc_server_info_new(envP, serverUrl);
  125. if (!envP->fault_occurred) {
  126. if (userName) {
  127. xmlrpc_server_info_set_basic_auth(
  128. envP, serverInfoP, userName, password);
  129. }
  130. }
  131. *serverInfoPP = serverInfoP;
  132. }
  133. static void
  134. readFile(xmlrpc_env * const envP,
  135. FILE * const ifP,
  136. xmlrpc_mem_block ** const fileContentsPP) {
  137. xmlrpc_mem_block * fileContentsP;
  138. fileContentsP = XMLRPC_MEMBLOCK_NEW(char, envP, 0);
  139. while (!envP->fault_occurred && !feof(ifP)) {
  140. char buffer[4096];
  141. size_t bytesRead;
  142. bytesRead = fread(buffer, 1, sizeof(buffer), ifP);
  143. XMLRPC_MEMBLOCK_APPEND(char, envP,
  144. fileContentsP, buffer, bytesRead);
  145. }
  146. if (envP->fault_occurred)
  147. XMLRPC_MEMBLOCK_FREE(char, fileContentsP);
  148. *fileContentsPP = fileContentsP;
  149. }
  150. static void
  151. writeFile(xmlrpc_env * const envP,
  152. FILE * const ofP,
  153. xmlrpc_mem_block * const fileContentsP) {
  154. size_t totalWritten;
  155. totalWritten = 0;
  156. while (!envP->fault_occurred &&
  157. totalWritten < XMLRPC_MEMBLOCK_SIZE(char, fileContentsP)) {
  158. size_t bytesWritten;
  159. bytesWritten = fwrite(
  160. XMLRPC_MEMBLOCK_CONTENTS(char, fileContentsP) + totalWritten,
  161. 1,
  162. XMLRPC_MEMBLOCK_SIZE(char, fileContentsP) - totalWritten,
  163. ofP);
  164. if (bytesWritten < 1)
  165. xmlrpc_env_set_fault_formatted(
  166. envP, XMLRPC_INTERNAL_ERROR,
  167. "Error writing output");
  168. totalWritten -= bytesWritten;
  169. }
  170. }
  171. int
  172. main(int const argc,
  173. const char ** const argv) {
  174. struct cmdlineInfo cmdline;
  175. xmlrpc_env env;
  176. xmlrpc_mem_block * callXmlP;
  177. xmlrpc_mem_block * respXmlP;
  178. const char * url;
  179. xmlrpc_server_info * serverInfoP;
  180. xmlrpc_env_init(&env);
  181. parseCommandLine(&env, argc, argv, &cmdline);
  182. die_if_fault_occurred(&env);
  183. computeUrl(cmdline.url, &url);
  184. createServerInfo(&env, url, cmdline.username, cmdline.password,
  185. &serverInfoP);
  186. die_if_fault_occurred(&env);
  187. fprintf(stderr, "Reading call data from Standard Input...\n");
  188. readFile(&env, stdin, &callXmlP);
  189. die_if_fault_occurred(&env);
  190. fprintf(stderr, "Making call...\n");
  191. doCall(&env, cmdline.transport, serverInfoP, callXmlP,
  192. &respXmlP);
  193. die_if_fault_occurred(&env);
  194. fprintf(stderr, "Writing response data to Standard Output\n");
  195. writeFile(&env, stdout, respXmlP);
  196. die_if_fault_occurred(&env);
  197. XMLRPC_MEMBLOCK_FREE(char, callXmlP);
  198. XMLRPC_MEMBLOCK_FREE(char, respXmlP);
  199. strfree(url);
  200. freeCmdline(cmdline);
  201. xmlrpc_env_clean(&env);
  202. return 0;
  203. }