//---------------------------------------------------------------------------- // // Copyright (C) Intel Corporation, 2003 - 2009. // // File: httpDigest.cpp // // Contents: Sample code for a gSOAP plugin to implement HTTP Digest // authentication. // // Limitations: // - MIME, DIME and HTTP chunks (SOAP_IO_CHUNK) are not supported. // - This implementationn will internally buffer the entire outgoing // message before sending // - This implementation will fail if challenge isn't received within // SOAP_BUFLEN bytes read. // - This implementation will fail if challenge or response are larger // than the constants we used. // - This implementation calculates the digest response for each call // and doesn't save information. // - This implementation assumes that the algorithm is MD5 and that // qop="auth". // // Usage: Add the httpDigest.h and httpDigest.cpp files to your project // // In your source, just after calling soap_init(), register this // plugin with soap_register_plugin( soap, http_digest ). // Use soap.userid and soap.passwd for the username and password. // As in gSOAP, username and password have to be provided for each call. // // e.g. // struct soap soap; // soap_init( &soap ); // soap_register_plugin( &soap, http_digest ); // soap.userid = "admin"; // soap.passwd = "admin"; // ... // soap_done(&soap); // //---------------------------------------------------------------------------- #include "httpDigest.h" #include "digcalc.h" #include #if 0 // ifdef out to avoid compiler warning // Debugging macros and variable: static int nest_level = 0; #define entry(routine) fprintf(stderr, "Enter - %d - %s\n", ++nest_level, #routine);fflush(stderr) #define leave(routine) fprintf(stderr, "Exit - %d - %s line %d\n", nest_level--, #routine, __LINE__);fflush(stderr) #define logstep(whatsgoingon) fprintf(stderr, "http_digest_frecv: - %d - line %d - %s\n", nest_level, __LINE__, whatsgoingon); fflush(stderr); static void soap_dump(struct soap *soap); // for debugging static void data_dump(struct http_digest_data *data); // for debugging #endif static bool valid_socket(int fd); // for debugging static bool debug = false; #define HDR_SIZE 1024 const char HTTP_DIGEST_ID[12] = "HTTP-Digest"; // plugin identification static const unsigned int SYN_DELAY = 400000; struct http_digest_data { struct soap *soap; // back pointer // send buffer parameters char *sendBuffer; // send buffer size_t sendMsgSize; // total length of the message size_t sendBufferLength; // length of data in buffer // receive buffer parameters char *rcvBuffer; // receive buffer size_t rcvSize; // length of buffer size_t rcvIdx; // current index size_t rcvRead; // amount of data read bool rcvErr; // error encountered when reading // open parameters char *endpoint; char *host; int port; // function pointers int (*fopen)(struct soap*, const char*, const char*, int); // open function int (*fsend)(struct soap*, const char*, size_t); // send function size_t (*frecv)(struct soap*, char*, size_t); // receive function int (*fposthdr)(struct soap*, const char*, const char*); // post header function int (*fclose)(struct soap*); // disconnect function char *username; char *password; char requestUrl[128]; char method[5]; int connect_count; // for tracking if we saw CONNECT command }; static int http_digest_init(struct soap *soap, struct http_digest_data *data); static int http_digest_copy(struct soap *soap, struct soap_plugin *dst, struct soap_plugin *src); static void http_digest_delete(struct soap *soap, struct soap_plugin *p); static int http_digest_fopen(struct soap *soap, const char *endpoint, const char *host, int port); static int http_digest_fsend(struct soap *soap, const char *buf, size_t size); static size_t http_digest_frecv(struct soap *soap, char *buf, size_t size); static int http_digest_fposthdr(struct soap *soap, const char *key, const char *value); static int http_digest_disconnect(struct soap *soap); static void reset_data(struct http_digest_data *data); /* * The entry point for HTTP digest plugin * Arguments: * soap - pointer to the soap runtime environment * p - pointer to the soap plugin * arg - reserved. Should be NULL * * Returns SOAP_OK for suceess. Other values for error */ int http_digest(struct soap *soap, struct soap_plugin *p, void *arg) { debug = (getenv("DEBUGME") != NULL); p->id = HTTP_DIGEST_ID; p->data = (void*)malloc(sizeof(struct http_digest_data)); p->fcopy = http_digest_copy; p->fdelete = http_digest_delete; if (p->data) { memset(p->data, 0, sizeof(struct http_digest_data)); if (http_digest_init(soap, (struct http_digest_data*)p->data)) { free(p->data); return SOAP_EOM; } return SOAP_OK; } return SOAP_EOM; } /* * Initializes the http digest data structure. * Arguments: * soap - pointer to the soap runtime environment * data - pointer to the http digest data structure * * Returns SOAP_OK for suceess. Other values for error */ static int http_digest_init(struct soap *soap, struct http_digest_data *data) { data->soap = soap; data->fopen = soap->fopen; soap->fopen = http_digest_fopen; data->fsend = soap->fsend; soap->fsend = http_digest_fsend; data->frecv = soap->frecv; soap->frecv = http_digest_frecv; data->fposthdr = soap->fposthdr; soap->fposthdr = http_digest_fposthdr; data->fclose = soap->fclose; soap->fclose = http_digest_disconnect; data->rcvBuffer = NULL; data->rcvSize = 0; data->rcvIdx = 0; data->rcvRead = 0; data->rcvErr = false; data->connect_count = 0; return SOAP_OK; } /* * Creates the HTTP digest response * Arguments: * userName - the user name * password - the password * method - the HTTP method ("GET", "POST") * realm - the realm for the authentication * uri - the URI from the HTTP request * nonce - the nonce from the challenge * cnonce - client generated nonce * digestResponse - The result authorization string * length - size of buffer for response * * Returns 0 for suceess. -1 for error */ static int CalculateResponse(char *userName, char *password, char *method, char *realm, char *uri, char *nonce, char *cnonce, char *digestResponse, size_t *length) { size_t currOffset = 0, segmentLength; static const char *INITIAL_HDR = "Authorization: Digest username=\""; static const char *REALM_HDR = "\", realm=\""; static const char *ALGO_HDR = "\", qop=\"auth\", algorithm=\"MD5\", uri=\""; static const char *NONCE_HDR = "\", nonce=\""; static const char *NC_HDR = "\", nc=00000002, cnonce=\""; static const char *RSP_HDR = "\", response=\""; HASHHEX HA1; HASHHEX HA2 = ""; HASHHEX response; //"Authorization: Digest username=" segmentLength = strlen(INITIAL_HDR); if (*length < (currOffset + segmentLength)) { return -1; } memcpy(digestResponse + currOffset, INITIAL_HDR, segmentLength); currOffset += segmentLength; //"Authorization: Digest username="username segmentLength = strlen(userName); if (*length < (currOffset + segmentLength)) { return -1; } memcpy(digestResponse + currOffset, userName, segmentLength); currOffset += segmentLength; //"Authorization: Digest username="username", realm=" segmentLength = strlen(REALM_HDR); if (*length < (currOffset + segmentLength)) { return -1; } memcpy(digestResponse + currOffset, REALM_HDR, segmentLength); currOffset += segmentLength; //"Authorization: Digest username="username", realm="realm segmentLength = strlen(realm); if (*length < (currOffset + segmentLength)) { return -1; } memcpy(digestResponse + currOffset, realm, segmentLength); currOffset += segmentLength; //"Authorization: Digest username="username", realm="myRealm", qop="auth", //algorithm="MD5", uri=" segmentLength = strlen(ALGO_HDR); if (*length < (currOffset + segmentLength)) { return -1; } memcpy(digestResponse + currOffset, ALGO_HDR, segmentLength); currOffset += segmentLength; //"Authorization: Digest username="username", realm="myRealm", qop="auth", //algorithm="MD5", uri="/....Service segmentLength = strlen(uri); if (*length < (currOffset + segmentLength)) { return -1; } memcpy(digestResponse + currOffset, uri, segmentLength); currOffset+= segmentLength; //"Authorization: Digest username="username", realm="myRealm", qop="auth", //algorithm="MD5", uri="/....Service", nonce=" segmentLength = strlen(NONCE_HDR); if (*length < (currOffset + segmentLength)) { return -1; } memcpy(digestResponse + currOffset, NONCE_HDR, segmentLength); currOffset += segmentLength; //"Authorization: Digest username="username", realm="myRealm", qop="auth", //algorithm="MD5", uri="/....Service", nonce="7a5c... segmentLength = strlen(nonce); if (*length < (currOffset + segmentLength)) { return -1; } memcpy(digestResponse + currOffset, nonce, segmentLength); currOffset += segmentLength; //"Authorization: Digest username="username", realm="myRealm", qop="auth", //algorithm="MD5", uri="/....Service", nonce="7a5c...", nc=00000002, //cnonce=" segmentLength = strlen(NC_HDR); if (*length < (currOffset + segmentLength)) { return -1; } memcpy(digestResponse + currOffset, NC_HDR, segmentLength); currOffset += segmentLength; //"Authorization: Digest username="username", realm="myRealm", qop="auth", //algorithm="MD5", uri="/....Service", nonce="7a5c...", nc=00000002, //cnonce="ab341... segmentLength = strlen(cnonce); if (*length < (currOffset + segmentLength)) { return -1; } memcpy(digestResponse + currOffset, cnonce, segmentLength); currOffset += segmentLength; //"Authorization: Digest username="username", realm="myRealm", qop="auth", //algorithm="MD5", uri="/....Service", nonce="7a5c...", nc=00000002, //cnonce="ab341...", response=" segmentLength = strlen(RSP_HDR); if (*length < (currOffset + segmentLength)) { return -1; } memcpy(digestResponse + currOffset, RSP_HDR, segmentLength); currOffset += segmentLength; //calc response DigestCalcHA1("MD5", userName, realm, password, nonce, cnonce, HA1); DigestCalcResponse(HA1, nonce, "00000002", cnonce, "auth", method, uri, HA2, response); //"Authorization: Digest username="username", realm="myRealm", qop="auth", //algorithm="MD5", uri="/....Service", nonce="7a5c...", nc=00000002, //cnonce="ab341...", response="8bbf2... segmentLength = strlen(response); if (*length < (currOffset + segmentLength)) { return -1; } memcpy(digestResponse + currOffset, response, segmentLength); currOffset += segmentLength; //"Authorization: Digest username="username", realm="myRealm", qop="auth", //algorithm="MD5", uri="/....Service", nonce="7a5c...", nc=00000002, //cnonce="ab341...", response="8bbf2..." if (*length < (currOffset + 2)) { return -1; } memcpy(digestResponse + currOffset, "\"", 1); currOffset += 1; //add null termination *(digestResponse+currOffset) = 0; *length = currOffset; return 0; } /* * generate a 32 byte random hexadecimal string such as "4f6ba982..." * Arguments: * outbuff - buffer to fill */ static void GenerateCNonce(char *outbuff) { srand((unsigned int)time(NULL)); for(int i = 0; i < 32; i++) { int num = (int)(((double) rand()/ ((double)RAND_MAX+1)) * 16); switch(num) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: outbuff[i] = '0' + num; break; case 10: case 11: case 12: case 13: case 14: case 15: outbuff[i] = 'a' + (num-10); break; default: outbuff[i] = 'f'; } } outbuff[32] = 0; } /* * Creates the HTTP digest response * Arguments: * data - the HTTP digest structure * authHeader - the HTTP digest challenge * responseLength - size of response buffer * digestResponse - buffer for HTTP digest response * * Returns 0 for suceess. -1 for error */ static int CreateDigestResponse(struct http_digest_data *data, char *authHeader, size_t *responseLength, char *digestResponse) { char cnonce[33]; char *realmPtrStart, *realmPtrEnd, *noncePtrStart, *noncePtrEnd; size_t segmentLength; char realm[HDR_SIZE], nonce[HDR_SIZE];; if (digestResponse == NULL || authHeader == NULL) { return -1; } GenerateCNonce(cnonce); //grep realm from challange realmPtrStart = strstr(authHeader, "realm="); if (realmPtrStart == NULL) { return -1; } //point to start of realm realmPtrStart += 7; realmPtrEnd = strstr(realmPtrStart, "\""); segmentLength = realmPtrEnd - realmPtrStart; memcpy(realm, realmPtrStart, segmentLength); //add NULL termination realm[segmentLength] = 0; //grep nonce from challange noncePtrStart = strstr(authHeader, "nonce="); if (noncePtrStart == NULL) { return -1; } //point to start of nonce noncePtrStart += 7; noncePtrEnd = strstr(noncePtrStart, "\""); segmentLength = noncePtrEnd - noncePtrStart; memcpy(nonce, noncePtrStart, segmentLength); //add NULL termination nonce[segmentLength]=0; // in case there is a proxy the full URL is given // hence take only the last part http://ip/XXXService --> /XXXService char* uri = strrchr(data->requestUrl, '/'); return CalculateResponse(data->username, data->password, data->method, realm, uri, nonce, cnonce,digestResponse, responseLength); } /* * Copies the contents of the plugin * Arguments: * soap - pointer to the soap runtime environment * dst - the destination plugin * src - the original plugin * * Returns SOAP_OK for suceess. Error value for error */ static int http_digest_copy(struct soap *soap, struct soap_plugin *dst, struct soap_plugin *src) { *dst = *src; dst->data = (void*)malloc(sizeof(struct http_digest_data)); if (!dst->data) { return SOAP_EOM; } memcpy(dst->data, src->data, sizeof(struct http_digest_data)); ((struct http_digest_data*)dst->data)->sendBuffer = NULL; return SOAP_OK; } /* * Deletes the contents of the plugin * Arguments: * soap - pointer to the soap runtime environment * p - the plugin */ static void http_digest_delete(struct soap *soap, struct soap_plugin *p) { struct http_digest_data *data = (struct http_digest_data*)soap_lookup_plugin(soap, HTTP_DIGEST_ID); if (data) { if (data->sendBuffer) { free(data->sendBuffer); } free(data); } } /* * Open function. Will be called when connection opened. Used for saving parameters. * Arguments: * soap - pointer to the soap runtime environment * endpoint - the URL * host - machine to connect to * port - port on the host * * Returns SOAP_OK for suceess. Error value for error */ static int http_digest_fopen(struct soap *soap, const char *endpoint, const char *host, int port) { struct http_digest_data *data = (struct http_digest_data *)soap_lookup_plugin(soap, HTTP_DIGEST_ID); data->endpoint = (char*)endpoint; data->host = (char*)host; data->port = port; soap->frecv = http_digest_frecv; if (debug) { fprintf(stderr, "BEFORE data->fopen\n"); valid_socket(soap->socket); } int ret = data->fopen(soap, endpoint, host, port); if (debug) { fprintf(stderr, "AFTER data->fopen\n"); valid_socket(soap->socket); fflush(stderr); } return ret; } /* * Post header function. Used to identify parameters of the HTTP message * Arguments: * soap - pointer to the soap runtime environment * key - the header key * value - the header value * * Returns SOAP_OK for suceess. Error value for error */ static int http_digest_fposthdr(struct soap *soap, const char *key, const char *value) { struct http_digest_data *data = (struct http_digest_data *)soap_lookup_plugin(soap, HTTP_DIGEST_ID); char *s1, *s2; if (key && !value) { if (strncmp(key, "CONNECT", 7) == 0) { data->connect_count++; int ret; ret = data->fposthdr(soap, key, value); if (debug) { fprintf(stderr, "fposthdr: to soap fposthdr: key = %s, value = %s\n", key, value); fflush(stderr); } return ret; } data->sendMsgSize = 0; data->sendBufferLength = 0; if (data->sendBuffer) { free(data->sendBuffer); data->sendBuffer = NULL; } data->password = soap->passwd; data->username = soap->userid; soap->passwd = soap->userid = NULL; soap->frecv = http_digest_frecv; // read the method and URI from the key if (strncmp(key, "GET", 3) == 0) memcpy(data->method, "GET", 4); else if (strncmp(key, "POST", 4) == 0) memcpy(data->method, "POST", 5); else { return soap->error = SOAP_EOM; } s1 = strstr(key, " "); if (!s1) { return soap->error = SOAP_EOM; } s1++; s2 = strstr(s1, " "); if (!s2) { return soap->error = SOAP_EOM; } if (sizeof(data->requestUrl) <= (size_t)(s2 - s1)) { return soap->error = SOAP_EOM; } memcpy(data->requestUrl, s1, s2-s1); data->requestUrl[s2-s1] = '\0'; } else if (value) { // determine the maximum length of this message so that we can // correctly determine when we have completed the send if (strcmp(key, "Content-Length") == 0) { data->sendMsgSize += strtoul(value, NULL, 10); } } // calculate the header size data->sendMsgSize += 2; if (key) { data->sendMsgSize += strlen(key); if (value) { data->sendMsgSize += (strlen(value) + 2); } } int ret = data->fposthdr(soap, key, value); if (debug) { fprintf(stderr, "fposthdr: to soap fposthdr 2: key = %s, value = %s\n", key, value); fflush(stderr); } return ret; } /* * Send function. Used to buffer the sent data and save for resends * Arguments: * soap - pointer to the soap runtime environment * buf - buffer to be sent * size - size of data to send * * Returns SOAP_OK for suceess. Error value for error */ static int http_digest_fsend(struct soap *soap, const char *buf, size_t size) { struct http_digest_data *data = (struct http_digest_data *)soap_lookup_plugin(soap, HTTP_DIGEST_ID); size_t newBufferLen = data->sendBufferLength + size; if (!data->sendBuffer || (newBufferLen > data->sendMsgSize)) { if (newBufferLen > data->sendMsgSize) { data->sendMsgSize = newBufferLen; } data->sendBuffer = (char *)realloc(data->sendBuffer, data->sendMsgSize); if (!data->sendBuffer) { return SOAP_EOM; } } memcpy(data->sendBuffer + data->sendBufferLength, buf, size); data->sendBufferLength = newBufferLen; // if we haven't got the entire length of the message yet, then // we return to gsoap and let it continue if (data->sendBufferLength < data->sendMsgSize) { return SOAP_OK; } // we've now got the entire message, now we can send the buffer int ret = data->fsend(soap, data->sendBuffer, data->sendBufferLength); return ret; } /* * Reads the next character. May need to read from the network * Arguments: * data - pointer to the http digest structure * * Returns the next character or EOF for failure. */ static char http_digest_getchar(struct http_digest_data *data) { size_t res; if (data->rcvIdx < data->rcvRead) return data->rcvBuffer[data->rcvIdx++]; if (debug) { fprintf(stderr,"getchar:\n"); valid_socket(data->soap->socket); } res = data->frecv(data->soap, (data->rcvBuffer + data->rcvRead), (data->rcvSize - data->rcvRead)); if (res <= 0) return EOF; data->rcvRead += res; return data->rcvBuffer[data->rcvIdx++]; } /* * Reads the next HTTP header line. * Arguments: * data - pointer to the http digest structure * line - buffer to store the line read * len - length of the line buffer * * Returns SOAP_OK for suceess. Error value for error. */ static int http_digest_getline(struct http_digest_data *data, char *line, size_t len) { unsigned int i = len; int c = 0; char *s = line; for (;;) { while (--i > 0) { c = http_digest_getchar(data); if (c == '\r') break; if (c == EOF) return SOAP_EOF; *s++ = c; } c = http_digest_getchar(data); if (c == '\n') { *s = '\0'; if (i+1 == len) // empty line: end of HTTP header break; c = http_digest_getchar(data); data->rcvIdx--; // return to previous character if (c != ' ' && c != '\t') // HTTP line continuation? break; } else if (c == EOF) return SOAP_EOF; } if (debug) { fprintf(stderr,"getline: got %s\n", line); fflush(stderr); } return SOAP_OK; } /* * receive function. Used to look for digest authentication challenge. * If the challenge is found will calculate the response and resend. * Arguments: * soap - pointer to the soap runtime environment * buf - buffer read data into * size - size of buf * * Returns number of characters read. 0 for error. */ static size_t http_digest_frecv(struct soap *soap, char *buf, size_t size) { // lookup plugin struct http_digest_data *data = (struct http_digest_data *)soap_lookup_plugin(soap, HTTP_DIGEST_ID); // declare variables char header[HDR_SIZE], authResponse[HDR_SIZE]; static const char *CHALLANGE = "WWW-Authenticate: Digest"; char *s; unsigned long httpStatus; size_t len; bool found = false; if (data->connect_count == 1) { int ret = data->frecv(soap, buf, size); if (debug) { fprintf(stderr,"frecv: got back >>%.*s<<\n", ret, buf); fflush(stderr); } /* * When reading the response to the CONNECT, we have to * transparently pass the entire header back to gSOAP. * So check for the end of the header by looking for two * successive ends-of-line. If we've seen them, increment * data->connect_count so that we don't hit this part of the * code again. Otherwise, we'll come back into this part * again to pass back the next chunk read from the proxy. * (Seen in real life with Apache on Windows as proxy.) */ if (strncmp(buf + ret - 4, "\r\n\r\n", 4) == 0) data->connect_count++; return ret; } // init private buffer data->rcvBuffer = new char[size]; data->rcvSize = size; data->rcvIdx = 0; data->rcvRead = 0; data->rcvErr = false; // first call to http_digest_getline will call data->frecv to read data // and store it in private buffer // read header lines and parse them to get httpStatus do { if (http_digest_getline(data, header, HDR_SIZE)) goto _out; if ((s = strchr(header, ' '))) httpStatus = soap_strtoul(s, NULL, 10); else httpStatus = 0; if ((httpStatus != 100) && (httpStatus != 401)) goto _out; for (;;) { if (http_digest_getline(data, header, SOAP_HDRLEN)) goto _out; if (!*header) break; if ((httpStatus == 401) && strncmp(header, CHALLANGE, strlen(CHALLANGE)) == 0) { found = true; break; } } } while (httpStatus == 100); // if we got here httpStatus==401 if (!found) goto _out; // create digest response // header is HTTP digest challenge len = HDR_SIZE; if (CreateDigestResponse(data, header, &len, authResponse)) goto _out; s = strstr(data->sendBuffer, "\r\n"); if (!s) goto _out; s += 2; // point to the start of second line // delay sending SYN to allow AMT to close connection gracefully usleep(SYN_DELAY); // reset soap connectivity if (data->connect_count || httpStatus == 401) soap->fclose(soap); // use real receiver for reopening connection // use real sender for reopening connection soap->frecv = data->frecv; soap->fsend = data->fsend; soap->fposthdr = data->fposthdr; // resend CONNECT; this reopens the socket and SSL soap->socket = data->fopen(soap, data->endpoint, data->host, data->port); if (soap->error || !soap_valid_socket(soap->socket)) { data->rcvErr = true; goto _out; } if (data->fsend(soap, data->sendBuffer, s-data->sendBuffer) || data->fsend(soap, authResponse, len) || data->fsend(soap, "\r\n", 2) || data->fsend(soap, s, data->sendBufferLength - (s-data->sendBuffer))) { data->rcvErr = true; goto _out; } // after send - send FIN if needed #ifdef WITH_OPENSSL if (!soap->ssl && soap_valid_socket(soap->socket) && !soap->keep_alive) { soap->fshutdownsocket(soap, (SOAP_SOCKET)soap->socket, 1); // Send TCP FIN } #else if (soap_valid_socket(soap->socket) && !soap->keep_alive) { soap->fshutdownsocket(soap, (SOAP_SOCKET)soap->socket, 1); // Send TCP FIN } #endif // receive data data->rcvRead = data->frecv(soap, data->rcvBuffer, size); data->connect_count = 0; // for next round soap->fsend = http_digest_fsend; soap->fposthdr = http_digest_fposthdr; // this new connection used by gSoap for further comm soap->keep_alive = 1; // return it to soap memcpy(buf, data->rcvBuffer, data->rcvRead); _out: if (data->sendBuffer) { free(data->sendBuffer); data->sendBuffer = NULL; } int ret; ret = data->rcvErr ? 0 : data->rcvRead; delete data->rcvBuffer; data->rcvBuffer = NULL; soap->userid = data->username; soap->passwd = data->password; if (data->connect_count) reset_data(data); return ret; } /* * disconnect function. Originally here for debugging. * Adds sleep for SYN_DELAY. * Arguments: * soap - pointer to the soap runtime environment * * Returns value of real disconnect function */ static int http_digest_disconnect(struct soap *soap) { struct http_digest_data *data = (struct http_digest_data *)soap_lookup_plugin(soap, HTTP_DIGEST_ID); // delay sending SYN to allow AMT to close connection gracefully usleep(SYN_DELAY); int ret = data->fclose(soap); return ret; } /* * reset_data function. * * Arguments: * data - pointer to the runtime data to be reset */ static void reset_data(struct http_digest_data *data) { data->endpoint = NULL; data->host = NULL; data->port = 0; data->username = NULL; data->password = NULL; data->rcvErr = false; memset(data->requestUrl, 0, sizeof(data->requestUrl)); memset(data->method, 0, sizeof(data->method)); } #if 0 // ifdef out to avoid compiler warning static void soap_dump(struct soap *soap) // for debugging { struct http_digest_data *data = (struct http_digest_data *)soap_lookup_plugin(soap, HTTP_DIGEST_ID); fprintf(stderr, "==== SOAP DUMP:\n"); fprintf(stderr, "\tsoap->userid = %s\n", soap->userid); fprintf(stderr, "\tsoap->passwd = %s\n", soap->passwd); fprintf(stderr, "\tsoap->host = %s\n", soap->host); fprintf(stderr, "\tsoap->path = %s\n", soap->path); fprintf(stderr, "\tsoap->port = %d\n", soap->port); fprintf(stderr, "\tsoap->socket = %d\n", soap->socket); fprintf(stderr, "\tsoap->keep_alive = %d\n", soap->keep_alive); fprintf(stderr, "\tsoap->fopen = %s\n", soap->fopen == http_digest_fopen ? "http_digest_fopen" : "default fopen"); fprintf(stderr, "\tsoap->fsend = %s\n", soap->fsend == http_digest_fsend ? "http_digest_fsend" : "default fsend"); fprintf(stderr, "\tsoap->frecv = %s\n", soap->frecv == http_digest_frecv ? "http_digest_frecv" : "default frecv"); fprintf(stderr, "\tsoap->fposthdr = %s\n", soap->fposthdr == http_digest_fposthdr ? "http_digest_fposthdr" : "default fposthdr"); fprintf(stderr, "\tsoap->fclose = %s\n", soap->fclose == http_digest_disconnect ? "http_digest_disconnect" : "default fclose"); if (data) data_dump(data); else fprintf(stderr, "NO DATA\n"); valid_socket(soap->socket); fprintf(stderr, "====\n\n"); fflush(stderr); } static void data_dump(struct http_digest_data *data) // for debugging { fprintf(stderr, "==== DATA DUMP:\n"); fprintf(stderr, "\tdata->connect_count = %d\n", data->connect_count); fprintf(stderr, "\tdata->endpoint = %s\n", data->endpoint); fprintf(stderr, "\tdata->host = %s\n", data->host); fprintf(stderr, "\tdata->port = %d\n", data->port); fprintf(stderr, "\tdata->username = %s\n", data->username); fprintf(stderr, "\tdata->password = %s\n", data->password); fprintf(stderr, "\tdata->requestUrl = %s\n", data->requestUrl); fprintf(stderr, "\tdata->method = %s\n", data->method); } #endif static bool valid_socket(int fd) { struct stat sbuf; bool ret = (fstat(fd, & sbuf) == 0); fprintf(stderr, "+++ valid_socket: %s\n", ret ? "TRUE" : "FALSE"); return ret; }