diff --git a/miniupnpc-libevent/miniupnpc-libevent.c b/miniupnpc-libevent/miniupnpc-libevent.c index 4ec3467..38320e5 100644 --- a/miniupnpc-libevent/miniupnpc-libevent.c +++ b/miniupnpc-libevent/miniupnpc-libevent.c @@ -1,4 +1,4 @@ -/* $Id: miniupnpc-libevent.c,v 1.17 2014/11/28 13:21:25 nanard Exp $ */ +/* $Id: miniupnpc-libevent.c,v 1.18 2014/12/01 17:41:11 nanard Exp $ */ /* miniupnpc-libevent * Copyright (c) 2008-2014, Thomas BERNARD * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ @@ -65,6 +65,9 @@ #define debug_printf(...) #endif +/* compare the begining of a string with a constant string */ +#define COMPARE(str, cstr) (0==memcmp(str, cstr, sizeof(cstr) - 1)) + /* stuctures */ struct upnp_args { @@ -74,7 +77,7 @@ struct upnp_args { /* private functions */ -static int upnpc_get_desc(upnpc_t * p, const char * url); +static int upnpc_get_desc(upnpc_device_t * p, const char * url); static char * build_url_string(const char * urlbase, const char * root_desc_url, const char * controlurl); /* data */ @@ -89,8 +92,8 @@ static const char * devices_to_search[] = { #ifdef DEBUG static void upnpc_conn_close_cb(struct evhttp_connection * conn, void * data) { - upnpc_t * p = (upnpc_t *)data; - debug_printf("upnpc_get_desc_conn_close_cb %p %p\n", conn, p); + upnpc_device_t * d = (upnpc_device_t *)data; + debug_printf("upnpc_get_desc_conn_close_cb %p %p\n", conn, d); } #endif /* DEBUG */ @@ -160,7 +163,7 @@ static void upnpc_send_ssdp_msearch(evutil_socket_t s, short events, upnpc_t * p addr.sin_port = htons(SSDP_PORT); addr.sin_addr.s_addr = inet_addr(SSDP_MCAST_ADDR); n = snprintf(bufr, sizeof(bufr), - MSearchMsgFmt, devices_to_search[p->device_index++], mx); + MSearchMsgFmt, devices_to_search[p->discover_device_index++], mx); debug_printf("upnpc_send_ssdp_msearch: %s", bufr); n = sendto(s, bufr, n, 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)); @@ -169,19 +172,31 @@ static void upnpc_send_ssdp_msearch(evutil_socket_t s, short events, upnpc_t * p } } -static int upnpc_set_root_desc_location(upnpc_t * p, const char * location, int locationsize) +static int upnpc_set_root_desc_location(upnpc_device_t * d, const char * location, int locationsize) { char * tmp; - tmp = realloc(p->root_desc_location, locationsize + 1); + tmp = realloc(d->root_desc_location, locationsize + 1); if(tmp == NULL) { return -1; } memcpy(tmp, location, locationsize); tmp[locationsize] = '\0'; - p->root_desc_location = tmp; + d->root_desc_location = tmp; return 0; } +static upnpc_device_t * upnpc_find_device_with_location(upnpc_t * p, const char * location, int locationsize) +{ + upnpc_device_t * d; + for(d = p->devices; d != NULL; d = d->next) { + if(d->root_desc_location + && ((int)strlen(d->root_desc_location) == locationsize) + && (0 == memcmp(location, d->root_desc_location, locationsize))) + return d; + } + return NULL; +} + static void upnpc_receive_and_parse_ssdp(evutil_socket_t s, short events, upnpc_t * p) { char bufr[2048]; @@ -190,13 +205,11 @@ static void upnpc_receive_and_parse_ssdp(evutil_socket_t s, short events, upnpc_ if(events == EV_TIMEOUT) { /* nothing received ... */ debug_printf("upnpc_receive_and_parse_ssdp() TIMEOUT\n"); - if(p->root_desc_location != NULL) { - /* we already have found a device */ - } else if(!devices_to_search[p->device_index]) { + if(!devices_to_search[p->discover_device_index]) { debug_printf("*** NO MORE DEVICES TO SEARCH ***\n"); event_del(p->ev_ssdp_recv); /* no device found : report error */ - p->ready_cb(UPNPC_ERR_NO_DEVICE_FOUND, p->cb_data); + p->ready_cb(UPNPC_ERR_NO_DEVICE_FOUND, p, NULL, p->cb_data); } else { /* send another SSDP M-SEARCH packet */ if(event_add(p->ev_ssdp_writable, NULL)) { @@ -221,11 +234,24 @@ static void upnpc_receive_and_parse_ssdp(evutil_socket_t s, short events, upnpc_ debug_printf("location = '%.*s'\n", locationsize, location); debug_printf("st = '%.*s'\n", stsize, st); if(location != NULL) { - if(upnpc_set_root_desc_location(p, location, locationsize) < 0) { - return; + upnpc_device_t * device; + device = upnpc_find_device_with_location(p, location, locationsize); + if(device) { + debug_printf("device already known\n"); + } else { + device = malloc(sizeof(upnpc_device_t)); + memset(device, 0, sizeof(upnpc_device_t)); + device->parent = p; + device->next = p->devices; + p->devices = device; + if(upnpc_set_root_desc_location(device, location, locationsize) < 0) { + return; + } + upnpc_get_desc(device, device->root_desc_location); } - upnpc_get_desc(p, p->root_desc_location); +#if 0 event_del(p->ev_ssdp_recv); /* stop receiving SSDP responses */ +#endif } else { /* or do nothing ? */ debug_printf("no location\n"); @@ -335,18 +361,18 @@ static void upnpc_desc_received(struct evhttp_request * req, void * pvoid) struct evbuffer * input_buffer; struct IGDdatas igd; struct xmlparser parser; - upnpc_t * p = (upnpc_t *)pvoid; + upnpc_device_t * d = (upnpc_device_t *)pvoid; input_buffer = evhttp_request_get_input_buffer(req); len = evbuffer_get_length(input_buffer); data = evbuffer_pullup(input_buffer, len); debug_printf("upnpc_desc_received %d (%d bytes)\n", evhttp_request_get_response_code(req), (int)len); if(evhttp_request_get_response_code(req) != HTTP_OK) { - p->ready_cb(evhttp_request_get_response_code(req), p->cb_data); + d->parent->ready_cb(evhttp_request_get_response_code(req), d->parent, d, d->parent->cb_data); return; } if(data == NULL) { - p->ready_cb(UPNPC_ERR_ROOT_DESC_ERROR, p->cb_data); + d->parent->ready_cb(UPNPC_ERR_ROOT_DESC_ERROR, d->parent, d, d->parent->cb_data); return; } debug_printf("%.*s\n", (int)len, (char *)data); @@ -363,15 +389,23 @@ static void upnpc_desc_received(struct evhttp_request * req, void * pvoid) #ifdef DEBUG printIGD(&igd); #endif /* DEBUG */ - p->control_conn_url = build_url_string(igd.urlbase, p->root_desc_location, igd.first.controlurl); - p->conn_service_type = strdup(igd.first.servicetype); - p->control_cif_url = build_url_string(igd.urlbase, p->root_desc_location, igd.CIF.controlurl); - p->cif_service_type = strdup(igd.CIF.servicetype); + d->control_conn_url = build_url_string(igd.urlbase, d->root_desc_location, igd.first.controlurl); + d->conn_service_type = strdup(igd.first.servicetype); + d->control_cif_url = build_url_string(igd.urlbase, d->root_desc_location, igd.CIF.controlurl); + d->cif_service_type = strdup(igd.CIF.servicetype); debug_printf("control_conn_url='%s'\n (service_type='%s')\n", - p->control_conn_url, p->conn_service_type); + d->control_conn_url, d->conn_service_type); debug_printf("control_cif_url='%s'\n (service_type='%s')\n", - p->control_cif_url, p->cif_service_type); - p->ready_cb(evhttp_request_get_response_code(req), p->cb_data); + d->control_cif_url, d->cif_service_type); + + if((d->cif_service_type == NULL) + || (strlen(d->cif_service_type) == 0) + || (!COMPARE(d->cif_service_type, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:"))) { + d->parent->ready_cb(UPNPC_ERR_NOT_IGD, d->parent, d, d->parent->cb_data); + } else { + d->state |= UPNPC_DEVICE_GETSTATUS; + upnpc_get_status_info(d); + } } static void upnpc_soap_response(struct evhttp_request * req, void * pvoid) @@ -379,23 +413,39 @@ static void upnpc_soap_response(struct evhttp_request * req, void * pvoid) size_t len; unsigned char * data; struct evbuffer * input_buffer; - upnpc_t * p = (upnpc_t *)pvoid; + upnpc_device_t * d = (upnpc_device_t *)pvoid; + int code = evhttp_request_get_response_code(req); input_buffer = evhttp_request_get_input_buffer(req); len = evbuffer_get_length(input_buffer); data = evbuffer_pullup(input_buffer, len); - debug_printf("upnpc_soap_response %d (%d bytes)\n", evhttp_request_get_response_code(req), (int)len); + debug_printf("upnpc_soap_response %d (%d bytes)\n", code, (int)len); debug_printf("%.*s\n", (int)len, (char *)data); if(data == NULL) return; - ClearNameValueList(&p->soap_response_data); + ClearNameValueList(&d->soap_response_data); ParseNameValue((char *)data, (int)len, - &p->soap_response_data); - p->soap_cb(evhttp_request_get_response_code(req), p->cb_data); + &d->soap_response_data); + if(d->state & UPNPC_DEVICE_READY) { + d->parent->soap_cb(code, d->parent, d, d->parent->cb_data); + } else if(d->state & UPNPC_DEVICE_GETSTATUS) { + const char * connection_status; + d->state &= ~UPNPC_DEVICE_GETSTATUS; + connection_status = GetValueFromNameValueList(&d->soap_response_data, "NewConnectionStatus"); + d->state |= UPNPC_DEVICE_READY; + if((code == 200) && connection_status && (0 == strcmp("Connected", connection_status))) { + d->parent->ready_cb(code, d->parent, d, d->parent->cb_data); + d->state |= UPNPC_DEVICE_CONNECTED; + event_del(d->parent->ev_ssdp_recv); + } else { + d->parent->ready_cb(UPNPC_ERR_NOT_CONNECTED, d->parent, d, d->parent->cb_data); + } + } + d->state &= ~UPNPC_DEVICE_SOAP_REQ; } -static int upnpc_get_desc(upnpc_t * p, const char * url) +static int upnpc_get_desc(upnpc_device_t * d, const char * url) { char hostname[MAXHOSTNAMELEN+1]; unsigned short port; @@ -404,26 +454,26 @@ static int upnpc_get_desc(upnpc_t * p, const char * url) struct evhttp_request * req; struct evkeyvalq * headers; - if(p->root_desc_location == 0) { + /* if(d->root_desc_location == NULL) { return -1; - } - if(!parseURL(url/*p->root_desc_location*/, hostname, &port, + } */ + if(!parseURL(url/*d->root_desc_location*/, hostname, &port, &path, &scope_id)) { return -1; } - if(p->desc_conn == NULL) { - p->desc_conn = evhttp_connection_base_new(p->base, NULL, hostname, port); + if(d->desc_conn == NULL) { + d->desc_conn = evhttp_connection_base_new(d->parent->base, NULL, hostname, port); } #ifdef DEBUG - evhttp_connection_set_closecb(p->desc_conn, upnpc_conn_close_cb, p); + evhttp_connection_set_closecb(d->desc_conn, upnpc_conn_close_cb, d); #endif /* DEBUG */ /*evhttp_connection_set_timeout(p->desc_conn, 600);*/ - req = evhttp_request_new(upnpc_desc_received/*callback*/, p); + req = evhttp_request_new(upnpc_desc_received/*callback*/, d); headers = evhttp_request_get_output_headers(req); evhttp_add_header(headers, "Host", hostname); evhttp_add_header(headers, "Connection", "close"); /*evhttp_add_header(headers, "User-Agent", "***");*/ - evhttp_make_request(p->desc_conn, req, EVHTTP_REQ_GET, path); + evhttp_make_request(d->desc_conn, req, EVHTTP_REQ_GET, path); return 0; } @@ -459,7 +509,7 @@ static char * build_url_string(const char * urlbase, const char * root_desc_url, #define SERVICEPREFIX "u" #define SERVICEPREFIX2 'u' -static int upnpc_send_soap_request(upnpc_t * p, const char * url, +static int upnpc_send_soap_request(upnpc_device_t * p, const char * url, const char * service, const char * method, const struct upnp_args * args, int arg_count) @@ -525,7 +575,7 @@ static int upnpc_send_soap_request(upnpc_t * p, const char * url, portstr[0] = '\0'; snprintf(action, sizeof(action), "\"%s#%s\"", service, method); if(p->soap_conn == NULL) { - p->soap_conn = evhttp_connection_base_new(p->base, NULL, hostname, port); + p->soap_conn = evhttp_connection_base_new(p->parent->base, NULL, hostname, port); } req = evhttp_request_new(upnpc_soap_response, p); headers = evhttp_request_get_output_headers(req); @@ -614,20 +664,34 @@ int upnpc_init(upnpc_t * p, struct event_base * base, const char * multicastif, return UPNPC_OK; } +static void upnpc_device_finalize(upnpc_device_t * d) +{ + d->state = 0; + free(d->root_desc_location); + d->root_desc_location = NULL; + free(d->control_cif_url); + d->control_cif_url = NULL; + free(d->cif_service_type); + d->cif_service_type = NULL; + free(d->control_conn_url); + d->control_conn_url = NULL; + free(d->conn_service_type); + d->conn_service_type = NULL; + if(d->desc_conn) { + evhttp_connection_free(d->desc_conn); + d->desc_conn = NULL; + } + if(d->soap_conn) { + evhttp_connection_free(d->soap_conn); + d->soap_conn = NULL; + } + ClearNameValueList(&d->soap_response_data); +} + int upnpc_finalize(upnpc_t * p) { if(!p) return UPNPC_ERR_INVALID_ARGS; - p->device_index = 0; - free(p->root_desc_location); - p->root_desc_location = NULL; - free(p->control_cif_url); - p->control_cif_url = NULL; - free(p->cif_service_type); - p->cif_service_type = NULL; - free(p->control_conn_url); - p->control_conn_url = NULL; - free(p->conn_service_type); - p->conn_service_type = NULL; + p->discover_device_index = 0; if(p->ssdp_socket >= 0) { close(p->ssdp_socket); p->ssdp_socket = -1; @@ -640,33 +704,30 @@ int upnpc_finalize(upnpc_t * p) event_free(p->ev_ssdp_writable); p->ev_ssdp_writable = NULL; } - if(p->desc_conn) { - evhttp_connection_free(p->desc_conn); - p->desc_conn = NULL; + while(p->devices != NULL) { + upnpc_device_t * d = p->devices; + upnpc_device_finalize(d); + p->devices = d->next; + free(d); } - if(p->soap_conn) { - evhttp_connection_free(p->soap_conn); - p->soap_conn = NULL; - } - ClearNameValueList(&p->soap_response_data); return UPNPC_OK; } -int upnpc_get_external_ip_address(upnpc_t * p) +int upnpc_get_external_ip_address(upnpc_device_t * p) { return upnpc_send_soap_request(p, p->control_conn_url, p->conn_service_type/*"urn:schemas-upnp-org:service:WANIPConnection:1"*/, "GetExternalIPAddress", NULL, 0); } -int upnpc_get_link_layer_max_rate(upnpc_t * p) +int upnpc_get_link_layer_max_rate(upnpc_device_t * p) { return upnpc_send_soap_request(p, p->control_cif_url, p->cif_service_type/*"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1"*/, "GetCommonLinkProperties", NULL, 0); } -int upnpc_delete_port_mapping(upnpc_t * p, +int upnpc_delete_port_mapping(upnpc_device_t * p, const char * remote_host, unsigned short ext_port, const char * proto) { @@ -688,7 +749,7 @@ int upnpc_delete_port_mapping(upnpc_t * p, args, 3); } -int upnpc_add_port_mapping(upnpc_t * p, +int upnpc_add_port_mapping(upnpc_device_t * p, const char * remote_host, unsigned short ext_port, unsigned short int_port, const char * int_client, const char * proto, const char * description, @@ -726,7 +787,7 @@ int upnpc_add_port_mapping(upnpc_t * p, args, 8); } -int upnpc_get_status_info(upnpc_t * p) +int upnpc_get_status_info(upnpc_device_t * p) { return upnpc_send_soap_request(p, p->control_conn_url, p->conn_service_type/*"urn:schemas-upnp-org:service:WANIPConnection:1"*/, diff --git a/miniupnpc-libevent/miniupnpc-libevent.h b/miniupnpc-libevent/miniupnpc-libevent.h index a6a82fe..e09e9a3 100644 --- a/miniupnpc-libevent/miniupnpc-libevent.h +++ b/miniupnpc-libevent/miniupnpc-libevent.h @@ -1,4 +1,4 @@ -/* $Id: miniupnpc-libevent.h,v 1.9 2014/11/25 22:49:19 nanard Exp $ */ +/* $Id: miniupnpc-libevent.h,v 1.10 2014/12/01 17:41:11 nanard Exp $ */ /* miniupnpc-libevent * Copyright (c) 2008-2014, Thomas BERNARD * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ @@ -33,15 +33,23 @@ extern "C" { #define UPNPC_ERR_NO_DEVICE_FOUND (-100) #define UPNPC_ERR_ROOT_DESC_ERROR (-101) +#define UPNPC_ERR_NOT_IGD (-102) +#define UPNPC_ERR_NOT_CONNECTED (-103) -typedef void(* upnpc_callback_fn)(int, void *); +/* device->state masks */ +#define UPNPC_DEVICE_SOAP_REQ (0x0001) +#define UPNPC_DEVICE_GETSTATUS (0x0002) +#define UPNPC_DEVICE_CONNECTED (0x4000) +#define UPNPC_DEVICE_READY (0x8000) -typedef struct { - struct event_base * base; - evutil_socket_t ssdp_socket; - struct event * ev_ssdp_recv; - struct event * ev_ssdp_writable; - int device_index; +typedef struct upnpc_device upnpc_device_t; +typedef struct upnpc upnpc_t; + +typedef void(* upnpc_callback_fn)(int, upnpc_t *, upnpc_device_t *, void *); + +struct upnpc_device { + upnpc_t * parent; + upnpc_device_t * next; char * root_desc_location; struct evhttp_connection * desc_conn; char * control_cif_url; @@ -50,31 +58,41 @@ typedef struct { char * conn_service_type; struct evhttp_connection * soap_conn; struct NameValueParserData soap_response_data; + unsigned int state; +}; + +struct upnpc { + struct event_base * base; + evutil_socket_t ssdp_socket; + struct event * ev_ssdp_recv; + struct event * ev_ssdp_writable; + int discover_device_index; + upnpc_device_t * devices; upnpc_callback_fn ready_cb; upnpc_callback_fn soap_cb; void * cb_data; -} upnpc_t; +}; int upnpc_init(upnpc_t * p, struct event_base * base, const char * multicastif, upnpc_callback_fn ready_cb, upnpc_callback_fn soap_cb, void * cb_data); int upnpc_finalize(upnpc_t * p); -int upnpc_get_external_ip_address(upnpc_t * p); +int upnpc_get_external_ip_address(upnpc_device_t * p); -int upnpc_get_link_layer_max_rate(upnpc_t * p); +int upnpc_get_link_layer_max_rate(upnpc_device_t * p); -int upnpc_add_port_mapping(upnpc_t * p, +int upnpc_add_port_mapping(upnpc_device_t * p, const char * remote_host, unsigned short ext_port, unsigned short int_port, const char * int_client, const char * proto, const char * description, unsigned int lease_duration); -int upnpc_delete_port_mapping(upnpc_t * p, +int upnpc_delete_port_mapping(upnpc_device_t * p, const char * remote_host, unsigned short ext_port, const char * proto); -int upnpc_get_status_info(upnpc_t * p); +int upnpc_get_status_info(upnpc_device_t * p); #ifdef UPNPC_USE_SELECT int upnpc_select_fds(upnpc_t * p, int * nfds, fd_set * readfds, fd_set * writefds); diff --git a/miniupnpc-libevent/upnpc-libevent.c b/miniupnpc-libevent/upnpc-libevent.c index a4e4836..b904784 100644 --- a/miniupnpc-libevent/upnpc-libevent.c +++ b/miniupnpc-libevent/upnpc-libevent.c @@ -1,4 +1,4 @@ -/* $Id: upnpc-libevent.c,v 1.9 2014/11/25 22:49:19 nanard Exp $ */ +/* $Id: upnpc-libevent.c,v 1.10 2014/12/01 17:41:11 nanard Exp $ */ /* miniupnpc-libevent * Copyright (c) 2008-2014, Thomas BERNARD * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ @@ -37,13 +37,14 @@ static void sighandler(int signal) } /* ready callback */ -static void ready(int code, void * data) +static void ready(int code, upnpc_t * p, upnpc_device_t * d, void * data) { - upnpc_t * p = (upnpc_t *)data; + (void)data; (void)p; + if(code == 200) { printf("READY ! %d\n", code); /* 1st request */ - upnpc_get_status_info(p); + upnpc_get_status_info(d); } else { printf("DISCOVER ERROR : %d\n", code); switch(code) { @@ -72,47 +73,50 @@ static enum { } state = EGetStatusInfo; /* soap callback */ -static void soap(int code, void * data) +static void soap(int code, upnpc_t * p, upnpc_device_t * d, void * data) { - upnpc_t * p = (upnpc_t *)data; + (void)data; (void)p; + printf("SOAP ! %d\n", code); if(code == 200) { switch(state) { case EGetStatusInfo: - printf("ConnectionStatus=%s\n", GetValueFromNameValueList(&p->soap_response_data, "NewConnectionStatus")); - printf("LastConnectionError=%s\n", GetValueFromNameValueList(&p->soap_response_data, "NewLastConnectionError")); - printf("Uptime=%s\n", GetValueFromNameValueList(&p->soap_response_data, "NewUptime")); - upnpc_get_external_ip_address(p); + printf("ConnectionStatus=%s\n", GetValueFromNameValueList(&d->soap_response_data, "NewConnectionStatus")); + printf("LastConnectionError=%s\n", GetValueFromNameValueList(&d->soap_response_data, "NewLastConnectionError")); + printf("Uptime=%s\n", GetValueFromNameValueList(&d->soap_response_data, "NewUptime")); + upnpc_get_external_ip_address(d); state = EGetExtIp; break; case EGetExtIp: - printf("ExternalIpAddress=%s\n", GetValueFromNameValueList(&p->soap_response_data, "NewExternalIPAddress")); - upnpc_get_link_layer_max_rate(p); + printf("ExternalIpAddress=%s\n", GetValueFromNameValueList(&d->soap_response_data, "NewExternalIPAddress")); + upnpc_get_link_layer_max_rate(d); state = EGetMaxRate; break; case EGetMaxRate: - printf("DownStream MaxBitRate = %s\t", GetValueFromNameValueList(&p->soap_response_data, "NewLayer1DownstreamMaxBitRate")); - upnpc_add_port_mapping(p, NULL, 60001, 60002, local_address, "TCP", "test port mapping", 0); - printf("UpStream MaxBitRate = %s\n", GetValueFromNameValueList(&p->soap_response_data, "NewLayer1UpstreamMaxBitRate")); + printf("DownStream MaxBitRate = %s\t", GetValueFromNameValueList(&d->soap_response_data, "NewLayer1DownstreamMaxBitRate")); + upnpc_add_port_mapping(d, NULL, 60001, 60002, local_address, "TCP", "test port mapping", 0); + printf("UpStream MaxBitRate = %s\n", GetValueFromNameValueList(&d->soap_response_data, "NewLayer1UpstreamMaxBitRate")); state = EAddPortMapping; break; case EAddPortMapping: printf("OK!\n"); - upnpc_delete_port_mapping(p, NULL, 60001, "TCP"); + upnpc_delete_port_mapping(d, NULL, 60001, "TCP"); state = EDeletePortMapping; break; case EDeletePortMapping: printf("OK!\n"); state = EFinished; - /*default: - event_base_loopbreak(base);*/ + break; + default: + printf("EFinished : breaking\n"); + event_base_loopbreak(base); } } else { printf("SOAP error :\n"); - printf(" faultcode='%s'\n", GetValueFromNameValueList(&p->soap_response_data, "faultcode")); - printf(" faultstring='%s'\n", GetValueFromNameValueList(&p->soap_response_data, "faultstring")); - printf(" errorCode=%s\n", GetValueFromNameValueList(&p->soap_response_data, "errorCode")); - printf(" errorDescription='%s'\n", GetValueFromNameValueList(&p->soap_response_data, "errorDescription")); + printf(" faultcode='%s'\n", GetValueFromNameValueList(&d->soap_response_data, "faultcode")); + printf(" faultstring='%s'\n", GetValueFromNameValueList(&d->soap_response_data, "faultstring")); + printf(" errorCode=%s\n", GetValueFromNameValueList(&d->soap_response_data, "errorCode")); + printf(" errorDescription='%s'\n", GetValueFromNameValueList(&d->soap_response_data, "errorDescription")); event_base_loopbreak(base); } }