This is a dereference of null pointer problem - in both the ANSI C & gSoap domains:
I am using the following public WSDL:
http://www.mobilefish.com/services/web_service/countries.php?wsdl
and have tested its behavior using soapUI.
I created client-side only ANSI C bindings using the wsdl2h and soapcpp2 utilities.
The problem:
In previous gsoap projects, results structures in the client soap_call functions (the fifth argument) required no initialization other than something like:
struct ns2__countryInfoByIanaResponse out, *pOut
pOut= &out;
this has always been sufficient until this project.
The client soap_call looks like this:
soap_call_ns2__countryInfoByIana(&soap, NULL, NULL, pIn, pOut); /* SOAP 1.2 RPC return element...*/
pIn
for this project is defined as a char *
, populated with a two character IANA code such as "us", or "nz". The return structure pOut
for this particular call is shaped like this:
struct ns2__countryInfoByIanaResponse
{
struct ns1__CountryData *countryinfo;
}
With ns1__CountryData
shaped like this:
struct ns1__CountryData
{
char *ianacode; /* required element of type xsd:string */
char *countryname; /* required element of type xsd:string */
float latitude; /* required element of type xsd:float */
float longitude; /* required element of type xsd:float */
};
A call to this function from my application is therefore set up like this:
//declare response structure:
struct ns2__countryInfoByIanaResponse o, *pO;
void main(void)
{
pO = &o;
if(GetCountryInfo(buf, pO)==0)
{
pO->countryinfo->countryname; //Error Occurs Here...
}
}
The error occurs at pO->countryinfo
as a dereference of null pointer
GetCountryInfo is defined here:
int DLL_EXPORT GetCountryInfo(char *pIn, struct ns2__countryInfoByIanaResponse *pOut)
{
int status = 0;
size_t len=2048;
char buf[2048];
if (soap_call_ns2__countryInfoByIana(&soap, NULL, NULL, pIn, pOut)== SOAP_OK)
{
status = 0;
}
else
{
//soap_print_fault(&soap, stderr);
soap_sprint_fault(&soap, buf, len);
MessagePopup("soap error", buf);
status = 1;
}
return status;
}
Other gSoap
projects using similar output structure shapes (i.e. structures containing structures containing char *) returned fully populated results when initialized with nothing other than what I have shown above.
Any ideas? Please let me know if I can provide any further details. Thanks.
It looks to me like the soap server has a bug. An example soap response from the countryInfoByIana function looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<SOAP-ENV:countryInfoByIanaResponse>
<return>
<ianacode xsi:type="xsd:string">nz</ianacode>
<countryname xsi:type="xsd:string">New Zealand</countryname>
<latitude xsi:type="xsd:float">-40.900558</latitude>
<longitude xsi:type="xsd:float">174.885971</longitude>
</return>
</SOAP-ENV:countryInfoByIanaResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
<SOAP-ENV:countryInfoByIanaResponse>
should have a different namespace.
Here is a part of the WSDL, which contains the same (invalid) namespace.
<operation name="countryInfoByIana">
<soap:operation soapAction="http://schemas.xmlsoap.org/soap/envelope/#Countries#countryInfoByIana" />
<input>
<soap:body use="encoded" namespace="http://schemas.xmlsoap.org/soap/envelope/" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
</input>
<output>
<soap:body use="encoded" namespace="http://schemas.xmlsoap.org/soap/envelope/" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
</output>
</operation>
EDIT:
Regarding your question why soapUI works fine; soapUI probably does not validate the return value the same way gsoap is doing.
I managed to let the program succeed on my pc using gsoap 2.7:
In soapClient.c line 56, change this line:
//soap_get_ns2__countryInfoByIanaResponse(soap, _param_1, "ns2:countryInfoByIanaResponse", "");
soap_get_ns2__countryInfoByIanaResponse(soap, _param_1, "SOAP-ENV:countryInfoByIanaResponse", "");
In soapC.c line 1470, change this line:
//if (soap_in_PointerTons1__CountryData(soap, "countryinfo", &a->countryinfo, "ns1:CountryData"))
if (soap_in_PointerTons1__CountryData(soap, "return", &a->countryinfo, "ns1:CountryData"))//return
But I don't think you should solve problems this way. Not only because both files are generated, so you will lose your changes when you generate it again.