compound_value_server.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. /* An XML-RPC server program written in C, as an example of using
  2. compound XML-RPC values.
  3. For a simple server program that just deals with integer values,
  4. see xmlrpc_sample_add_server.c. This example focuses just on the
  5. compound XML-RPC values and not the server functions.
  6. This server provides the example.divide XML-RPC method that the example
  7. client program compound_value_client.c invokes. See that program for
  8. details on what the method does.
  9. The program takes one argument: the HTTP port number on which the server
  10. is to accept connections, in decimal.
  11. Example:
  12. $ ./compound_value_server 8080&
  13. $ ./compound_value_client
  14. */
  15. #include <stdlib.h>
  16. #include <stdio.h>
  17. #include <xmlrpc-c/base.h>
  18. #include <xmlrpc-c/server.h>
  19. #include <xmlrpc-c/server_abyss.h>
  20. #include "config.h" /* information about this build environment */
  21. static void
  22. computeQuotient(xmlrpc_env * const envP,
  23. xmlrpc_value * const ratioP,
  24. xmlrpc_double * const quotientP) {
  25. xmlrpc_value * dividendP;
  26. xmlrpc_struct_find_value(envP, ratioP, "DIVIDEND", &dividendP);
  27. if (!envP->fault_occurred) {
  28. if (!dividendP)
  29. xmlrpc_env_set_fault(
  30. envP, 0, "Structure is missing 'DIVIDEND' member");
  31. else {
  32. xmlrpc_value * divisorP;
  33. xmlrpc_struct_find_value(envP, ratioP, "DIVISOR", &divisorP);
  34. if (!envP->fault_occurred) {
  35. if (!divisorP)
  36. xmlrpc_env_set_fault(
  37. envP, 0, "Structure is missing 'DIVISOR' member");
  38. else {
  39. xmlrpc_double dividend;
  40. xmlrpc_read_double(envP, dividendP, &dividend);
  41. if (!envP->fault_occurred) {
  42. xmlrpc_double divisor;
  43. xmlrpc_read_double(envP, divisorP, &divisor);
  44. if (!envP->fault_occurred)
  45. *quotientP = dividend / divisor;
  46. }
  47. xmlrpc_DECREF(divisorP);
  48. }
  49. }
  50. xmlrpc_DECREF(dividendP);
  51. }
  52. }
  53. }
  54. static void
  55. computeQuotients(xmlrpc_env * const envP,
  56. xmlrpc_value * const ratioArrayP,
  57. xmlrpc_value ** const quotientArrayPP) {
  58. xmlrpc_value * quotientArrayP;
  59. quotientArrayP = xmlrpc_array_new(envP);
  60. if (!envP->fault_occurred) {
  61. unsigned int const ratioCt = xmlrpc_array_size(envP, ratioArrayP);
  62. unsigned int i;
  63. for (i = 0; i < ratioCt && !envP->fault_occurred; ++i) {
  64. xmlrpc_value * ratioP;
  65. xmlrpc_array_read_item(envP, ratioArrayP, i, &ratioP);
  66. if (!envP->fault_occurred) {
  67. xmlrpc_double quotient;
  68. computeQuotient(envP, ratioP, &quotient);
  69. if (!envP->fault_occurred) {
  70. xmlrpc_value * quotientP;
  71. quotientP = xmlrpc_double_new(envP, quotient);
  72. if (!envP->fault_occurred) {
  73. xmlrpc_array_append_item(envP, quotientArrayP,
  74. quotientP);
  75. xmlrpc_DECREF(quotientP);
  76. }
  77. }
  78. xmlrpc_DECREF(ratioP);
  79. }
  80. }
  81. if (envP->fault_occurred)
  82. xmlrpc_DECREF(quotientArrayP);
  83. else
  84. *quotientArrayPP = quotientArrayP;
  85. }
  86. }
  87. static xmlrpc_value *
  88. example_divide(xmlrpc_env * const envP,
  89. xmlrpc_value * const paramArrayP,
  90. void * const serverInfo,
  91. void * const channelInfo) {
  92. xmlrpc_value * retvalP;
  93. xmlrpc_int32 argVersion;
  94. xmlrpc_value * ratioArrayP;
  95. xmlrpc_decompose_value(envP, paramArrayP, "(iA)",
  96. &argVersion, &ratioArrayP);
  97. if (envP->fault_occurred)
  98. return NULL;
  99. if (argVersion != 1) {
  100. xmlrpc_env_set_fault(envP, 0, "Parameter list version must be 1");
  101. return NULL;
  102. }
  103. computeQuotients(envP, ratioArrayP, &retvalP);
  104. xmlrpc_DECREF(ratioArrayP);
  105. if (envP->fault_occurred)
  106. return NULL;
  107. return retvalP;
  108. }
  109. int
  110. main(int const argc,
  111. const char ** const argv) {
  112. struct xmlrpc_method_info3 const methodInfo = {
  113. /* .methodName = */ "example.divide",
  114. /* .methodFunction = */ &example_divide,
  115. };
  116. xmlrpc_server_abyss_parms serverparm;
  117. xmlrpc_registry * registryP;
  118. xmlrpc_env env;
  119. if (argc-1 != 1) {
  120. fprintf(stderr, "You must specify 1 argument: The TCP port "
  121. "number on which the server will accept connections "
  122. "for RPCs (8080 is a common choice). "
  123. "You specified %d arguments.\n", argc-1);
  124. exit(1);
  125. }
  126. xmlrpc_env_init(&env);
  127. registryP = xmlrpc_registry_new(&env);
  128. xmlrpc_registry_add_method3(&env, registryP, &methodInfo);
  129. /* In the modern form of the Abyss API, we supply parameters in memory
  130. like a normal API. We select the modern form by setting
  131. config_file_name to NULL:
  132. */
  133. serverparm.config_file_name = NULL;
  134. serverparm.registryP = registryP;
  135. serverparm.port_number = atoi(argv[1]);
  136. serverparm.log_file_name = "/tmp/xmlrpc_log";
  137. printf("Running XML-RPC server...\n");
  138. xmlrpc_server_abyss(&env, &serverparm, XMLRPC_APSIZE(log_file_name));
  139. /* xmlrpc_server_abyss() never returns */
  140. return 0;
  141. }