gsoap_calcserver.c

Interim Notes:

caveats

client code (no drama here)

// ===================================================================
// title   : calcclient_102.c (copied from gsoap ver 2.8.117)
// source  : https://www.genivia.com/examples/calc/index.html
// purpose : Example calculator client in C
// changes : Neil Rieck (Waterloo, Ontario, Canada)
// platform: CentOS-7 or Rocky-8
// prepare :
//  1) yum install gsoap\*		# CentOS-7
//     dnf install gsoap\*		# Rocky-8
// build   :
//  1) soapcpp2 -c -x calc.h  		# generate wsdl from calc.h 
//  2) gcc -o calcclient calcclient_102.c soapC.c soapClient.c -lgsoap
//  3) gcc -o calcserver calcserver_101.c soapC.c soapServer.c -lgsoap -lm
// test-1  :
//  1) ./calcserver 5001
//  2) ./calcclient add 123 456
// notes   :
//  1) I installed gsoap-2.8.16 via 'yum'
//  2) Many of the new demos are targeted to a higher version
//  3) Some tweaks are needed for use with gcc on Linux (CentOS-7)
//  4) connecting to calcserve2 is done by cgi-bin
// 5) connecting to calcserve3 is done by the mod_gsoap plugin // history : // 20211207 NSR copied source code here // 20211207 NSR modified for use with CentOS-7 (see aaa_help.txt) // 20230216 NSR updated for start of next phase project // =================================================================== #include "soapH.h" #include "calc.nsmap" char *url[] = { // array of string pointers "http://websrv.cs.fsu.edu/~engelen/calcserver.cgi", "http://localhost:5001", "http://kawc4n.on.bell.ca/cgi-bin/calcserver2", "http://kawc4n.on.bell.ca/calcserver3"}; char server[255]; char buffer[255]; int choice; int i; int menusize; // // the big kahoona // int main(int argc, char **argv) { struct soap soap; double a, b, result; if (argc < 4){ fprintf(stderr, "Usage: %s [add|sub|mul|div|pow] num num\n", argv[0]); exit(0); } printf("Program: %s\n", argv[0]); printf("Destination Menu:\n"); menusize = sizeof(url) / sizeof(url[0]); for(i=0;i<menusize;i++){ printf(" %ld %s\n",i+1, url[i]); } printf(" 1024-5999 for any local port\n"); printf("choice? "); fgets(buffer, sizeof (buffer), stdin); for (i=0; sizeof (buffer); i++){ if (buffer[i] == '\n'){ buffer[i] = '\0'; break; } } choice = strtol(buffer, NULL, 10); if ((choice > 0) && (choice <= menusize)){ sprintf(server,"%s", url[choice-1]); } else if ((choice >=1024) && (choice <=5999)){ sprintf(server,"%s%s","http://localhost:",buffer); } else { printf("-e-bad choice\n"); exit(1); } printf("%s\n",server); // // original code continues // soap_init1(&soap, SOAP_XML_INDENT); a = strtod(argv[2], NULL); b = strtod(argv[3], NULL); switch (*argv[1]) { case 'a': soap_call_ns__add(&soap, server, "", a, b, &result); break; case 's': soap_call_ns__sub(&soap, server, "", a, b, &result); break; case 'm': soap_call_ns__mul(&soap, server, "", a, b, &result); break; case 'd': soap_call_ns__div(&soap, server, "", a, b, &result); break; case 'p': soap_call_ns__pow(&soap, server, "", a, b, &result); break; default: fprintf(stderr, "Unknown command\n"); exit(0); } if (soap.error) soap_print_fault(&soap, stderr); else printf("result = %g\n", result); soap_destroy(&soap); soap_end(&soap); soap_done(&soap); return 0; }

server code (initial)

caveat: the official docs say to replace "main()" with "IMPLEMENT_GSOAP_SERVER()" which did not work for me. A little hack with the "nm" proved that I needed both of them when building recipe-3

