/* stdsoap2.c[pp] 2.2.3d The contents of this file are subject to the gSOAP Public License Version 1.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.cs.fsu.edu/~engelen/soaplicense.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. The Initial Developer of the Original Code is Robert A. van Engelen. Copyright (C) 2000-2003 Robert A. van Engelen, Genivia inc. All Rights Reserved. Note: Win32 build needs winsock.dll (Visual C++ "wsock32.lib") To do this in Visual C++ 6.0, go to "Project", "settings", select the "Link" tab (the project file needs to be selected in the file view) and add "wsock32.lib" to the "Object/library modules" entry */ #include "stdafx.h" #include "emule.h" #include "stdsoap2.h" #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif #pragma warning(disable:4706) // assignment within conditional expression #pragma warning(disable:4310) // cast truncates constant value #pragma warning(disable:4701) // local variable 'c' may be used without having been initialized #pragma warning(disable:4127) // conditional expression is constant // eMule has to *ensure* that the "gzip compression" is compiled. Do NOT change this!! #if !defined(_DEBUG_SOAP) && (!defined(WITH_GZIP) || !defined(WITH_ZLIB)) #error "You have to define WITH_GZIP and WITH_ZLIB to complile this module for usage in the eMule project!" #endif #ifdef __cplusplus SOAP_SOURCE_STAMP("@(#) stdsoap2.cpp ver 2.2.3c 2003-03-06 12:00:00 GMT") extern "C" { #else SOAP_SOURCE_STAMP("@(#) stdsoap2.c ver 2.2.3c 2003-03-06 12:00:00 GMT") #endif /* EOF=-1 */ #define LT (-2) /* XML character '<' */ #define TT (-3) /* XML character '' */ #define QT (-5) /* XML character '"' */ #define AP (-6) /* XML character ''' */ #define blank(c) ((c)>=0 && (c)<=32) #define notblank(c) ((c)>32) #define hash_ptr(p) (((long)(p)>>3)&(SOAP_PTRHASH-1)) static const char soap_env1[42] = "http://schemas.xmlsoap.org/soap/envelope/"; static const char soap_enc1[42] = "http://schemas.xmlsoap.org/soap/encoding/"; static const char soap_env2[40] = "http://www.w3.org/2002/06/soap-envelope"; static const char soap_enc2[40] = "http://www.w3.org/2002/06/soap-encoding"; static wchar soap_char(struct soap*); static wchar soap_getchunkchar(struct soap*); static int hash_id(const char*); static void soap_update_ptrs(struct soap*, char*, char*, long); static void soap_add_copies(struct soap*, char*, char*, long); static int soap_putdimefield(struct soap*, const char*, size_t); static char *soap_getdimefield(struct soap*, int); static int soap_puthttphdr(struct soap*, int, size_t); static void soap_init_iht(struct soap*); static void soap_free_iht(struct soap*); static void soap_init_pht(struct soap*); static void soap_free_pht(struct soap*); static int soap_set_error(struct soap*, const char*, const char*, const char*, int); static int soap_set_sender_error(struct soap*, const char*, const char*, int); static int soap_set_receiver_error(struct soap*, const char*, const char*, int); static int soap_copy_fault(struct soap*, const char*, const char*, const char*); static int soap_element(struct soap*, const char*, int, const char*); static int soap_getattrval(struct soap*, char*, size_t, wchar); static size_t soap_begin_dime(struct soap*); static void soap_close_logfile(struct soap*, int); static void soap_set_logfile(struct soap*, int, const char*); static void soap_set_local_namespaces(struct soap*); #ifdef WITH_GZIP static int soap_getgzipheader(struct soap*); #endif #ifndef UNDER_CE static time_t soap_timegm(struct tm*); #endif static int http_post(struct soap*, const char*, const char*, int, const char*, const char*, size_t); static int http_post_header(struct soap*, const char*, const char*); static int http_response(struct soap*, int, size_t); static int http_parse(struct soap*); static int http_parse_header(struct soap*, const char*, const char*); static int tcp_connect(struct soap*, const char*, const char*, int); static int tcp_accept(struct soap*, int, struct sockaddr*, int*); static int tcp_disconnect(struct soap*); static int fsend(struct soap*, const char*, size_t); static size_t frecv(struct soap*, char*, size_t); static int fignore(struct soap*, const char*); static void *fplugin(struct soap*, const char*); static const char base64o[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const char base64i[81] = "\76XXX\77\64\65\66\67\70\71\72\73\74\75XXXXXXX\00\01\02\03\04\05\06\07\10\11\12\13\14\15\16\17\20\21\22\23\24\25\26\27\30\31XXXXXX\32\33\34\35\36\37\40\41\42\43\44\45\46\47\50\51\52\53\54\55\56\57\60\61\62\63"; struct soap_double_nan soap_double_nan = {0xFFFFFFFF, 0xFFFFFFFF}; struct code_map { int code; const char *string; }; static struct code_map h_errno_codes[] = { #ifdef HOST_NOT_FOUND { HOST_NOT_FOUND, "Host not found" }, #endif #ifdef TRY_AGAIN { TRY_AGAIN, "Try Again" }, #endif #ifdef NO_RECOVERY { NO_RECOVERY, "No Recovery" }, #endif #ifdef NO_DATA { NO_DATA, "No Data" }, #endif #ifdef NO_ADDRESS { NO_ADDRESS, "No Address" }, #endif {0, NULL} }; #ifdef WITH_OPENSSL static struct code_map h_ssl_error_codes[] = { #define _SSL_ERROR(e) { e, #e } _SSL_ERROR(SSL_ERROR_SSL), _SSL_ERROR(SSL_ERROR_ZERO_RETURN), _SSL_ERROR(SSL_ERROR_WANT_READ), _SSL_ERROR(SSL_ERROR_WANT_WRITE), _SSL_ERROR(SSL_ERROR_WANT_CONNECT), _SSL_ERROR(SSL_ERROR_WANT_X509_LOOKUP), _SSL_ERROR(SSL_ERROR_SYSCALL), {0, NULL} }; static SSL_CTX *soap_ssl_ctx = NULL; static const char *soap_ssl_pw = NULL; #endif #ifdef WIN32 static int tcp_done = 0; #endif /******************************************************************************/ #ifndef MAC_CARBON /******************************************************************************/ static int fsend(struct soap *soap, const char *s, size_t n) { int nwritten; while (n) { if (soap->socket >= 0) { if (soap->send_timeout) { struct timeval timeout; fd_set fd; if (soap->send_timeout > 0) { timeout.tv_sec = soap->send_timeout; timeout.tv_usec = 0; } else { timeout.tv_sec = -soap->send_timeout/1000000; timeout.tv_usec = -soap->send_timeout%1000000; } FD_ZERO(&fd); FD_SET(soap->socket, &fd); for (;;) { int r = select(soap->socket + 1, NULL, &fd, &fd, &timeout); if (r > 0) break; if (!r) { soap->errnum = 0; return SOAP_EOF; } if (soap_socket_errno != SOAP_EINTR) { soap->errnum = soap_socket_errno; return SOAP_EOF; } } } #ifdef WITH_OPENSSL if (soap->ssl) nwritten = SSL_write(soap->ssl, s, n); else #endif nwritten = send(soap->socket, s, n, soap->socket_flags); if (nwritten <= 0) { #ifdef WITH_OPENSSL if (soap->ssl && SSL_get_error(soap->ssl, nwritten) != SSL_ERROR_NONE) return SOAP_EOF; #endif if (soap_socket_errno != SOAP_EINTR && soap_socket_errno != SOAP_EWOULDBLOCK && soap_socket_errno != SOAP_EAGAIN) { soap->errnum = soap_socket_errno; return SOAP_EOF; } nwritten = 0; /* and call write() again */ } } else { #ifdef WITH_FASTCGI nwritten = fwrite(s, 1, n, stdout); fflush(stdout); #else #ifdef UNDER_CE nwritten = fwrite(s, 1, n, soap->sendfd); #else nwritten = write(soap->sendfd, s, n); #endif #endif if (nwritten <= 0) { if (soap_errno != SOAP_EINTR && soap_errno != SOAP_EWOULDBLOCK && soap_errno != SOAP_EAGAIN) { soap->errnum = soap_errno; return SOAP_EOF; } nwritten = 0; /* and call write() again */ } } n -= nwritten; s += nwritten; } return SOAP_OK; } /******************************************************************************/ #endif /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_flush_raw(struct soap *soap, const char *s, size_t n) { if ((soap->mode & SOAP_IO) == SOAP_IO_STORE) { char *t; if (!(t = (char*)soap_push_block(soap, n))) return soap->error = SOAP_EOM; memcpy(t, s, n); return SOAP_OK; } if ((soap->mode & SOAP_IO) == SOAP_IO_CHUNK) { char t[16]; sprintf(t, "\r\n%lX\r\n" + (soap->chunksize ? 0 : 2), (unsigned long)n); DBGMSG(SENT, t, strlen(t)); if ((soap->error = soap->fsend(soap, t, strlen(t)))) return soap->error; soap->chunksize += n; } DBGMSG(SENT, s, n); return soap->error = soap->fsend(soap, s, n); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_flush(struct soap *soap) { if (soap->bufidx) { #ifdef WITH_ZLIB if (soap->mode & SOAP_ENC_ZLIB) { soap->d_stream.next_in = (Byte*)soap->buf; soap->d_stream.avail_in = (unsigned int)soap->bufidx; #ifdef WITH_GZIP soap->z_crc = crc32(soap->z_crc, (Byte*)soap->buf, (unsigned int)soap->bufidx); #endif do { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Deflating %u bytes\n", soap->d_stream.avail_in)); if (deflate(&soap->d_stream, Z_NO_FLUSH) != Z_OK) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Unable to deflate: %s\n", soap->d_stream.msg?soap->d_stream.msg:"")); return soap->error = SOAP_ZLIB_ERROR; } if (!soap->d_stream.avail_out) { if (soap_flush_raw(soap, soap->z_buf, SOAP_BUFLEN)) return soap->error; soap->d_stream.next_out = (Byte*)soap->z_buf; soap->d_stream.avail_out = SOAP_BUFLEN; } } while (soap->d_stream.avail_in); } else #endif if (soap_flush_raw(soap, soap->buf, soap->bufidx)) return soap->error; soap->bufidx = 0; } return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_send_raw(struct soap *soap, const char *s, size_t n) { if (soap->mode & SOAP_IO_LENGTH) { soap->count += n; return SOAP_OK; } if (soap->mode & SOAP_IO) { size_t i = SOAP_BUFLEN - soap->bufidx; while (n >= i) { memcpy(soap->buf + soap->bufidx, s, i); soap->bufidx = SOAP_BUFLEN; if (soap_flush(soap)) return soap->error; s += i; n -= i; i = SOAP_BUFLEN; } memcpy(soap->buf + soap->bufidx, s, n); soap->bufidx += n; return SOAP_OK; } return soap_flush_raw(soap, s, n); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_send(struct soap *soap, const char *s) { if (s) return soap_send_raw(soap, s, strlen(s)); return SOAP_OK; } /******************************************************************************/ #ifndef MAC_CARBON /******************************************************************************/ static size_t frecv(struct soap *soap, char *s, size_t n) { int r; if (soap->socket >= 0) { for (;;) { if (soap->recv_timeout) { struct timeval timeout; fd_set fd; if (soap->recv_timeout > 0) { timeout.tv_sec = soap->recv_timeout; timeout.tv_usec = 0; } else { timeout.tv_sec = -soap->recv_timeout/1000000; timeout.tv_usec = -soap->recv_timeout%1000000; } FD_ZERO(&fd); FD_SET(soap->socket, &fd); for (;;) { r = select(soap->socket + 1, &fd, NULL, &fd, &timeout); if (r > 0) break; if (!r) { soap->errnum = 0; return 0; } if (soap_socket_errno != SOAP_EINTR) { soap->errnum = soap_socket_errno; return 0; } } } #ifdef WITH_OPENSSL if (soap->ssl) { r = SSL_read(soap->ssl, s, n); if (SSL_get_error(soap->ssl, r) == SSL_ERROR_NONE) return (size_t)r; return 0; } #endif r = recv(soap->socket, s, n, soap->socket_flags); if (r >= 0) return (size_t)r; if (soap_socket_errno != SOAP_EINTR && soap_socket_errno != SOAP_EAGAIN) { soap->errnum = soap_socket_errno; return 0; } else { struct timeval timeout; fd_set fd; timeout.tv_sec = 1; timeout.tv_usec = 0; FD_ZERO(&fd); FD_SET(soap->socket, &fd); r = select(soap->socket + 1, &fd, NULL, &fd, &timeout); if (r < 0 && soap_socket_errno != SOAP_EINTR) { soap->errnum = soap_socket_errno; return 0; } } } } #ifdef WITH_FASTCGI return fread(s, 1, n, stdin); #else #ifdef UNDER_CE return fread(s, 1, n, soap->recvfd); #else r = read(soap->recvfd, s, n); if (r >= 0) return r; return 0; #endif #endif } /******************************************************************************/ #endif /******************************************************************************/ static wchar soap_getchunkchar(struct soap *soap) { if (soap->bufidx < soap->buflen) return soap->buf[soap->bufidx++]; soap->bufidx = 0; soap->buflen = soap->chunkbuflen = soap->frecv(soap, soap->buf, SOAP_BUFLEN); DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Read %u bytes\n", (unsigned int)soap->buflen)); DBGMSG(RECV, soap->buf, soap->buflen); if (soap->buflen) return soap->buf[soap->bufidx++]; return EOF; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_recv_raw(struct soap *soap) { size_t ret; #ifdef WITH_ZLIB if (soap->mode & SOAP_ENC_ZLIB) { if (soap->d_stream.next_out == Z_NULL) return EOF; if (soap->d_stream.avail_in || !soap->d_stream.avail_out) { int r; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Inflating\n")); soap->d_stream.next_out = (Byte*)soap->buf; soap->d_stream.avail_out = SOAP_BUFLEN; r = inflate(&soap->d_stream, Z_NO_FLUSH); if (r == Z_OK || r == Z_STREAM_END) { soap->bufidx = 0; soap->buflen = SOAP_BUFLEN - soap->d_stream.avail_out; if (soap->zlib_in == SOAP_ZLIB_GZIP) soap->z_crc = crc32(soap->z_crc, (Byte*)soap->buf, (unsigned int)soap->buflen); if (r == Z_STREAM_END) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Inflated %lu->%lu bytes\n", soap->d_stream.total_in, soap->d_stream.total_out)); soap->z_ratio_in = (float)soap->d_stream.total_in / (float)soap->d_stream.total_out; soap->d_stream.next_out = Z_NULL; } if (soap->buflen) { soap->count += soap->buflen; return SOAP_OK; } } else if (r != Z_BUF_ERROR) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Inflate error: %s\n", soap->d_stream.msg?soap->d_stream.msg:"")); soap->d_stream.next_out = Z_NULL; return EOF; } } zlib_again: if ((soap->mode & SOAP_IO) == SOAP_IO_CHUNK && !soap->chunksize) { memcpy(soap->buf, soap->z_buf, SOAP_BUFLEN); soap->buflen = soap->z_buflen; } } #endif if ((soap->mode & SOAP_IO) == SOAP_IO_CHUNK) /* read HTTP chunked transfer */ { chunk_again: if (soap->chunksize) { if (soap->chunksize > SOAP_BUFLEN) soap->buflen = ret = soap->frecv(soap, soap->buf, SOAP_BUFLEN); else soap->buflen = ret = soap->frecv(soap, soap->buf, soap->chunksize); DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Getting chunk: read %u bytes\n", (unsigned int)ret)); DBGMSG(RECV, soap->buf, ret); soap->bufidx = 0; soap->chunksize -= ret; } else { wchar c; char tmp[8], *t; t = tmp; if (!soap->chunkbuflen) { soap->chunkbuflen = ret = soap->frecv(soap, soap->buf, SOAP_BUFLEN); DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Read %u bytes\n", (unsigned int)ret)); DBGMSG(RECV, soap->buf, ret); soap->bufidx = 0; if (!ret) return EOF; } else soap->bufidx = soap->buflen; soap->buflen = soap->chunkbuflen; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Getting chunk size (%u %u)\n", (unsigned int)soap->bufidx, (unsigned int)soap->buflen)); while (!isxdigit(c = soap_getchunkchar(soap))) if (c == EOF) return EOF; do *t++ = (char)c; while (isxdigit(c = soap_getchunkchar(soap)) && t - tmp < 7); while (c != EOF && c != '\n') c = soap_getchunkchar(soap); if (c == EOF) return EOF; *t = '\0'; soap->chunksize = strtoul(tmp, &t, 16); if (!soap->chunksize) { soap->chunkbuflen = 0; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "End of chunked message\n")); while (c != EOF && c != '\n') c = soap_getchunkchar(soap); return EOF; } soap->buflen = soap->bufidx + soap->chunksize; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Moving buf len to %u (%u %s)\n", (unsigned int)soap->buflen, (unsigned int)soap->bufidx, tmp)); if (soap->buflen > soap->chunkbuflen) { soap->buflen = soap->chunkbuflen; soap->chunksize -= soap->buflen - soap->bufidx; soap->chunkbuflen = 0; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Passed end of buffer for chunked HTTP (%lu bytes left)\n", (unsigned long)(soap->buflen - soap->bufidx))); } else if (soap->chunkbuflen) soap->chunksize = 0; ret = soap->buflen - soap->bufidx; if (!ret) goto chunk_again; } } else { soap->bufidx = 0; soap->buflen = ret = soap->frecv(soap, soap->buf, SOAP_BUFLEN); DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Read %u bytes\n", (unsigned int)ret)); DBGMSG(RECV, soap->buf, ret); } #ifdef WITH_ZLIB if (soap->mode & SOAP_ENC_ZLIB) { int r; memcpy(soap->z_buf, soap->buf, SOAP_BUFLEN); soap->d_stream.next_in = (Byte*)(soap->z_buf + soap->bufidx); soap->d_stream.avail_in = (unsigned int)ret; soap->d_stream.next_out = (Byte*)soap->buf; soap->d_stream.avail_out = SOAP_BUFLEN; r = inflate(&soap->d_stream, Z_NO_FLUSH); if (r == Z_OK || r == Z_STREAM_END) { soap->bufidx = 0; soap->z_buflen = soap->buflen; soap->buflen = ret = SOAP_BUFLEN - soap->d_stream.avail_out; if (soap->zlib_in == SOAP_ZLIB_GZIP) soap->z_crc = crc32(soap->z_crc, (Byte*)soap->buf, (unsigned int)soap->buflen); DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Inflated %u bytes\n", (unsigned int)ret)); if (!ret) goto zlib_again; if (r == Z_STREAM_END) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Inflated %lu->%lu bytes\n", soap->d_stream.total_in, soap->d_stream.total_out)); soap->z_ratio_in = (float)soap->d_stream.total_in / (float)soap->d_stream.total_out; soap->d_stream.next_out = Z_NULL; } } else { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Unable to inflate: (%d) %s\n", r, soap->d_stream.msg?soap->d_stream.msg:"")); soap->d_stream.next_out = Z_NULL; return EOF; } } #endif soap->count += ret; return !ret; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_recv(struct soap *soap) { if (soap->mode & SOAP_ENC_DIME) { if (soap->dime_buflen) { char *s; int i; unsigned char tmp[12]; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "DIME hdr for chunked DIME is in buffer\n")); soap->count += soap->dime_buflen - soap->buflen; soap->buflen = soap->dime_buflen; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Skip padding (%u bytes)\n", -(int)soap->dime_size&3)); for (i = -(int)soap->dime_size&3; i > 0; i--) { soap->bufidx++; if (soap->bufidx >= soap->buflen) if (soap_recv_raw(soap)) return EOF; } DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Get DIME hdr for next chunk\n")); s = (char*)tmp; for (i = 12; i > 0; i--) { *s++ = soap->buf[soap->bufidx++]; if (soap->bufidx >= soap->buflen) if (soap_recv_raw(soap)) return EOF; } soap->dime_flags = tmp[0]&0x7; soap->dime_size = tmp[8] << 24 | tmp[9] << 16 | tmp[10] << 8 | tmp[11]; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Get DIME chunk (%u bytes)\n", (unsigned int)soap->dime_size)); if (soap->dime_flags & SOAP_DIME_CF) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "More chunking\n")); soap->dime_chunksize = soap->dime_size; if (soap->buflen - soap->bufidx >= soap->dime_size) { soap->dime_buflen = soap->buflen; soap->buflen = soap->bufidx + soap->dime_chunksize; } else soap->dime_chunksize -= soap->buflen - soap->bufidx; } else { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Last chunk\n")); soap->dime_buflen = 0; soap->dime_chunksize = 0; } soap->count = soap->buflen - soap->bufidx; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "%u bytes remaining\n", (unsigned int)soap->count)); return SOAP_OK; } if (soap->dime_chunksize) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Get next DIME hdr for chunked DIME (%u bytes chunk)\n", (unsigned int)soap->dime_chunksize)); if (soap_recv_raw(soap)) return EOF; if (soap->buflen - soap->bufidx >= soap->dime_chunksize) { soap->dime_buflen = soap->buflen; soap->count -= soap->buflen - soap->bufidx - soap->dime_chunksize; soap->buflen = soap->bufidx + soap->dime_chunksize; } else soap->dime_chunksize -= soap->buflen - soap->bufidx; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "%lu bytes remaining, count=%u\n", (unsigned long)(soap->buflen-soap->bufidx), (unsigned int)soap->count)); return SOAP_OK; } } return soap_recv_raw(soap); } /******************************************************************************/ SOAP_FMAC1 wchar SOAP_FMAC2 soap_getchar(struct soap *soap) { register wchar c; if (soap->ahead) { c = soap->ahead; soap->ahead = 0; return c; } return soap_get1(soap); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_tag_cmp(register const char *s, register const char *t) { for (; *s; s++, t++) if (tolower(*s) != tolower(*t)) if (*t != '-') { if (*t != '*') return 1; if (*++t) { register int c = tolower(*t); for (; *s; s++) { if (tolower(*s) == c) if (!soap_tag_cmp(s+1, t+1)) return 0; } break; } else return 0; } if (*t == '*' && !t[1]) return 0; return *t; } /******************************************************************************/ static wchar soap_char(struct soap *soap) { int i, c; char tmp[8], *t = tmp; for (i = 0; i < 7; i++) { c = soap_get1(soap); if (c == ';' || c == EOF) break; *t++ = c; } *t = '\0'; if (*tmp == '#') { if (tmp[1] == 'x' || tmp[1] == 'X') return strtol(tmp + 2, NULL, 16) | 0x80000000; return atol(tmp + 1) | 0x80000000; } if (!soap_tag_cmp(tmp, "lt")) return '<'; if (!soap_tag_cmp(tmp, "gt")) return '>'; if (!soap_tag_cmp(tmp, "amp")) return '&'; if (!soap_tag_cmp(tmp, "quot")) return '"'; if (!soap_tag_cmp(tmp, "apos")) return '\''; return '?'; } /******************************************************************************/ SOAP_FMAC1 wchar SOAP_FMAC2 soap_get(struct soap *soap) { register wchar c; if (soap->ahead) { c = soap->ahead; soap->ahead = 0; } else c = soap_get1(soap); redo: if (soap->cdata) { if (c == ']') { c = soap_get1(soap); if (c == ']') { soap->cdata = 0; c = soap_get1(soap); /* skip > */ c = soap_get1(soap); goto redo; } else { /* soap->ahead2 = c; */ soap_revget1(soap); return ']'; } } else return c; } switch (c) { case '<': do c = soap_get1(soap); while (blank(c)); if (c == '!' || c == '?' || c == '%') { if (c == '!') { c = soap_get1(soap); if (c == '[') { do c = soap_get1(soap); while (c != EOF && c != '['); if (c == EOF) return EOF; soap->cdata = 1; return soap_get1(soap); } if (c == '-' && (c = soap_get1(soap)) == '-') { do { c = soap_get1(soap); if (c == '-' && (c = soap_get1(soap)) == '-') break; } while (c != EOF); } } while (c != EOF && c != '>') c = soap_get1(soap); if (c == '>') { c = soap_get1(soap); goto redo; } return EOF; } if (c == '/') return TT; /* soap->ahead2 = c; */ soap_revget1(soap); return LT; case '>': return GT; case '"': return QT; case '\'': return AP; case '&': c = soap_char(soap); } return c; } /******************************************************************************/ SOAP_FMAC1 wchar SOAP_FMAC2 soap_advance(struct soap *soap) { wchar c; while (((c = soap_get(soap)) != EOF) && c != LT && c != TT) ; return c; } /******************************************************************************/ SOAP_FMAC1 wchar SOAP_FMAC2 soap_skip(struct soap *soap) { register wchar c; do c = soap_get(soap); while (blank(c)); return c; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_move(struct soap *soap, int n) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Moving %d bytes forward\n", n)); for (; n > 0; n--) if (soap_getchar(soap) == EOF) return SOAP_EOF; return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 size_t SOAP_FMAC2 soap_tell(struct soap *soap) { return soap->count - soap->buflen + soap->bufidx - (soap->ahead != 0); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_pututf8(struct soap *soap, wchar c) { char tmp[16]; if (c > 0 && c < 0x80) { tmp[0] = (char)c; tmp[1] = '\0'; } else sprintf(tmp, "&#%lu;", (unsigned long)c); return soap_send(soap, tmp); } /******************************************************************************/ SOAP_FMAC1 wchar SOAP_FMAC2 soap_getutf8(struct soap *soap) { register wchar c; c = soap_get(soap); if (c < 0x80) return c; if (c < 0xE0) return (wchar)(c & 0x1F) << 6 | (wchar)(soap_get1(soap) & 0x3F); if (c < 0xF0) return (wchar)(c & 0x0F) << 12 | (wchar)(soap_get1(soap) & 0x3F) << 6 | (wchar)(soap_get1(soap) & 0x3F); if (c < 0xF8) return (wchar)(c & 0x07) << 18 | (wchar)(soap_get1(soap) & 0x3F) << 12 | (wchar)(soap_get1(soap) & 0x3F) << 6 | (wchar)(soap_get1(soap) & 0x3F); if (c < 0xFA) return (wchar)(c & 0x07) << 24 | (wchar)(soap_get1(soap) & 0x3F) << 18 | (wchar)(soap_get1(soap) & 0x3F) << 12 | (wchar)(soap_get1(soap) & 0x3F) << 6 | (wchar)(soap_get1(soap) & 0x3F); return (wchar)(c & 0x07) << 30 | (wchar)(soap_get1(soap) & 0x3F) << 24 | (wchar)(soap_get1(soap) & 0x3F) << 18 | (wchar)(soap_get1(soap) & 0x3F) << 12 | (wchar)(soap_get1(soap) & 0x3F) << 6 | (wchar)(soap_get1(soap) & 0x3F); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_puthex(struct soap *soap, int n) { char d[2]; d[0] = (n >> 4) + (n > 159 ? '7' : '0'); n &= 0x0F; d[1] = n + (n > 9 ? '7' : '0'); return soap_send_raw(soap, d, 2); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_gethex(struct soap *soap) { wchar c; char d1, d2; if ((c = soap_get(soap)) < 0) { soap_unget(soap, c); return EOF; } d1 = (char)c; if ((c = soap_get(soap)) < 0) { soap_unget(soap, c); return EOF; } d2 = (char)c; return ((d1 >= 'A' ? (d1 & 0x7) + 9 : d1 - '0') << 4) + (d2 >= 'A' ? (d2 & 0x7) + 9 : d2 - '0'); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_putbase64(struct soap *soap, const unsigned char *s, size_t n) { register size_t i; register unsigned long m; char d[4]; if (!s) return SOAP_OK; for (; n > 2; n -= 3, s += 3) { m = s[0] << 16 | s[1] << 8 | s[2]; for (i = 4; i > 0; m >>= 6) d[--i] = base64o[m & 0x3F]; if (soap_send_raw(soap, d, 4)) return soap->error; } if (n) { m = 0; for (i = 0; i < n; i++) m = m << 8 | *s++; for (; i < 3; i++) m <<= 8; for (i++; i > 0; m >>= 6) d[--i] = base64o[m & 0x3F]; for (i = 3; i > n; i--) d[i] = '='; if (soap_send_raw(soap, d, 4)) return soap->error; } return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 unsigned char* SOAP_FMAC2 soap_getbase64(struct soap *soap, size_t *n, int malloc_flag) { register int i, j; register wchar c; register unsigned long m; register char *s; unsigned char *p; if (soap_new_block(soap)) return NULL; for (;;) { s = (char*)soap_push_block(soap, 3*SOAP_BLKLEN); /* must be multiple of 3 */ if (!s) { soap_end_block(soap); *n = 0; return NULL; } for (i = 0; i < SOAP_BLKLEN; i++) { m = 0; j = 0; while (j < 4) { c = soap_get(soap); if (c == '=' || c < 0) { i *= 3; switch (j) { case 2: *s++ = (char)((m >> 4) & 0xFF); i++; break; case 3: *s++ = (char)((m >> 10) & 0xFF); *s++ = (char)((m >> 2) & 0xFF); i += 2; } if (n) *n = soap_size_block(soap, i); p = (unsigned char*)soap_save_block(soap, NULL); if (c >= 0) c = soap_advance(soap); soap_unget(soap, c); return p; } c -= '+'; if (c >= 0 && c <= 79) { m = (m << 6) + base64i[c]; j++; } } *s++ = (char)((m >> 16) & 0xFF); *s++ = (char)((m >> 8) & 0xFF); *s++ = (char)(m & 0xFF); } } } /******************************************************************************/ static char* soap_strerror(struct soap *soap, int soaperror) { if (soaperror) { #ifndef UNDER_CE return strerror(soaperror); #else FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, NULL, soaperror, 0, (LPTSTR)&soap->werrorstr, 256, NULL); wcstombs(soap->errorstr, soap->werrorstr, 256); return soap->errorstr; #endif } return NULL; } /******************************************************************************/ static int soap_set_error(struct soap *soap, const char *faultcode, const char *faultstring, const char *faultdetail, int soaperror) { const char **s = soap_faultdetail(soap); *soap_faultcode(soap) = faultcode; *soap_faultstring(soap) = faultstring; if (s) *s = faultdetail; return soap->error = soaperror; } /******************************************************************************/ static int soap_set_sender_error(struct soap *soap, const char *faultstring, const char *faultdetail, int soaperror) { return soap_set_error(soap, soap->version == 2 ? "SOAP-ENV:Sender" : "SOAP-ENV:Client", faultstring, faultdetail, soaperror); } /******************************************************************************/ static int soap_set_receiver_error(struct soap *soap, const char *faultstring, const char *faultdetail, int soaperror) { return soap_set_error(soap, soap->version == 2 ? "SOAP-ENV:Receiver" : "SOAP-ENV:Server", faultstring, faultdetail, soaperror); } /******************************************************************************/ static int soap_copy_fault(struct soap *soap, const char *faultcode, const char *faultstring, const char *faultdetail) { char *s = NULL, *t = NULL; if (faultstring) { s = (char*)soap_malloc(soap, strlen(faultstring)+1); if (s) strcpy(s, faultstring); } if (faultdetail) { t = (char*)soap_malloc(soap, strlen(faultdetail)+1); if (t) strcpy(t, faultdetail); } return soap_set_error(soap, faultcode, s, t, SOAP_FAULT); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_sender_fault(struct soap *soap, const char *faultstring, const char *faultdetail) { return soap_copy_fault(soap, soap->version == 2 ? "SOAP-ENV:Sender" : "SOAP-ENV:Client", faultstring, faultdetail); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_receiver_fault(struct soap *soap, const char *faultstring, const char *faultdetail) { return soap_copy_fault(soap, soap->version == 2 ? "SOAP-ENV:Receiver" : "SOAP-ENV:Server", faultstring, faultdetail); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_new_block(struct soap *soap) { struct soap_blist *p; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "New block sequence (prev=%p)\n", soap->blist)); if (!(p = (struct soap_blist*)malloc(sizeof(struct soap_blist)))) return SOAP_EOM; p->next = soap->blist; p->ptr = NULL; p->size = 0; soap->blist = p; return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 void* SOAP_FMAC2 soap_push_block(struct soap *soap, size_t n) { char *p; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Push block of %u bytes (%u bytes total)\n", (unsigned int)n, (unsigned int)soap->blist->size)); if (!(p = (char*)malloc(n + sizeof(char*) + sizeof(size_t)))) { soap->error = SOAP_EOM; return NULL; } *(char**)p = soap->blist->ptr; *(size_t*)(p + sizeof(char*)) = n; soap->blist->ptr = p; soap->blist->size += n; return p + sizeof(char*) + sizeof(size_t); } /******************************************************************************/ SOAP_FMAC1 void SOAP_FMAC2 soap_pop_block(struct soap *soap) { char *p; if (!soap->blist->ptr) return; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Pop block\n")); p = soap->blist->ptr; soap->blist->size -= *(size_t*)(p + sizeof(char*)); soap->blist->ptr = *(char**)p; free(p); } /******************************************************************************/ static void soap_update_ptrs(struct soap *soap, char *start, char *end, long offset) { int i; struct soap_ilist *ip; void *p, **q; for (i = 0; i < SOAP_IDHASH; i++) for (ip = soap->iht[i]; ip; ip = ip->next) { if (ip->ptr && (char*)ip->ptr >= start && (char*)ip->ptr < end) ip->ptr = (char*)ip->ptr + offset; for (q = &ip->link; q; q = (void**)p) { p = *q; if (p && (char*)p >= start && (char*)p < end) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Link update id='%s' %p\n", ip->id, p)); *q = (char*)p + offset; } } for (q = &ip->copy; q; q = (void**)p) { p = *q; if (p && (char*)p >= start && (char*)p < end) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Copy update id='%s' %p\n", ip->id, p)); *q = (char*)p + offset; } } } } /******************************************************************************/ static void soap_add_copies(struct soap *soap, char *start, char *end, long offset) { int i; register struct soap_ilist *ip; register char *p; for (i = 0; i < SOAP_IDHASH; i++) for (ip = soap->iht[i]; ip; ip = ip->next) { for (p = (char*)ip->copy; p; p = *(char**)p) { if (p >= start && p < end) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Copy added id='%s' %p to %p (prev in chain = %p)\n", ip->id, p, p+offset, ip->copy)); *(void**)(p + offset) = ip->copy; ip->copy = (void*)(p + offset); } } } } /******************************************************************************/ SOAP_FMAC1 void SOAP_FMAC2 soap_resolve_ptr(struct soap_ilist *ip) { register void *p, **q, *r; q = (void**)ip->link; ip->link = NULL; r = ip->ptr; while (q) { p = *q; *q = r; q = (void**)p; } } /******************************************************************************/ SOAP_FMAC1 size_t SOAP_FMAC2 soap_size_block(struct soap *soap, size_t n) { if (soap->blist->ptr) { soap->blist->size -= *(size_t*)(soap->blist->ptr + sizeof(char*)) - n; *(size_t*)(soap->blist->ptr + sizeof(char*)) = n; } return soap->blist->size; } /******************************************************************************/ SOAP_FMAC1 char* SOAP_FMAC2 soap_first_block(struct soap *soap) { char *p, *q, *r; if (!(p = soap->blist->ptr)) return NULL; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "First block\n")); r = NULL; do { q = *(char**)p; *(char**)p = r; r = p; p = q; } while (p); soap->blist->ptr = r; return r + sizeof(char*) + sizeof(size_t); } /******************************************************************************/ SOAP_FMAC1 char* SOAP_FMAC2 soap_next_block(struct soap *soap) { char *p; if ((p = soap->blist->ptr)) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Next block\n")); soap->blist->ptr = *(char**)p; free(p); if (soap->blist->ptr) return soap->blist->ptr + sizeof(char*) + sizeof(size_t); } return NULL; } /******************************************************************************/ SOAP_FMAC1 size_t SOAP_FMAC2 soap_block_size(struct soap *soap) { return *(size_t*)(soap->blist->ptr + sizeof(char*)); } /******************************************************************************/ SOAP_FMAC1 void SOAP_FMAC2 soap_end_block(struct soap *soap) { struct soap_blist *bp; char *p, *q; if ((bp = soap->blist)) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "End of block sequence, free all remaining blocks\n")); for (p = bp->ptr; p; p = q) { q = *(char**)p; free(p); } soap->blist = bp->next; free(bp); } DBGLOG(TEST, if (soap->blist) SOAP_MESSAGE(fdebug, "Restore previous block sequence\n")); } /******************************************************************************/ SOAP_FMAC1 char* SOAP_FMAC2 soap_save_block(struct soap *soap, char *p) { size_t n; char *q, *s; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Save all blocks in contiguous memory space of %u bytes (%p->%p)\n", (unsigned int)soap->blist->size, soap->blist->ptr, p)); if (soap->blist->size) { if (!p) p = (char*)soap_malloc(soap, soap->blist->size); if (p) for (s = p, q = soap_first_block(soap); q; q = soap_next_block(soap)) { n = soap_block_size(soap); soap_update_ptrs(soap, q, q + n, s - q); /* s and q may or may not be related */ DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Copy %u bytes from %p to %p\n", (unsigned int)n, q, s)); memcpy(s, q, n); s += n; } else soap->error = SOAP_EOM; } soap_end_block(soap); return p; } /******************************************************************************/ SOAP_FMAC1 char* SOAP_FMAC2 soap_store_block(struct soap *soap, char *p) { p = soap_save_block(soap, p); if (!soap->blist) { struct soap_ilist *ip; int i; for (i = 0; i < SOAP_IDHASH; i++) for (ip = soap->iht[i]; ip; ip = ip->next) if (ip->ptr) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Resolve link chain to point to %p\n", ip->ptr)); soap_resolve_ptr(ip); } } return p; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_push_namespace(struct soap *soap, const char *id, const char *ns) { int i; struct soap_nlist *np; if (!soap->local_namespaces) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "No namespace table\n")); return SOAP_NAMESPACE; } np = (struct soap_nlist*)malloc(sizeof(struct soap_nlist) + strlen(id)); if (!np) return soap->error = SOAP_EOM; np->next = soap->nlist; soap->nlist = np; strcpy(np->id, id); np->level = soap->level; np->index = -1; np->ns = NULL; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Push namespace binding (level=%u) '%s' '%s'\n", soap->level, id, ns)); for (i = 0; soap->local_namespaces[i].id; i++) { if (soap->local_namespaces[i].ns) if (!soap_tag_cmp(ns, soap->local_namespaces[i].ns)) break; if (soap->local_namespaces[i].in) if (!soap_tag_cmp(ns, soap->local_namespaces[i].in)) { if (soap->local_namespaces[i].out) free(soap->local_namespaces[i].out); if ((soap->local_namespaces[i].out = (char*)malloc(strlen(ns) + 1))) strcpy(soap->local_namespaces[i].out, ns); if (i == 0) { if (!strcmp(ns, soap_env1)) { soap->version = 1; /* and make sure we use SOAP 1.1 encoding */ if (soap->local_namespaces[1].out) free(soap->local_namespaces[1].out); if ((soap->local_namespaces[1].out = (char*)malloc(sizeof(soap_enc1)))) strcpy(soap->local_namespaces[1].out, soap_enc1); } else if (!strcmp(ns, soap_env2)) { soap->version = 2; /* and make sure we use the SOAP 1.2 encoding */ if (soap->local_namespaces[1].out) free(soap->local_namespaces[1].out); if ((soap->local_namespaces[1].out = (char*)malloc(sizeof(soap_enc2)))) strcpy(soap->local_namespaces[1].out, soap_enc2); } } break; } } if (soap->local_namespaces[i].id) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Push OK ('%s' matches '%s' in namespace table)\n", id, soap->local_namespaces[i].id)); np->index = i; } else { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Push NOT OK: no match found for '%s' in namespace mapping table\n", ns)); np->ns = (char*)malloc(strlen(ns) + 1); strcpy(np->ns, ns); } return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 void SOAP_FMAC2 soap_pop_namespace(struct soap *soap) { struct soap_nlist *np; while (soap->nlist && soap->nlist->level >= soap->level) { np = soap->nlist->next; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Popped namespace binding (level=%u) '%s'\n", soap->level, soap->nlist->id)); if (soap->nlist->ns) free(soap->nlist->ns); free(soap->nlist); soap->nlist = np; } } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_match_namespace(struct soap *soap, const char *id1, const char *id2, int n1, int n2) { struct soap_nlist *np = soap->nlist; while (np && (strncmp(np->id, id1, n1) || np->id[n1])) np = np->next; if (np) { if (np->index < 0 || (np->index >= 0 && soap->local_namespaces[np->index].id && (strncmp(soap->local_namespaces[np->index].id, id2, n2) || soap->local_namespaces[np->index].id[n2]))) return SOAP_NAMESPACE; return SOAP_OK; } return SOAP_SYNTAX_ERROR; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_match_tag(struct soap *soap, const char *tag1, const char *tag2) { const char *s, *t; if (!tag1 || !tag2) return SOAP_OK; s = strchr(tag1, ':'); t = strchr(tag2, ':'); if (s) { if (t) { if (soap_tag_cmp(s+1, t+1) || soap_match_namespace(soap, tag1, tag2, s-tag1, t-tag2)) return SOAP_TAG_MISMATCH; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Tags and namespaces match: '%s' '%s'\n", tag1, tag2)); return SOAP_OK; } t = tag2; s++; } else if (t) { s = tag1; t++; } else { s = tag1; t = tag2; } if (soap_tag_cmp(s, t)) return SOAP_TAG_MISMATCH; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Tags match: '%s' '%s'\n", tag1, tag2)); return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_match_array(struct soap *soap, const char *type) { if (*soap->type && *soap->arrayType) if (soap_match_tag(soap, soap->arrayType, type) && soap_match_tag(soap, soap->arrayType, "xsd:anyType") && soap_match_tag(soap, soap->arrayType, "xsd:ur-type") ) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Array type mismatch: '%s' '%s'\n", soap->arrayType, type)); return SOAP_TAG_MISMATCH; } return SOAP_OK; } /******************************************************************************/ #ifdef WITH_OPENSSL /******************************************************************************/ static int ssl_init() { static int done = 0; if (done) return 0; done = 1; SSL_library_init(); SSL_load_error_strings(); soap_ssl_ctx = SSL_CTX_new(SSLv23_method()); return !soap_ssl_ctx; } /******************************************************************************/ static const char * ssl_error(struct soap *soap, int ret) { int err = SSL_get_error(soap->ssl, ret); struct code_map *map = h_ssl_error_codes; while (map->code && map->code != err) map++; if (map->code) strcpy(soap->msgbuf, map->string); else return ERR_error_string(err, soap->msgbuf); if (err == SSL_ERROR_SYSCALL) { if (ERR_peek_error()) { unsigned long r; while ((r = ERR_get_error())) ERR_error_string_n(r, soap->msgbuf + strlen(soap->msgbuf), sizeof(soap->msgbuf) - strlen(soap->msgbuf)); } else { switch (ret) { case 0: strcpy(soap->msgbuf, "EOF was observed that violates the protocol. The client probably provided invalid authentication information."); break; case -1: sprintf(soap->msgbuf, "Error observed by underlying BIO: %s", strerror(errno)); break; } } } return soap->msgbuf; } /******************************************************************************/ static int fpassword(char *buf, int num, int rwflag, void *userdata) { if (num < (int)strlen(soap_ssl_pw)+1) return 0; strcpy(buf, soap_ssl_pw); return strlen(soap_ssl_pw); } /******************************************************************************/ static int ssl_auth_init(struct soap *soap) { ssl_init(); if (soap->keyfile) if (!(SSL_CTX_use_certificate_chain_file(soap_ssl_ctx, soap->keyfile))) return soap_set_receiver_error(soap, "SSL error", "Can't read certificate file", SOAP_SSL_ERROR); if (soap->password && soap->keyfile) { soap_ssl_pw = soap->password; SSL_CTX_set_default_passwd_cb(soap_ssl_ctx, fpassword); if (!(SSL_CTX_use_PrivateKey_file(soap_ssl_ctx, soap->keyfile, SSL_FILETYPE_PEM))) return soap_set_receiver_error(soap, "SSL error", "Can't read key file", SOAP_SSL_ERROR); } if (soap->cafile) if (!(SSL_CTX_load_verify_locations(soap_ssl_ctx, soap->cafile, 0))) return soap_set_receiver_error(soap, "SSL error", "Can't read CA list", SOAP_SSL_ERROR); if (soap->rsa) { RSA *rsa = RSA_generate_key(512, RSA_F4, NULL, NULL); if (!SSL_CTX_set_tmp_rsa(soap_ssl_ctx, rsa)) return soap_set_receiver_error(soap, "SSL error", "Can't set RSA key", SOAP_SSL_ERROR); RSA_free(rsa); } else if (soap->dhfile) { DH *dh = 0; BIO *bio; bio = BIO_new_file(soap->dhfile, "r"); if (!bio) return soap_set_receiver_error(soap, "SSL error", "Can't read DH file", SOAP_SSL_ERROR); dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); BIO_free(bio); if (SSL_CTX_set_tmp_dh(soap_ssl_ctx, dh) < 0) return soap_set_receiver_error(soap, "SSL error", "Can't set DH parameters", SOAP_SSL_ERROR); DH_free(dh); } #if (OPENSSL_VERSION_NUMBER < 0x00905100L) SSL_CTX_set_verify_depth(soap_ssl_ctx, 1); #endif if (soap->randfile) { if (!RAND_load_file(soap->randfile, -1)) return soap_set_receiver_error(soap, "SSL error", "Can't load randomness", SOAP_SSL_ERROR); } else { RAND_seed(soap->buf, sizeof(soap->buf)); while (!RAND_status()) { int r; #ifdef HAVE_RAND_R unsigned int s; r = rand_r(&s); #else r = rand(); #endif RAND_seed(&r, sizeof(int)); } } return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_ssl_accept(struct soap *soap) { int r; soap->error = ssl_auth_init(soap); if (soap->error) return soap->error; if (soap->socket < 0) return soap_set_receiver_error(soap, "SSL error", "No socket in soap_ssl_accept()", SOAP_SSL_ERROR); soap->ssl = SSL_new(soap_ssl_ctx); if (!soap->ssl) return soap_set_receiver_error(soap, "SSL error", "SSL_new() failed in soap_ssl_accept()", SOAP_SSL_ERROR); soap->imode |= SOAP_ENC_SSL; soap->omode |= SOAP_ENC_SSL; soap->bio = BIO_new_socket(soap->socket, BIO_NOCLOSE); SSL_set_bio(soap->ssl, soap->bio, soap->bio); r = SSL_accept(soap->ssl); if (r <= 0) return soap_set_receiver_error(soap, ssl_error(soap, r), "SSL_accept() failed in soap_ssl_accept()", SOAP_SSL_ERROR); return SOAP_OK; } /******************************************************************************/ #endif /******************************************************************************/ static int tcp_init(struct soap *soap) { soap->errmode = 1; #ifdef WIN32 if (tcp_done) return 0; tcp_done = 1; // { WSADATA w; // if (WSAStartup(MAKEWORD(1, 1), &w)) // { tcp_done = 0; // return -1; // } // } #endif return 0; } /******************************************************************************/ SOAP_FMAC1 void SOAP_FMAC2 soap_done(struct soap *soap) { int i; soap_free(soap); while (soap->clist) { struct soap_clist *p = soap->clist->next; free(soap->clist); soap->clist = p; } soap->keep_alive = 0; /* to force close the socket */ soap_closesock(soap); #ifdef WITH_COOKIES soap_free_cookies(soap); #endif while (soap->plugins) { struct soap_plugin *p = soap->plugins->next; if (!soap->copy) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Removing plugin '%s'\n", soap->plugins->id)); soap->plugins->fdelete(soap, soap->plugins); } free(soap->plugins); soap->plugins = p; } soap->fpost = http_post; soap->fposthdr = http_post_header; soap->fresponse = http_response; soap->fparse = http_parse; soap->fparsehdr = http_parse_header; soap->faccept = tcp_accept; #ifndef MAC_CARBON soap->fopen = tcp_connect; soap->fclose = tcp_disconnect; soap->fsend = fsend; soap->frecv = frecv; #endif soap->fignore = fignore; soap->fplugin = fplugin; if (!soap->copy && soap->master >= 0) { closesocket(soap->master); soap->master = -1; } for (i = 0; i < SOAP_MAXLOGS; i++) { soap_close_logfile(soap, i); if (!soap->copy && soap->logfile[i]) { free((void*)soap->logfile[i]); soap->logfile[i] = NULL; } } } /******************************************************************************/ SOAP_FMAC1 void SOAP_FMAC2 soap_cleanup(struct soap *soap) { soap_done(soap); #ifdef WIN32 if (!tcp_done) return; tcp_done = 0; // VERIFY( WSACleanup() == 0 ); #endif } /******************************************************************************/ static const char* tcp_error(struct soap *soap) { const char *msg = NULL; switch (soap->errmode) { case 0: msg = soap_strerror(soap, soap->errnum); break; case 1: msg = "WSAStartup failed"; break; case 2: { struct code_map *map = h_errno_codes; while (map->code && map->code != soap->errnum) map++; if (map->code) msg = map->string; else { sprintf(soap->msgbuf, "Unknown TCP error code %d\n", soap->errnum); msg = soap->msgbuf; } } } return msg; } /******************************************************************************/ #ifndef MAC_CARBON /******************************************************************************/ static int soap_gethost(struct soap *soap, const char *addr, struct in_addr *inaddr) { unsigned long iadd; struct hostent hostent, *host = &hostent; iadd = inet_addr(addr); if ((int)iadd != -1) { memcpy(inaddr, &iadd, sizeof(iadd)); return 0; } #if defined(__GLIBC__) if (gethostbyname_r(addr, &hostent, soap->buf, SOAP_BUFLEN, &host, &soap->errnum) < 0) host = NULL; #elif defined(HAVE_GETHOSTBYNAME_R) host = gethostbyname_r(addr, &hostent, soap->buf, SOAP_BUFLEN, &soap->errnum); #else if (!(host = gethostbyname(addr))) soap->errnum = h_errno; #endif if (!host) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Host name not found\n")); return -1; } memcpy(inaddr, host->h_addr, host->h_length); return 0; } /******************************************************************************/ #endif /******************************************************************************/ static int tcp_connect(struct soap *soap, const char *endpoint, const char *host, int port) { struct sockaddr_in sockaddr; int len = SOAP_BUFLEN; int set = 1; if (tcp_init(soap)) { soap_set_sender_error(soap, tcp_error(soap), "TCP initialization failed in tcp_connect()", SOAP_TCP_ERROR); return -1; } if (soap->socket >= 0) closesocket(soap->socket); soap->errmode = 0; if ((soap->socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) { soap->errnum = soap_socket_errno; soap_set_sender_error(soap, tcp_error(soap), "TCP socket failed in tcp_connect()", SOAP_TCP_ERROR); return -1; } if (soap->connect_flags && setsockopt(soap->socket, SOL_SOCKET, soap->connect_flags, (char*)&set, sizeof(int))) { soap->errnum = soap_socket_errno; soap_set_sender_error(soap, tcp_error(soap), "TCP setsockopt failed in tcp_connect()", SOAP_TCP_ERROR); return -1; } if (soap->keep_alive && setsockopt(soap->socket, SOL_SOCKET, SO_KEEPALIVE, (char*)&set, sizeof(int))) { soap->errnum = soap_socket_errno; soap_set_sender_error(soap, tcp_error(soap), "TCP setsockopt SO_KEEPALIVE failed in tcp_connect()", SOAP_TCP_ERROR); return -1; } #ifndef UNDER_CE if (setsockopt(soap->socket, SOL_SOCKET, SO_SNDBUF, (char*)&len, sizeof(int))) { soap->errnum = soap_socket_errno; soap_set_sender_error(soap, tcp_error(soap), "TCP setsockopt SO_SNDBUF failed in tcp_connect()", SOAP_TCP_ERROR); return -1; } if (setsockopt(soap->socket, SOL_SOCKET, SO_RCVBUF, (char*)&len, sizeof(int))) { soap->errnum = soap_socket_errno; soap_set_sender_error(soap, tcp_error(soap), "TCP setsockopt SO_RCVBUF failed in tcp_connect()", SOAP_TCP_ERROR); return -1; } #endif #ifdef TCP_NODELAY if (setsockopt(soap->socket, IPPROTO_TCP, TCP_NODELAY, (char*)&set, sizeof(int))) { soap->errnum = soap_socket_errno; soap_set_sender_error(soap, tcp_error(soap), "TCP setsockopt TCP_NODELAY failed in tcp_connect()", SOAP_TCP_ERROR); return -1; } #endif memset(&sockaddr, 0, sizeof(sockaddr)); sockaddr.sin_family = AF_INET; DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Open socket %d to host='%s'\n", soap->socket, host)); soap->errmode = 2; if (soap->proxy_host) { if (soap_gethost(soap, soap->proxy_host, &sockaddr.sin_addr)) { soap_set_sender_error(soap, tcp_error(soap), "TCP get proxy host by name failed in tcp_connect()", SOAP_TCP_ERROR); return -1; } sockaddr.sin_port = htons((short)soap->proxy_port); } else { if (soap_gethost(soap, host, &sockaddr.sin_addr)) { soap_set_sender_error(soap, tcp_error(soap), "TCP get host by name failed in tcp_connect()", SOAP_TCP_ERROR); return -1; } sockaddr.sin_port = htons((short)port); } soap->errmode = 0; if (soap->connect_timeout) #ifdef WIN32 { u_long nonblocking = 1; ioctlsocket(soap->socket, FIONBIO, &nonblocking); } #else fcntl(soap->socket, F_SETFL, fcntl(soap->socket, F_GETFL)|O_NONBLOCK); #endif for (;;) { if (connect(soap->socket, (struct sockaddr*)&sockaddr, sizeof(sockaddr))) { if (soap->connect_timeout && (soap_socket_errno == SOAP_EINPROGRESS || soap_socket_errno == SOAP_EWOULDBLOCK)) { struct timeval timeout; #if defined(SOCKLEN_T) SOCKLEN_T n = sizeof(struct sockaddr_in); #elif defined(__socklen_t_defined) || defined(_SOCKLEN_T) || defined(CYGWIN) socklen_t n = sizeof(struct sockaddr_in); #elif defined(WIN32) || defined(__APPLE__) || defined(HP_UX) || defined(SUN_OS) || defined(OPENSERVER) || defined(TRU64) int n = sizeof(struct sockaddr_in); #else size_t n = sizeof(struct sockaddr_in); #endif fd_set fd; if (soap->connect_timeout > 0) { timeout.tv_sec = soap->connect_timeout; timeout.tv_usec = 0; } else { timeout.tv_sec = -soap->connect_timeout/1000000; timeout.tv_usec = -soap->connect_timeout%1000000; } FD_ZERO(&fd); FD_SET(soap->socket, &fd); for (;;) { int r = select(soap->socket + 1, NULL, &fd, NULL, &timeout); if (r > 0) break; if (!r) { soap->errnum = 0; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Connect timeout\n")); soap_closesock(soap); soap_set_sender_error(soap, "Timeout", "TCP connect failed in tcp_connect()", SOAP_TCP_ERROR); return -1; } if (soap_socket_errno != SOAP_EINTR) { soap->errnum = soap_socket_errno; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Could not connect to host\n")); soap_closesock(soap); soap_set_sender_error(soap, tcp_error(soap), "TCP connect failed in tcp_connect()", SOAP_TCP_ERROR); return -1; } } if (!getsockopt(soap->socket, SOL_SOCKET, SO_ERROR, (char*)&soap->errnum, &n) && !soap->errnum) break; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Could not connect to host\n")); soap_closesock(soap); soap_set_sender_error(soap, tcp_error(soap), "TCP connect failed in tcp_connect()", SOAP_TCP_ERROR); return -1; } else if (soap_socket_errno != SOAP_EINTR) { soap->errnum = soap_socket_errno; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Could not connect to host\n")); soap_closesock(soap); soap_set_sender_error(soap, tcp_error(soap), "TCP connect failed in tcp_connect()", SOAP_TCP_ERROR); return -1; } } else break; } if (soap->connect_timeout) #ifdef WIN32 { u_long blocking = 0; ioctlsocket(soap->socket, FIONBIO, &blocking); } #else fcntl(soap->socket, F_SETFL, fcntl(soap->socket, F_GETFL)&~O_NONBLOCK); #endif #ifdef WITH_OPENSSL soap->imode &= ~SOAP_ENC_SSL; soap->omode &= ~SOAP_ENC_SSL; if (!strncmp(endpoint, "https:", 6)) { int r; size_t n; if (soap->proxy_host) { soap_begin_send(soap); sprintf(soap->tmpbuf, "CONNECT %s:%d HTTP/%s", host, port, soap->http_version); DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Connecting to proxy server\n")); if ((soap->error = soap->fposthdr(soap, soap->tmpbuf, NULL)) || (soap->error = soap->fposthdr(soap, NULL, NULL))) return -1; if (soap_end_send(soap)) return -1; n = soap->count; /* save the content length */ r = soap->mode; /* make sure we only parse HTTP */ soap->mode &= 0xFF00; if (soap_begin_recv(soap)) return -1; soap->mode = (short)r; soap->count = n; soap_begin_send(soap); } if (ssl_auth_init(soap)) { soap_set_sender_error(soap, "SSL error", "SSL authentication failed in tcp_connect(): check password, key file, and ca file.", SOAP_SSL_ERROR); return -1; } soap->ssl = SSL_new(soap_ssl_ctx); if (!soap->ssl) { soap->error = SOAP_SSL_ERROR; return -1; } soap->imode |= SOAP_ENC_SSL; soap->omode |= SOAP_ENC_SSL; soap->bio = BIO_new_socket(soap->socket, BIO_NOCLOSE); SSL_set_bio(soap->ssl, soap->bio, soap->bio); if ((r = SSL_connect(soap->ssl)) <= 0) { soap_set_sender_error(soap, ssl_error(soap, r), "SSL connect failed in tcp_connect()", SOAP_SSL_ERROR); return -1; } if (soap->require_server_auth) { X509 *peer; if (SSL_get_verify_result(soap->ssl) != X509_V_OK) { soap_set_sender_error(soap, "SSL error", "SSL certificate cannot be verified in tcp_connect()", SOAP_SSL_ERROR); return -1; } peer = SSL_get_peer_certificate(soap->ssl); X509_NAME_get_text_by_NID(X509_get_subject_name(peer), NID_commonName, soap->msgbuf, sizeof(soap->msgbuf)); if (soap_tag_cmp(soap->msgbuf, host)) { soap_set_sender_error(soap, "SSL error", "SSL certificate host name mismatch in tcp_connect()", SOAP_SSL_ERROR); return -1; } } } #endif return soap->socket; } /******************************************************************************/ static int tcp_accept(struct soap *soap, int s, struct sockaddr *a, int *n) { #if defined(SOCKLEN_T) return accept(s, a, (SOCKLEN_T*)n); #elif defined(__socklen_t_defined) || defined(_SOCKLEN_T) || defined(CYGWIN) return accept(s, a, (socklen_t*)n); #elif defined(WIN32) || defined(__APPLE__) || defined(HP_UX) || defined(SUN_OS) || defined(OPENSERVER) || defined(TRU64) return accept(s, a, n); #else return accept(s, a, (size_t*)n); #endif } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_bind(struct soap *soap, const char *host, int port, int backlog) { struct sockaddr_in sockaddr; int len = SOAP_BUFLEN; int set = 1; if (soap->master >= 0) { closesocket(soap->master); soap->master = -1; } soap->socket = -1; soap->errmode = 1; if (tcp_init(soap)) { soap_set_receiver_error(soap, tcp_error(soap), "TCP init failed in soap_bind()", SOAP_TCP_ERROR); return -1; } soap->errmode = 0; if ((soap->master = socket(AF_INET, SOCK_STREAM, 0)) < 0) { soap->errnum = soap_socket_errno; soap_set_receiver_error(soap, tcp_error(soap), "TCP socket failed in soap_bind()", SOAP_TCP_ERROR); return -1; } if (soap->bind_flags && setsockopt(soap->master, SOL_SOCKET, soap->bind_flags, (char*)&set, sizeof(int))) { soap->errnum = soap_socket_errno; soap_set_receiver_error(soap, tcp_error(soap), "TCP setsockopt failed in soap_bind()", SOAP_TCP_ERROR); return -1; } if (soap->keep_alive && setsockopt(soap->master, SOL_SOCKET, SO_KEEPALIVE, (char*)&set, sizeof(int))) { soap->errnum = soap_socket_errno; soap_set_receiver_error(soap, tcp_error(soap), "TCP setsockopt SO_KEEPALIVE failed in soap_bind()", SOAP_TCP_ERROR); return -1; } #ifndef UNDER_CE if (setsockopt(soap->master, SOL_SOCKET, SO_SNDBUF, (char*)&len, sizeof(int))) { soap->errnum = soap_socket_errno; soap_set_receiver_error(soap, tcp_error(soap), "TCP setsockopt SO_SNDBUF failed in soap_bind()", SOAP_TCP_ERROR); return -1; } if (setsockopt(soap->master, SOL_SOCKET, SO_RCVBUF, (char*)&len, sizeof(int))) { soap->errnum = soap_socket_errno; soap_set_receiver_error(soap, tcp_error(soap), "TCP setsockopt SO_RCVBUF failed in soap_bind()", SOAP_TCP_ERROR); return -1; } #endif #ifdef TCP_NODELAY if (setsockopt(soap->master, IPPROTO_TCP, TCP_NODELAY, (char*)&set, sizeof(int))) { soap->errnum = soap_socket_errno; soap_set_receiver_error(soap, tcp_error(soap), "TCP setsockopt TCP_NODELAY failed in soap_bind()", SOAP_TCP_ERROR); return -1; } #endif memset(&sockaddr, 0, sizeof(sockaddr)); sockaddr.sin_family = AF_INET; soap->errmode = 2; if (host) { if (soap_gethost(soap, host, &sockaddr.sin_addr)) { soap_set_receiver_error(soap, tcp_error(soap), "TCP get host by name failed in soap_bind()", SOAP_TCP_ERROR); return -1; } } else sockaddr.sin_addr.s_addr = htonl(INADDR_ANY); sockaddr.sin_port = htons((short)port); soap->errmode = 0; if (bind(soap->master, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) || listen(soap->master, backlog)) { soap->errnum = soap_socket_errno; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Could not bind to host\n")); soap_closesock(soap); soap_set_receiver_error(soap, tcp_error(soap), "TCP bind failed in soap_bind()", SOAP_TCP_ERROR); return -1; } return soap->master; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_poll(struct soap *soap) { struct timeval timeout; fd_set fd; int r; timeout.tv_sec = 0; timeout.tv_usec = 0; FD_ZERO(&fd); if (soap->socket >= 0) { FD_SET(soap->socket, &fd); r = select(soap->socket + 1, &fd, &fd, &fd, &timeout); } else if (soap->master >= 0) { FD_SET(soap->master, &fd); r = select(soap->master + 1, &fd, &fd, &fd, &timeout); } else { FD_SET(soap->sendfd, &fd); FD_SET(soap->recvfd, &fd); r = select((soap->sendfd > soap->recvfd ? soap->sendfd : soap->recvfd) + 1, &fd, &fd, &fd, &timeout); } if (r > 0) return SOAP_OK; if (r < 0 && (soap->master >= 0 || soap->socket >= 0) && soap_socket_errno != SOAP_EINTR) { soap->errnum = soap_socket_errno; soap_set_receiver_error(soap, tcp_error(soap), "select failed in soap_poll()", SOAP_TCP_ERROR); return soap->error = SOAP_TCP_ERROR; } else soap->errnum = soap_errno; return SOAP_EOF; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_accept(struct soap *soap) { struct sockaddr_in sockaddr; int len = SOAP_BUFLEN; int set = 1; int n = sizeof(struct sockaddr_in); memset(&sockaddr, 0, sizeof(sockaddr)); soap->socket = -1; soap->errmode = 0; if (soap->master >= 0) { for (;;) { if (soap->accept_timeout) { struct timeval timeout; fd_set fd; if (soap->accept_timeout > 0) { timeout.tv_sec = soap->accept_timeout; timeout.tv_usec = 0; } else { timeout.tv_sec = -soap->accept_timeout/1000000; timeout.tv_usec = -soap->accept_timeout%1000000; } FD_ZERO(&fd); FD_SET(soap->master, &fd); for (;;) { int r = select(soap->master + 1, &fd, &fd, NULL, &timeout); if (r > 0) break; if (!r) { soap->errnum = 0; soap_set_receiver_error(soap, "Timeout", "TCP accept failed in soap_accept()", SOAP_TCP_ERROR); return -1; } if (soap_socket_errno != SOAP_EINTR) { soap->errnum = soap_socket_errno; soap_closesock(soap); soap_set_sender_error(soap, tcp_error(soap), "TCP accept failed in soap_accept()", SOAP_TCP_ERROR); return -1; } } #ifdef WIN32 #ifdef WITH_OPENSSL if (!soap->ssl) /* fixes win32+OpenSSL problem */ #endif { u_long nonblocking = 1; ioctlsocket(soap->master, FIONBIO, &nonblocking); } #else fcntl(soap->master, F_SETFL, fcntl(soap->master, F_GETFL)|O_NONBLOCK); #endif } if ((soap->socket = soap->faccept(soap, soap->master, (struct sockaddr*)&sockaddr, &n)) >= 0) { soap->ip = ntohl(sockaddr.sin_addr.s_addr); if (soap->accept_flags && setsockopt(soap->socket, SOL_SOCKET, soap->accept_flags, (char*)&set, sizeof(int))) { soap->errnum = soap_socket_errno; soap_set_receiver_error(soap, tcp_error(soap), "TCP setsockopt failed in soap_accept()", SOAP_TCP_ERROR); return -1; } soap->keep_alive = ((soap->imode & SOAP_IO_KEEPALIVE) != 0); if (soap->keep_alive && setsockopt(soap->socket, SOL_SOCKET, SO_KEEPALIVE, (char*)&set, sizeof(int))) { soap->errnum = soap_socket_errno; soap_set_receiver_error(soap, tcp_error(soap), "TCP setsockopt SO_KEEPALIVE failed in soap_accept()", SOAP_TCP_ERROR); return -1; } #ifndef UNDER_CE if (setsockopt(soap->socket, SOL_SOCKET, SO_SNDBUF, (char*)&len, sizeof(int))) { soap->errnum = soap_socket_errno; soap_set_receiver_error(soap, tcp_error(soap), "TCP setsockopt SO_SNDBUF failed in soap_accept()", SOAP_TCP_ERROR); return -1; } if (setsockopt(soap->socket, SOL_SOCKET, SO_RCVBUF, (char*)&len, sizeof(int))) { soap->errnum = soap_socket_errno; soap_set_receiver_error(soap, tcp_error(soap), "TCP setsockopt SO_RCVBUF failed in soap_accept()", SOAP_TCP_ERROR); return -1; } #endif #ifdef TCP_NODELAY if (setsockopt(soap->socket, IPPROTO_TCP, TCP_NODELAY, (char*)&set, sizeof(int))) { soap->errnum = soap_socket_errno; soap_set_receiver_error(soap, tcp_error(soap), "TCP setsockopt TCP_NODELAY failed in soap_accept()", SOAP_TCP_ERROR); return -1; } #endif if (soap->accept_timeout) #ifdef WIN32 { u_long blocking = 0; ioctlsocket(soap->master, FIONBIO, &blocking); } #else fcntl(soap->master, F_SETFL, fcntl(soap->master, F_GETFL)&~O_NONBLOCK); #endif return soap->socket; } else if (soap_socket_errno != SOAP_EINTR && soap_socket_errno != SOAP_EAGAIN) { soap->errnum = soap_socket_errno; soap_set_receiver_error(soap, tcp_error(soap), "TCP accept failed in soap_accept()", SOAP_TCP_ERROR); return -1; } } } else { soap_set_receiver_error(soap, "", "TCP no master socket in soap_accept()", SOAP_TCP_ERROR); return -1; } } /******************************************************************************/ static int tcp_disconnect(struct soap *soap) { #ifdef WITH_OPENSSL if (soap->ssl) { int r = SSL_shutdown(soap->ssl); int s = 0; if (r != 1) { s = ERR_get_error(); if (s) { if (soap->socket >= 0) { shutdown(soap->socket, 1); soap->socket = -1; } r = SSL_shutdown(soap->ssl); } } DBGLOG(TEST, if (s) SOAP_MESSAGE(fdebug, "Shutdown failed: %d\n", SSL_get_error(soap->ssl, r))); SSL_free(soap->ssl); soap->ssl = NULL; if (s) return SOAP_SSL_ERROR; } #endif if (soap->socket >= 0) { DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Closing socket %d\n", soap->socket)); closesocket(soap->socket); } return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_closesock(struct soap *soap) { #ifndef MAC_CARBON if (!soap->keep_alive) { soap->error = soap->fclose(soap); soap->socket = -1; } #endif return soap->error; } /******************************************************************************/ static int hash_id(register const char *s) { register int h = 0; while (*s) h += *s++ & 0x1F; return h % SOAP_IDHASH; } /******************************************************************************/ static void soap_init_pht(struct soap *soap) { int i; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Initializing pointer hashtable\n")); for (i = 0; i < SOAP_PTRHASH; i++) soap->pht[i] = NULL; } /******************************************************************************/ SOAP_FMAC1 struct soap* SOAP_FMAC2 soap_new() { struct soap *soap = (struct soap*)malloc(sizeof(struct soap)); if (soap) soap_init(soap); return soap; } /******************************************************************************/ static void soap_free_pht(struct soap *soap) { struct soap_plist *pp, *next; int i; for (i = 0; i < SOAP_PTRHASH; i++) { for (pp = soap->pht[i]; pp; pp = next) { next = pp->next; free(pp); } soap->pht[i] = NULL; } } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_pointer_lookup(struct soap *soap, const void *p, int type, struct soap_plist **ppp) { struct soap_plist *pp; *ppp = NULL; if (!p) return 0; for (pp = soap->pht[hash_ptr(p)]; pp; pp = pp->next) if (pp->ptr == p && pp->type == type) { *ppp = pp; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Lookup location=%p type=%d id=%d\n", p, type, pp->id)); return pp->id; } DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Lookup location=%p type=%d: not found\n", p, type)); return 0; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_array_pointer_lookup(struct soap *soap, const void *p, const struct soap_array *a, int n, int type, struct soap_plist **ppp) { struct soap_plist *pp; *ppp = NULL; if (!p || !a->__ptr) return 0; for (pp = soap->pht[hash_ptr(a->__ptr)]; pp; pp = pp->next) if (pp->type == type && pp->array && pp->array->__ptr == a->__ptr && pp->array->__size == n) { *ppp = pp; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Array lookup location=%p type=%d id=%d\n", a->__ptr, type, pp->id)); return pp->id; } DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Array lookup location=%p type=%d: not found\n", a->__ptr, type)); return 0; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_pointer_enter(struct soap *soap, const void *p, int type, struct soap_plist **ppp) { int h; struct soap_plist *pp; if (!p) { *ppp = NULL; return 0; } DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Enter location=%p type=%d id=%d\n", p, type, soap->idnum+1)); *ppp = pp = (struct soap_plist*)malloc(sizeof(struct soap_plist)); if (pp) { h = hash_ptr(p); pp->next = soap->pht[h]; pp->type = type; if ((soap->mode & SOAP_XML_TREE) || soap->is_in_header) { pp->mark1 = 0; pp->mark2 = 0; } else { pp->mark1 = 1; pp->mark2 = 1; } pp->ptr = p; pp->array = NULL; pp->id = ++soap->idnum; soap->pht[h] = pp; } else return 0; return pp->id; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_array_pointer_enter(struct soap *soap, const void *p, const struct soap_array *a, int type, struct soap_plist **ppp) { int h; struct soap_plist *pp; *ppp = NULL; if (!p || !a->__ptr) return 0; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Array enter location=%p type=%d id=%d\n", a->__ptr, type, soap->idnum+1)); pp = (struct soap_plist*)malloc(sizeof(struct soap_plist)); *ppp = pp; if (pp) { h = hash_ptr(a->__ptr); pp->next = soap->pht[h]; pp->type = type; if ((soap->mode & SOAP_XML_TREE) || soap->is_in_header) { pp->mark1 = 0; pp->mark2 = 0; } else { pp->mark1 = 1; pp->mark2 = 1; } pp->ptr = p; pp->array = a; pp->id = ++soap->idnum; soap->pht[h] = pp; } else return 0; return pp->id; } /******************************************************************************/ SOAP_FMAC1 void SOAP_FMAC2 soap_begin_count(struct soap *soap) { soap_clr_attr(soap); soap_set_local_namespaces(soap); if (soap->mode & SOAP_ENC_DIME) soap->mode = soap->omode | SOAP_IO_LENGTH | SOAP_ENC_DIME; else { soap->mode = soap->omode; if ((soap->mode & (SOAP_IO_STORE | SOAP_IO_CHUNK)) || (soap->mode & SOAP_ENC_XML)) soap->mode &= ~SOAP_IO_LENGTH; else soap->mode |= SOAP_IO_LENGTH; } if ((soap->mode & SOAP_ENC_ZLIB) && (soap->mode & SOAP_IO) == SOAP_IO_FLUSH) { if (!(soap->mode & SOAP_ENC_DIME)) soap->mode &= ~SOAP_IO_LENGTH; if (soap->mode & SOAP_ENC_XML) soap->mode |= SOAP_IO_BUFFER; else soap->mode |= SOAP_IO_STORE; } soap->count = 0; soap->ns = 0; soap->null = 0; soap->position = 0; soap->mustUnderstand = 0; soap->is_in_header = 0; soap->dime_count = 0; /* count # of attachments */ soap->dime_size = 0; /* accumulate total size of attachments */ DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Begin count phase\n")); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_begin_send(struct soap *soap) { soap_clr_attr(soap); soap_set_local_namespaces(soap); soap->mode = (soap->omode & ~SOAP_IO_LENGTH) | (soap->mode & SOAP_ENC_DIME); if ((soap->mode & SOAP_ENC_ZLIB) && (soap->mode & SOAP_IO) == SOAP_IO_FLUSH) { if (soap->mode & SOAP_ENC_XML) soap->mode |= SOAP_IO_BUFFER; else soap->mode |= SOAP_IO_STORE; } if ((soap->mode & SOAP_IO) == SOAP_IO_STORE) soap_new_block(soap); else if ((soap->mode & SOAP_IO) == SOAP_IO_FLUSH && soap->socket >= 0) soap->mode |= SOAP_IO_BUFFER; if (!(soap->mode & SOAP_IO_KEEPALIVE)) soap->keep_alive = 0; #ifdef WIN32 #ifndef UNDER_CE if (soap->socket < 0) /* Set win32 stdout or soap->sendfd to BINARY, e.g. to support DIME */ #ifndef WITH_FASTCGI #ifdef __BORLANDC__ setmode(soap->sendfd, O_BINARY); #else _setmode(soap->sendfd, _O_BINARY); #endif #endif #endif #endif soap->bufidx = 0; soap->buflen = 0; soap->chunksize = 0; soap->ns = 0; soap->null = 0; soap->position = 0; soap->mustUnderstand = 0; soap->is_in_header = 0; soap->idnum = 0; #ifdef WITH_ZLIB soap->z_ratio_out = 1.0; if (soap->mode & SOAP_ENC_ZLIB) { #ifdef WITH_GZIP memcpy(soap->z_buf, "\37\213\10\0\0\0\0\0\0\377", 10); soap->d_stream.next_out = (Byte*)soap->z_buf + 10; soap->d_stream.avail_out = SOAP_BUFLEN - 10; soap->z_crc = crc32(0L, NULL, 0); if (deflateInit2(&soap->d_stream, soap->z_level, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY) != Z_OK) #else soap->d_stream.next_out = (Byte*)soap->z_buf; soap->d_stream.avail_out = SOAP_BUFLEN; if (deflateInit(&soap->d_stream, soap->z_level) != Z_OK) #endif return soap->error = SOAP_ZLIB_ERROR; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Deflate initialized\n")); } #endif DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Begin send phase (socket=%d mode=%hd count=%lu)\n", soap->socket, soap->mode, (unsigned long)soap->count)); return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 void SOAP_FMAC2 soap_embedded(struct soap *soap, const void *p, int t) { struct soap_plist *pp; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Embedded %p type=%d\n", p, t)); if (soap_pointer_lookup(soap, p, t, &pp)) { pp->mark1 = 1; pp->mark2 = 1; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Embedded %p type=%d set to %d\n", p, t, (int)pp->mark1)); } } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_reference(struct soap *soap, const void *p, int t) { int i; struct soap_plist *pp; if (!p) return 1; i = soap_pointer_lookup(soap, p, t, &pp); if (i) { if (pp->mark1 == 0) { pp->mark1 = 2; pp->mark2 = 2; } } else { soap_pointer_enter(soap, p, t, &pp); pp->mark1 = 0; pp->mark2 = 0; } DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Reference %p type = %d (%d %d)\n", p, t, (int)pp->mark1, (int)pp->mark2)); return pp->mark1; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_array_reference(struct soap *soap, const void *p, const struct soap_array *a, int n, int t) { int i; struct soap_plist *pp; if (!p) return 1; i = soap_array_pointer_lookup(soap, p, a, n, t, &pp); if (i) { if (pp->mark1 == 0) { pp->mark1 = 2; pp->mark2 = 2; } } else if (!soap_array_pointer_enter(soap, p, a, t, &pp)) return 1; pp->mark1 = 0; pp->mark2 = 0; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Array reference %p type = %d (%d %d)\n", p, t, (int)pp->mark1, (int)pp->mark2)); return pp->mark1; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_embedded_id(struct soap *soap, int id, const void *p, int t) { struct soap_plist *pp; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Embedded_id %p type=%d id=%d\n", p, t, id)); if (soap->version == 1 && !(soap->mode & (SOAP_XML_TREE | SOAP_XML_GRAPH)) && !soap->is_in_header) { if (id < 0) { id = soap_pointer_lookup(soap, p, t, &pp); if (id > 0 && pp) { if (soap->mode & SOAP_IO_LENGTH) pp->mark1 = 2; else pp->mark2 = 2; } return -1; } return id; } if (id < 0) id = soap_pointer_lookup(soap, p, t, &pp); else soap_pointer_lookup(soap, p, t, &pp); if (id > 0 && pp) { if (soap->mode & SOAP_IO_LENGTH) pp->mark1 = 1; else pp->mark2 = 1; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Embedded_id id=%d %p type=%d = (%d %d)\n", id, p, t, (int)pp->mark1, (int)pp->mark2)); } return id; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_is_embedded(struct soap *soap, struct soap_plist *pp) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Is embedded? %d %d\n", (int)pp->mark1, (int)pp->mark2)); if (soap->version == 1 && !(soap->mode & (SOAP_XML_TREE | SOAP_XML_GRAPH)) && !soap->is_in_header) { if (soap->mode & SOAP_IO_LENGTH) return pp->mark1 != 0; return pp->mark2 != 0; } if (soap->mode & SOAP_IO_LENGTH) return pp->mark1 == 1; return pp->mark2 == 1; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_is_single(struct soap *soap, struct soap_plist *pp) { if ((soap->mode & SOAP_XML_TREE) || soap->is_in_header) return 1; if (soap->mode & SOAP_IO_LENGTH) return pp->mark1 == 0; return pp->mark2 == 0; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_is_multi(struct soap *soap, struct soap_plist *pp) { if (soap->mode & SOAP_IO_LENGTH) return pp->mark1 == 2; return pp->mark2 == 2; } /******************************************************************************/ SOAP_FMAC1 void SOAP_FMAC2 soap_set_embedded(struct soap *soap, struct soap_plist *pp) { if (soap->mode & SOAP_IO_LENGTH) pp->mark1 = 1; else pp->mark2 = 1; } /******************************************************************************/ SOAP_FMAC1 void SOAP_FMAC2 soap_set_attached(struct soap *soap, struct soap_plist *pp, const char *id, const char *type, const char *options, size_t size) { if (soap->mode & SOAP_IO_LENGTH) { if (pp->mark1 != 3) { pp->mark1 = 3; soap->dime_count++; /* one more attachment found */ soap->dime_size += 12; /* increase total size (DIME fields) */ if (id) soap->dime_size += (strlen(id)+3)&-4; if (type) soap->dime_size += (strlen(type)+3)&-4; if (options) soap->dime_size += 4 + (((((unsigned char)options[2] << 8 | (unsigned char)options[3]))+3)&-4); soap->dime_size += (size+3)&-4; } } else if (pp->mark2 != 3) pp->mark2 = 3; } /******************************************************************************/ static void soap_init_iht(struct soap *soap) { int i; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Initializing ID hashtable\n")); for (i = 0; i < SOAP_IDHASH; i++) soap->iht[i] = NULL; } /******************************************************************************/ static void soap_free_iht(struct soap *soap) { int i; struct soap_ilist *ip, *next; for (i = 0; i < SOAP_IDHASH; i++) { for (ip = soap->iht[i]; ip; ip = next) { next = ip->next; free(ip); } soap->iht[i] = NULL; } } /******************************************************************************/ SOAP_FMAC1 struct soap_ilist * SOAP_FMAC2 soap_lookup(struct soap *soap, const char *id) { struct soap_ilist *ip; for (ip = soap->iht[hash_id(id)]; ip; ip = ip->next) if (!strcmp(ip->id, id)) return ip; return NULL; } /******************************************************************************/ SOAP_FMAC1 struct soap_ilist * SOAP_FMAC2 soap_enter(struct soap *soap, const char *id) { int h; struct soap_ilist *ip; ip = (struct soap_ilist*)malloc(sizeof(struct soap_ilist) + strlen(id)); if (ip) { h = hash_id(id); strcpy(ip->id, id); ip->next = soap->iht[h]; soap->iht[h] = ip; return ip; } return NULL; } /******************************************************************************/ SOAP_FMAC1 void* SOAP_FMAC2 soap_malloc(struct soap *soap, size_t n) { char *p; if (!n) return NULL; if (!soap) return malloc(n); n += (-(long)n) & 7; if (!(p = (char*)malloc(n + 16))) { soap->error = SOAP_EOM; return NULL; } /* keep chain of alloced cells for later destruction */ soap->alloced = 1; *(void**)(p + n) = soap->alist; *(size_t*)(p + n + sizeof(void*) + sizeof(size_t)) = n; soap->alist = p + n; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Malloc %u bytes at location %p\n", (unsigned int)n, p)); return p; } /******************************************************************************/ SOAP_FMAC1 void SOAP_FMAC2 soap_dealloc(struct soap *soap, void *p) { if (!soap) return; if (p) { char **q; for (q = (char**)&soap->alist; *q; q = *(char***)q) { if (p == (void*)(*q - *(size_t*)(*q + 8))) { *q = **(char***)q; free(p); DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Freed data %p\n", p)); return; } } DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Could not dealloc data %p: address not in list\n", p)); } else { char *q; while (soap->alist) { q = (char*)soap->alist; soap->alist = *(void**)q; q -= *(size_t*)(q + 8); if (q == (char*)soap->fault) soap->fault = NULL; /* this was deallocated */ else if (q == (char*)soap->header) soap->header = NULL; /* this was deallocated */ free(q); } DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Dealloc all data done\n")); } } /******************************************************************************/ SOAP_FMAC1 void SOAP_FMAC2 soap_unlink(struct soap *soap, void *p) { char **q; struct soap_clist **cp; if (!soap) return; for (q = (char**)&soap->alist; *q; q = *(char***)q) { if (p == (void*)(*q - *(size_t*)(*q + 8))) { *q = **(char***)q; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Unlinked data %p\n", p)); return; } } for (cp = &soap->clist; *cp; cp = &(*cp)->next) { if (p == (*cp)->ptr) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Unlinked class instance %p\n", p)); p = (void*)*cp; *cp = (*cp)->next; free(p); return; } } } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_lookup_type(struct soap *soap, const char *id) { struct soap_ilist *ip; if (*id) { ip = soap_lookup(soap, id); if (ip) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Lookup id='%s' type=%d\n", id, ip->type)); return ip->type; } if (*id != '#' && !strchr(id, ':')) /* try content id "cid:" with DIME attachments */ { char cid[SOAP_TAGLEN]; strcpy(cid, "cid:"); strncat(cid + 4, id, SOAP_TAGLEN - 5); cid[SOAP_TAGLEN - 1] = '\0'; ip = soap_lookup(soap, cid); if (ip) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Lookup id='%s' type=%d\n", cid, ip->type)); return ip->type; } } } DBGLOG(TEST, SOAP_MESSAGE(fdebug, "lookup type id='%s' NOT FOUND! Need to get it from xsi:type\n", id)); return 0; } /******************************************************************************/ SOAP_FMAC1 void* SOAP_FMAC2 soap_id_lookup(struct soap *soap, const char *id, void **p, int t, size_t n, int k) { struct soap_ilist *ip; void *q; if (*id == '\0') return p; soap->alloced = 0; if (!p) p = (void**)soap_malloc(soap, sizeof(void*)); ip = soap_lookup(soap, id); /* lookup pointer to hash table entry for string id */ if (!ip) { ip = soap_enter(soap, id); /* new hash table entry for string id */ DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Forwarding first href='%s' %p (%u bytes)\n", id, p, (unsigned int)n)); ip->type = t; ip->size = n; ip->link = p; ip->copy = NULL; ip->ptr = NULL; ip->level = k; *p = NULL; } else if (!soap->blist && ip->ptr) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Resolved href='%s' (%u bytes)\n", id, (unsigned int)n)); if (ip->type != t) { soap->error = SOAP_HREF; return NULL; } while (ip->level < k) { q = soap_malloc(soap, sizeof(void*)); *p = q; p = (void**)q; k--; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Descending one level...\n")); } *p = ip->ptr; } else if (ip->level > k) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Resolving level %d pointers to href='%s'\n", ip->level, id)); while (ip->level > k) { void *s, **r = &ip->link; q = ip->link; while (q) { *r = soap_malloc(soap, sizeof(void*)); s = *(void**)q; *(void**)q = *r; r = *(void***)q; q = s; } *r = NULL; ip->size = n; ip->copy = NULL; ip->level = ip->level-1; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Descending one level...\n")); } q = ip->link; ip->link = p; *p = q; } else { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Forwarded href='%s' (%u bytes)\n", id, (unsigned int)n)); while (ip->level < k) { q = soap_malloc(soap, sizeof(void*)); *p = q; p = (void**)q; k--; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Descending one level...\n")); } q = ip->link; ip->link = p; *p = q; } return p; } /******************************************************************************/ SOAP_FMAC1 void* SOAP_FMAC2 soap_id_forward(struct soap *soap, const char *href, void *p, int t, size_t n) { struct soap_ilist *ip; if (!*href) return p; ip = soap_lookup(soap, soap->href); /* lookup pointer to hash table entry for string id */ if (!ip) { if (n >= sizeof(void*)) { ip = soap_enter(soap, href); /* new hash table entry for string id */ ip->type = t; ip->size = n; ip->link = NULL; ip->copy = p; *(void**)p = NULL; ip->ptr = NULL; ip->level = 0; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Forwarding first copying address %p for type %d href='%s'\n", p, t, href)); return p; } DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Forwarding problem: copying location %p too small (%u) for href='%s'\n", p, (unsigned int)n, href)); soap->error = SOAP_HREF; return NULL; } else if (ip->ptr) { if (ip->size == n) memcpy(p, ip->ptr, n); else { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Reference to object of different size (ref=%u, object=%u)\n", (unsigned int)n, (unsigned int)ip->size)); soap->error = SOAP_HREF; return NULL; } } else if (n >= sizeof(void*)) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Forwarding copying address %p for type %d href='%s' (prev in chain = %p)\n", p, t, href, ip->copy)); *(void**)p = ip->copy; ip->copy = p; return p; } else { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Forwarding problem: copying location %p too small (%u) for href='%s'\n", p, (unsigned int)n, href)); soap->error = SOAP_HREF; /* href to object too small to hold pointer */ return NULL; } return ip->ptr; } /******************************************************************************/ SOAP_FMAC1 void* SOAP_FMAC2 soap_id_enter(struct soap *soap, const char *id, void *p, int t, size_t n, int k) { struct soap_ilist *ip; DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Enter id='%s' type=%d loc=%p size=%d level=%d\n", id, t, p, (int)n, k)); soap->alloced = 0; if (*id == '\0') { if (!p) return soap_malloc(soap, n); else return p; } ip = soap_lookup(soap, id); /* lookup pointer to hash table entry for string id */ DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Lookup entry id='%s'\n", id)); if (!ip) { ip = soap_enter(soap, id); /* new hash table entry for string id */ DBGLOG(TEST,SOAP_MESSAGE(fdebug, "New entry id='%s' type=%d size=%u\n", id, t, (unsigned int)n)); ip->type = t; ip->size = n; ip->link = NULL; ip->copy = NULL; if (!p) p = soap_malloc(soap, n); ip->ptr = p; ip->level = k; } else if (ip->ptr) /* storage address was forwarded */ { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Multiply defined id='%s'\n", id)); if (p) { soap->error = SOAP_MULTI_ID; return NULL; } } else { if (!p) p = soap_malloc(soap, n); ip->ptr = p; if (!soap->blist) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Resolve link chain to point to %p\n", ip->ptr)); soap_resolve_ptr(ip); } } return ip->ptr; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_end_send(struct soap *soap) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "End send\n")); if (soap->mode & SOAP_IO) /* need to flush the remaining data in buffer */ { if (soap_flush(soap)) return soap->error; #ifdef WITH_ZLIB if (soap->mode & SOAP_ENC_ZLIB) { int r; soap->d_stream.avail_in = 0; do { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Deflating remainder\n")); r = deflate(&soap->d_stream, Z_FINISH); if (soap->d_stream.avail_out != SOAP_BUFLEN) { if (soap_flush_raw(soap, soap->z_buf, SOAP_BUFLEN - soap->d_stream.avail_out)) return soap->error; soap->d_stream.next_out = (Byte*)soap->z_buf; soap->d_stream.avail_out = SOAP_BUFLEN; } } while (r == Z_OK); DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Deflated %lu->%lu bytes\n", soap->d_stream.total_in, soap->d_stream.total_out)); soap->z_ratio_out = (float)soap->d_stream.total_out / (float)soap->d_stream.total_in; soap->mode &= ~SOAP_ENC_ZLIB; if (deflateEnd(&soap->d_stream) != Z_OK || r != Z_STREAM_END) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Unable to end deflate: %s\n", soap->d_stream.msg?soap->d_stream.msg:"")); return soap->error = SOAP_ZLIB_ERROR; } #ifdef WITH_GZIP soap->z_buf[0] = soap->z_crc & 0xFF; soap->z_buf[1] = soap->z_crc >> 8 & 0xFF; soap->z_buf[2] = soap->z_crc >> 16 & 0xFF; soap->z_buf[3] = soap->z_crc >> 24 & 0xFF; soap->z_buf[4] = soap->d_stream.total_in & 0xFF; soap->z_buf[5] = soap->d_stream.total_in >> 8 & 0xFF; soap->z_buf[6] = soap->d_stream.total_in >> 16 & 0xFF; soap->z_buf[7] = soap->d_stream.total_in >> 24 & 0xFF; if (soap_flush_raw(soap, soap->z_buf, 8)) return soap->error; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "gzip crc32=%lu\n", soap->z_crc)); #endif } #endif if ((soap->mode & SOAP_IO) == SOAP_IO_STORE) { char *p; if (!(soap->mode & SOAP_ENC_XML)) { soap->mode--; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Sending buffered message of length %u\n", (unsigned int)soap->blist->size)); if (soap->status >= SOAP_POST) soap->error = soap->fpost(soap, soap->endpoint, soap->host, soap->port, soap->path, soap->action, soap->blist->size); else soap->error = soap->fresponse(soap, soap->status, soap->blist->size); if (soap->error || soap_flush(soap)) return soap->error; soap->mode++; } for (p = soap_first_block(soap); p; p = soap_next_block(soap)) { DBGMSG(SENT, p, soap_block_size(soap)); if ((soap->error = soap->fsend(soap, p, soap_block_size(soap)))) return soap->error; } soap_end_block(soap); } else if ((soap->mode & SOAP_IO) == SOAP_IO_CHUNK) { DBGMSG(SENT, "\r\n0\r\n\r\n", 7); if ((soap->error = soap->fsend(soap, "\r\n0\r\n\r\n", 7))) return soap->error; } } DBGLOG(TEST, SOAP_MESSAGE(fdebug, "End of send message ok\n")); return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_end_recv(struct soap *soap) { int flag1 = 0, flag2; register int i; register struct soap_ilist *ip; for (i = 0; i < SOAP_IDHASH; i++) for (ip = soap->iht[i]; ip; ip = ip->next) { if (ip->ptr) soap_resolve_ptr(ip); else if (*ip->id == '#') flag1 = 1; } do { flag2 = 0; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Resolving forwarded data\n")); for (i = 0; i < SOAP_IDHASH; i++) for (ip = soap->iht[i]; ip; ip = ip->next) if (ip->copy && ip->ptr) { register void *p, **q = (void**)ip->copy; DBGLOG(TEST, if (q) SOAP_MESSAGE(fdebug, "Traversing copy chain to resolve id='%s'\n", ip->id)); ip->copy = NULL; do { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "... copy %p -> %p (%u bytes)\n", ip->ptr, q, (unsigned int)ip->size)); p = *q; memcpy(q, ip->ptr, ip->size); soap_add_copies(soap, (char*)ip->ptr, (char*)ip->ptr + ip->size, (char*)q - (char*)ip->ptr); q = (void**)p; } while (q); flag2 = 1; } } while (flag2); DBGLOG(TEST,SOAP_MESSAGE(fdebug, "End of receive message ok\n")); #ifdef WITH_ZLIB if (soap->mode & SOAP_ENC_ZLIB) { soap->mode &= ~SOAP_ENC_ZLIB; memcpy(soap->buf, soap->z_buf, SOAP_BUFLEN); soap->bufidx = (char*)soap->d_stream.next_in - soap->z_buf; soap->buflen = soap->z_buflen; if (inflateEnd(&soap->d_stream) != Z_OK) return soap->error = SOAP_ZLIB_ERROR; #ifdef WITH_GZIP if (soap->zlib_in == SOAP_ZLIB_GZIP) { wchar c; for (i = 0; i < 8; i++) { if ((c = soap_getchar(soap)) == EOF) return soap->error = SOAP_EOF; soap->z_buf[i] = (char)c; } if (soap->z_crc != ((unsigned char)soap->z_buf[0] | (unsigned long)((unsigned char)soap->z_buf[1] << 8) | (unsigned long)((unsigned char)soap->z_buf[2] << 16) | (unsigned long)((unsigned char)soap->z_buf[3] << 24))) { DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Gzip error: crc check failed, message corrupted? (crc32=%lu)\n", soap->z_crc)); return soap->error = SOAP_ZLIB_ERROR; } if (soap->d_stream.total_out != ((unsigned char)soap->z_buf[4] | (unsigned long)((unsigned char)soap->z_buf[5] << 8) | (unsigned long)((unsigned char)soap->z_buf[6] << 16) | (unsigned long)((unsigned char)soap->z_buf[7] << 24))) { DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Gzip error: incorrect message length\n")); return soap->error = SOAP_ZLIB_ERROR; } } #endif } #endif if ((soap->mode & SOAP_IO) == SOAP_IO_CHUNK) while (soap_getchar(soap) != EOF) /* advance to last chunk */ ; if (flag1) return soap->error = SOAP_MISSING_ID; return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 void SOAP_FMAC2 soap_free(struct soap *soap) { struct soap_nlist *np; struct soap_attribute *tp; struct Namespace *ns; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Free namespace stack\n")); while (soap->nlist) { np = soap->nlist->next; if (soap->nlist->ns) free(soap->nlist->ns); free(soap->nlist); soap->nlist = np; } DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Free any remaining temp blocks\n")); while (soap->blist) soap_end_block(soap); DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Free attributes\n")); while (soap->attributes) { tp = soap->attributes->next; free(soap->attributes->value); free(soap->attributes); soap->attributes = tp; } DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Free pointer hashtable\n")); soap_free_pht(soap); DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Free ID hashtable\n")); soap_free_iht(soap); if (soap->action) { free(soap->action); soap->action = NULL; } ns = soap->local_namespaces; if (ns) { for (; ns->id; ns++) { if (ns->out) { free(ns->out); if (soap->encodingStyle == ns->out) soap->encodingStyle = ""; ns->out = NULL; } if (soap->encodingStyle == ns->ns) soap->encodingStyle = ""; } free(soap->local_namespaces); soap->local_namespaces = NULL; } } /******************************************************************************/ static void soap_init_logs(struct soap *soap) { int i; for (i = 0; i < SOAP_MAXLOGS; i++) { soap->logfile[i] = NULL; soap->fdebug[i] = NULL; } #ifdef SOAP_DEBUG soap_set_recv_logfile(soap, "RECV.log"); soap_set_sent_logfile(soap, "SENT.log"); soap_set_test_logfile(soap, "TEST.log"); #endif } /******************************************************************************/ SOAP_FMAC1 void SOAP_FMAC2 soap_open_logfile(struct soap *soap, int i) { if (soap->logfile[i]) soap->fdebug[i] = fopen(soap->logfile[i], i < 2 ? "ab" : "a"); } /******************************************************************************/ static void soap_close_logfile(struct soap *soap, int i) { if (soap->fdebug[i]) { fclose(soap->fdebug[i]); soap->fdebug[i] = NULL; } } /******************************************************************************/ SOAP_FMAC1 void SOAP_FMAC2 soap_close_logfiles(struct soap *soap) { int i; for (i = 0; i < SOAP_MAXLOGS; i++) soap_close_logfile(soap, i); } /******************************************************************************/ static void soap_set_logfile(struct soap *soap, int i, const char *logfile) { char *s = NULL; soap_close_logfile(soap, i); if (logfile) { s = (char*)malloc(strlen(logfile)+1); if (s) strcpy(s, logfile); } if (soap->logfile[i]) free((void*)soap->logfile[i]); soap->logfile[i] = s; } /******************************************************************************/ SOAP_FMAC1 void SOAP_FMAC2 soap_set_recv_logfile(struct soap *soap, const char *logfile) { soap_set_logfile(soap, SOAP_INDEX_RECV, logfile); } /******************************************************************************/ SOAP_FMAC1 void SOAP_FMAC2 soap_set_sent_logfile(struct soap *soap, const char *logfile) { soap_set_logfile(soap, SOAP_INDEX_SENT, logfile); } /******************************************************************************/ SOAP_FMAC1 void SOAP_FMAC2 soap_set_test_logfile(struct soap *soap, const char *logfile) { soap_set_logfile(soap, SOAP_INDEX_TEST, logfile); } /******************************************************************************/ SOAP_FMAC1 struct soap* SOAP_FMAC2 soap_copy(struct soap *soap) { struct soap *copy = (struct soap*)malloc(sizeof(struct soap)); if (copy) { struct soap_plugin *p; memcpy(copy, soap, sizeof(struct soap)); copy->copy = 1; copy->user = NULL; copy->userid = NULL; copy->passwd = NULL; copy->nlist = NULL; copy->blist = NULL; copy->clist = NULL; copy->alist = NULL; copy->attributes = NULL; copy->local_namespaces = NULL; soap_init_iht(copy); soap_init_pht(copy); soap_init_logs(copy); copy->header = NULL; copy->fault = NULL; copy->action = NULL; *copy->host = '\0'; copy->port = 0; #ifdef WITH_COOKIES copy->cookies = soap_copy_cookies(soap); #else copy->cookies = NULL; #endif copy->plugins = NULL; for (p = soap->plugins; p; p = p->next) { struct soap_plugin *q = (struct soap_plugin*)malloc(sizeof(struct soap_plugin)); if (!q) return NULL; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Copying plugin '%s'\n", p->id)); *q = *p; if ((soap->error = p->fcopy(soap, q, p))) { free(q); return NULL; } q->next = copy->plugins; copy->plugins = q; } } else soap->error = SOAP_EOM; return copy; } /******************************************************************************/ SOAP_FMAC1 void SOAP_FMAC2 soap_init(struct soap *soap) { soap->version = 1; /* default SOAP 1.1 */ soap_imode(soap, SOAP_IO_DEFAULT); soap_omode(soap, SOAP_IO_DEFAULT); soap->mode = 0; soap->copy = 0; soap->plugins = NULL; soap->user = NULL; soap->userid = NULL; soap->passwd = NULL; soap->fpost = http_post; soap->fposthdr = http_post_header; soap->fresponse = http_response; soap->fparse = http_parse; soap->fparsehdr = http_parse_header; soap->faccept = tcp_accept; #ifndef MAC_CARBON soap->fopen = tcp_connect; soap->fclose = tcp_disconnect; soap->fsend = fsend; soap->frecv = frecv; #endif soap->fignore = fignore; soap->fplugin = fplugin; soap->fdimereadopen = NULL; soap->fdimewriteopen = NULL; soap->fdimereadclose = NULL; soap->fdimewriteclose = NULL; soap->fdimeread = NULL; soap->fdimewrite = NULL; soap->float_format = "%.9G"; /* .9G preserves single FP precision */ soap->double_format = "%.18G"; /* .18G preserves double FP precision */ soap->dime_id_format = "cid:id%d"; /* default DIME id format */ soap->http_version = "1.0"; soap->encodingStyle = ""; soap->defaultNamespace = NULL; soap->actor = NULL; soap->keep_alive = 0; soap->recv_timeout = 0; soap->send_timeout = 0; soap->connect_timeout = 0; soap->accept_timeout = 0; soap->socket_flags = 0; soap->connect_flags = 0; soap->bind_flags = 0; soap->accept_flags = 0; soap->ip = 0; #ifndef WITH_NONAMESPACES soap->namespaces = namespaces; #else soap->namespaces = NULL; #endif soap->local_namespaces = NULL; soap->nlist = NULL; soap->blist = NULL; soap->clist = NULL; soap->alist = NULL; soap->attributes = NULL; soap->header = NULL; soap->fault = NULL; soap->master = -1; soap->socket = -1; #ifndef UNDER_CE soap->recvfd = 0; soap->sendfd = 1; #else soap->recvfd = stdin; soap->sendfd = stdout; #endif *soap->host = '\0'; soap->port = 0; *soap->endpoint = '\0'; *soap->path = '\0'; soap->action = NULL; soap->proxy_host = NULL; soap->proxy_port = 8080; soap->proxy_userid = NULL; soap->proxy_passwd = NULL; soap->cookies = NULL; soap->cookie_domain = NULL; soap->cookie_path = NULL; soap->cookie_max = 32; #ifdef WITH_OPENSSL soap->bio = NULL; soap->ssl = NULL; soap->require_server_auth = 0; soap->rsa = 0; soap->keyfile = NULL; soap->password = NULL; soap->dhfile = NULL; soap->cafile = NULL; soap->randfile = NULL; #endif #ifdef WITH_ZLIB soap->zlib_in = SOAP_ZLIB_NONE; soap->zlib_out = SOAP_ZLIB_NONE; soap->d_stream.zalloc = NULL; soap->d_stream.zfree = NULL; soap->d_stream.opaque = NULL; soap->z_level = 6; #endif soap_init_logs(soap); soap_init_iht(soap); soap_init_pht(soap); soap_begin(soap); } /******************************************************************************/ SOAP_FMAC1 void SOAP_FMAC2 soap_init2(struct soap *soap, int imode, int omode) { soap_init(soap); soap_imode(soap, imode); soap_omode(soap, omode); } /******************************************************************************/ SOAP_FMAC1 void SOAP_FMAC2 soap_begin(struct soap *soap) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Initializing\n")); if (!soap->keep_alive) { soap->buflen = 0; soap->bufidx = 0; } soap->null = 0; soap->position = 0; soap->mustUnderstand = 0; soap->mode = 0; soap->ns = 0; soap->is_in_header = 0; soap->alloced = 0; soap->count = 0; soap->length = 0; soap->cdata = 0; soap->status = SOAP_POST; soap->error = SOAP_OK; soap->errnum = 0; soap->peeked = 0; soap->ahead = 0; soap->idnum = 0; soap->level = 0; *soap->endpoint = '\0'; *soap->path = '\0'; soap->dime_chunksize = 0; soap->dime_buflen = 0; soap->dot_net_bug = 0; soap_free(soap); } /******************************************************************************/ static void soap_set_local_namespaces(struct soap *soap) { if (soap->namespaces && !soap->local_namespaces) { struct Namespace *ns; size_t n = 1; for (ns = soap->namespaces; ns->id; ns++) n++; if (n > 3) { n *= sizeof(struct Namespace); ns = (struct Namespace*)malloc(n); if (ns) { memcpy(ns, soap->namespaces, n); ns[0].id = "SOAP-ENV"; ns[1].id = "SOAP-ENC"; ns[2].id = "xsi"; if (ns[0].ns) { if (!strcmp(ns[0].ns, soap_env1)) soap->version = 1; else if (!strcmp(ns[0].ns, soap_env2)) soap->version = 2; } soap->local_namespaces = ns; } } } } /******************************************************************************/ SOAP_FMAC1 void SOAP_FMAC2 soap_end(struct soap *soap) { struct soap_clist *cp; soap_free(soap); soap_dealloc(soap, NULL); while (soap->clist) { cp = soap->clist->next; free(soap->clist); soap->clist = cp; } soap_closesock(soap); soap_close_logfiles(soap); } /******************************************************************************/ static int soap_element(struct soap *soap, const char *tag, int id, const char *type) { struct soap_attribute *tp; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Element begin tag='%s' id='%d' type='%s'\n", tag, id, type?type:"")); if (!soap->ns) { struct Namespace *ns = soap->local_namespaces; if (soap_send(soap, "<") || soap_send(soap, tag)) return soap->error; for (; ns && ns->id; ns++) { *soap->tmpbuf = '\0'; if (*ns->id && (ns->out || ns->ns)) sprintf(soap->tmpbuf," xmlns:%s=\"%s\"", ns->id, ns->out?ns->out:ns->ns); else if (!soap->defaultNamespace && ns->ns) sprintf(soap->tmpbuf," xmlns=\"%s\"", ns->ns); if (soap_send(soap, soap->tmpbuf)) return soap->error; } if (soap->defaultNamespace) { sprintf(soap->tmpbuf, " xmlns=\"%s\"", soap->defaultNamespace); if (soap_send(soap, soap->tmpbuf)) return soap->error; } soap->ns = 1; } else if (soap_send(soap, "<") || soap_send(soap, tag)) return soap->error; if (id > 0) { sprintf(soap->tmpbuf, " id=\"_%d\"", id); if (soap_send(soap, soap->tmpbuf)) return soap->error; } if (type && *type) { if (soap_send(soap, " xsi:type=\"") || soap_send(soap, type) || soap_send(soap, "\"")) return soap->error; } if (soap->null && soap->position > 0) { int i; sprintf(soap->tmpbuf, " SOAP-ENC:position=\"[%d", soap->positions[0]); for (i = 1; i < soap->position; i++) sprintf(soap->tmpbuf + strlen(soap->tmpbuf), ",%d", soap->positions[i]); strcat(soap->tmpbuf, "]\""); if (soap_send(soap, soap->tmpbuf)) return soap->error; } if (soap->mustUnderstand) { if (soap->actor) { if (soap->version == 2) { if (soap_send(soap, " SOAP-ENV:role=\"") || soap_send(soap, soap->actor) || soap_send(soap, "\"")) return soap->error; } else if (soap_send(soap, " SOAP-ENV:actor=\"") || soap_send(soap, soap->actor) || soap_send(soap, "\"")) return soap->error; } if (soap->version == 2) { if (soap_send(soap, " SOAP-ENV:mustUnderstand=\"true\"")) return soap->error; } else if (soap_send(soap, " SOAP-ENV:mustUnderstand=\"1\"")) return soap->error; soap->mustUnderstand = 0; } for (tp = soap->attributes; tp; tp = tp->next) { if (tp->visible) { if (soap_send(soap, " ") || soap_send(soap, tp->name)) return soap->error; if (tp->value) if (soap_send(soap, "=\"") || soap_string_out(soap, tp->value) || soap_send(soap, "\"")) return soap->error; tp->visible = 0; } } soap->null = 0; return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_element_begin_out(struct soap *soap, const char *tag, int id, const char *type) { if (soap_element(soap, tag, id, type)) return soap->error; return soap_send(soap, ">"); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_array_begin_out(struct soap *soap, const char *tag, int id, const char *type, const char *offset) { if (soap_element(soap, tag, id, "SOAP-ENC:Array")) return soap->error; if (offset && soap->version != 2) { if (soap_send(soap, " SOAP-ENC:offset=\"") || soap_send(soap, offset) || soap_send(soap, "\"")) return soap->error; } if (type && *type) { if (soap->version == 2) { const char *s; s = strrchr(type, '['); if (s-type < SOAP_TAGLEN) { strncpy(soap->tmpbuf, type, s-type); soap->tmpbuf[s-type] = '\0'; if (soap_send(soap, " SOAP-ENC:itemType=\"") || soap_send(soap, soap->tmpbuf) || soap_send(soap, "\">")) return soap->error; } if (s && (soap_send(soap, " SOAP-ENC:arraySize=\"") || soap_send(soap, s+1) || soap_send(soap, "\">"))) return soap->error; } else if (soap_send(soap, " SOAP-ENC:arrayType=\"") || soap_send(soap, type) || soap_send(soap, "\">")) return soap->error; } return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_element_end_out(struct soap *soap, const char *tag) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Element ending tag='%s'\n", tag)); if (soap_send(soap, "")) return soap->error; return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_element_ref(struct soap *soap, const char *tag, int id, int href) { if (soap_element(soap, tag, id, NULL)) return soap->error; if (soap->version == 2) sprintf(soap->tmpbuf, " ref=\"_%d\"/>", href); else sprintf(soap->tmpbuf, " href=\"#_%d\"/>", href); return soap_send(soap, soap->tmpbuf); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_element_href(struct soap *soap, const char *tag, int id, const char *href) { if (soap_element(soap, tag, id, NULL)) return soap->error; if (soap_send(soap, " href=\"") || soap_send(soap, href) || soap_send(soap, "\"/>")) return soap->error; return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_element_null(struct soap *soap, const char *tag, int id, const char *type) { if ((soap->version == 2 && soap->position > 0) || id > 0 || (soap->mode & SOAP_XML_NIL)) { if (soap_element(soap, tag, id, type)) return soap->error; return soap_send(soap, " xsi:nil=\"true\"/>"); } soap->null = 1; soap->mustUnderstand = 0; return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_element_begin_in(struct soap *soap, const char *tag) { if (!soap_peek_element(soap)) { if (soap->other) return soap->error = SOAP_TAG_MISMATCH; if (!(soap->error = soap_match_tag(soap, soap->tag, tag))) { soap->peeked = 0; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Begin element found (level=%u) '%s'='%s'\n", soap->level, soap->tag, tag?tag:"" )); if (soap->body) soap->level++; } } return soap->error; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_element_end_in(struct soap *soap, const char *tag) { int c; char *s; const char *t; soap->error = SOAP_OK; soap->level--; soap_pop_namespace(soap); if (soap->peeked) { if (*soap->tag == '\0') soap->peeked = 0; else return soap->error = SOAP_SYNTAX_ERROR; } else { c = soap_advance(soap); if (c == EOF) return soap->error = SOAP_EOF; if (c != TT) return soap->error = SOAP_SYNTAX_ERROR; } s = soap->tag; c = soap_skip(soap); do { *s++ = c; c = soap_get(soap); } while (notblank(c)); if (c == EOF) return soap->error = SOAP_EOF; *s = '\0'; if ((s = strchr(soap->tag, ':'))) s++; else s = soap->tag; t = tag; if (t && (t = strchr(t, ':'))) t++; else if (t && (t = strchr(t, '_')) && t[1] == '_') t += 2; if (blank(c)) c = soap_skip(soap); if (c != GT) return soap->error = SOAP_SYNTAX_ERROR; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "End element found (level=%u) '%s'='%s'\n", soap->level, soap->tag, tag?tag:"" )); if (!t || !soap_tag_cmp(s, t)) return SOAP_OK; return soap->error = SOAP_SYNTAX_ERROR; } /******************************************************************************/ SOAP_FMAC1 struct soap_attribute * SOAP_FMAC2 soap_attr(struct soap *soap, const char *name) { struct soap_attribute *tp; for (tp = soap->attributes; tp; tp = tp->next) if (!soap_match_tag(soap, tp->name, name)) return tp; return NULL; } /******************************************************************************/ SOAP_FMAC1 const char * SOAP_FMAC2 soap_attr_value(struct soap *soap, const char *name) { struct soap_attribute *tp = soap_attr(soap, name); if (tp && tp->visible) return tp->value; return NULL; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_set_attr(struct soap *soap, const char *name, const char *value) { struct soap_attribute *tp = soap_attr(soap, name); if (!tp) { if (!(tp = (struct soap_attribute*)malloc(sizeof(struct soap_attribute)))) return soap->error = SOAP_EOM; tp->next = soap->attributes; soap->attributes = tp; tp->value = NULL; } else if (tp->value && tp->size <= strlen(value)) { free(tp->value); tp->value = NULL; } tp->visible = 1; tp->name = name; if (!tp->value) { tp->size = strlen(value) + 1; if (!(tp->value = (char*)malloc(tp->size))) return soap->error = SOAP_EOM; } strcpy(tp->value, value); return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 void SOAP_FMAC2 soap_clr_attr(struct soap *soap) { struct soap_attribute *tp; for (tp = soap->attributes; tp; tp = tp->next) tp->visible = 0; } /******************************************************************************/ static int soap_getattrval(struct soap *soap, char *s, size_t n, wchar d) { size_t i; wchar c; for (i = 0; i < n; i++) { c = soap_getutf8(soap); switch (c) { case EOF: return soap->error = SOAP_EOF; case TT: *s++ = '<'; soap_unget(soap, '/'); break; case LT: *s++ = '<'; break; case GT: if (d == ' ') { soap_unget(soap, c); *s = '\0'; return SOAP_OK; } *s++ = '>'; break; case QT: if (c == d) { *s = '\0'; return SOAP_OK; } *s++ = '"'; break; case AP: if (c == d) { *s = '\0'; return SOAP_OK; } *s++ = '\''; break; case '\t': case '\n': case '\r': case ' ': case '/': if (d == ' ') { soap_unget(soap, c); *s = '\0'; return SOAP_OK; } default: *s++ = (char)c; } } return soap->error = SOAP_EOM; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_peek_element(struct soap *soap) { struct soap_attribute *tp; char *s, *t; wchar c; int i; if (soap->peeked) { if (*soap->tag == '\0') return soap->error = SOAP_NO_TAG; return SOAP_OK; } soap->peeked = 1; if ((c = soap_advance(soap)) == EOF) return soap->error = SOAP_EOF; if (c == TT) { *soap->tag = '\0'; return soap->error = SOAP_NO_TAG; /* ending tag found */ } s = soap->tag; c = soap_skip(soap); i = SOAP_TAGLEN; while (c != '/' && notblank(c)) { if (--i > 0) *s++ = (char)c; c = soap_get(soap); } while (blank(c)) c = soap_get(soap); *s = '\0'; *soap->id = '\0'; *soap->href = '\0'; *soap->type = '\0'; *soap->arrayType = '\0'; *soap->arraySize = '\0'; *soap->arrayOffset = '\0'; soap->other = 0; soap->root = -1; soap->position = 0; soap->null = 0; soap->mustUnderstand = 0; soap_clr_attr(soap); soap_pop_namespace(soap); do { s = soap->tmpbuf; *s = '\0'; if (c == EOF || c == GT || c == '/') break; i = SOAP_TAGLEN; while (c != '=' && c != GT && c != '/' && notblank(c)) { if (--i > 0) *s++ = (char)c; c = soap_get(soap); } *s = '\0'; if (!strncmp(soap->tmpbuf, "xmlns:", 6)) { soap->tmpbuf[5] = '\0'; t = soap->tmpbuf + 6; } else t = NULL; tp = soap_attr(soap, soap->tmpbuf); if (!tp) { tp = (struct soap_attribute*)malloc(sizeof(struct soap_attribute) + strlen(soap->tmpbuf) + 1); /* reserve node + space for name */ if (!tp) return soap->error = SOAP_EOM; s = (char*)tp + sizeof(struct soap_attribute); strcpy(s, soap->tmpbuf); tp->name = s; tp->value = NULL; tp->size = 0; tp->next = soap->attributes; soap->attributes = tp; } tp->visible = 1; /* seen this attribute */ if (blank(c)) c = soap_skip(soap); if (c == '=') { wchar d = soap_skip(soap); if (d != QT && d != AP) { soap_unget(soap, d); d = ' '; /* blank delimiter */ } if (soap_getattrval(soap, tp->value, tp->size, d)) { size_t size; if (soap->error == SOAP_EOM) soap->error = SOAP_OK; else return soap->error; if (soap_new_block(soap)) return soap->error; for (;;) { if (!(s = (char*)soap_push_block(soap, SOAP_BLKLEN))) return soap->error; if (soap_getattrval(soap, s, SOAP_BLKLEN, d)) { if (soap->error == SOAP_EOM) soap->error = SOAP_OK; else return soap->error; } else break; } size = tp->size + soap->blist->size; if (!(s = (char*)malloc(size))) return soap->error = SOAP_EOM; soap_save_block(soap, s + tp->size); if (tp->value) { memcpy(s, tp->value, tp->size); free(tp->value); } tp->value = s; tp->size = size; } c = soap_skip(soap); } if (t) { if (soap_push_namespace(soap, t, tp->value)) return soap->error; tp->visible = 0; } } while (c != EOF && c != GT && c != '/'); if (c == EOF) return soap->error = SOAP_EOF; for (tp = soap->attributes; tp; tp = tp->next) { if (tp->visible) { if (!soap_match_tag(soap, tp->name, "id")) { if (!soap->is_in_header || !soap->dot_net_bug) { *soap->id = '#'; strncpy(soap->id + 1, tp->value, SOAP_TAGLEN - 2); } } else if (!soap_match_tag(soap, tp->name, "href")) strncpy(soap->href, tp->value, SOAP_TAGLEN - 1); else if (soap->version == 2 && !soap_match_tag(soap, tp->name, "ref")) { *soap->href = '#'; strncpy(soap->href + 1, tp->value, SOAP_TAGLEN - 2); } else if (!soap_match_tag(soap, tp->name, "xsi:type")) strncpy(soap->type, tp->value, SOAP_TAGLEN - 1); else if (soap->version == 1 && !soap_match_tag(soap, tp->name, "SOAP-ENC:arrayType")) { s = strrchr(tp->value, '['); if (s && s-tp->value < SOAP_TAGLEN) { strncpy(soap->arrayType, tp->value, s-tp->value); soap->arrayType[s-tp->value] = '\0'; strncpy(soap->arraySize, s, SOAP_TAGLEN - 1); } else strncpy(soap->arrayType, tp->value, SOAP_TAGLEN - 1); } else if (soap->version == 2 && !soap_match_tag(soap, tp->name, "SOAP-ENC:itemType")) strncpy(soap->arrayType, tp->value, SOAP_TAGLEN-1); else if (soap->version == 2 && !soap_match_tag(soap, tp->name, "SOAP-ENC:arraySize")) strncpy(soap->arraySize, tp->value, SOAP_TAGLEN-1); else if (soap->version == 1 && !soap_match_tag(soap, tp->name, "SOAP-ENC:offset")) strncpy(soap->arrayOffset, tp->value, SOAP_TAGLEN); else if (soap->version == 1 && !soap_match_tag(soap, tp->name, "SOAP-ENC:position")) soap->position = soap_getposition(tp->value, soap->positions); else if (soap->version == 1 && !soap_match_tag(soap, tp->name, "SOAP-ENC:root")) soap->root = ((!strcmp(tp->value, "1") || !strcmp(tp->value, "true"))); else if (!soap_match_tag(soap, tp->name, "SOAP-ENV:actor") || !soap_match_tag(soap, tp->name, "SOAP-ENV:role")) { if ((!soap->actor || strcmp(soap->actor, tp->value)) && strcmp(tp->value, "http://schemas.xmlsoap.org/soap/actor/next") && strcmp(tp->value, "http://www.w3.org/2002/06/soap-envelope/role/next")) soap->other = 1; } else if (!soap_match_tag(soap, tp->name, "SOAP-ENV:mustUnderstand") && (!strcmp(tp->value, "1") || !strcmp(tp->value, "true"))) soap->mustUnderstand = 1; else if ((!soap_match_tag(soap, tp->name, "xsi:null") || !soap_match_tag(soap, tp->name, "xsi:nil")) && (!strcmp(tp->value, "1") || !strcmp(tp->value, "true"))) soap->null = 1; } } if (!(soap->body = (c != '/'))) soap_skip(soap); return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 void SOAP_FMAC2 soap_revert(struct soap *soap) { soap->peeked = 1; if (soap->body) soap->level--; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_ignore_element(struct soap *soap) { if (!soap_peek_element(soap) || soap->error == SOAP_TAG_MISMATCH) { soap->peeked = 0; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Unknown element '%s' (level=%u, %d)\n", soap->tag, soap->level, soap->body)); if (soap->mustUnderstand && !soap->other) return soap->error = SOAP_MUSTUNDERSTAND; soap->error = soap->fignore(soap, soap->tag); DBGLOG(TEST, if (!soap->error) SOAP_MESSAGE(fdebug, "IGNORING element '%s'\n", soap->tag)); if (!soap->error && soap->body) { soap->level++; while (!soap_ignore_element(soap)) ; if (soap->error == SOAP_NO_TAG) soap_element_end_in(soap, NULL); } } return soap->error; } /******************************************************************************/ static int fignore(struct soap *soap, const char *tag) { if (soap->mode & SOAP_XML_STRICT) return SOAP_TAG_MISMATCH; return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_string_out(struct soap *soap, const char *s) { const char *t; char tmp[16]; register short c; register short mask = 0; if (soap->mode & SOAP_C_UTFSTRING) mask = (short)0x8000; while ((c = *s++)) { switch (c) { case '&': t = "&"; break; case '<': t = "<"; break; case '>': t = ">"; break; case '"': t = """; break; case '\'': t = "'"; break; default: if (c >= 32 || (c & mask)) { tmp[0] = (char)c; if (soap_send_raw(soap, tmp, 1)) return soap->error; } else { sprintf(tmp, "&#%u;", (unsigned char)c); if (soap_send(soap, tmp)) return soap->error; } continue; } if (soap_send(soap, t)) return soap->error; } return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 char * SOAP_FMAC2 soap_string_in(struct soap *soap, int flag) { char *t; register char *s; register int i; register int n; register wchar c; n = 0; if (soap_new_block(soap)) return NULL; for (;;) { if (!(s = (char*)soap_push_block(soap, SOAP_BLKLEN))) return NULL; if (flag) { for (i = 0; i < SOAP_BLKLEN; i++) { if (soap->mode & SOAP_C_UTFSTRING) c = soap_get(soap); else c = soap_getutf8(soap); switch (c) { case EOF: goto end; case TT: if (n == 0) goto end; n--; *s++ = '<'; soap_unget(soap, '/'); break; case LT: n++; *s++ = '<'; break; case GT: *s++ = '>'; break; case QT: *s++ = '"'; break; case AP: *s++ = '\''; break; case '/': if (n > 0) { c = soap_get(soap); if (c == GT) n--; soap_unget(soap, c); } *s++ = '/'; break; default: *s++ = (char)c; } } } else { for (i = 0; i < SOAP_BLKLEN; i++) { c = soap_getchar(soap); switch (c) { case EOF: goto end; case '<': c = soap_getchar(soap); if (c == '/') { if (n == 0) { c = TT; goto end; } else n--; } else n++; *s++ = '<'; soap_unget(soap, c); break; case '/': if (n > 0) { c = soap_getchar(soap); if (c == '>') n--; soap_unget(soap, c); } *s++ = '/'; break; default: *s++ = (char)c; } } } } end: soap_unget(soap, c); *s = '\0'; soap_size_block(soap, i+1); t = soap_save_block(soap, NULL); if (flag == 2) if (soap_s2QName(soap, t, &t)) return NULL; return t; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_wstring_out(struct soap *soap, const wchar_t *s) { const char *t; wchar c; while ((c = *s++)) { switch (c) { case '&': t = "&"; break; case '<': t = "<"; break; case '>': t = ">"; break; case '"': t = """; break; case '\'': t = "'"; break; default: if (soap_pututf8(soap, c)) return soap->error; continue; } if (soap_send(soap, t)) return soap->error; } return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 wchar_t * SOAP_FMAC2 soap_wstring_in(struct soap *soap, int flag) { wchar_t *s; int i, n; wchar c; n = 0; if (soap_new_block(soap)) return NULL; for (;;) { if (!(s = (wchar_t*)soap_push_block(soap, sizeof(wchar_t)*SOAP_BLKLEN))) return NULL; for (i = 0; i < SOAP_BLKLEN; i++) { c = soap_getutf8(soap); switch (c) { case EOF: goto end; case TT: if (n == 0) goto end; n--; *s++ = '<'; soap_unget(soap, '/'); break; case LT: n++; *s++ = '<'; break; case GT: *s++ = '>'; break; case QT: *s++ = '"'; break; case AP: *s++ = '\''; break; case '/': if (n > 0) { c = soap_getutf8(soap); if (c == GT) n--; soap_unget(soap, c); } *s++ = '/'; break; default: *s++ = (wchar_t)c & 0x7FFFFFFF; } } } end: soap_unget(soap, c); *s = '\0'; soap_size_block(soap, sizeof(wchar_t)*(i+1)); return (wchar_t*)soap_save_block(soap, NULL); } /******************************************************************************/ SOAP_FMAC1 const char* SOAP_FMAC2 soap_int2s(struct soap *soap, int n) { sprintf(soap->tmpbuf, "%d", n); return soap->tmpbuf; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_outint(struct soap *soap, const char *tag, int id, const int *p, const char *type, int n) { if (soap_element_begin_out(soap, tag, soap_embedded_id(soap, id, p, n), type) || soap_send(soap, soap_int2s(soap, *p))) return soap->error; return soap_element_end_out(soap, tag); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_s2int(struct soap *soap, const char *s, int *p) { if (s) { char *r; *p = (int)strtol(s, &r, 10); if (*r) return soap->error = SOAP_TYPE_MISMATCH; } return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 int * SOAP_FMAC2 soap_inint(struct soap *soap, const char *tag, int *p, const char *type, int t) { if (soap_element_begin_in(soap, tag)) return NULL; if (soap->null) { if (soap->mode & SOAP_XML_NIL) { soap->error = SOAP_NULL; return NULL; } return p; } if (*soap->type != '\0' && soap_match_tag(soap, soap->type, type) && soap_match_tag(soap, soap->type, "int") && soap_match_tag(soap, soap->type, "short") && soap_match_tag(soap, soap->type, "byte") && soap_match_tag(soap, soap->type, "unsignedInt") && soap_match_tag(soap, soap->type, "unsignedShort") && soap_match_tag(soap, soap->type, "unsignedByte")) { soap->error = SOAP_TYPE_MISMATCH; soap_revert(soap); return NULL; } if (soap->body && !*soap->href) { p = (int*)soap_id_enter(soap, soap->id, p, t, sizeof(int), 0); if (!p || soap_s2int(soap, soap_value(soap), p)) return NULL; } else p = (int*)soap_id_forward(soap, soap->href, p, t, sizeof(int)); if (soap->body && soap_element_end_in(soap, tag)) return NULL; return p; } /******************************************************************************/ SOAP_FMAC1 const char* SOAP_FMAC2 soap_long2s(struct soap *soap, long n) { sprintf(soap->tmpbuf, "%ld", n); return soap->tmpbuf; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_outlong(struct soap *soap, const char *tag, int id, const long *p, const char *type, int n) { if (soap_element_begin_out(soap, tag, soap_embedded_id(soap, id, p, n), type) || soap_send(soap, soap_long2s(soap, *p))) return soap->error; return soap_element_end_out(soap, tag); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_s2long(struct soap *soap, const char *s, long *p) { if (s) { char *r; *p = strtol(s, &r, 10); if (*r) return soap->error = SOAP_TYPE_MISMATCH; } return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 long * SOAP_FMAC2 soap_inlong(struct soap *soap, const char *tag, long *p, const char *type, int t) { if (soap_element_begin_in(soap, tag)) return NULL; if (soap->null) { if (soap->mode & SOAP_XML_NIL) { soap->error = SOAP_NULL; return NULL; } return p; } if (*soap->type != '\0' && soap_match_tag(soap, soap->type, type) && soap_match_tag(soap, soap->type, "long") && soap_match_tag(soap, soap->type, "int") && soap_match_tag(soap, soap->type, "short") && soap_match_tag(soap, soap->type, "byte") && soap_match_tag(soap, soap->type, "unsignedLong") && soap_match_tag(soap, soap->type, "unsignedInt") && soap_match_tag(soap, soap->type, "unsignedShort") && soap_match_tag(soap, soap->type, "unsignedByte")) { soap->error = SOAP_TYPE_MISMATCH; soap_revert(soap); return NULL; } if (soap->body && !*soap->href) { p = (long*)soap_id_enter(soap, soap->id, p, t, sizeof(long), 0); if (!p || soap_s2long(soap, soap_value(soap), p)) return NULL; } else p = (long*)soap_id_forward(soap, soap->href, p, t, sizeof(long)); if (soap->body && soap_element_end_in(soap, tag)) return NULL; return p; } /******************************************************************************/ SOAP_FMAC1 const char* SOAP_FMAC2 soap_LONG642s(struct soap *soap, LONG64 n) { sprintf(soap->tmpbuf, SOAP_LONG_FORMAT, n); return soap->tmpbuf; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_outLONG64(struct soap *soap, const char *tag, int id, const LONG64 *p, const char *type, int n) { if (soap_element_begin_out(soap, tag, soap_embedded_id(soap, id, p, n), type) || soap_send(soap, soap_LONG642s(soap, *p))) return soap->error; return soap_element_end_out(soap, tag); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_s2LONG64(struct soap *soap, const char *s, LONG64 *p) { if (s && sscanf(s, SOAP_LONG_FORMAT, p) != 1) return soap->error = SOAP_TYPE_MISMATCH; return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 LONG64 * SOAP_FMAC2 soap_inLONG64(struct soap *soap, const char *tag, LONG64 *p, const char *type, int t) { if (soap_element_begin_in(soap, tag)) return NULL; if (soap->null) { if (soap->mode & SOAP_XML_NIL) { soap->error = SOAP_NULL; return NULL; } return p; } if (*soap->type != '\0' && soap_match_tag(soap, soap->type, type) && soap_match_tag(soap, soap->type, "integer") && soap_match_tag(soap, soap->type, "positiveInteger") && soap_match_tag(soap, soap->type, "negativeInteger") && soap_match_tag(soap, soap->type, "nonPositiveInteger") && soap_match_tag(soap, soap->type, "nonNegativeInteger") && soap_match_tag(soap, soap->type, "long") && soap_match_tag(soap, soap->type, "int") && soap_match_tag(soap, soap->type, "short") && soap_match_tag(soap, soap->type, "byte") && soap_match_tag(soap, soap->type, "unsignedLong") && soap_match_tag(soap, soap->type, "unsignedInt") && soap_match_tag(soap, soap->type, "unsignedShort") && soap_match_tag(soap, soap->type, "unsignedByte")) { soap->error = SOAP_TYPE_MISMATCH; soap_revert(soap); return NULL; } if (soap->body && !*soap->href) { p = (LONG64*)soap_id_enter(soap, soap->id, p, t, sizeof(LONG64), 0); if (!p || soap_s2LONG64(soap, soap_value(soap), p)) return NULL; } else p = (LONG64*)soap_id_forward(soap, soap->href, p, t, sizeof(LONG64)); if (soap->body && soap_element_end_in(soap, tag)) return NULL; return p; } /******************************************************************************/ SOAP_FMAC1 const char* SOAP_FMAC2 soap_byte2s(struct soap *soap, char n) { return soap_int2s(soap, (int)n); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_outbyte(struct soap *soap, const char *tag, int id, const char *p, const char *type, int n) { if (soap_element_begin_out(soap, tag, soap_embedded_id(soap, id, p, n), type) || soap_send(soap, soap_byte2s(soap, *p))) return soap->error; return soap_element_end_out(soap, tag); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_s2byte(struct soap *soap, const char *s, char *p) { if (s) { char *r; *p = (char)strtol(s, &r, 10); if (*r) return soap->error = SOAP_TYPE_MISMATCH; } return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 char * SOAP_FMAC2 soap_inbyte(struct soap *soap, const char *tag, char *p, const char *type, int t) { if (soap_element_begin_in(soap, tag)) return NULL; if (soap->null) { if (soap->mode & SOAP_XML_NIL) { soap->error = SOAP_NULL; return NULL; } return p; } if (*soap->type != '\0' && soap_match_tag(soap, soap->type, type) && soap_match_tag(soap, soap->type, "byte") && soap_match_tag(soap, soap->type, "unsignedByte")) { soap->error = SOAP_TYPE_MISMATCH; soap_revert(soap); return NULL; } if (soap->body && !*soap->href) { p = (char*)soap_id_enter(soap, soap->id, p, t, sizeof(char), 0); if (!p || soap_s2byte(soap, soap_value(soap), p)) return NULL; } else p = (char*)soap_id_forward(soap, soap->href, p, t, sizeof(char)); if (soap->body && soap_element_end_in(soap, tag)) return NULL; return p; } /******************************************************************************/ SOAP_FMAC1 const char* SOAP_FMAC2 soap_short2s(struct soap *soap, short n) { return soap_int2s(soap, (int)n); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_outshort(struct soap *soap, const char *tag, int id, const short *p, const char *type, int n) { if (soap_element_begin_out(soap, tag, soap_embedded_id(soap, id, p, n), type) || soap_send(soap, soap_short2s(soap, *p))) return soap->error; return soap_element_end_out(soap, tag); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_s2short(struct soap *soap, const char *s, short *p) { if (s && sscanf(s, "%hd", p) != 1) return soap->error = SOAP_TYPE_MISMATCH; return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 short * SOAP_FMAC2 soap_inshort(struct soap *soap, const char *tag, short *p, const char *type, int t) { if (soap_element_begin_in(soap, tag)) return NULL; if (soap->null) { if (soap->mode & SOAP_XML_NIL) { soap->error = SOAP_NULL; return NULL; } return p; } if (*soap->type != '\0' && soap_match_tag(soap, soap->type, type) && soap_match_tag(soap, soap->type, "short") && soap_match_tag(soap, soap->type, "byte") && soap_match_tag(soap, soap->type, "unsignedShort") && soap_match_tag(soap, soap->type, "unsignedByte")) { soap->error = SOAP_TYPE_MISMATCH; soap_revert(soap); return NULL; } if (soap->body && !*soap->href) { p = (short*)soap_id_enter(soap, soap->id, p, t, sizeof(short), 0); if (!p || soap_s2short(soap, soap_value(soap), p)) return NULL; } else p = (short*)soap_id_forward(soap, soap->href, p, t, sizeof(short)); if (soap->body && soap_element_end_in(soap, tag)) return NULL; return p; } /******************************************************************************/ SOAP_FMAC1 const char* SOAP_FMAC2 soap_float2s(struct soap *soap, float n) { const char *s; if (isnan(n)) s = "NaN"; else if (n >= FLT_PINFTY) s = "INF"; else if (n <= FLT_NINFTY) s = "-INF"; else { sprintf(soap->tmpbuf, soap->float_format, n); s = soap->tmpbuf; } return s; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_outfloat(struct soap *soap, const char *tag, int id, const float *p, const char *type, int n) { if (soap_element_begin_out(soap, tag, soap_embedded_id(soap, id, p, n), type) || soap_send(soap, soap_float2s(soap, *p))) return soap->error; return soap_element_end_out(soap, tag); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_s2float(struct soap *soap, const char *s, float *p) { if (s) { if (!soap_tag_cmp(s, "INF")) *p = FLT_PINFTY; else if (!soap_tag_cmp(s, "+INF")) *p = FLT_PINFTY; else if (!soap_tag_cmp(s, "-INF")) *p = FLT_NINFTY; else if (!soap_tag_cmp(s, "NaN")) *p = FLT_NAN; else { char *r; *p = (float)strtod(s, &r); if (*r && sscanf(s, soap->float_format, p) != 1) return soap->error = SOAP_TYPE_MISMATCH; } } return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 float * SOAP_FMAC2 soap_infloat(struct soap *soap, const char *tag, float *p, const char *type, int t) { if (soap_element_begin_in(soap, tag)) return NULL; if (soap->null) { if (soap->mode & SOAP_XML_NIL) { soap->error = SOAP_NULL; return NULL; } return p; } if (*soap->type != '\0' && soap_match_tag(soap, soap->type, type) && soap_match_tag(soap, soap->type, "float") && soap_match_tag(soap, soap->type, "decimal") && soap_match_tag(soap, soap->type, "integer") && soap_match_tag(soap, soap->type, "positiveInteger") && soap_match_tag(soap, soap->type, "negativeInteger") && soap_match_tag(soap, soap->type, "nonPositiveInteger") && soap_match_tag(soap, soap->type, "nonNegativeInteger") && soap_match_tag(soap, soap->type, "long") && soap_match_tag(soap, soap->type, "int") && soap_match_tag(soap, soap->type, "short") && soap_match_tag(soap, soap->type, "byte") && soap_match_tag(soap, soap->type, "unsignedLong") && soap_match_tag(soap, soap->type, "unsignedInt") && soap_match_tag(soap, soap->type, "unsignedShort") && soap_match_tag(soap, soap->type, "unsignedByte")) { soap->error = SOAP_TYPE_MISMATCH; soap_revert(soap); return NULL; } if (soap->body && !*soap->href) { p = (float*)soap_id_enter(soap, soap->id, p, t, sizeof(float), 0); if (!p || soap_s2float(soap, soap_value(soap), p)) return NULL; } else p = (float*)soap_id_forward(soap, soap->href, p, t, sizeof(float)); if (soap->body && soap_element_end_in(soap, tag)) return NULL; return p; } /******************************************************************************/ SOAP_FMAC1 const char* SOAP_FMAC2 soap_double2s(struct soap *soap, double n) { const char *s; if (isnan(n)) s = "NaN"; else if (n >= DBL_PINFTY) s = "INF"; else if (n <= DBL_NINFTY) s = "-INF"; else { sprintf(soap->tmpbuf, soap->double_format, n); s = soap->tmpbuf; } return s; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_outdouble(struct soap *soap, const char *tag, int id, const double *p, const char *type, int n) { if (soap_element_begin_out(soap, tag, soap_embedded_id(soap, id, p, n), type) || soap_send(soap, soap_double2s(soap, *p))) return soap->error; return soap_element_end_out(soap, tag); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_s2double(struct soap *soap, const char *s, double *p) { if (s) { if (!soap_tag_cmp(s, "INF")) *p = DBL_PINFTY; else if (!soap_tag_cmp(s, "+INF")) *p = DBL_PINFTY; else if (!soap_tag_cmp(s, "-INF")) *p = DBL_NINFTY; else if (!soap_tag_cmp(s, "NaN")) *p = DBL_NAN; else { char *r; *p = (float)strtod(s, &r); if (*r && sscanf(s, soap->double_format, p) != 1) return soap->error = SOAP_TYPE_MISMATCH; } } return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 double * SOAP_FMAC2 soap_indouble(struct soap *soap, const char *tag, double *p, const char *type, int t) { if (soap_element_begin_in(soap, tag)) return NULL; if (soap->null) { if (soap->mode & SOAP_XML_NIL) { soap->error = SOAP_NULL; return NULL; } return p; } if (*soap->type != '\0' && soap_match_tag(soap, soap->type, type) && soap_match_tag(soap, soap->type, "float") && soap_match_tag(soap, soap->type, "double") && soap_match_tag(soap, soap->type, "decimal") && soap_match_tag(soap, soap->type, "integer") && soap_match_tag(soap, soap->type, "positiveInteger") && soap_match_tag(soap, soap->type, "negativeInteger") && soap_match_tag(soap, soap->type, "nonPositiveInteger") && soap_match_tag(soap, soap->type, "nonNegativeInteger") && soap_match_tag(soap, soap->type, "long") && soap_match_tag(soap, soap->type, "int") && soap_match_tag(soap, soap->type, "short") && soap_match_tag(soap, soap->type, "byte") && soap_match_tag(soap, soap->type, "unsignedLong") && soap_match_tag(soap, soap->type, "unsignedInt") && soap_match_tag(soap, soap->type, "unsignedShort") && soap_match_tag(soap, soap->type, "unsignedByte")) { soap->error = SOAP_TYPE_MISMATCH; soap_revert(soap); return NULL; } if (soap->body && !*soap->href) { p = (double*)soap_id_enter(soap, soap->id, p, t, sizeof(double), 0); if (!p || soap_s2double(soap, soap_value(soap), p)) return NULL; } else p = (double*)soap_id_forward(soap, soap->href, p, t, sizeof(double)); if (soap->body && soap_element_end_in(soap, tag)) return NULL; return p; } /******************************************************************************/ SOAP_FMAC1 const char* SOAP_FMAC2 soap_unsignedByte2s(struct soap *soap, unsigned char n) { return soap_unsignedInt2s(soap, (unsigned int)n); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_outunsignedByte(struct soap *soap, const char *tag, int id, const unsigned char *p, const char *type, int n) { if (soap_element_begin_out(soap, tag, soap_embedded_id(soap, id, p, n), type) || soap_send(soap, soap_unsignedByte2s(soap, *p))) return soap->error; return soap_element_end_out(soap, tag); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_s2unsignedByte(struct soap *soap, const char *s, unsigned char *p) { if (s) { char *r; *p = (unsigned char)strtol(s, &r, 10); if (*r) return soap->error = SOAP_TYPE_MISMATCH; } return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 unsigned char * SOAP_FMAC2 soap_inunsignedByte(struct soap *soap, const char *tag, unsigned char *p, const char *type, int t) { if (soap_element_begin_in(soap, tag)) return NULL; if (soap->null) { if (soap->mode & SOAP_XML_NIL) { soap->error = SOAP_NULL; return NULL; } return p; } if (*soap->type != '\0' && soap_match_tag(soap, soap->type, type) && soap_match_tag(soap, soap->type, "unsignedByte")) { soap->error = SOAP_TYPE_MISMATCH; soap_revert(soap); return NULL; } if (soap->body && !*soap->href) { p = (unsigned char*)soap_id_enter(soap, soap->id, p, t, sizeof(unsigned char), 0); if (!p || soap_s2unsignedByte(soap, soap_value(soap), p)) return NULL; } else p = (unsigned char*)soap_id_forward(soap, soap->href, p, t, sizeof(unsigned char)); if (soap->body && soap_element_end_in(soap, tag)) return NULL; return p; } /******************************************************************************/ SOAP_FMAC1 const char* SOAP_FMAC2 soap_unsignedShort2s(struct soap *soap, unsigned short n) { return soap_unsignedInt2s(soap, (unsigned int)n); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_outunsignedShort(struct soap *soap, const char *tag, int id, const unsigned short *p, const char *type, int n) { if (soap_element_begin_out(soap, tag, soap_embedded_id(soap, id, p, n), type) || soap_send(soap, soap_unsignedShort2s(soap, *p))) return soap->error; return soap_element_end_out(soap, tag); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_s2unsignedShort(struct soap *soap, const char *s, unsigned short *p) { if (s && sscanf(s, "%hu", p) != 1) return soap->error = SOAP_TYPE_MISMATCH; return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 unsigned short * SOAP_FMAC2 soap_inunsignedShort(struct soap *soap, const char *tag, unsigned short *p, const char *type, int t) { if (soap_element_begin_in(soap, tag)) return NULL; if (soap->null) { if (soap->mode & SOAP_XML_NIL) { soap->error = SOAP_NULL; return NULL; } return p; } if (*soap->type != '\0' && soap_match_tag(soap, soap->type, type) && soap_match_tag(soap, soap->type, "unsignedShort") && soap_match_tag(soap, soap->type, "unsignedByte")) { soap->error = SOAP_TYPE_MISMATCH; soap_revert(soap); return NULL; } if (soap->body && !*soap->href) { p = (unsigned short*)soap_id_enter(soap, soap->id, p, t, sizeof(unsigned short), 0); if (!p || soap_s2unsignedShort(soap, soap_value(soap), p)) return NULL; } else p = (unsigned short*)soap_id_forward(soap, soap->href, p, t, sizeof(unsigned short)); if (soap->body && soap_element_end_in(soap, tag)) return NULL; return p; } /******************************************************************************/ SOAP_FMAC1 const char* SOAP_FMAC2 soap_unsignedInt2s(struct soap *soap, unsigned int n) { sprintf(soap->tmpbuf, "%u", n); return soap->tmpbuf; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_outunsignedInt(struct soap *soap, const char *tag, int id, const unsigned int *p, const char *type, int n) { if (soap_element_begin_out(soap, tag, soap_embedded_id(soap, id, p, n), type) || soap_send(soap, soap_unsignedInt2s(soap, *p))) return soap->error; return soap_element_end_out(soap, tag); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_s2unsignedInt(struct soap *soap, const char *s, unsigned int *p) { if (s) { char *r; *p = strtoul(s, &r, 10); if (*r) return soap->error = SOAP_TYPE_MISMATCH; } return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 unsigned int * SOAP_FMAC2 soap_inunsignedInt(struct soap *soap, const char *tag, unsigned int *p, const char *type, int t) { if (soap_element_begin_in(soap, tag)) return NULL; if (soap->null) { if (soap->mode & SOAP_XML_NIL) { soap->error = SOAP_NULL; return NULL; } return p; } if (*soap->type != '\0' && soap_match_tag(soap, soap->type, type) && soap_match_tag(soap, soap->type, "unsignedInt") && soap_match_tag(soap, soap->type, "unsignedShort") && soap_match_tag(soap, soap->type, "unsignedByte")) { soap->error = SOAP_TYPE_MISMATCH; soap_revert(soap); return NULL; } if (soap->body && !*soap->href) { p = (unsigned int*)soap_id_enter(soap, soap->id, p, t, sizeof(unsigned int), 0); if (!p || soap_s2unsignedInt(soap, soap_value(soap), p)) return NULL; } else p = (unsigned int*)soap_id_forward(soap, soap->href, p, t, sizeof(unsigned int)); if (soap->body && soap_element_end_in(soap, tag)) return NULL; return p; } /******************************************************************************/ SOAP_FMAC1 const char* SOAP_FMAC2 soap_unsignedLong2s(struct soap *soap, unsigned long n) { sprintf(soap->tmpbuf, "%lu", n); return soap->tmpbuf; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_outunsignedLong(struct soap *soap, const char *tag, int id, const unsigned long *p, const char *type, int n) { if (soap_element_begin_out(soap, tag, soap_embedded_id(soap, id, p, n), type) || soap_send(soap, soap_unsignedLong2s(soap, *p))) return soap->error; return soap_element_end_out(soap, tag); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_s2unsignedLong(struct soap *soap, const char *s, unsigned long *p) { if (s) { char *r; *p = strtoul(s, &r, 10); if (*r) return soap->error = SOAP_TYPE_MISMATCH; } return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 unsigned long * SOAP_FMAC2 soap_inunsignedLong(struct soap *soap, const char *tag, unsigned long *p, const char *type, int t) { if (soap_element_begin_in(soap, tag)) return NULL; if (soap->null) { if (soap->mode & SOAP_XML_NIL) { soap->error = SOAP_NULL; return NULL; } return p; } if (*soap->type != '\0' && soap_match_tag(soap, soap->type, type) && soap_match_tag(soap, soap->type, "unsignedLong") && soap_match_tag(soap, soap->type, "unsignedInt") && soap_match_tag(soap, soap->type, "unsignedShort") && soap_match_tag(soap, soap->type, "unsignedByte")) { soap->error = SOAP_TYPE_MISMATCH; soap_revert(soap); return NULL; } if (soap->body && !*soap->href) { p = (unsigned long*)soap_id_enter(soap, soap->id, p, t, sizeof(unsigned long), 0); if (!p || soap_s2unsignedLong(soap, soap_value(soap), p)) return NULL; } else p = (unsigned long*)soap_id_forward(soap, soap->href, p, t, sizeof(unsigned long)); if (soap->body && soap_element_end_in(soap, tag)) return NULL; return p; } /******************************************************************************/ SOAP_FMAC1 const char* SOAP_FMAC2 soap_ULONG642s(struct soap *soap, ULONG64 n) { sprintf(soap->tmpbuf, SOAP_ULONG_FORMAT, n); return soap->tmpbuf; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_outULONG64(struct soap *soap, const char *tag, int id, const ULONG64 *p, const char *type, int n) { if (soap_element_begin_out(soap, tag, soap_embedded_id(soap, id, p, n), type) || soap_send(soap, soap_ULONG642s(soap, *p))) return soap->error; return soap_element_end_out(soap, tag); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_s2ULONG64(struct soap *soap, const char *s, ULONG64 *p) { if (s && sscanf(s, SOAP_ULONG_FORMAT, p) != 1) return soap->error = SOAP_TYPE_MISMATCH; return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 ULONG64 * SOAP_FMAC2 soap_inULONG64(struct soap *soap, const char *tag, ULONG64 *p, const char *type, int t) { if (soap_element_begin_in(soap, tag)) return NULL; if (soap->null) { if (soap->mode & SOAP_XML_NIL) { soap->error = SOAP_NULL; return NULL; } return p; } if (*soap->type != '\0' && soap_match_tag(soap, soap->type, type) && soap_match_tag(soap, soap->type, "positiveInteger") && soap_match_tag(soap, soap->type, "nonNegativeInteger") && soap_match_tag(soap, soap->type, "unsignedLong") && soap_match_tag(soap, soap->type, "unsignedInt") && soap_match_tag(soap, soap->type, "unsignedShort") && soap_match_tag(soap, soap->type, "unsignedByte")) { soap->error = SOAP_TYPE_MISMATCH; soap_revert(soap); return NULL; } if (soap->body && !*soap->href) { p = (ULONG64*)soap_id_enter(soap, soap->id, p, t, sizeof(ULONG64), 0); if (!p || soap_s2ULONG64(soap, soap_value(soap), p)) return NULL; } else p = (ULONG64*)soap_id_forward(soap, soap->href, p, t, sizeof(ULONG64)); if (soap->body && soap_element_end_in(soap, tag)) return NULL; return p; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_s2string(struct soap *soap, const char *s, char **t) { if (s) { *t = (char*)soap_malloc(soap, strlen(s) + 1); if (!*t) return soap->error = SOAP_EOM; strcpy(*t, s); } return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_s2QName(struct soap *soap, const char *s, char **t) { if (s) { const char *p = strchr(s, ':'); if (p) { struct soap_nlist *np = soap->nlist; int n = p - s; while (np && (np->id[n] || strncmp(np->id, s, n))) np = np->next; if (np) { if (np->index >= 0 && soap->local_namespaces) { const char *q = soap->local_namespaces[np->index].id; if (q) { *t = (char*)soap_malloc(soap, strlen(p) + strlen(q) + 1); strcpy(*t, q); strcat(*t, p); return SOAP_OK; } } if (np->ns) { *t = (char*)soap_malloc(soap, strlen(p) + strlen(np->ns) + 3); sprintf(*t, "\"%s\"%s", np->ns, p); return SOAP_OK; } } DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Namespace prefix of '%s' not defined\n", s)); return soap->error = SOAP_SYNTAX_ERROR; } *t = (char*)soap_malloc(soap, strlen(s) + 1); if (!*t) return soap->error = SOAP_EOM; strcpy(*t, s); } return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_outstring(struct soap *soap, const char *tag, int id, char *const*p, const char *type, int n) { if (!*p) { if (soap_element_null(soap, tag, id, type)) return soap->error; } else { struct soap_plist *pp; int i = soap_pointer_lookup(soap, *p, n, &pp); if (id > 0) { if (i) { if (soap_element_begin_out(soap, tag, id, type) || soap_string_out(soap, *p) || soap_element_end_out(soap, tag)) return soap->error; soap_set_embedded(soap, pp); } else { i = soap_pointer_enter(soap, *p, n, &pp); if (soap_element_begin_out(soap, tag, id, type) || soap_string_out(soap, *p) || soap_element_end_out(soap, tag)) return soap->error; if (soap->mode & SOAP_IO_LENGTH) pp->mark1 = 0; else pp->mark2 = 0; } } else if (i) { if (soap_is_embedded(soap, pp)) { if (soap_element_ref(soap, tag, 0, i)) return soap->error; } else if (soap_is_single(soap, pp)) { if (soap_element_begin_out(soap, tag, 0, type) || soap_string_out(soap, *p) || soap_element_end_out(soap, tag)) return soap->error; } else { if (soap_element_begin_out(soap, tag, i, type) || soap_string_out(soap, *p) || soap_element_end_out(soap, tag)) return soap->error; soap_set_embedded(soap, pp); } } else { soap_pointer_enter(soap, *p, n, &pp); if (soap_element_begin_out(soap, tag, id, type) || soap_string_out(soap, *p) || soap_element_end_out(soap, tag)) return soap->error; if (soap->mode & SOAP_IO_LENGTH) pp->mark1 = 0; else pp->mark2 = 0; } } return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 char ** SOAP_FMAC2 soap_instring(struct soap *soap, const char *tag, char **p, const char *type, int t, int flag) { if (soap_element_begin_in(soap, tag)) return NULL; if (soap->null) { p = (char**)soap_id_enter(soap, soap->id, p, t, sizeof(char**), 0); if (p) *p = NULL; } else if (soap->body && !*soap->href) { if (soap_match_tag(soap, soap->type, "PointerTostring") == 0) { p = (char**)soap_id_enter(soap, soap->id, p, t, sizeof(char**), 0); p = (char**)soap_instring(soap, "string", p, type, t, flag); } else { if (!p) if ((p = (char**)soap_id_enter(soap, "", p, t, sizeof(char**), 0)) == NULL) return NULL; *p = (char*)soap_id_enter(soap, soap->id, soap_string_in(soap, flag), t, 0, 0); } } else p = (char**)soap_id_lookup(soap, soap->href, (void**)p, t, sizeof(char*), 0); if (soap->body && soap_element_end_in(soap, tag)) return NULL; return p; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_outwstring(struct soap *soap, const char *tag, int id, wchar_t *const*p, const char *type, int n) { if (!*p) { if (soap_element_null(soap, tag, id, type)) return soap->error; } else { struct soap_plist *pp; int i = soap_pointer_lookup(soap, *p, n, &pp); if (id > 0) { if (i) { if (soap_element_begin_out(soap, tag, id, type) || soap_wstring_out(soap, *p) || soap_element_end_out(soap, tag)) return soap->error; soap_set_embedded(soap, pp); } else { i = soap_pointer_enter(soap, *p, n, &pp); if (soap_element_begin_out(soap, tag, id, type) || soap_wstring_out(soap, *p) || soap_element_end_out(soap, tag)) return soap->error; if (soap->mode & SOAP_IO_LENGTH) pp->mark1 = 0; else pp->mark2 = 0; } } else if (i) { if (soap_is_embedded(soap, pp)) { if (soap_element_ref(soap, tag, 0, i)) return soap->error; } else if (soap_is_single(soap, pp)) { if (soap_element_begin_out(soap, tag, 0, type) || soap_wstring_out(soap, *p) || soap_element_end_out(soap, tag)) return soap->error; } else { if (soap_element_begin_out(soap, tag, i, type) || soap_wstring_out(soap, *p) || soap_element_end_out(soap, tag)) return soap->error; soap_set_embedded(soap, pp); } } else { if (soap_element_begin_out(soap, tag, id, type) || soap_wstring_out(soap, *p) || soap_element_end_out(soap, tag)) return soap->error; if (soap->mode & SOAP_IO_LENGTH) pp->mark1 = 0; else pp->mark2 = 0; } } return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 wchar_t ** SOAP_FMAC2 soap_inwstring(struct soap *soap, const char *tag, wchar_t **p, const char *type, int t) { if (soap_element_begin_in(soap, tag)) return NULL; if (soap->null) { p = (wchar_t**)soap_id_enter(soap, soap->id, p, t, sizeof(wchar_t**), 0); if (p) *p = NULL; } else if (soap->body && !*soap->href) { if (soap_match_tag(soap, soap->type, "PointerTostring") == 0) p = (wchar_t**)soap_inwstring(soap, "string", (wchar_t**)soap_id_enter(soap, soap->id, p, t, sizeof(wchar_t**), 0), type, t); else { if (!p) if (!(p = (wchar_t**)soap_id_enter(soap, "", p, t, sizeof(wchar_t**), 0))) return NULL; *p = (wchar_t*)soap_id_enter(soap, soap->id, soap_wstring_in(soap, 1), t, 0, 0); } } else p = (wchar_t**)soap_id_lookup(soap, soap->href, (void**)p, t, sizeof(wchar_t*), 0); if (soap->body && soap_element_end_in(soap, tag)) return NULL; return p; } /******************************************************************************/ #ifndef MAC_CARBON #ifndef UNDER_CE /******************************************************************************/ static time_t soap_timegm(struct tm *T) { #if defined(HAVE_TIMEGM) return timegm(T); #elif defined(HAVE_FTIME) struct timeb t; ftime(&t); T->tm_min -= t.timezone; T->tm_isdst = -1; return mktime(T); #else #warning "time_t (de)serialization is not MT safe on this platform" time_t t; char *tz = getenv("TZ"); putenv("TZ=UTC"); tzset(); t = mktime(T); if (tz) { char tmp[16]; strcpy(tmp, "TZ="); strncat(tmp, tz, 12); tmp[15] = '\0'; putenv(tmp); } else putenv("TZ="); tzset(); return t; #endif } /******************************************************************************/ SOAP_FMAC1 const char* SOAP_FMAC2 soap_dateTime2s(struct soap *soap, time_t n) { #if defined(HAVE_GMTIME_R) struct tm T; strftime(soap->tmpbuf, sizeof(soap->tmpbuf), "%Y-%m-%dT%H:%M:%SZ", gmtime_r(&n, &T)); #elif defined(HAVE_GMTIME) strftime(soap->tmpbuf, sizeof(soap->tmpbuf), "%Y-%m-%dT%H:%M:%SZ", gmtime(&n)); #elif defined(HAVE_FTIME) struct timeb t; #if defined(HAVE_LOCALTIME_R) struct tm T; ftime(&t); strftime(soap->tmpbuf, sizeof(soap->tmpbuf), "%Y-%m-%dT%H:%M:%S", localtime_r(&n, &T)); sprintf(soap->tmpbuf + strlen(soap->tmpbuf), "%+03d:%02d", -t.timezone/60, abs(t.timezone)%60); #else ftime(&t); strftime(soap->tmpbuf, sizeof(soap->tmpbuf), "%Y-%m-%dT%H:%M:%S", localtime(&n)); sprintf(soap->tmpbuf + strlen(soap->tmpbuf), "%+03d:%02d", -t.timezone/60, abs(t.timezone)%60); #endif #elif defined(HAVE_LOCALTIME_R) struct tm T; strftime(soap->tmpbuf, sizeof(soap->tmpbuf), "%Y-%m-%dT%H:%M:%S", localtime_r(&n, &T)); #else strftime(soap->tmpbuf, sizeof(soap->tmpbuf), "%Y-%m-%dT%H:%M:%S", localtime(&n)); #endif return soap->tmpbuf; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_outdateTime(struct soap *soap, const char *tag, int id, const time_t *p, const char *type, int n) { if (soap_element_begin_out(soap, tag, soap_embedded_id(soap, id, p, n), type) || soap_send(soap, soap_dateTime2s(soap, *p))) return soap->error; return soap_element_end_out(soap, tag); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_s2dateTime(struct soap *soap, const char *s, time_t *p) { if (s) { struct tm T; char zone[16]; memset(&T, 0, sizeof(struct tm)); zone[sizeof(zone)-1] = '\0'; sscanf(s, "%d-%d-%dT%d:%d:%d%15s", &T.tm_year, &T.tm_mon, &T.tm_mday, &T.tm_hour, &T.tm_min, &T.tm_sec, zone); if (T.tm_year <= 1901 && T.tm_year != 1) *p = -1; else if (T.tm_year >= 2038) *p = -1; else { if (T.tm_year == 1) T.tm_year = 70; else T.tm_year -= 1900; T.tm_mon--; if (*zone) { if (*zone == '.') { for (s = zone+1; *s; s++) if (*s < '0' || *s > '9') break; } else s = zone; if (*s != 'Z') { int h = 0, m = 0; sscanf(s, "%d:%d", &h, &m); T.tm_hour -= h; if (h >= 0) T.tm_min -= m; else T.tm_min += m; } *p = soap_timegm(&T); } else *p = mktime(&T); /* no time zone: suppose it is localtime? */ } } return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 time_t * SOAP_FMAC2 soap_indateTime(struct soap *soap, const char *tag, time_t *p, const char * type, int t) { if (soap_element_begin_in(soap, tag)) return NULL; if (soap->null) { if (soap->mode & SOAP_XML_NIL) { soap->error = SOAP_NULL; return NULL; } return p; } if (*soap->type != '\0' && soap_match_tag(soap, soap->type, type) && soap_match_tag(soap, soap->type, "dateTime")) { soap->error = SOAP_TYPE_MISMATCH; soap_revert(soap); return NULL; } if (soap->body && !*soap->href) { p = (time_t*)soap_id_enter(soap, soap->id, p, t, sizeof(time_t), 0); if (!p || soap_s2dateTime(soap, soap_value(soap), p)) return NULL; } else p = (time_t*)soap_id_forward(soap, soap->href, p, t, sizeof(time_t)); if (soap->body && soap_element_end_in(soap, tag)) return NULL; return p; } /******************************************************************************/ #endif #endif /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_outliteral(struct soap *soap, const char *tag, char *const*p) { int i; const char *t; if ((t = strchr(tag, ':'))) { strncpy(soap->tmpbuf, tag, t-tag); soap->tmpbuf[t-tag] = '\0'; for (i = 0; soap->local_namespaces[i].id; i++) if (!strcmp(soap->tmpbuf, soap->local_namespaces[i].id)) break; sprintf(soap->tmpbuf, "<%s xmlns=\"%s\">", t+1, soap->local_namespaces[i].ns ? soap->local_namespaces[i].ns : ""); } else sprintf(soap->tmpbuf, "<%s>", tag); if (soap_send(soap, soap->tmpbuf)) return soap->error; if (p && *p) { if (soap_send(soap, *p)) return soap->error; } if (t) sprintf(soap->tmpbuf, "", t+1); else sprintf(soap->tmpbuf, "", tag); return soap_send(soap, soap->tmpbuf); } /******************************************************************************/ SOAP_FMAC1 char ** SOAP_FMAC2 soap_inliteral(struct soap *soap, const char *tag, char **p) { if (soap_element_begin_in(soap, tag)) return NULL; if (!p) if (!(p = (char**)soap_malloc(soap, sizeof(char*)))) return NULL; if (soap->null) *p = NULL; else if (soap->body) *p = soap_string_in(soap, 0); else *p = NULL; if (soap->body && soap_element_end_in(soap, tag)) return NULL; return p; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_outwliteral(struct soap *soap, const char *tag, wchar_t *const*p) { int i; const char *t; wchar_t c; const wchar_t *s; if ((t = strchr(tag, ':'))) { strncpy(soap->tmpbuf, tag, t-tag); soap->tmpbuf[t-tag] = '\0'; for (i = 0; soap->local_namespaces[i].id; i++) if (!strcmp(soap->tmpbuf, soap->local_namespaces[i].id)) break; sprintf(soap->tmpbuf, "<%s xmlns=\"%s\">", t+1, soap->local_namespaces[i].ns ? soap->local_namespaces[i].ns : ""); } else sprintf(soap->tmpbuf, "<%s>", tag); if (soap_send(soap, soap->tmpbuf)) return soap->error; if (p) { s = *p; while ((c = *s++)) if (soap_pututf8(soap, c)) return soap->error; } if (t) sprintf(soap->tmpbuf,"", t+1); else sprintf(soap->tmpbuf,"", tag); return soap_send(soap, soap->tmpbuf); } /******************************************************************************/ SOAP_FMAC1 wchar_t ** SOAP_FMAC2 soap_inwliteral(struct soap *soap, const char *tag, wchar_t **p) { if (soap_element_begin_in(soap, tag)) return NULL; if (!p) if (!(p = (wchar_t**)soap_malloc(soap, sizeof(wchar_t*)))) return NULL; if (soap->null) *p = NULL; else if (soap->body) *p = soap_wstring_in(soap, 0); else *p = NULL; if (soap->body && soap_element_end_in(soap, tag)) return NULL; return p; } /******************************************************************************/ SOAP_FMAC1 char * SOAP_FMAC2 soap_value(struct soap *soap) { size_t i; wchar c = 0; char *s; s = soap->tmpbuf; for (i = 0; i < sizeof(soap->tmpbuf)-1; i++) { c = soap_get(soap); if (c == TT || c == EOF || blank(c)) break; *s++ = (char)c; } if (c == EOF || c == TT) soap_unget(soap, c); *s = '\0'; return soap->tmpbuf; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_getline(struct soap *soap, char *s, int len) { int i = len; wchar c = 0; for (;;) { while (--i > 0) { c = soap_getchar(soap); if (c == '\r' || c == '\n' || c == EOF) break; *s++ = (char)c; } *s = '\0'; while (c != '\n' && c != EOF) c = soap_getchar(soap); if (c == EOF) return SOAP_EOF; if (i+1 == len) /* empty line: end of HTTP header */ break; c = soap_unget(soap, soap_getchar(soap)); if (c != ' ' && c != '\t') /* HTTP line continuation? */ break; } return SOAP_OK; } /******************************************************************************/ static size_t soap_begin_dime(struct soap *soap) { if (soap->mode & SOAP_ENC_DIME) { size_t count; sprintf(soap->id, soap->dime_id_format, 0); soap->dime_id = soap->id; if (soap->local_namespaces) { if (soap->local_namespaces[0].out) soap->dime_type = (char*)soap->local_namespaces[0].out; else soap->dime_type = (char*)soap->local_namespaces[0].ns; } soap->dime_options = NULL; count = soap->dime_size + 12 + ((soap->count+3)&-4) + ((strlen(soap->dime_id)+3)&-4) + ((strlen(soap->dime_type)+3)&-4); soap->dime_size = soap->count; if (soap->dime_count) soap->dime_flags = SOAP_DIME_MB | SOAP_DIME_ABSURI; else soap->dime_flags = SOAP_DIME_MB | SOAP_DIME_ME | SOAP_DIME_ABSURI; return count; } return soap->count; } /******************************************************************************/ static int soap_putdimefield(struct soap *soap, const char *s, size_t n) { if (soap_send_raw(soap, s, n)) return soap->error; return soap_send_raw(soap, "\0\0\0", -(int)n&3); } /******************************************************************************/ SOAP_FMAC1 char * SOAP_FMAC2 soap_dime_option(struct soap *soap, unsigned short type, const char *option) { size_t n; char *s = NULL; if (option) { n = strlen(option); s = (char*)soap_malloc(soap, n + 5); if (s) { s[0] = type >> 8; s[1] = type & 0xFF; s[2] = n >> 8; s[3] = n & 0xFF; strcpy(s + 4, option); } } return s; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_putdimehdr(struct soap *soap) { unsigned char tmp[12]; size_t optlen = 0, idlen = 0, typelen = 0; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Put DIME header id='%s'\n", soap->dime_id?soap->dime_id:"")); if (soap->dime_options) optlen = ((unsigned char)soap->dime_options[2] << 8 | (unsigned char)soap->dime_options[3]) + 4; if (soap->dime_id) idlen = strlen(soap->dime_id); if (soap->dime_type) typelen = strlen(soap->dime_type); tmp[0] = SOAP_DIME_VERSION | (soap->dime_flags & 0x7); tmp[1] = soap->dime_flags & 0xF0; tmp[2] = optlen >> 8; tmp[3] = optlen & 0xFF; tmp[4] = idlen >> 8; tmp[5] = idlen & 0xFF; tmp[6] = typelen >> 8; tmp[7] = typelen & 0xFF; tmp[8] = soap->dime_size >> 24; tmp[9] = soap->dime_size >> 16 & 0xFF; tmp[10] = soap->dime_size >> 8 & 0xFF; tmp[11] = soap->dime_size & 0xFF; if (soap_send_raw(soap, (char*)tmp, 12) || soap_putdimefield(soap, soap->dime_options, optlen) || soap_putdimefield(soap, soap->dime_id, idlen) || soap_putdimefield(soap, soap->dime_type, typelen)) return soap->error; return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_putdime(struct soap *soap, int i, char *id, char *type, char *options, void *ptr, size_t size) { void *h; if (id) soap->dime_id = id; else { sprintf(soap->tmpbuf, soap->dime_id_format, i); soap->dime_id = soap->tmpbuf; } soap->dime_type = type; soap->dime_options = options; soap->dime_size = size; soap->dime_flags = SOAP_DIME_VERSION | SOAP_DIME_MEDIA; if (--soap->dime_count == 0) soap->dime_flags |= SOAP_DIME_ME; if (soap_putdimehdr(soap)) return soap->error; if (soap->fdimereadopen && ((h = soap->fdimereadopen(soap, (void*)ptr, soap->dime_id, type, options)) || soap->error)) { size_t n; if (!h) return soap->error; while (size) { if (size < sizeof(soap->tmpbuf)) n = size; else n = sizeof(soap->tmpbuf); if (!(n = soap->fdimeread(soap, h, soap->tmpbuf, n))) { soap->error = SOAP_EOF; break; } if (soap_send_raw(soap, soap->tmpbuf, n)) break; size -= n; } soap->fdimereadclose(soap, h); soap_send_raw(soap, "\0\0\0", -(int)soap->dime_size&3); return soap->error; } return soap_putdimefield(soap, (char*)ptr, size); } /******************************************************************************/ static char * soap_getdimefield(struct soap *soap, int n) { register wchar c; register int i; register char *s; char *p = NULL; if (n) { p = (char*)soap_malloc(soap, n + 1); if (p) { s = p; for (i = n; i > 0; i--) { if ((c = soap_get1(soap)) == EOF) { soap->error = SOAP_EOF; return NULL; } *s++ = (char)c; } *s = '\0'; if ((soap->error = soap_move(soap, -n&3))) return NULL; } else soap->error = SOAP_EOM; } return p; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_getdimehdr(struct soap *soap) { register wchar c; register char *s; register int i; unsigned char tmp[12]; int optlen, idlen, typelen; if (!(soap->mode & SOAP_ENC_DIME)) return soap->error = SOAP_EOD; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Get DIME header\n")); if (soap->dime_buflen || soap->dime_chunksize) { if (soap_move(soap, soap->dime_size-soap_tell(soap))) return soap->error = SOAP_EOF; soap_unget(soap, soap_getchar(soap)); /* skip padding and get hdr */ DBGLOG(TEST, SOAP_MESSAGE(fdebug, "... From chunked\n")); return SOAP_OK; } s = (char*)tmp; for (i = 12; i > 0; i--) { if ((c = soap_getchar(soap)) == EOF) return soap->error = SOAP_EOF; *s++ = (char)c; } if ((tmp[0]&0xF8) != SOAP_DIME_VERSION) return soap->error = SOAP_DIME_MISMATCH; soap->dime_flags = (tmp[0]&0x7) | (tmp[1]&0xF0); optlen = tmp[2] << 8 | tmp[3]; idlen = tmp[4] << 8 | tmp[5]; typelen = tmp[6] << 8 | tmp[7]; soap->dime_size = tmp[8] << 24 | tmp[9] << 16 | tmp[10] << 8 | tmp[11]; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "DIME size=%u flags=0x%X\n", (unsigned int)soap->dime_size, soap->dime_flags)); if (!(soap->dime_options = soap_getdimefield(soap, optlen)) && soap->error) return soap->error; if (!(soap->dime_id = soap_getdimefield(soap, idlen)) && soap->error) return soap->error; if (!(soap->dime_type = soap_getdimefield(soap, typelen)) && soap->error) return soap->error; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "DIME id=%s, type=%s, options=%s\n", soap->dime_id?soap->dime_id:"", soap->dime_type?soap->dime_type:"", soap->dime_options?soap->dime_options+4:"")); if (soap->dime_flags & SOAP_DIME_ME) soap->mode &= ~SOAP_ENC_DIME; return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_getdime(struct soap *soap) { if (soap_getdimehdr(soap)) return soap->error; if (soap->fdimewriteopen && ((soap->dime_ptr = (char*)soap->fdimewriteopen(soap, soap->dime_id, soap->dime_type, soap->dime_options)) || soap->error)) { char *id, *type, *options; size_t size, n; if (!soap->dime_ptr) return soap->error; id = soap->dime_id; type = soap->dime_type; options = soap->dime_options; for (;;) { size = soap->dime_size; for (;;) { n = soap->buflen - soap->bufidx; if (size < n) n = size; if ((soap->error = soap->fdimewrite(soap, (void*)soap->dime_ptr, soap->buf + soap->bufidx, n))) break; size -= n; if (!size) { soap->bufidx += n; break; } if (soap_recv(soap)) { soap->error = SOAP_EOF; goto end; } } if (soap_move(soap, -(int)soap->dime_size&3)) { soap->error = SOAP_EOF; break; } if (!(soap->dime_flags & SOAP_DIME_CF)) break; if (soap_getdimehdr(soap)) break; } end: if (soap->fdimewriteclose) soap->fdimewriteclose(soap, (void*)soap->dime_ptr); soap->dime_size = 0; soap->dime_id = id; soap->dime_type = type; soap->dime_options = options; } else if (soap->dime_flags & SOAP_DIME_CF) { char *id, *type, *options; register wchar c; register char *s; register int i; id = soap->dime_id; type = soap->dime_type; options = soap->dime_options; if (soap_new_block(soap)) return SOAP_EOM; for (;;) { s = (char*)soap_push_block(soap, soap->dime_size); if (!s) return soap->error = SOAP_EOM; for (i = soap->dime_size; i > 0; i--) { if ((c = soap_get1(soap)) == EOF) return soap->error = SOAP_EOF; *s++ = (char)c; } if (soap_move(soap, -(int)soap->dime_size&3)) return soap->error = SOAP_EOF; if (!(soap->dime_flags & SOAP_DIME_CF)) break; if (soap_getdimehdr(soap)) return soap->error; } soap->dime_size = soap->blist->size++; /* allocate one more for '\0' */ if (!(soap->dime_ptr = soap_save_block(soap, NULL))) return soap->error; soap->dime_ptr[soap->dime_size] = '\0'; /* make 0-terminated to enable string-based attachments */ soap->dime_id = id; soap->dime_type = type; soap->dime_options = options; } else soap->dime_ptr = soap_getdimefield(soap, soap->dime_size); return soap->error; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_encode_string(const char *s, char *t, int len) { register int c; int n = len; while ((c = *s++) && --n > 0) { if (c == ' ') *t++ = '+'; else if (c == '!' || c == '$' || (c >= '(' && c <= '.') || (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || c == '_' || (c >= 'a' && c <= 'z')) *t++ = c; else if (n > 2) { *t++ = '%'; *t++ = (c>>4) + (c > 159 ? '7' : '0'); c &= 0xF; *t++ = c + (c > 9 ? '7' : '0'); n -= 2; } else break; } *t = '\0'; return len - n; } /******************************************************************************/ SOAP_FMAC1 const char* SOAP_FMAC2 soap_decode_string(char *buf, int len, const char *val) { const char *s; char *t; for (s = val; *s; s++) if (*s != ' ' && *s != '=') break; if (*s == '"') { t = buf; s++; while (*s && *s != '"' && --len) *t++ = *s++; *t = '\0'; do s++; while (*s && *s != '&' && *s != ';' && *s != '='); } else { t = buf; while (*s && *s != '&' && *s != ';' && *s != '=' && --len) switch (*s) { case '+': *t++ = ' '; case ' ': s++; break; case '%': *t++ = ((s[1] >= 'A' ? (s[1]&0x7) + 9 : s[1] - '0') << 4) + (s[2] >= 'A' ? (s[2]&0x7) + 9 : s[2] - '0'); s += 3; break; default: *t++ = *s++; } *t = '\0'; } return s; } /******************************************************************************/ #ifdef WITH_COOKIES /******************************************************************************/ SOAP_FMAC1 struct soap_cookie* SOAP_FMAC2 soap_cookie(struct soap *soap, const char *name, const char *domain, const char *path) { struct soap_cookie *p; size_t n; if (!domain) domain = soap->cookie_domain; if (!path) path = soap->cookie_path; if (*path == '/') path++; n = strlen(path); for (p = soap->cookies; p; p = p->next) if (!strcmp(p->name, name) && !strcmp(p->domain, domain) && !strncmp(p->path, path, n)) break; return p; } /******************************************************************************/ SOAP_FMAC1 struct soap_cookie* SOAP_FMAC2 soap_set_cookie(struct soap *soap, const char *name, const char *value, const char *domain, const char *path) { struct soap_cookie **p, *q; int n; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Set cookie: %s=%s domain=%s path=%s\n", name, value?value:"", domain?domain:"", path?path:"")); if (!domain) domain = soap->cookie_domain; if (!domain) { soap_set_receiver_error(soap, "Cookie domain not set", NULL, SOAP_HTTP_ERROR); return NULL; } if (!path) path = soap->cookie_path; if (!path) { soap_set_receiver_error(soap, "Cookie path not set", NULL, SOAP_HTTP_ERROR); return NULL; } if (*path == '/') path++; q = soap_cookie(soap, name, domain, path); if (!q) { if ((q = (struct soap_cookie*)malloc(sizeof(struct soap_cookie)))) { if ((q->name = (char*)malloc(strlen(name)+1))) strcpy(q->name, name); q->value = NULL; q->domain = NULL; q->path = NULL; q->expire = -1; q->version = 0; q->secure = 0; q->env = 0; q->modified = 0; for (p = &soap->cookies, n = soap->cookie_max; *p && n; p = &(*p)->next, n--) if (!strcmp((*p)->name, name) && (*p)->path && strcmp((*p)->path, path) < 0) break; if (n) { q->next = *p; *p = q; } else { free(q->name); free(q); q = NULL; } } } else q->modified = 1; if (q) { if (q->value) { free(q->value); q->value = NULL; } if (q->domain) { free(q->domain); q->domain = NULL; } if (q->path) { free(q->path); q->path = NULL; } if (value && *value && (q->value = (char*)malloc(strlen(value)+1))) strcpy(q->value, value); if ((q->domain = (char*)malloc(strlen(domain)+1))) strcpy(q->domain, domain); if ((q->path = (char*)malloc(strlen(path)+1))) strcpy(q->path, path); q->session = 1; } return q; } /******************************************************************************/ SOAP_FMAC1 void SOAP_FMAC2 soap_clr_cookie(struct soap *soap, const char *name, const char *domain, const char *path) { struct soap_cookie **p, *q; if (!domain) domain = soap->cookie_domain; if (!domain) { soap_set_receiver_error(soap, "Cookie domain not set", "", SOAP_HTTP_ERROR); return; } if (!path) path = soap->cookie_path; if (!path) { soap_set_receiver_error(soap, "Cookie path not set", "", SOAP_HTTP_ERROR); return; } if (*path == '/') path++; for (p = &soap->cookies, q = *p; q; p = &q->next, q = *p) if (!strcmp(q->name, name) && !strcmp(q->domain, domain) && !strncmp(q->path, path, strlen(q->path))) { if (q->value) free(q->value); if (q->domain) free(q->domain); if (q->path) free(q->path); *p = q->next; free(q); } } /******************************************************************************/ SOAP_FMAC1 char * SOAP_FMAC2 soap_cookie_value(struct soap *soap, const char *name, const char *domain, const char *path) { struct soap_cookie *p; if ((p = soap_cookie(soap, name, domain, path))) return p->value; return NULL; } /******************************************************************************/ SOAP_FMAC1 long SOAP_FMAC2 soap_cookie_expire(struct soap *soap, const char *name, const char *domain, const char *path) { struct soap_cookie *p; if ((p = soap_cookie(soap, name, domain, path))) return p->expire; return -1; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_set_cookie_expire(struct soap *soap, const char *name, long expire, const char *domain, const char *path) { struct soap_cookie *p; if ((p = soap_cookie(soap, name, domain, path))) { p->expire = expire; p->modified = 1; return SOAP_OK; } return SOAP_EOF; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_set_cookie_session(struct soap *soap, const char *name, const char *domain, const char *path) { struct soap_cookie *p; if ((p = soap_cookie(soap, name, domain, path))) { p->session = 1; p->modified = 1; return SOAP_OK; } return SOAP_EOF; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_clr_cookie_session(struct soap *soap, const char *name, const char *domain, const char *path) { struct soap_cookie *p; if ((p = soap_cookie(soap, name, domain, path))) { p->session = 0; p->modified = 1; return SOAP_OK; } return SOAP_EOF; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_putsetcookies(struct soap *soap) { struct soap_cookie *p; char *s, tmp[4096]; for (p = soap->cookies; p; p = p->next) if (p->modified || !p->env) { s = tmp; if (p->name) s += soap_encode_string(p->name, s, tmp-s+4064); if (p->value) { *s++ = '='; s += soap_encode_string(p->value, s, tmp-s+4064); } if (p->domain && (int)strlen(p->domain) < tmp-s+4064) sprintf(s, ";Domain=%s", p->domain); else if (soap->cookie_domain && (int)strlen(soap->cookie_domain) < tmp-s+4064) sprintf(s, ";Domain=%s", soap->cookie_domain); s += strlen(s); if (p->path && (int)strlen(p->path) < tmp-s+4064) sprintf(s, ";Path=/%s", p->path); else if (soap->cookie_path && (int)strlen(soap->cookie_path) < tmp-s+4064) sprintf(s, ";Path=/%s", soap->cookie_path); else strcpy(s, ";Path=/"); s += strlen(s); if (p->version > 0) { sprintf(s, ";Version=%u", p->version); s += strlen(s); } if (p->expire >= 0) { sprintf(s, ";Max-Age=%ld", p->expire); s += strlen(s); } if (p->secure) strcpy(s, ";Secure"); DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Set-Cookie: %s\n", tmp)); if (soap->fposthdr(soap, "Set-Cookie", tmp)) return soap->error; } return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_putcookies(struct soap *soap, const char *domain, const char *path, int secure) { struct soap_cookie **p, *q; unsigned int version = 0; time_t now = time(NULL); char *s, tmp[4096]; p = &soap->cookies; while ((q = *p)) { if (q->expire && now > q->expire) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Cookie %s expired\n", q->name)); free(q->name); if (q->value) free(q->value); if (q->domain) free(q->domain); if (q->path) free(q->path); *p = q->next; free(q); } else if ((!q->domain || !strcmp(q->domain, domain)) && (!q->path || !strncmp(q->path, path, strlen(q->path))) && (!q->secure || secure)) { s = tmp; if (q->version != version) { sprintf(s, "$Version=%u;", q->version); version = q->version; } if (q->name) s += soap_encode_string(q->name, s, tmp-s+4080); if (q->value) { *s++ = '='; s += soap_encode_string(q->value, s, tmp-s+4080); } if (q->path && (int)strlen(q->path) < tmp-s+4080) { sprintf(s, ";$Path=/%s", q->path); s += strlen(s); } if (q->domain && (int)strlen(q->domain) < tmp-s+4080) sprintf(s, ";$Domain=%s", q->domain); DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Cookie: %s\n", tmp)); if (soap->fposthdr(soap, "Cookie", tmp)) return soap->error; p = &q->next; } else p = &q->next; } return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 void SOAP_FMAC2 soap_getcookies(struct soap *soap, const char *val) { struct soap_cookie *p = NULL, *q; const char *s; char *t, tmp[4096]; /* cookie size is up to 4096 bytes [RFC2109] */ char *domain = NULL; char *path = NULL; unsigned int version = 0; time_t now = time(NULL); if (!val) return; s = val; while (*s) { s = soap_decode_string(tmp, sizeof(tmp), s); if (!soap_tag_cmp(tmp, "$Version")) { if ((s = soap_decode_string(tmp, sizeof(tmp), s))) { if (p) p->version = (int)atol(tmp); else version = (int)atol(tmp); } } else if (!soap_tag_cmp(tmp, "$Path")) { s = soap_decode_string(tmp, sizeof(tmp), s); if (*tmp) { t = (char*)malloc(strlen(tmp)+1); strcpy(t, tmp); } else t = NULL; if (p) p->path = t; else { if (path) free(path); path = t; } } else if (!soap_tag_cmp(tmp, "$Domain")) { s = soap_decode_string(tmp, sizeof(tmp), s); if (*tmp) { t = (char*)malloc(strlen(tmp)+1); strcpy(t, tmp); } else t = NULL; if (p) p->domain = t; else { if (domain) free(domain); domain = t; } } else if (p && !soap_tag_cmp(tmp, "Path")) { s = soap_decode_string(tmp, sizeof(tmp), s); if (*tmp) { p->path = (char*)malloc(strlen(tmp)+1); strcpy(p->path, tmp); } else p->path = NULL; } else if (p && !soap_tag_cmp(tmp, "Domain")) { s = soap_decode_string(tmp, sizeof(tmp), s); if (*tmp) { p->domain = (char*)malloc(strlen(tmp)+1); strcpy(p->domain, tmp); } else p->domain = NULL; } else if (p && !soap_tag_cmp(tmp, "Version")) { s = soap_decode_string(tmp, sizeof(tmp), s); p->version = (unsigned int)atol(tmp); } else if (p && !soap_tag_cmp(tmp, "Max-Age")) { s = soap_decode_string(tmp, sizeof(tmp), s); p->expire = now + atol(tmp); } else if (p && !soap_tag_cmp(tmp, "Expires")) { struct tm T; char a[3]; static const char mns[] = "anebarprayunulugepctovec"; s = soap_decode_string(tmp, sizeof(tmp), s); memset(&T, 0, sizeof(struct tm)); a[0] = tmp[4]; a[1] = tmp[5]; a[2] = '\0'; T.tm_mday = (int)atol(a); a[0] = tmp[8]; a[1] = tmp[9]; T.tm_mon = (strstr(mns, a) - mns) / 2; a[0] = tmp[11]; a[1] = tmp[12]; T.tm_year = 100 + (int)atol(a); a[0] = tmp[13]; a[1] = tmp[14]; T.tm_hour = (int)atol(a); a[0] = tmp[16]; a[1] = tmp[17]; T.tm_min = (int)atol(a); a[0] = tmp[19]; a[1] = tmp[20]; T.tm_sec = (int)atol(a); p->expire = soap_timegm(&T); } else if (p && !soap_tag_cmp(tmp, "Secure")) p->secure = 1; else { if (p) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Got environment cookie %s=%s domain=%s path=%s expire=%ld secure=%d\n", p->name, p->value?p->value:"", p->domain?p->domain:"", p->path?p->path:"", p->expire, p->secure)); if ((q = soap_set_cookie(soap, p->name, p->value, p->domain, p->path))) { q->version = p->version; q->expire = p->expire; q->secure = p->secure; q->env = 1; } if (p->name) free(p->name); if (p->value) free(p->value); if (p->domain) free(p->domain); if (p->path) free(p->path); free(p); } if ((p = (struct soap_cookie*)malloc(sizeof(struct soap_cookie)))); { p->name = (char*)malloc(strlen(tmp)+1); strcpy(p->name, tmp); s = soap_decode_string(tmp, sizeof(tmp), s); if (*tmp) { p->value = (char*)malloc(strlen(tmp)+1); strcpy(p->value, tmp); } else p->value = NULL; p->domain = domain; p->path = path; p->expire = 0; p->secure = 0; p->version = version; } } if (*s == ';') s++; } if (p) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Got cookie %s=%s domain=%s path=%s expire=%ld secure=%d\n", p->name, p->value?p->value:"", p->domain?p->domain:"", p->path?p->path:"", p->expire, p->secure)); if ((q = soap_set_cookie(soap, p->name, p->value, p->domain, p->path))) { q->version = p->version; q->expire = p->expire; q->secure = p->secure; } if (p->name) free(p->name); if (p->value) free(p->value); if (p->domain) free(p->domain); if (p->path) free(p->path); free(p); } if (domain) free(domain); if (path) free(path); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_getenv_cookies(struct soap *soap) { struct soap_cookie *p; const char *s; char key[4096], val[4096]; /* cookie size is up to 4096 bytes [RFC2109] */ if (!(s = getenv("HTTP_COOKIE"))) return SOAP_EOF; do { s = soap_decode_string(key, sizeof(key), s); s = soap_decode_string(val, sizeof(val), s); p = soap_set_cookie(soap, key, val, NULL, NULL); if (p) p->env = 1; if (*s == ';') s++; } while (*s); return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 struct soap_cookie* SOAP_FMAC2 soap_copy_cookies(struct soap *soap) { struct soap_cookie *p, **q, *r; q = &r; for (p = soap->cookies; p; p = p->next) { *q = (struct soap_cookie*)malloc(sizeof(struct soap_cookie)); **q = *p; if (p->name) { (*q)->name = (char*)malloc(strlen(p->name)+1); strcpy((*q)->name, p->name); } if (p->value) { (*q)->value = (char*)malloc(strlen(p->value)+1); strcpy((*q)->value, p->value); } if (p->domain) { (*q)->domain = (char*)malloc(strlen(p->domain)+1); strcpy((*q)->domain, p->domain); } if (p->path) { (*q)->path = (char*)malloc(strlen(p->path)+1); strcpy((*q)->path, p->path); } q = &(*q)->next; } *q = NULL; return r; } /******************************************************************************/ SOAP_FMAC1 void SOAP_FMAC2 soap_free_cookies(struct soap *soap) { struct soap_cookie *p; for (p = soap->cookies; p; p = soap->cookies) { soap->cookies = p->next; free(p->name); if (p->value) free(p->value); if (p->domain) free(p->domain); if (p->path) free(p->path); free(p); } } /******************************************************************************/ #endif #ifdef WITH_GZIP /******************************************************************************/ static int soap_getgzipheader(struct soap *soap) { int i; wchar c, f = 0; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Get gzip header\n")); for (i = 0; i < 9; i++) { if ((c = soap_get1(soap) == EOF)) return soap->error = SOAP_EOF; if (i == 2) f = c; } if (f & 0x04) /* FEXTRA */ { for (i = soap_get1(soap) + (soap_get1(soap) << 8); i; i--) if (soap_get1(soap) == EOF) return soap->error = SOAP_EOF; } if (f & 0x08) /* FNAME */ do c = soap_get1(soap); while (c && c != EOF); if (c != EOF && (f & 0x10)) /* FCOMMENT */ do c = soap_get1(soap); while (c && f != EOF); if (c != EOF && (f & 0x01)) /* FHCRC */ { if ((c = soap_get1(soap)) != EOF) c = soap_get1(soap); } if (c == EOF) return soap->error = SOAP_EOF; return SOAP_OK; } /******************************************************************************/ #endif /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_begin_recv(struct soap *soap) { wchar c; soap_set_local_namespaces(soap); soap->mode = soap->imode; if (!soap->keep_alive) { soap->buflen = 0; soap->bufidx = 0; } if (!(soap->mode & SOAP_IO_KEEPALIVE)) soap->keep_alive = 0; soap->ahead = 0; soap->peeked = 0; soap->level = 0; soap->is_in_header = 0; soap->alloced = 0; soap->count = 0; soap->length = 0; soap->cdata = 0; *soap->endpoint = '\0'; soap->userid = NULL; soap->passwd = NULL; soap->dime_chunksize = 0; soap->dime_buflen = 0; #ifdef WIN32 #ifndef UNDER_CE if (soap->socket < 0) #ifndef WITH_FASTCGI #ifdef __BORLANDC__ setmode(soap->recvfd, O_BINARY); #else _setmode(soap->recvfd, _O_BINARY); #endif #endif #endif #endif #ifdef WITH_ZLIB soap->zlib_in = SOAP_ZLIB_NONE; soap->zlib_out = SOAP_ZLIB_NONE; soap->d_stream.next_in = Z_NULL; soap->d_stream.avail_in = 0; soap->d_stream.next_out = (Byte*)soap->buf; soap->d_stream.avail_out = SOAP_BUFLEN; soap->z_ratio_in = 1.0; #endif c = soap_getchar(soap); if ((c & 0xFFFC) == (SOAP_DIME_VERSION | SOAP_DIME_MB) && (soap_get0(soap) & 0xFFF0) == 0x20) soap->mode |= SOAP_ENC_DIME; #ifdef WITH_GZIP else if (c == 0x1F) { if (soap_getgzipheader(soap)) return soap->error; if (inflateInit2(&soap->d_stream, -MAX_WBITS) != Z_OK) return soap->error = SOAP_ZLIB_ERROR; soap->mode |= SOAP_ENC_ZLIB; soap->zlib_in = SOAP_ZLIB_GZIP; soap->z_crc = crc32(0L, NULL, 0); DBGLOG(TEST, SOAP_MESSAGE(fdebug, "gzip initialized\n")); memcpy(soap->z_buf, soap->buf, SOAP_BUFLEN); /* should not chunk over plain transport, so why bother to check? */ /* if ((soap->mode & SOAP_IO) == SOAP_IO_CHUNK) */ /* soap->z_buflen = soap->bufidx; */ /* else */ soap->d_stream.next_in = (Byte*)(soap->z_buf + soap->bufidx); soap->d_stream.avail_in = soap->buflen - soap->bufidx; soap->z_buflen = soap->buflen; soap->buflen = soap->bufidx; } #endif else while (blank(c)) c = soap_getchar(soap); if (c == EOF) return soap->error = SOAP_EOF; soap_unget(soap, c); if (c != '<' && !(soap->mode & (SOAP_ENC_DIME | SOAP_ENC_ZLIB))) { soap->mode &= ~SOAP_IO; if ((soap->error = soap->fparse(soap))) return soap->error; if ((soap->mode & SOAP_IO) == SOAP_IO_CHUNK) { soap->chunkbuflen = soap->buflen; soap->buflen = soap->bufidx; soap->chunksize = 0; } #ifdef WITH_ZLIB if (soap->zlib_in) { /* fparse should not use soap_unget */ #ifdef WITH_GZIP c = soap_get1(soap); if (c == 0x1F) { if (soap_getgzipheader(soap)) return soap->error; if (inflateInit2(&soap->d_stream, -MAX_WBITS) != Z_OK) return soap->error = SOAP_ZLIB_ERROR; soap->z_crc = crc32(0L, NULL, 0); DBGLOG(TEST, SOAP_MESSAGE(fdebug, "gzip initialized\n")); } else { soap_revget1(soap); #else { #endif if (inflateInit(&soap->d_stream) != Z_OK) return soap->error = SOAP_ZLIB_ERROR; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Inflate initialized\n")); } soap->mode |= SOAP_ENC_ZLIB; memcpy(soap->z_buf, soap->buf, SOAP_BUFLEN); soap->d_stream.next_in = (Byte*)(soap->z_buf + soap->bufidx); soap->d_stream.avail_in = soap->buflen - soap->bufidx; soap->z_buflen = soap->buflen; soap->buflen = soap->bufidx; } #endif } if (soap->mode & SOAP_ENC_DIME) { if (soap_getdimehdr(soap)) return soap->error; if (soap->dime_flags & SOAP_DIME_CF) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Chunked DIME SOAP message\n")); soap->dime_chunksize = soap->dime_size; if (soap->buflen - soap->bufidx >= soap->dime_chunksize) { soap->dime_buflen = soap->buflen; soap->buflen = soap->bufidx + soap->dime_chunksize; } else soap->dime_chunksize -= soap->buflen - soap->bufidx; } soap->count = soap->buflen - soap->bufidx; } return SOAP_OK; } /******************************************************************************/ static int http_parse(struct soap *soap) { char header[SOAP_HDRLEN], *s; unsigned short g = 0, k; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Waiting for response...\n")); *soap->endpoint = '\0'; *soap->path = '\0'; soap->length = 0; do { if (soap_getline(soap, soap->msgbuf, sizeof(soap->msgbuf))) return SOAP_EOF; DBGLOG(TEST,SOAP_MESSAGE(fdebug, "HTTP status: %s\n", soap->msgbuf)); for (;;) { if (soap_getline(soap, header, SOAP_HDRLEN)) return SOAP_EOF; if (!*header) break; DBGLOG(TEST,SOAP_MESSAGE(fdebug, "HTTP header: %s\n", header)); s = strchr(header, ':'); if (s) { *s = '\0'; do s++; while (*s && *s <= 32); } if ((soap->error = soap->fparsehdr(soap, header, s))) return soap->error; } if ((s = strchr(soap->msgbuf, ' '))) k = (unsigned short)strtoul(s, NULL, 10); else k = 0; } while (k == 100); DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Finished HTTP header parsing\n")); s = strstr(soap->msgbuf, "HTTP/"); if (soap->keep_alive > 0 && s && s[7] != '1') soap->keep_alive = 0; else if (soap->keep_alive < 0) soap->keep_alive = 1; DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Keep alive connection = %d\n", soap->keep_alive)); if (s && (((g = !strncmp(soap->msgbuf, "GET ", 4))) || !strncmp(soap->msgbuf, "POST ", 5))) { size_t m = strlen(soap->endpoint); size_t n = m + (s - soap->msgbuf) - 5 - (!g); if (n >= (int)sizeof(soap->endpoint)) n = sizeof(soap->endpoint) - 1; strncpy(soap->path, soap->msgbuf + 4 + (!g), n - m); soap->path[n - m] = '\0'; strcat(soap->endpoint, soap->path); DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Target endpoint='%s'\n", soap->endpoint)); if (g) return soap->error = SOAP_GET_METHOD; return SOAP_OK; } if (k == 0 || k == 200 || k == 400 || k == 500) return SOAP_OK; return soap_set_receiver_error(soap, "HTTP error", soap->msgbuf, SOAP_HTTP_ERROR); } /******************************************************************************/ static int http_parse_header(struct soap *soap, const char *key, const char *val) { if (!soap_tag_cmp(key, "Host")) { #ifdef WITH_OPENSSL if (soap->imode & SOAP_ENC_SSL) strcpy(soap->endpoint, "https://"); else #endif strcpy(soap->endpoint, "http://"); strncat(soap->endpoint, val, sizeof(soap->endpoint) - 8); soap->endpoint[sizeof(soap->endpoint) - 1] = '\0'; } else if (!soap_tag_cmp(key, "Content-Type")) { if (!soap_tag_cmp(val, "*application/dime*")) soap->mode |= SOAP_ENC_DIME; } else if (!soap_tag_cmp(key, "Content-Length")) soap->length = strtoul(val, NULL, 10); else if (!soap_tag_cmp(key, "Content-Encoding")) { if (!soap_tag_cmp(val, "deflate*")) #ifdef WITH_ZLIB soap->zlib_in = SOAP_ZLIB_DEFLATE; #else return SOAP_ZLIB_ERROR; #endif else if (!soap_tag_cmp(val, "gzip*")) #ifdef WITH_GZIP soap->zlib_in = SOAP_ZLIB_GZIP; #else return SOAP_ZLIB_ERROR; #endif } #ifdef WITH_ZLIB else if (!soap_tag_cmp(key, "Accept-Encoding")) { #ifdef WITH_GZIP if (strchr(val, '*') || !soap_tag_cmp(val, "*gzip*")) soap->zlib_out = SOAP_ZLIB_GZIP; else #endif if (strchr(val, '*') || !soap_tag_cmp(val, "*deflate*")) soap->zlib_out = SOAP_ZLIB_DEFLATE; else soap->zlib_out = SOAP_ZLIB_NONE; } #endif else if (!soap_tag_cmp(key, "Transfer-Encoding")) { soap->mode &= ~SOAP_IO; if (!soap_tag_cmp(val, "chunked*")) soap->mode |= SOAP_IO_CHUNK; } else if (!soap_tag_cmp(key, "Connection")) { if (!soap_tag_cmp(val, "keep-alive*")) soap->keep_alive = -soap->keep_alive; else if (!soap_tag_cmp(val, "close*")) soap->keep_alive = 0; } else if (!soap_tag_cmp(key, "Authorization")) { if (!soap_tag_cmp(val, "basic *")) { size_t n; char *s; soap_base642s(soap, val + 6, soap->tmpbuf, sizeof(soap->tmpbuf) - 1, &n); soap->tmpbuf[n] = '\0'; if ((s = strchr(soap->tmpbuf, ':'))) { *s = '\0'; soap->userid = (char*)soap_malloc(soap, strlen(soap->tmpbuf) + 1); strcpy(soap->userid, soap->tmpbuf); soap->passwd = (char*)soap_malloc(soap, strlen(s + 1) + 1); strcpy(soap->passwd, s + 1); } } } else if (!soap_tag_cmp(key, "SOAPAction")) { if (*val && (soap->action = (char*)malloc(strlen(val)))) { strcpy(soap->action, val + 1); soap->action[strlen(soap->action) - 1] = '\0'; } } /* [ Deal with .NET bug (invalid XML) */ else if (!soap_tag_cmp(key, "Server")) { if (!soap_tag_cmp(val, "Microsoft-IIS*")) soap->dot_net_bug = 1; } else if (!soap_tag_cmp(key, "User-Agent")) { if (!soap_tag_cmp(val, "*.NET CLR*") || !soap_tag_cmp(val, "*MS Web Services Client Protocol*")) soap->dot_net_bug = 1; } /* ] */ #ifdef WITH_COOKIES else if (!soap_tag_cmp(key, "Cookie") || !soap_tag_cmp(key, "Set-Cookie")) soap_getcookies(soap, val); #endif return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_envelope_begin_out(struct soap *soap) { return soap_element_begin_out(soap, "SOAP-ENV:Envelope", 0, NULL); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_envelope_end_out(struct soap *soap) { return soap_send(soap, ""); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_envelope_begin_in(struct soap *soap) { if (soap_element_begin_in(soap, "SOAP-ENV:Envelope")) return soap->error = SOAP_VERSIONMISMATCH; return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_envelope_end_in(struct soap *soap) { return soap_element_end_in(soap, "SOAP-ENV:Envelope"); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_body_begin_out(struct soap *soap) { if (soap->encodingStyle && !*soap->encodingStyle && soap->local_namespaces) { if (soap->local_namespaces[1].out) soap->encodingStyle = soap->local_namespaces[1].out; else soap->encodingStyle = soap->local_namespaces[1].ns; } if (soap->encodingStyle) { if (soap_send(soap, "encodingStyle) || soap_send(soap, "\">")) return soap->error; return SOAP_OK; } return soap_send(soap, ""); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_body_end_out(struct soap *soap) { return soap_send(soap, ""); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_body_begin_in(struct soap *soap) { return soap_element_begin_in(soap, "SOAP-ENV:Body"); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_body_end_in(struct soap *soap) { return soap_element_end_in(soap, "SOAP-ENV:Body"); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_recv_header(struct soap *soap) { if (soap_getheader(soap) && soap->error == SOAP_TAG_MISMATCH) soap->error = SOAP_OK; return soap->error; } /******************************************************************************/ SOAP_FMAC1 void SOAP_FMAC2 soap_set_endpoint(struct soap *soap, const char *endpoint) { const char *s; size_t i, j, n; *soap->endpoint = '\0'; *soap->host = '\0'; *soap->path = '\0'; soap->port = 80; if (!endpoint || !*endpoint) return; #ifdef WITH_OPENSSL if (!strncmp(endpoint, "https:", 6)) soap->port = 443; #endif strncpy(soap->endpoint, endpoint, SOAP_TAGLEN); s = strchr(endpoint, ':'); if (s && s[1] == '/' && s[2] == '/') s += 3; else s = endpoint; n = strlen(s); if (n >= SOAP_TAGLEN) n = SOAP_TAGLEN; for (i = 0; i < n; i++) { soap->host[i] = s[i]; if (s[i] == '/' || s[i] == ':') break; } soap->host[i] = '\0'; if (s[i] == ':') { soap->port = (int)atol(s + i + 1); for (i++; i < n; i++) if (s[i] == '/') break; } for (j = i++; j < n; j++) soap->path[j - i] = s[j]; soap->path[j - i]='\0'; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_connect(struct soap *soap, const char *endpoint, const char *action) { char host[SOAP_TAGLEN]; int port; size_t count; strcpy(host, soap->host); /* save to compare */ port = soap->port; /* save to compare */ soap_set_endpoint(soap, endpoint); if (action) { soap->action = (char*)malloc(strlen(action) + 1); strcpy(soap->action, action); } if (*soap->host) { if (soap->socket < 0 || strcmp(soap->host, host) || soap->port != port) { soap->keep_alive = 0; /* force close */ soap_closesock(soap); DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Connect to host='%s' path='%s' port=%d\n", soap->host, soap->path, soap->port)); soap->socket = soap->fopen(soap, endpoint, soap->host, soap->port); if (soap->socket < 0 && soap->error) return soap->error; soap->keep_alive = ((soap->omode & SOAP_IO_KEEPALIVE) != 0); } else { #ifndef MAC_CARBON if (soap_poll(soap) != SOAP_OK) { soap->keep_alive = 0; /* force close */ soap_closesock(soap); DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Reconnect to host='%s' path='%s' port=%d\n", soap->host, soap->path, soap->port)); soap->socket = soap->fopen(soap, endpoint, soap->host, soap->port); if (soap->socket < 0 && soap->error) return soap->error; } #endif } } soap->status = SOAP_POST; count = soap_begin_dime(soap); if (soap_begin_send(soap)) return soap->error; if ((soap->mode & SOAP_IO) != SOAP_IO_STORE && !(soap->mode & SOAP_ENC_XML) && endpoint) { int n = soap->mode; soap->mode &= ~(SOAP_IO | SOAP_ENC_ZLIB); if ((n & SOAP_IO) != SOAP_IO_FLUSH) soap->mode |= SOAP_IO_BUFFER; if ((soap->error = soap->fpost(soap, endpoint, soap->host, soap->port, soap->path, action, count))) return soap->error; if ((n & SOAP_IO) == SOAP_IO_CHUNK) { if (soap_flush(soap)) return soap->error; } soap->mode = n; } if (soap->mode & SOAP_ENC_DIME) return soap_putdimehdr(soap); return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_s2base64(struct soap *soap, const char *s, char *t, size_t n) { register size_t i; register unsigned long m; char d[5]; if (!s || !t) return SOAP_EOM; *t = '\0'; d[4] = '\0'; for (; n > 2; n -= 3, s += 3) { m = s[0] << 16 | s[1] << 8 | s[2]; for (i = 4; i > 0; m >>= 6) d[--i] = base64o[m&0x3F]; strcat(t, d); } if (n > 0) { m = 0; for (i = 0; i < n; i++) m = m << 8 | *s++; for (; i < 3; i++) m <<= 8; for (i++; i > 0; m >>= 6) d[--i] = base64o[m&0x3F]; for (i = 3; i > n; i--) d[i] = '='; strcat(t, d); } return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 const char* SOAP_FMAC2 soap_base642s(struct soap *soap, const char *s, char *t, size_t l, size_t *n) { register int i, j, c; register unsigned long m; char *p = t; if (n) *n = 0; for (;;) { for (i = 0; i < SOAP_BLKLEN; i++) { m = 0; j = 0; while (j < 4) { c = *s++; if (c == '=' || !c) { i *= 3; switch (j) { case 2: *t++ = (char)((m >> 4) & 0xFF); i++; break; case 3: *t++ = (char)((m >> 10) & 0xFF); *t++ = (char)((m >> 2) & 0xFF); i += 2; } if (n) *n += i; return p; } c -= '+'; if (c >= 0 && c <= 79) { m = (m << 6) + base64i[c]; j++; } } *t++ = (char)((m >> 16) & 0xFF); *t++ = (char)((m >> 8) & 0xFF); *t++ = (char)(m & 0xFF); if (l < 3) { if (n) *n += i; return p; } l -= 3; } if (n) *n += 3 * SOAP_BLKLEN; } } /******************************************************************************/ static int soap_puthttphdr(struct soap *soap, int status, size_t count) { const char *s; if (status == SOAP_FILE) s = soap->http_content; else if (status == SOAP_HTML) s = "text/html; charset=utf-8"; else if (soap->mode & SOAP_ENC_DIME) s = "application/dime; charset=us-ascii"; else if (soap->version == 2) s = "application/soap+xml; charset=utf-8"; else s = "text/xml; charset=utf-8"; soap->error = soap->fposthdr(soap, "Content-Type", s); if (soap->error) return soap->error; #ifdef WITH_ZLIB if (soap->omode & SOAP_ENC_ZLIB) #ifdef WITH_GZIP soap->error = soap->fposthdr(soap, "Content-Encoding", "gzip"); #else soap->error = soap->fposthdr(soap, "Content-Encoding", "deflate"); #endif #endif if ((soap->omode & SOAP_IO) == SOAP_IO_CHUNK) soap->error = soap->fposthdr(soap, "Transfer-Encoding", "chunked"); else if (count > 0) { sprintf(soap->tmpbuf, "%lu", (unsigned long)count); soap->error = soap->fposthdr(soap, "Content-Length", soap->tmpbuf); } if (soap->error) return soap->error; return soap->error = soap->fposthdr(soap, "Connection", soap->keep_alive ? "keep-alive" : "close"); } /******************************************************************************/ static int http_post(struct soap *soap, const char *endpoint, const char *host, int port, const char *path, const char *action, size_t count) { const char *s; if (soap->status == SOAP_GET) s = "GET"; else s = "POST"; if (!endpoint || (strncmp(endpoint, "http:", 5) && strncmp(endpoint, "https:", 6) && strncmp(endpoint, "httpg:", 6))) return SOAP_OK; if (soap->proxy_host) sprintf(soap->tmpbuf, "%s %s HTTP/%s", s, endpoint, soap->http_version); else sprintf(soap->tmpbuf, "%s /%s HTTP/%s", s, path, soap->http_version); if ((soap->error = soap->fposthdr(soap, soap->tmpbuf, NULL))) return soap->error; if (port != 80) sprintf(soap->tmpbuf, "%s:%d", host, port); else strcpy(soap->tmpbuf, host); char szUserAgent[40]; _snprintf(szUserAgent, ARRSIZE(szUserAgent), "eMule/%s gSOAP/2.2", theApp.m_strCurVersionLong); if ((soap->error = soap->fposthdr(soap, "Host", soap->tmpbuf)) || (soap->error = soap->fposthdr(soap, "User-Agent", szUserAgent)) || (soap->error = soap_puthttphdr(soap, SOAP_OK, count))) return soap->error; #ifdef WITH_ZLIB #ifdef WITH_GZIP if ((soap->error = soap->fposthdr(soap, "Accept-Encoding", "gzip, deflate"))) #else if ((soap->error = soap->fposthdr(soap, "Accept-Encoding", "deflate"))) #endif return soap->error; #endif if (soap->userid && soap->passwd && strlen(soap->userid) + strlen(soap->passwd) < 761) { sprintf(soap->tmpbuf + 262, "%s:%s", soap->userid, soap->passwd); strcpy(soap->tmpbuf, "Basic "); soap_s2base64(soap, soap->tmpbuf + 262, soap->tmpbuf + 6, strlen(soap->tmpbuf + 262)); if ((soap->error = soap->fposthdr(soap, "Authorization", soap->tmpbuf))) return soap->error; } if (soap->proxy_userid && soap->proxy_passwd && strlen(soap->proxy_userid) + strlen(soap->proxy_passwd) < 761) { sprintf(soap->tmpbuf + 262, "%s:%s", soap->proxy_userid, soap->proxy_passwd); strcpy(soap->tmpbuf, "Basic "); soap_s2base64(soap, soap->tmpbuf + 262, soap->tmpbuf + 6, strlen(soap->tmpbuf + 262)); if ((soap->error = soap->fposthdr(soap, "Proxy-Authorization", soap->tmpbuf))) return soap->error; } #ifdef WITH_COOKIES #ifdef WITH_OPENSSL if (soap_putcookies(soap, host, path, soap->ssl != NULL)) return soap->error; #else if (soap_putcookies(soap, host, path, 0)) return soap->error; #endif #endif if (action) { sprintf(soap->tmpbuf, "\"%s\"", action); if ((soap->error = soap->fposthdr(soap, "SOAPAction", soap->tmpbuf))) return soap->error; } return soap->error = soap->fposthdr(soap, NULL, NULL); } /******************************************************************************/ static int http_post_header(struct soap *soap, const char *key, const char *val) { if (key) { if (soap_send(soap, key)) return soap->error; if (val && (soap_send(soap, ": ") || soap_send(soap, val))) return soap->error; } return soap_send(soap, "\r\n"); } /******************************************************************************/ static int http_response(struct soap *soap, int status, size_t count) { if (!status || status == SOAP_HTML || status == SOAP_FILE) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "OK 200\n")); if (soap->master >= 0 || soap->socket >= 0) /* standalone application */ { sprintf(soap->tmpbuf, "HTTP/%s 200 OK", soap->http_version); if ((soap->error = soap->fposthdr(soap, soap->tmpbuf, NULL))) return soap->error; } else if ((soap->error = soap->fposthdr(soap, "Status", "200 OK"))) return soap->error; } else { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Error 500\n")); if (soap->master >= 0 || soap->socket >= 0) /* standalone application */ { if (soap->version == 2 && strcmp(*soap_faultcode(soap), "SOAP-ENV:Sender")) sprintf(soap->tmpbuf, "HTTP/%s 400 Bad Request", soap->http_version); else sprintf(soap->tmpbuf, "HTTP/%s 500 Internal Server Error", soap->http_version); if ((soap->error = soap->fposthdr(soap, soap->tmpbuf, NULL))) return soap->error; } else if ((soap->error = soap->fposthdr(soap, "Status", "500 Internal Server Error"))) return soap->error; } if ((soap->error = soap->fposthdr(soap, "Server", "gSOAP/2.2")) || (soap->error = soap_puthttphdr(soap, status, count))) return soap->error; #ifdef WITH_COOKIES if (soap_putsetcookies(soap)) return soap->error; #endif return soap->error = soap->fposthdr(soap, NULL, NULL); } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_response(struct soap *soap, int status) { size_t count; soap->status = status; count = soap_begin_dime(soap); if (soap_begin_send(soap)) return soap->error; if ((soap->mode & SOAP_IO) != SOAP_IO_STORE && !(soap->mode & SOAP_ENC_XML)) { int n = soap->mode; soap->mode &= ~(SOAP_IO | SOAP_ENC_ZLIB); if ((n & SOAP_IO) != SOAP_IO_FLUSH) soap->mode |= SOAP_IO_BUFFER; if ((soap->error = soap->fresponse(soap, status, count))) return soap->error; if ((n & SOAP_IO) == SOAP_IO_CHUNK) { if (soap_flush(soap)) return soap->error; } soap->mode = n; } if (soap->mode & SOAP_ENC_DIME) return soap_putdimehdr(soap); return SOAP_OK; } /******************************************************************************/ SOAP_FMAC1 void SOAP_FMAC2 soap_set_fault(struct soap *soap) { const char **c = soap_faultcode(soap); const char **s = soap_faultstring(soap); const char **d = soap_faultdetail(soap); if (!*c) { if (soap->version == 2) *c = "SOAP-ENV:Sender"; else *c = "SOAP-ENV:Client"; } if (*s) return; switch (soap->error) { case SOAP_CLI_FAULT: *s = "Client fault"; break; case SOAP_SVR_FAULT: *s = "Server fault"; break; case SOAP_TAG_MISMATCH: sprintf(soap->msgbuf, "Tag mismatch: element '%s' does not correspond to expected element", soap->tag); *s = soap->msgbuf; break; case SOAP_TYPE_MISMATCH: sprintf(soap->msgbuf, "Data type '%s' mismatch in element '%s'", soap->type, soap->tag); *s = soap->msgbuf; break; case SOAP_SYNTAX_ERROR: *s = "XML syntax error"; break; case SOAP_NO_TAG: *s = "No XML element tag found"; break; case SOAP_MUSTUNDERSTAND: *c = "SOAP-ENV:MustUnderstand"; sprintf(soap->msgbuf, "The data in element '%s' must be understood but cannot be handled", soap->tag); *s = soap->msgbuf; break; case SOAP_VERSIONMISMATCH: *c = "SOAP-ENV:VersionMismatch"; *s = "SOAP version mismatch or invalid SOAP message"; break; case SOAP_DIME_MISMATCH: *s = "DIME version mismatch"; break; case SOAP_NAMESPACE: sprintf(soap->msgbuf, "Namespace URI mismatch in element '%s'", soap->tag); *s = soap->msgbuf; if (d) *d = "The namespace URI in the message was not found in the namespace table"; break; case SOAP_OBJ_MISMATCH: *s = "Object mismatch"; break; case SOAP_FATAL_ERROR: *s = "Fatal error"; break; case SOAP_NO_METHOD: sprintf(soap->msgbuf, "Method '%s' not implemented", soap->tag); *s = soap->msgbuf; break; case SOAP_GET_METHOD: *s = "HTTP GET method not implemented"; break; case SOAP_EOM: *s = "Out of memory"; break; case SOAP_IOB: *s = "Array index out of bounds"; break; case SOAP_NULL: sprintf(soap->msgbuf, "Cannot create nilable object for type '%s' in element '%s'", soap->type, soap->tag); *s = soap->msgbuf; if (d) *d = "The object is not nilable because the XML schema type for this element is not nilable"; break; case SOAP_MULTI_ID: *s = "Non-unique id attribute"; break; case SOAP_MISSING_ID: *s = "Missing id: referenced data is missing or had to be ignored"; break; case SOAP_HREF: *s = "Invalid XML: object reference with href attribute is incompatible with actual object referred to"; break; case SOAP_FAULT: break; case SOAP_TCP_ERROR: *s = tcp_error(soap); break; case SOAP_HTTP_ERROR: *s = "HTTP error"; break; case SOAP_SSL_ERROR: *s = "SSL error"; break; case SOAP_PLUGIN_ERROR: *s = "Plugin registry error"; break; case SOAP_DIME_ERROR: *s = "DIME error"; break; case SOAP_ZLIB_ERROR: #ifdef WITH_ZLIB *s = "Zlib/gzip error"; if (d) *d = soap->d_stream.msg; #else *s = "Zlib not installed for required message (de)compression"; #endif break; case SOAP_EOD: *s = "End of DIME error"; break; case SOAP_EOF: *s = "End of file or no input"; if (d) *d = soap_strerror(soap, soap->errnum ? soap->errnum : soap_errno); break; default: *s = "Unknown error code"; } } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_send_fault(struct soap *soap) { int status = soap->error; if (status == SOAP_STOP) return status; DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Sending back fault struct for error code %d\n", soap->error)); soap->keep_alive = 0; /* to terminate connection */ soap_set_fault(soap); if (status != SOAP_EOF || soap_poll(soap) == SOAP_OK) { soap->error = SOAP_OK; soap_serializeheader(soap); soap_serializefault(soap); soap_begin_count(soap); if (soap->mode & SOAP_IO_LENGTH) { soap_envelope_begin_out(soap); soap_putheader(soap); soap_body_begin_out(soap); soap_putfault(soap); soap_body_end_out(soap); soap_envelope_end_out(soap); } if (soap_response(soap, status) || soap_envelope_begin_out(soap) || soap_putheader(soap) || soap_body_begin_out(soap) || soap_putfault(soap) || soap_body_end_out(soap) || soap_envelope_end_out(soap)) { soap_closesock(soap); return soap->error; } if (soap->mode & SOAP_ENC_DIME) soap_send_raw(soap, "\0\0\0", -(int)soap->count&3); soap_end_send(soap); } soap_closesock(soap); return soap->error = status; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_recv_fault(struct soap *soap) { int status; DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Receiving SOAP Fault\n")); status = soap->error; if (soap_getfault(soap)) { DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Error: soap_get_soapfault() failed. Is this a SOAP message at all?\n")); soap->error = status; if (soap->version == 2) *soap_faultcode(soap) = "SOAP-ENV:Sender"; else *soap_faultcode(soap) = "SOAP-ENV:Client"; soap_set_fault(soap); return soap->error; } /* Use the soap fault received to set soap->error to the appropriate value */ if (!soap_match_tag(soap, *soap_faultcode(soap), "SOAP-ENV:Server") || !soap_match_tag(soap, *soap_faultcode(soap), "SOAP-ENV:Receiver")) status = SOAP_SVR_FAULT; else if (!soap_match_tag(soap, *soap_faultcode(soap), "SOAP-ENV:Client") || !soap_match_tag(soap, *soap_faultcode(soap), "SOAP-ENV:Sender")) status = SOAP_CLI_FAULT; else if (!soap_match_tag(soap, *soap_faultcode(soap), "SOAP-ENV:MustUnderstand")) status = SOAP_MUSTUNDERSTAND; else if (!soap_match_tag(soap, *soap_faultcode(soap), "SOAP-ENV:VersionMismatch")) status = SOAP_VERSIONMISMATCH; else { DBGLOG(TEST,SOAP_MESSAGE(fdebug, "Fault code %s\n", *soap_faultcode(soap) )); status = SOAP_FAULT; } if (soap_body_end_in(soap) || soap_envelope_end_in(soap) || soap_end_recv(soap)) return soap->error; soap_closesock(soap); return soap->error = status; } /******************************************************************************/ SOAP_FMAC1 void SOAP_FMAC2 soap_print_fault(struct soap *soap, FILE *fd) { if (soap->error) { const char **s = soap_faultdetail(soap); if (!*soap_faultcode(soap)) soap_set_fault(soap); if (!*soap_faultstring(soap)) *soap_faultstring(soap) = ""; fprintf(fd, "SOAP FAULT: %s\n\"%s\"\n", *soap_faultcode(soap), *soap_faultstring(soap)); if (s && *s) fprintf(fd, "Detail: %s\n", *s); } } /******************************************************************************/ SOAP_FMAC1 void SOAP_FMAC2 soap_print_fault_location(struct soap *soap, FILE *fd) { int c; if (soap->error && soap->buflen > 0) { if (soap->bufidx == 0) soap->bufidx = 1; c = soap->buf[soap->bufidx-1]; soap->buf[soap->bufidx-1] = '\0'; soap->buf[soap->buflen-1] = '\0'; if (soap->bufidx < soap->buflen) fprintf(fd, "%s%c\n** HERE **\n%s\n", soap->buf, c, soap->buf+soap->bufidx); else fprintf(fd, "%s%c\n** HERE **\n", soap->buf, c); } } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_size(const int *size, int dim) { int i, n = size[0]; for (i = 1; i < dim; i++) n *= size[i]; return n; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_getoffsets(const char *attr, const int *size, int *offset, int dim) { int i, j = 0; if (offset) for (i = 0; i < dim && attr && *attr; i++) { attr++; j *= size[i]; j += offset[i] = (int)atol(attr); attr = strchr(attr, ','); } else for (i = 0; i < dim && attr && *attr; i++) { attr++; j *= size[i]; j += (int)atol(attr); attr = strchr(attr, ','); } return j; } /******************************************************************************/ SOAP_FMAC1 char * SOAP_FMAC2 soap_putsize(struct soap *soap, const char *type, int size) { if (!type) return NULL; if (soap->version == 2) sprintf(soap->type, "%s[%d", type, size); else sprintf(soap->type, "%s[%d]", type, size); return soap->type; } /******************************************************************************/ SOAP_FMAC1 char * SOAP_FMAC2 soap_putsizesoffsets(struct soap *soap, const char *type, const int *size, const int *offset, int dim) { int i; if (!type) return NULL; if (soap->version == 2) { sprintf(soap->type, "%s[%d", type, size[0]); for (i = 1; i < dim; i++) sprintf(soap->type + strlen(soap->type), " %d", size[i]); } else { sprintf(soap->type, "%s[%d", type, size[0]+offset[0]); for (i = 1; i < dim; i++) sprintf(soap->type + strlen(soap->type), ",%d", size[i] + offset[i]); strcat(soap->type, "]"); } return soap->type; } /******************************************************************************/ SOAP_FMAC1 char * SOAP_FMAC2 soap_putsizes(struct soap *soap, const char *type, const int *size, int dim) { int i; if (!type) return NULL; sprintf(soap->type, "%s[%d", type, size[0]); if (soap->version == 2) { for (i = 1; i < dim; i++) sprintf(soap->type + strlen(soap->type), " %d", size[i]); } else { for (i = 1; i < dim; i++) sprintf(soap->type + strlen(soap->type), ",%d", size[i]); strcat(soap->type, "]"); } return soap->type; } /******************************************************************************/ SOAP_FMAC1 char * SOAP_FMAC2 soap_putoffset(struct soap *soap, int offset) { sprintf(soap->arrayOffset, "[%d]", offset); return soap->arrayOffset; } /******************************************************************************/ SOAP_FMAC1 char * SOAP_FMAC2 soap_putoffsets(struct soap *soap, const int *offset, int dim) { int i; sprintf(soap->arrayOffset, "[%d", offset[0]); for (i = 1; i < dim; i++) sprintf(soap->arrayOffset + strlen(soap->arrayOffset), ",%d", offset[i]); strcat(soap->arrayOffset, "]"); return soap->arrayOffset; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_getsize(const char *attr1, const char *attr2, int *j) { int n, k; char *s; *j = 0; if (!*attr1) return -1; n = 1; do { attr1++; k = (int)strtol(attr1, &s, 10); if (s == attr1) return -1; n *= k; attr1 = strchr(s, ','); if (!attr1) attr1 = strchr(s, ' '); if (attr2 && *attr2) { attr2++; *j *= k; *j += (int)strtol(attr2, &s, 10); attr2 = s; } } while (attr1 && *attr1 != ']'); return n - *j; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_getsizes(const char *attr, int *size, int dim) { int i, n; if (!*attr) return -1; i = strlen(attr); n = 1; do { for (i = i-1; i >= 0; i--) if (attr[i] == '[' || attr[i] == ',' || attr[i] == ' ') break; n *= size[--dim] = (int)atol(attr + i + 1); } while (i >= 0 && attr[i] != '['); return n; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_getposition(const char *attr, int *pos) { int i, n; if (!*attr) return -1; n = 0; i = 1; do { pos[n++] = (int)atol(attr + i); while (attr[i] && attr[i] != ',' && attr[i] != ']') i++; if (attr[i] == ',') i++; } while (n < 32 && attr[i] && attr[i] != ']'); return n; } /******************************************************************************/ SOAP_FMAC1 int SOAP_FMAC2 soap_register_plugin_arg(struct soap *soap, int (*fcreate)(struct soap*, struct soap_plugin*, void*), void *arg) { struct soap_plugin *p; int r; p = (struct soap_plugin*)malloc(sizeof(struct soap_plugin)); p->id = NULL; p->data = NULL; p->fcopy = NULL; p->fdelete = NULL; if (!p) return soap->error = SOAP_EOM; r = fcreate(soap, p, arg); if (!r && p->fcopy && p->fdelete) { p->next = soap->plugins; soap->plugins = p; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Registered '%s' plugin\n", p->id)); return SOAP_OK; } free(p); DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Could not register plugin '%s': plugin returned error %d (or fcopy and fdelete callbacks were not set)\n", p->id?p->id:"?", r)); return r; } /******************************************************************************/ static void* fplugin(struct soap *soap, const char *id) { struct soap_plugin *p; for (p = soap->plugins; p; p = p->next) if (p->id == id || !strcmp(p->id, id)) return soap->plugins->data; return NULL; } /******************************************************************************/ SOAP_FMAC1 void * SOAP_FMAC2 soap_lookup_plugin(struct soap *soap, const char *id) { return soap->fplugin(soap, id); } /******************************************************************************/ #ifdef __cplusplus } #endif