[05/10] webservices: Add support for outgoing TCP connections.
Hans Leidekker
hans at codeweavers.com
Thu Apr 20 03:45:47 CDT 2017
Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
dlls/webservices/channel.c | 286 ++++++++++++++++++++++++++-------
dlls/webservices/listener.c | 16 +-
dlls/webservices/webservices_private.h | 5 +
3 files changed, 240 insertions(+), 67 deletions(-)
diff --git a/dlls/webservices/channel.c b/dlls/webservices/channel.c
index e777e8c0bc..7080acdab0 100644
--- a/dlls/webservices/channel.c
+++ b/dlls/webservices/channel.c
@@ -95,9 +95,20 @@ struct channel
WS_ENDPOINT_ADDRESS addr;
WS_XML_WRITER *writer;
WS_XML_READER *reader;
- HINTERNET http_session;
- HINTERNET http_connect;
- HINTERNET http_request;
+ WS_MESSAGE *msg;
+ union
+ {
+ struct
+ {
+ HINTERNET session;
+ HINTERNET connect;
+ HINTERNET request;
+ } http;
+ struct
+ {
+ SOCKET socket;
+ } tcp;
+ } u;
char *read_buf;
ULONG read_buflen;
ULONG read_size;
@@ -130,15 +141,27 @@ static void reset_channel( struct channel *channel )
heap_free( channel->addr.url.chars );
channel->addr.url.chars = NULL;
channel->addr.url.length = 0;
+ channel->msg = NULL;
+ channel->read_size = 0;
- WinHttpCloseHandle( channel->http_request );
- channel->http_request = NULL;
- WinHttpCloseHandle( channel->http_connect );
- channel->http_connect = NULL;
- WinHttpCloseHandle( channel->http_session );
- channel->http_session = NULL;
+ switch (channel->binding)
+ {
+ case WS_HTTP_CHANNEL_BINDING:
+ WinHttpCloseHandle( channel->u.http.request );
+ channel->u.http.request = NULL;
+ WinHttpCloseHandle( channel->u.http.connect );
+ channel->u.http.connect = NULL;
+ WinHttpCloseHandle( channel->u.http.session );
+ channel->u.http.session = NULL;
+ break;
- channel->read_size = 0;
+ case WS_TCP_CHANNEL_BINDING:
+ closesocket( channel->u.tcp.socket );
+ channel->u.tcp.socket = -1;
+ break;
+
+ default: break;
+ }
}
static void free_channel( struct channel *channel )
@@ -181,6 +204,15 @@ static HRESULT create_channel( WS_CHANNEL_TYPE type, WS_CHANNEL_BINDING binding,
channel->type = type;
channel->binding = binding;
+ switch (channel->binding)
+ {
+ case WS_TCP_CHANNEL_BINDING:
+ channel->u.tcp.socket = -1;
+ break;
+
+ default: break;
+ }
+
*ret = channel;
return S_OK;
}
@@ -202,12 +234,13 @@ HRESULT WINAPI WsCreateChannel( WS_CHANNEL_TYPE type, WS_CHANNEL_BINDING binding
if (!handle) return E_INVALIDARG;
- if (type != WS_CHANNEL_TYPE_REQUEST)
+ if (type != WS_CHANNEL_TYPE_REQUEST && type != WS_CHANNEL_TYPE_DUPLEX &&
+ type != WS_CHANNEL_TYPE_DUPLEX_SESSION)
{
FIXME( "channel type %u not implemented\n", type );
return E_NOTIMPL;
}
- if (binding != WS_HTTP_CHANNEL_BINDING)
+ if (binding != WS_HTTP_CHANNEL_BINDING && binding != WS_TCP_CHANNEL_BINDING)
{
FIXME( "channel binding %u not implemented\n", binding );
return E_NOTIMPL;
@@ -453,7 +486,7 @@ HRESULT WINAPI WsCloseChannel( WS_CHANNEL *handle, const WS_ASYNC_CONTEXT *ctx,
return S_OK;
}
-static HRESULT parse_url( const WCHAR *url, ULONG len, URL_COMPONENTS *uc )
+static HRESULT parse_http_url( const WCHAR *url, ULONG len, URL_COMPONENTS *uc )
{
HRESULT hr = E_OUTOFMEMORY;
WCHAR *tmp;
@@ -494,7 +527,7 @@ error:
return hr;
}
-static HRESULT connect_channel( struct channel *channel, WS_MESSAGE *msg )
+static HRESULT connect_channel_http( struct channel *channel )
{
static const WCHAR agentW[] =
{'M','S','-','W','e','b','S','e','r','v','i','c','e','s','/','1','.','0',0};
@@ -506,7 +539,9 @@ static HRESULT connect_channel( struct channel *channel, WS_MESSAGE *msg )
DWORD flags = 0;
HRESULT hr;
- if ((hr = parse_url( channel->addr.url.chars, channel->addr.url.length, &uc )) != S_OK) return hr;
+ if (channel->u.http.request) return S_OK;
+
+ if ((hr = parse_http_url( channel->addr.url.chars, channel->addr.url.length, &uc )) != S_OK) return hr;
if (!uc.dwExtraInfoLength) path = uc.lpszUrlPath;
else if (!(path = heap_alloc( (uc.dwUrlPathLength + uc.dwExtraInfoLength + 1) * sizeof(WCHAR) )))
{
@@ -527,8 +562,7 @@ static HRESULT connect_channel( struct channel *channel, WS_MESSAGE *msg )
break;
default:
- FIXME( "scheme %u not supported\n", uc.nScheme );
- hr = E_NOTIMPL;
+ hr = WS_E_INVALID_ENDPOINT_URL;
goto done;
}
@@ -548,11 +582,11 @@ static HRESULT connect_channel( struct channel *channel, WS_MESSAGE *msg )
goto done;
}
- if ((hr = message_insert_http_headers( msg, req )) != S_OK) goto done;
+ if ((hr = message_insert_http_headers( channel->msg, req )) != S_OK) goto done;
- channel->http_session = ses;
- channel->http_connect = con;
- channel->http_request = req;
+ channel->u.http.session = ses;
+ channel->u.http.connect = con;
+ channel->u.http.request = req;
done:
if (hr != S_OK)
@@ -568,11 +602,58 @@ done:
return hr;
}
-HRESULT set_output( WS_XML_WRITER *writer )
+static HRESULT connect_channel_tcp( struct channel *channel )
{
- WS_XML_WRITER_TEXT_ENCODING text = { {WS_XML_WRITER_ENCODING_TYPE_TEXT}, WS_CHARSET_UTF8 };
- WS_XML_WRITER_BUFFER_OUTPUT buf = { {WS_XML_WRITER_OUTPUT_TYPE_BUFFER} };
- return WsSetOutput( writer, &text.encoding, &buf.output, NULL, 0, NULL );
+ struct sockaddr_storage storage;
+ struct sockaddr *addr = (struct sockaddr *)&storage;
+ int addr_len;
+ WS_URL_SCHEME_TYPE scheme;
+ WCHAR *host;
+ USHORT port;
+ HRESULT hr;
+
+ if (channel->u.tcp.socket != -1) return S_OK;
+
+ if ((hr = parse_url( &channel->addr.url, &scheme, &host, &port )) != S_OK) return hr;
+ if (scheme != WS_URL_NETTCP_SCHEME_TYPE)
+ {
+ heap_free( host );
+ return WS_E_INVALID_ENDPOINT_URL;
+ }
+
+ winsock_init();
+
+ hr = resolve_hostname( host, port, addr, &addr_len );
+ heap_free( host );
+ if (hr != S_OK) return hr;
+
+ if ((channel->u.tcp.socket = socket( addr->sa_family, SOCK_STREAM, 0 )) == -1)
+ return HRESULT_FROM_WIN32( WSAGetLastError() );
+
+ if (connect( channel->u.tcp.socket, addr, addr_len ) < 0)
+ {
+ closesocket( channel->u.tcp.socket );
+ channel->u.tcp.socket = -1;
+ return HRESULT_FROM_WIN32( WSAGetLastError() );
+ }
+
+ return S_OK;
+}
+
+static HRESULT connect_channel( struct channel *channel )
+{
+ switch (channel->binding)
+ {
+ case WS_HTTP_CHANNEL_BINDING:
+ return connect_channel_http( channel );
+
+ case WS_TCP_CHANNEL_BINDING:
+ return connect_channel_tcp( channel );
+
+ default:
+ ERR( "unhandled binding %u\n", channel->binding );
+ return E_NOTIMPL;
+ }
}
static HRESULT write_message( WS_MESSAGE *handle, WS_XML_WRITER *writer, const WS_ELEMENT_DESCRIPTION *desc,
@@ -584,45 +665,82 @@ static HRESULT write_message( WS_MESSAGE *handle, WS_XML_WRITER *writer, const W
return WsWriteEnvelopeEnd( handle, NULL );
}
-static HRESULT send_message( struct channel *channel, BYTE *data, ULONG len )
+static HRESULT send_message_http( HANDLE request, BYTE *data, ULONG len )
{
- if (!WinHttpSendRequest( channel->http_request, NULL, 0, data, len, len, 0 ))
+ if (!WinHttpSendRequest( request, NULL, 0, data, len, len, 0 ))
return HRESULT_FROM_WIN32( GetLastError() );
- if (!WinHttpReceiveResponse( channel->http_request, NULL ))
+ if (!WinHttpReceiveResponse( request, NULL ))
return HRESULT_FROM_WIN32( GetLastError() );
return S_OK;
}
-HRESULT channel_send_message( WS_CHANNEL *handle, WS_MESSAGE *msg )
+static HRESULT send_message_sock( SOCKET socket, BYTE *data, ULONG len )
+{
+ if (send( socket, (const char *)data, len, 0 ) < 0)
+ return HRESULT_FROM_WIN32( WSAGetLastError() );
+ return S_OK;
+}
+
+static HRESULT send_message( struct channel *channel, WS_MESSAGE *msg )
{
- struct channel *channel = (struct channel *)handle;
WS_XML_WRITER *writer;
WS_BYTES buf;
HRESULT hr;
- EnterCriticalSection( &channel->cs );
+ channel->msg = msg;
+ if ((hr = connect_channel( channel )) != S_OK) return hr;
- if (channel->magic != CHANNEL_MAGIC)
+ WsGetMessageProperty( channel->msg, WS_MESSAGE_PROPERTY_BODY_WRITER, &writer, sizeof(writer), NULL );
+ WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BYTES, &buf, sizeof(buf), NULL );
+
+ switch (channel->binding)
{
- LeaveCriticalSection( &channel->cs );
- return E_INVALIDARG;
+ case WS_HTTP_CHANNEL_BINDING:
+ return send_message_http( channel->u.http.request, buf.bytes, buf.length );
+
+ case WS_TCP_CHANNEL_BINDING:
+ return send_message_sock( channel->u.tcp.socket, buf.bytes, buf.length );
+
+ default:
+ ERR( "unhandled binding %u\n", channel->binding );
+ return E_NOTIMPL;
}
+}
+
+HRESULT channel_send_message( WS_CHANNEL *handle, WS_MESSAGE *msg )
+{
+ struct channel *channel = (struct channel *)handle;
+ HRESULT hr;
+
+ EnterCriticalSection( &channel->cs );
- if ((hr = connect_channel( channel, msg )) != S_OK)
+ if (channel->magic != CHANNEL_MAGIC)
{
LeaveCriticalSection( &channel->cs );
- return hr;
+ return E_INVALIDARG;
}
- WsGetMessageProperty( msg, WS_MESSAGE_PROPERTY_BODY_WRITER, &writer, sizeof(writer), NULL );
- WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BYTES, &buf, sizeof(buf), NULL );
- hr = send_message( channel, buf.bytes, buf.length );
+ hr = send_message( channel, msg );
LeaveCriticalSection( &channel->cs );
return hr;
}
+HRESULT set_output( WS_XML_WRITER *writer )
+{
+ WS_XML_WRITER_TEXT_ENCODING text = { {WS_XML_WRITER_ENCODING_TYPE_TEXT}, WS_CHARSET_UTF8 };
+ WS_XML_WRITER_BUFFER_OUTPUT buf = { {WS_XML_WRITER_OUTPUT_TYPE_BUFFER} };
+ return WsSetOutput( writer, &text.encoding, &buf.output, NULL, 0, NULL );
+}
+
+static HRESULT init_writer( struct channel *channel )
+{
+ HRESULT hr;
+ if (!channel->writer && (hr = WsCreateWriter( NULL, 0, &channel->writer, NULL )) != S_OK) return hr;
+ return set_output( channel->writer );
+}
+
/**************************************************************************
* WsSendMessage [webservices.@]
*/
@@ -651,13 +769,13 @@ HRESULT WINAPI WsSendMessage( WS_CHANNEL *handle, WS_MESSAGE *msg, const WS_MESS
if ((hr = WsAddressMessage( msg, &channel->addr, NULL )) != S_OK) goto done;
if ((hr = message_set_action( msg, desc->action )) != S_OK) goto done;
- if (!channel->writer && (hr = WsCreateWriter( NULL, 0, &channel->writer, NULL )) != S_OK) goto done;
- if ((hr = set_output( channel->writer )) != S_OK) goto done;
- hr = write_message( msg, channel->writer, desc->bodyElementDescription, option, body, size );
+ if ((hr = init_writer( channel )) != S_OK) goto done;
+ if ((hr = write_message( msg, channel->writer, desc->bodyElementDescription, option, body, size )) != S_OK)
+ goto done;
+ hr = send_message( channel, msg );
done:
LeaveCriticalSection( &channel->cs );
- if (hr == S_OK) hr = channel_send_message( handle, msg );
return hr;
}
@@ -680,10 +798,29 @@ static HRESULT resize_read_buffer( struct channel *channel, ULONG size )
return S_OK;
}
+static HRESULT set_input( WS_XML_READER *reader, char *data, ULONG size )
+{
+ WS_XML_READER_TEXT_ENCODING text = {{WS_XML_READER_ENCODING_TYPE_TEXT}, WS_CHARSET_UTF8};
+ WS_XML_READER_BUFFER_INPUT buf;
+
+ buf.input.inputType = WS_XML_READER_INPUT_TYPE_BUFFER;
+ buf.encodedData = data;
+ buf.encodedDataSize = size;
+ return WsSetInput( reader, &text.encoding, &buf.input, NULL, 0, NULL );
+}
+
+static HRESULT init_reader( struct channel *channel )
+{
+ HRESULT hr;
+ if (!channel->reader && (hr = WsCreateReader( NULL, 0, &channel->reader, NULL )) != S_OK) return hr;
+ return set_input( channel->reader, channel->read_buf, channel->read_size );
+}
+
#define INITIAL_READ_BUFFER_SIZE 4096
-static HRESULT receive_message( struct channel *channel )
+static HRESULT receive_message_http( struct channel *channel )
{
- DWORD len, max_len, bytes_read, offset = 0, size = INITIAL_READ_BUFFER_SIZE;
+ DWORD len, bytes_read, offset = 0, size = INITIAL_READ_BUFFER_SIZE;
+ ULONG max_len;
HRESULT hr;
prop_get( channel->prop, channel->prop_count, WS_CHANNEL_PROPERTY_MAX_BUFFERED_MESSAGE_SIZE,
@@ -691,10 +828,9 @@ static HRESULT receive_message( struct channel *channel )
if ((hr = resize_read_buffer( channel, size )) != S_OK) return hr;
channel->read_size = 0;
-
for (;;)
{
- if (!WinHttpQueryDataAvailable( channel->http_request, &len ))
+ if (!WinHttpQueryDataAvailable( channel->u.http.request, &len ))
{
return HRESULT_FROM_WIN32( GetLastError() );
}
@@ -702,7 +838,7 @@ static HRESULT receive_message( struct channel *channel )
if (channel->read_size + len > max_len) return WS_E_QUOTA_EXCEEDED;
if ((hr = resize_read_buffer( channel, channel->read_size + len )) != S_OK) return hr;
- if (!WinHttpReadData( channel->http_request, channel->read_buf + offset, len, &bytes_read ))
+ if (!WinHttpReadData( channel->u.http.request, channel->read_buf + offset, len, &bytes_read ))
{
return HRESULT_FROM_WIN32( GetLastError() );
}
@@ -710,18 +846,49 @@ static HRESULT receive_message( struct channel *channel )
channel->read_size += bytes_read;
offset += bytes_read;
}
- return S_OK;
+
+ return init_reader( channel );
}
-static HRESULT set_input( WS_XML_READER *reader, char *data, ULONG size )
+static HRESULT receive_message_sock( struct channel *channel, SOCKET socket )
{
- WS_XML_READER_TEXT_ENCODING text = {{WS_XML_READER_ENCODING_TYPE_TEXT}, WS_CHARSET_UTF8};
- WS_XML_READER_BUFFER_INPUT buf;
+ int bytes_read;
+ ULONG max_len;
+ HRESULT hr;
- buf.input.inputType = WS_XML_READER_INPUT_TYPE_BUFFER;
- buf.encodedData = data;
- buf.encodedDataSize = size;
- return WsSetInput( reader, &text.encoding, &buf.input, NULL, 0, NULL );
+ prop_get( channel->prop, channel->prop_count, WS_CHANNEL_PROPERTY_MAX_BUFFERED_MESSAGE_SIZE,
+ &max_len, sizeof(max_len) );
+
+ if ((hr = resize_read_buffer( channel, max_len )) != S_OK) return hr;
+
+ channel->read_size = 0;
+ if ((bytes_read = recv( socket, channel->read_buf, max_len, 0 )) < 0)
+ {
+ return HRESULT_FROM_WIN32( WSAGetLastError() );
+ }
+ channel->read_size = bytes_read;
+
+ return init_reader( channel );
+}
+
+static HRESULT receive_message( struct channel *channel )
+{
+ HRESULT hr;
+
+ if ((hr = connect_channel( channel )) != S_OK) return hr;
+
+ switch (channel->binding)
+ {
+ case WS_HTTP_CHANNEL_BINDING:
+ return receive_message_http( channel );
+
+ case WS_TCP_CHANNEL_BINDING:
+ return receive_message_sock( channel, channel->u.tcp.socket );
+
+ default:
+ ERR( "unhandled binding %u\n", channel->binding );
+ return E_NOTIMPL;
+ }
}
HRESULT channel_receive_message( WS_CHANNEL *handle )
@@ -737,11 +904,8 @@ HRESULT channel_receive_message( WS_CHANNEL *handle )
return E_INVALIDARG;
}
- if ((hr = receive_message( channel )) != S_OK) goto done;
- if (!channel->reader && (hr = WsCreateReader( NULL, 0, &channel->reader, NULL )) != S_OK) goto done;
- if ((hr = set_input( channel->reader, channel->read_buf, channel->read_size )) != S_OK) goto done;
+ hr = receive_message( channel );
-done:
LeaveCriticalSection( &channel->cs );
return hr;
}
@@ -814,8 +978,6 @@ HRESULT WINAPI WsReceiveMessage( WS_CHANNEL *handle, WS_MESSAGE *msg, const WS_M
}
if ((hr = receive_message( channel )) != S_OK) goto done;
- if (!channel->reader && (hr = WsCreateReader( NULL, 0, &channel->reader, NULL )) != S_OK) goto done;
- if ((hr = set_input( channel->reader, channel->read_buf, channel->read_size )) != S_OK) goto done;
hr = read_message( msg, channel->reader, desc[0]->bodyElementDescription, read_option, heap, value, size );
done:
diff --git a/dlls/webservices/listener.c b/dlls/webservices/listener.c
index 99402ffa46..01d35aced3 100644
--- a/dlls/webservices/listener.c
+++ b/dlls/webservices/listener.c
@@ -20,7 +20,6 @@
#include "windef.h"
#include "winbase.h"
-#include "ws2tcpip.h"
#include "webservices.h"
#include "wine/debug.h"
@@ -41,7 +40,7 @@ static BOOL WINAPI winsock_startup( INIT_ONCE *once, void *param, void **ctx )
return TRUE;
}
-static void winsock_init(void)
+void winsock_init(void)
{
static INIT_ONCE once = INIT_ONCE_STATIC_INIT;
InitOnceExecuteOnce( &once, winsock_startup, NULL, NULL );
@@ -201,7 +200,7 @@ void WINAPI WsFreeListener( WS_LISTENER *handle )
free_listener( listener );
}
-static HRESULT resolve_hostname( const WCHAR *host, USHORT port, struct sockaddr *addr, int *addr_len )
+HRESULT resolve_hostname( const WCHAR *host, USHORT port, struct sockaddr *addr, int *addr_len )
{
static const WCHAR fmtW[] = {'%','u',0};
WCHAR service[6];
@@ -225,7 +224,7 @@ static HRESULT resolve_hostname( const WCHAR *host, USHORT port, struct sockaddr
return hr;
}
-static HRESULT parse_url( const WS_STRING *str, WCHAR **host, USHORT *port )
+HRESULT parse_url( const WS_STRING *str, WS_URL_SCHEME_TYPE *scheme, WCHAR **host, USHORT *port )
{
WS_HEAP *heap;
WS_NETTCP_URL *url;
@@ -249,6 +248,7 @@ static HRESULT parse_url( const WS_STRING *str, WCHAR **host, USHORT *port )
memcpy( *host, url->host.chars, url->host.length * sizeof(WCHAR) );
(*host)[url->host.length] = 0;
}
+ *scheme = url->url.scheme;
*port = url->port;
WsFreeHeap( heap );
@@ -260,11 +260,17 @@ static HRESULT open_listener( struct listener *listener, const WS_STRING *url )
struct sockaddr_storage storage;
struct sockaddr *addr = (struct sockaddr *)&storage;
int addr_len;
+ WS_URL_SCHEME_TYPE scheme;
WCHAR *host;
USHORT port;
HRESULT hr;
- if ((hr = parse_url( url, &host, &port )) != S_OK) return hr;
+ if ((hr = parse_url( url, &scheme, &host, &port )) != S_OK) return hr;
+ if (scheme != WS_URL_NETTCP_SCHEME_TYPE)
+ {
+ heap_free( host );
+ return WS_E_INVALID_ENDPOINT_URL;
+ }
winsock_init();
diff --git a/dlls/webservices/webservices_private.h b/dlls/webservices/webservices_private.h
index c1972b7f56..a4791341e8 100644
--- a/dlls/webservices/webservices_private.h
+++ b/dlls/webservices/webservices_private.h
@@ -16,6 +16,7 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "ws2tcpip.h"
#include "winhttp.h"
struct xmlbuf
@@ -121,6 +122,10 @@ HRESULT channel_send_message( WS_CHANNEL *, WS_MESSAGE * ) DECLSPEC_HIDDEN;
HRESULT channel_receive_message( WS_CHANNEL * ) DECLSPEC_HIDDEN;
HRESULT channel_get_reader( WS_CHANNEL *, WS_XML_READER ** ) DECLSPEC_HIDDEN;
+void winsock_init(void) DECLSPEC_HIDDEN;
+HRESULT resolve_hostname( const WCHAR *, USHORT, struct sockaddr *, int * ) DECLSPEC_HIDDEN;
+HRESULT parse_url( const WS_STRING *, WS_URL_SCHEME_TYPE *, WCHAR **, USHORT * ) DECLSPEC_HIDDEN;
+
#define TICKS_PER_SEC 10000000
#define TICKS_PER_MIN (60 * (ULONGLONG)TICKS_PER_SEC)
#define TICKS_PER_HOUR (3600 * (ULONGLONG)TICKS_PER_SEC)
--
2.11.0
More information about the wine-patches
mailing list