//========================================================================
// file : calcserver_101.c
// notes:
// 1) Started by copying calcserver_100.c then added compiler directives
//    Normally you would only publish one program but I did not want to
//    complicate a simple demo written with pedagogical intent) 
// 2) Find additional notes in file 'calcserver_100.c' (this folder)
// build: CentOS-7.7 via gcc:
// 0) build wsdl etc (for all three recipes)
//    soapcpp2 -c -x calc.h
// 1) compile server (standalone)
//    gcc	calcserver_101.c soapC.c soapServer.c	\
//		-o calcserver				\
//		-lgsoap -lm -DRECIPE=1
// 2) compile server (for Apache via cgi-bin)
//    gcc	calcserver_101.c soapC.c soapServer.c	\
//		-o calcserver2				\
//		-lgsoap -lm -DRECIPE=2
// 3) compile server (for Apache via mod_gsoap)
//    # a hack to force the installed file to be calcserver3
//    cp calcserver_101.c calcserver3.c	# my hack
//    soapcpp2 -c -x calc.h		# make files
//    sudo apxs -i -n calcserver3 -c -DRECIPE=3		\
//    -I/home/neil/gsoap/apache/mod_gsoap-0.6/apache_20	\
//    calcserver3.c soapC.c soapServer.c		\
//    -lgsoap -lm    
//========================================================================
#include "soapH.h"
#include "calc.nsmap"
// macro: RECIPE
// value: 1: default (interactive)
//        2: for Apache cgi-bin
//        3: for Apache plugin 'mod_gsoap'
#ifndef RECIPE
# define RECIPE 1
#endif
//-----------------------------------------------------------
// NSR change
// 1) copied the following block from file stdsoap2.h of gsoap version 2.8.117
// 2) alternatively, replace all 'SOAP_SNPRINTF' code with something like this:
//    { char *s = (char*)soap_malloc(soap, 1024);
//    sprintf(s, "<error xmlns=\"http://tempuri.org/\">Can't divide %f by %f</error>", a, b);
//    return soap_sender_fault(soap, "Division by zero", s); }
//-----------------------------------------------------------
# ifdef HAVE_SNPRINTF
#  if _MSC_VER >= 1400
#   define SOAP_SNPRINTF(buf, len, num) void)_snprintf_s((buf), (len), _TRUNCATE
#   define SOAP_SNPRINTF_SAFE(buf, len) void)_snprintf_s((buf), (len), _TRUNCATE
#  else
#   define SOAP_SNPRINTF(buf, len, num) void)snprintf((buf), (len)
#   define SOAP_SNPRINTF_SAFE(buf, len) void)snprintf((buf), (len)
#  endif
# else
#  define SOAP_SNPRINTF(buf, len, num) (len) <= (num)) ? (void)((buf)[0] = '\0') : (void)sprintf((buf)
#  define SOAP_SNPRINTF_SAFE(buf, len) void)sprintf((buf)
# endif
//--------------------------------------------------------
#if (RECIPE==1)
//
//	original code resumes (mostly an interactive demo) 
//	notes:
//	1) if you start with an argument it will listen on that port (eg. 5001)
//	2) the CGI part of this demo works with mod_gsoap via apache-1.3 
//	   but not mod_gsoap via apache-2.4 (read on)
//
int main(int argc, char **argv) {
  SOAP_SOCKET m, s;	/* sockets */
  struct soap soap;
  soap_init(&soap);
  if (argc < 2) {
    soap_serve(&soap);	/* serve as CGI application */
  }
  else
  {
    m = soap_bind(&soap, NULL, atoi(argv[1]), 1);
    if (!soap_valid_socket(m)) {
      soap_print_fault(&soap, stderr);
      exit(1);
    }
    fprintf(stderr, "Socket connection successful: master socket = %d\n", m);
    for ( ; ; )
    {
      s = soap_accept(&soap);
      fprintf(stderr, "Socket connection successful: slave socket = %d\n", s);
      if (!soap_valid_socket(s))
      {
        soap_print_fault(&soap, stderr);
        exit(1);
      } 
      soap_serve(&soap);
      soap_end(&soap);
    }
  }
  return 0;
}
#endif
//-------------------------------------------------------------------
//	RECIPE 2 (for Apache cgi-bin)
//
#if ((RECIPE==2)||(RECIPE==3))
int main() {
	return soap_serve(soap_new());
}
#endif
//-------------------------------------------------------------------
//      RECIPE 3 (for use with Apache plugin: mod_gsoap)
//
#if (RECIPE==3)
#include "apache_gsoap.h"
IMPLEMENT_GSOAP_SERVER()
#endif
//-------------------------------------------------------------------
//	common code for all recipes
//-------------------------------------------------------------------
int ns__add(struct soap *soap, double a, double b, double *result)
{
  (void)soap;
  *result = a + b;
  return SOAP_OK;
} 

int ns__sub(struct soap *soap, double a, double b, double *result)
{
  (void)soap;
  *result = a - b;
  return SOAP_OK;
} 

int ns__mul(struct soap *soap, double a, double b, double *result)
{
  (void)soap;
  *result = a * b;
  return SOAP_OK;
} 

int ns__div(struct soap *soap, double a, double b, double *result)
{
  if (b)
    *result = a / b;
  else
  {
    char *s = (char*)soap_malloc(soap, 1024);
    (SOAP_SNPRINTF(s, 1024, 100),
     	"<error xmlns=\"http://tempuri.org/\">Can't divide %f by %f</error>", a, b);
    return soap_sender_fault(soap, "Division by zero", s);
  }
  return SOAP_OK;
} 

int ns__pow(struct soap *soap, double a, double b, double *result)
{
  *result = pow(a, b);
  if (soap_errno == EDOM)	/* soap_errno is like errno, but compatible with Win32 */
  {
    char *s = (char*)soap_malloc(soap, 1024);
    (SOAP_SNPRINTF(s, 1024, 100),
     	"<error xmlns=\"http://tempuri.org/\">Can't raise %f to %f</error>", a, b);
    return soap_sender_fault(soap, "Power function domain error", s);
  }
  return SOAP_OK;
}
//-------------------------------------------------------------------

left handBack to Linux Demo Index
home Back to Home
Neil Rieck
Waterloo, Ontario, Canada.