4 * Copyright 2001 Ove Kåven, TransGaming Technologies
5 * Copyright 2003 Mike Hearn
6 * Copyright 2004 Filip Navara
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
37 #include "wine/unicode.h"
42 #include "wine/debug.h"
44 #include "rpc_binding.h"
45 #include "rpc_message.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
49 LPSTR
RPCRT4_strndupA(LPCSTR src
, INT slen
)
53 if (!src
) return NULL
;
54 if (slen
== -1) slen
= strlen(src
);
56 s
= HeapAlloc(GetProcessHeap(), 0, len
+1);
62 LPSTR
RPCRT4_strdupWtoA(LPWSTR src
)
66 if (!src
) return NULL
;
67 len
= WideCharToMultiByte(CP_ACP
, 0, src
, -1, NULL
, 0, NULL
, NULL
);
68 s
= HeapAlloc(GetProcessHeap(), 0, len
);
69 WideCharToMultiByte(CP_ACP
, 0, src
, -1, s
, len
, NULL
, NULL
);
73 LPWSTR
RPCRT4_strdupAtoW(LPSTR src
)
77 if (!src
) return NULL
;
78 len
= MultiByteToWideChar(CP_ACP
, 0, src
, -1, NULL
, 0);
79 s
= HeapAlloc(GetProcessHeap(), 0, len
*sizeof(WCHAR
));
80 MultiByteToWideChar(CP_ACP
, 0, src
, -1, s
, len
);
84 LPWSTR
RPCRT4_strndupW(LPWSTR src
, INT slen
)
88 if (!src
) return NULL
;
89 if (slen
== -1) slen
= strlenW(src
);
91 s
= HeapAlloc(GetProcessHeap(), 0, (len
+1)*sizeof(WCHAR
));
92 memcpy(s
, src
, len
*sizeof(WCHAR
));
97 void RPCRT4_strfree(LPSTR src
)
99 if (src
) HeapFree(GetProcessHeap(), 0, src
);
102 RPC_STATUS
RPCRT4_CreateConnection(RpcConnection
** Connection
, BOOL server
, LPSTR Protseq
, LPSTR NetworkAddr
, LPSTR Endpoint
, LPSTR NetworkOptions
, RpcBinding
* Binding
)
104 RpcConnection
* NewConnection
;
106 NewConnection
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(RpcConnection
));
107 NewConnection
->server
= server
;
108 NewConnection
->Protseq
= RPCRT4_strdupA(Protseq
);
109 NewConnection
->NetworkAddr
= RPCRT4_strdupA(NetworkAddr
);
110 NewConnection
->Endpoint
= RPCRT4_strdupA(Endpoint
);
111 NewConnection
->Used
= Binding
;
112 NewConnection
->MaxTransmissionSize
= RPC_MAX_PACKET_SIZE
;
114 TRACE("connection: %p\n", NewConnection
);
115 *Connection
= NewConnection
;
120 RPC_STATUS
RPCRT4_DestroyConnection(RpcConnection
* Connection
)
122 TRACE("connection: %p\n", Connection
);
124 RPCRT4_CloseConnection(Connection
);
125 RPCRT4_strfree(Connection
->Endpoint
);
126 RPCRT4_strfree(Connection
->NetworkAddr
);
127 RPCRT4_strfree(Connection
->Protseq
);
128 HeapFree(GetProcessHeap(), 0, Connection
);
132 RPC_STATUS
RPCRT4_OpenConnection(RpcConnection
* Connection
)
134 TRACE("(Connection == ^%p)\n", Connection
);
135 if (!Connection
->conn
) {
136 if (Connection
->server
) { /* server */
137 /* protseq=ncalrpc: supposed to use NT LPC ports,
138 * but we'll implement it with named pipes for now */
139 if (strcmp(Connection
->Protseq
, "ncalrpc") == 0) {
140 static LPCSTR prefix
= "\\\\.\\pipe\\lrpc\\";
142 pname
= HeapAlloc(GetProcessHeap(), 0, strlen(prefix
) + strlen(Connection
->Endpoint
) + 1);
143 strcat(strcpy(pname
, prefix
), Connection
->Endpoint
);
144 TRACE("listening on %s\n", pname
);
145 Connection
->conn
= CreateNamedPipeA(pname
, PROFILE_SERVER
| PIPE_ACCESS_DUPLEX
,
146 PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
, PIPE_UNLIMITED_INSTANCES
,
147 RPC_MAX_PACKET_SIZE
, RPC_MAX_PACKET_SIZE
, 5000, NULL
);
148 HeapFree(GetProcessHeap(), 0, pname
);
149 memset(&Connection
->ovl
, 0, sizeof(Connection
->ovl
));
150 Connection
->ovl
.hEvent
= CreateEventA(NULL
, TRUE
, FALSE
, NULL
);
151 if (!ConnectNamedPipe(Connection
->conn
, &Connection
->ovl
)) {
152 WARN("Couldn't ConnectNamedPipe (error was %ld)\n", GetLastError());
153 if (GetLastError() == ERROR_PIPE_CONNECTED
) {
154 SetEvent(Connection
->ovl
.hEvent
);
156 } else if (GetLastError() == ERROR_IO_PENDING
) {
159 return RPC_S_SERVER_UNAVAILABLE
;
162 /* protseq=ncacn_np: named pipes */
163 else if (strcmp(Connection
->Protseq
, "ncacn_np") == 0) {
164 static LPCSTR prefix
= "\\\\.";
166 pname
= HeapAlloc(GetProcessHeap(), 0, strlen(prefix
) + strlen(Connection
->Endpoint
) + 1);
167 strcat(strcpy(pname
, prefix
), Connection
->Endpoint
);
168 TRACE("listening on %s\n", pname
);
169 Connection
->conn
= CreateNamedPipeA(pname
, PROFILE_SERVER
| PIPE_ACCESS_DUPLEX
,
170 PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
| PIPE_WAIT
, PIPE_UNLIMITED_INSTANCES
,
171 RPC_MAX_PACKET_SIZE
, RPC_MAX_PACKET_SIZE
, 5000, NULL
);
172 HeapFree(GetProcessHeap(), 0, pname
);
173 memset(&Connection
->ovl
, 0, sizeof(Connection
->ovl
));
174 Connection
->ovl
.hEvent
= CreateEventA(NULL
, TRUE
, FALSE
, NULL
);
175 if (!ConnectNamedPipe(Connection
->conn
, &Connection
->ovl
)) {
176 WARN("Couldn't ConnectNamedPipe (error was %ld)\n", GetLastError());
177 if (GetLastError() == ERROR_PIPE_CONNECTED
) {
178 SetEvent(Connection
->ovl
.hEvent
);
181 return RPC_S_SERVER_UNAVAILABLE
;
185 ERR("protseq %s not supported\n", Connection
->Protseq
);
186 return RPC_S_PROTSEQ_NOT_SUPPORTED
;
190 /* protseq=ncalrpc: supposed to use NT LPC ports,
191 * but we'll implement it with named pipes for now */
192 if (strcmp(Connection
->Protseq
, "ncalrpc") == 0) {
193 static LPCSTR prefix
= "\\\\.\\pipe\\lrpc\\";
199 pname
= HeapAlloc(GetProcessHeap(), 0, strlen(prefix
) + strlen(Connection
->Endpoint
) + 1);
200 strcat(strcpy(pname
, prefix
), Connection
->Endpoint
);
201 TRACE("connecting to %s\n", pname
);
203 if (WaitNamedPipeA(pname
, NMPWAIT_WAIT_FOREVER
)) {
204 conn
= CreateFileA(pname
, GENERIC_READ
|GENERIC_WRITE
, 0, NULL
,
205 OPEN_EXISTING
, 0, 0);
206 if (conn
!= INVALID_HANDLE_VALUE
) break;
207 err
= GetLastError();
208 if (err
== ERROR_PIPE_BUSY
) continue;
209 TRACE("connection failed, error=%lx\n", err
);
210 HeapFree(GetProcessHeap(), 0, pname
);
211 return RPC_S_SERVER_TOO_BUSY
;
213 err
= GetLastError();
214 TRACE("connection failed, error=%lx\n", err
);
215 HeapFree(GetProcessHeap(), 0, pname
);
216 return RPC_S_SERVER_UNAVAILABLE
;
221 HeapFree(GetProcessHeap(), 0, pname
);
222 memset(&Connection
->ovl
, 0, sizeof(Connection
->ovl
));
223 /* pipe is connected; change to message-read mode. */
224 dwMode
= PIPE_READMODE_MESSAGE
;
225 SetNamedPipeHandleState(conn
, &dwMode
, NULL
, NULL
);
226 Connection
->ovl
.hEvent
= CreateEventA(NULL
, TRUE
, FALSE
, NULL
);
227 Connection
->conn
= conn
;
229 /* protseq=ncacn_np: named pipes */
230 else if (strcmp(Connection
->Protseq
, "ncacn_np") == 0) {
231 static LPCSTR prefix
= "\\\\.";
237 pname
= HeapAlloc(GetProcessHeap(), 0, strlen(prefix
) + strlen(Connection
->Endpoint
) + 1);
238 strcat(strcpy(pname
, prefix
), Connection
->Endpoint
);
239 TRACE("connecting to %s\n", pname
);
240 conn
= CreateFileA(pname
, GENERIC_READ
|GENERIC_WRITE
, 0, NULL
,
241 OPEN_EXISTING
, 0, 0);
242 if (conn
== INVALID_HANDLE_VALUE
) {
243 err
= GetLastError();
244 /* we don't need to handle ERROR_PIPE_BUSY here,
245 * the doc says that it is returned to the app */
246 TRACE("connection failed, error=%lx\n", err
);
247 HeapFree(GetProcessHeap(), 0, pname
);
248 if (err
== ERROR_PIPE_BUSY
)
249 return RPC_S_SERVER_TOO_BUSY
;
251 return RPC_S_SERVER_UNAVAILABLE
;
255 HeapFree(GetProcessHeap(), 0, pname
);
256 memset(&Connection
->ovl
, 0, sizeof(Connection
->ovl
));
257 /* pipe is connected; change to message-read mode. */
258 dwMode
= PIPE_READMODE_MESSAGE
;
259 SetNamedPipeHandleState(conn
, &dwMode
, NULL
, NULL
);
260 Connection
->ovl
.hEvent
= CreateEventA(NULL
, TRUE
, FALSE
, NULL
);
261 Connection
->conn
= conn
;
263 ERR("protseq %s not supported\n", Connection
->Protseq
);
264 return RPC_S_PROTSEQ_NOT_SUPPORTED
;
271 RPC_STATUS
RPCRT4_CloseConnection(RpcConnection
* Connection
)
273 TRACE("(Connection == ^%p)\n", Connection
);
274 if (Connection
->conn
) {
275 CancelIo(Connection
->conn
);
276 CloseHandle(Connection
->conn
);
277 Connection
->conn
= 0;
279 if (Connection
->ovl
.hEvent
) {
280 CloseHandle(Connection
->ovl
.hEvent
);
281 Connection
->ovl
.hEvent
= 0;
286 RPC_STATUS
RPCRT4_SpawnConnection(RpcConnection
** Connection
, RpcConnection
* OldConnection
)
288 RpcConnection
* NewConnection
;
289 RPC_STATUS err
= RPCRT4_CreateConnection(&NewConnection
, OldConnection
->server
, OldConnection
->Protseq
,
290 OldConnection
->NetworkAddr
, OldConnection
->Endpoint
, NULL
, NULL
);
291 if (err
== RPC_S_OK
) {
292 /* because of the way named pipes work, we'll transfer the connected pipe
293 * to the child, then reopen the server binding to continue listening */
294 NewConnection
->conn
= OldConnection
->conn
;
295 NewConnection
->ovl
= OldConnection
->ovl
;
296 OldConnection
->conn
= 0;
297 memset(&OldConnection
->ovl
, 0, sizeof(OldConnection
->ovl
));
298 *Connection
= NewConnection
;
299 RPCRT4_OpenConnection(OldConnection
);
304 RPC_STATUS
RPCRT4_AllocBinding(RpcBinding
** Binding
, BOOL server
)
306 RpcBinding
* NewBinding
;
308 NewBinding
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(RpcBinding
));
309 NewBinding
->refs
= 1;
310 NewBinding
->server
= server
;
312 *Binding
= NewBinding
;
317 RPC_STATUS
RPCRT4_CreateBindingA(RpcBinding
** Binding
, BOOL server
, LPSTR Protseq
)
319 RpcBinding
* NewBinding
;
321 RPCRT4_AllocBinding(&NewBinding
, server
);
322 NewBinding
->Protseq
= RPCRT4_strdupA(Protseq
);
324 TRACE("binding: %p\n", NewBinding
);
325 *Binding
= NewBinding
;
330 RPC_STATUS
RPCRT4_CreateBindingW(RpcBinding
** Binding
, BOOL server
, LPWSTR Protseq
)
332 RpcBinding
* NewBinding
;
334 RPCRT4_AllocBinding(&NewBinding
, server
);
335 NewBinding
->Protseq
= RPCRT4_strdupWtoA(Protseq
);
337 TRACE("binding: %p\n", NewBinding
);
338 *Binding
= NewBinding
;
343 RPC_STATUS
RPCRT4_CompleteBindingA(RpcBinding
* Binding
, LPSTR NetworkAddr
, LPSTR Endpoint
, LPSTR NetworkOptions
)
345 TRACE("(RpcBinding == ^%p, NetworkAddr == \"%s\", EndPoint == \"%s\", NetworkOptions == \"%s\")\n", Binding
,
346 debugstr_a(NetworkAddr
), debugstr_a(Endpoint
), debugstr_a(NetworkOptions
));
348 RPCRT4_strfree(Binding
->NetworkAddr
);
349 Binding
->NetworkAddr
= RPCRT4_strdupA(NetworkAddr
);
350 RPCRT4_strfree(Binding
->Endpoint
);
352 Binding
->Endpoint
= RPCRT4_strdupA(Endpoint
);
354 Binding
->Endpoint
= RPCRT4_strdupA("");
356 if (!Binding
->Endpoint
) ERR("out of memory?\n");
361 RPC_STATUS
RPCRT4_CompleteBindingW(RpcBinding
* Binding
, LPWSTR NetworkAddr
, LPWSTR Endpoint
, LPWSTR NetworkOptions
)
363 TRACE("(RpcBinding == ^%p, NetworkAddr == \"%s\", EndPoint == \"%s\", NetworkOptions == \"%s\")\n", Binding
,
364 debugstr_w(NetworkAddr
), debugstr_w(Endpoint
), debugstr_w(NetworkOptions
));
366 RPCRT4_strfree(Binding
->NetworkAddr
);
367 Binding
->NetworkAddr
= RPCRT4_strdupWtoA(NetworkAddr
);
368 RPCRT4_strfree(Binding
->Endpoint
);
370 Binding
->Endpoint
= RPCRT4_strdupWtoA(Endpoint
);
372 Binding
->Endpoint
= RPCRT4_strdupA("");
374 if (!Binding
->Endpoint
) ERR("out of memory?\n");
379 RPC_STATUS
RPCRT4_ResolveBinding(RpcBinding
* Binding
, LPSTR Endpoint
)
381 TRACE("(RpcBinding == ^%p, EndPoint == \"%s\"\n", Binding
, Endpoint
);
383 RPCRT4_strfree(Binding
->Endpoint
);
384 Binding
->Endpoint
= RPCRT4_strdupA(Endpoint
);
389 RPC_STATUS
RPCRT4_SetBindingObject(RpcBinding
* Binding
, UUID
* ObjectUuid
)
391 TRACE("(*RpcBinding == ^%p, UUID == %s)\n", Binding
, debugstr_guid(ObjectUuid
));
392 if (ObjectUuid
) memcpy(&Binding
->ObjectUuid
, ObjectUuid
, sizeof(UUID
));
393 else UuidCreateNil(&Binding
->ObjectUuid
);
397 RPC_STATUS
RPCRT4_MakeBinding(RpcBinding
** Binding
, RpcConnection
* Connection
)
399 RpcBinding
* NewBinding
;
400 TRACE("(*RpcBinding == ^%p, Connection == ^%p)\n", *Binding
, Connection
);
402 RPCRT4_AllocBinding(&NewBinding
, Connection
->server
);
403 NewBinding
->Protseq
= RPCRT4_strdupA(Connection
->Protseq
);
404 NewBinding
->NetworkAddr
= RPCRT4_strdupA(Connection
->NetworkAddr
);
405 NewBinding
->Endpoint
= RPCRT4_strdupA(Connection
->Endpoint
);
406 NewBinding
->FromConn
= Connection
;
408 TRACE("binding: %p\n", NewBinding
);
409 *Binding
= NewBinding
;
414 RPC_STATUS
RPCRT4_ExportBinding(RpcBinding
** Binding
, RpcBinding
* OldBinding
)
416 InterlockedIncrement(&OldBinding
->refs
);
417 *Binding
= OldBinding
;
421 RPC_STATUS
RPCRT4_DestroyBinding(RpcBinding
* Binding
)
423 if (InterlockedDecrement(&Binding
->refs
))
426 TRACE("binding: %p\n", Binding
);
427 /* FIXME: release connections */
428 RPCRT4_strfree(Binding
->Endpoint
);
429 RPCRT4_strfree(Binding
->NetworkAddr
);
430 RPCRT4_strfree(Binding
->Protseq
);
431 HeapFree(GetProcessHeap(), 0, Binding
);
435 RPC_STATUS
RPCRT4_OpenBinding(RpcBinding
* Binding
, RpcConnection
** Connection
,
436 PRPC_SYNTAX_IDENTIFIER TransferSyntax
,
437 PRPC_SYNTAX_IDENTIFIER InterfaceId
)
439 RpcConnection
* NewConnection
;
442 TRACE("(Binding == ^%p)\n", Binding
);
444 /* if we try to bind a new interface and the connection is already opened,
445 * close the current connection and create a new with the new binding. */
446 if (!Binding
->server
&& Binding
->FromConn
&&
447 memcmp(&Binding
->FromConn
->ActiveInterface
, InterfaceId
,
448 sizeof(RPC_SYNTAX_IDENTIFIER
))) {
450 TRACE("releasing pre-existing connection\n");
451 RPCRT4_DestroyConnection(Binding
->FromConn
);
452 Binding
->FromConn
= NULL
;
454 /* we already have an connection with acceptable binding, so use it */
455 if (Binding
->FromConn
) {
456 *Connection
= Binding
->FromConn
;
461 /* create a new connection */
462 RPCRT4_CreateConnection(&NewConnection
, Binding
->server
, Binding
->Protseq
, Binding
->NetworkAddr
, Binding
->Endpoint
, NULL
, Binding
);
463 *Connection
= NewConnection
;
464 status
= RPCRT4_OpenConnection(NewConnection
);
465 if (status
!= RPC_S_OK
) {
469 /* we need to send a binding packet if we are client. */
470 if (!(*Connection
)->server
) {
474 RpcPktHdr
*response_hdr
;
476 TRACE("sending bind request to server\n");
478 hdr
= RPCRT4_BuildBindHeader(NDR_LOCAL_DATA_REPRESENTATION
,
479 RPC_MAX_PACKET_SIZE
, RPC_MAX_PACKET_SIZE
,
480 InterfaceId
, TransferSyntax
);
482 status
= RPCRT4_Send(*Connection
, hdr
, NULL
, 0);
483 if (status
!= RPC_S_OK
) {
484 RPCRT4_DestroyConnection(*Connection
);
488 response
= HeapAlloc(GetProcessHeap(), 0, RPC_MAX_PACKET_SIZE
);
489 if (response
== NULL
) {
490 WARN("Can't allocate memory for binding response\n");
491 RPCRT4_DestroyConnection(*Connection
);
492 return E_OUTOFMEMORY
;
496 if (!ReadFile(NewConnection
->conn
, response
, RPC_MAX_PACKET_SIZE
, &count
, NULL
)) {
497 WARN("ReadFile failed with error %ld\n", GetLastError());
498 RPCRT4_DestroyConnection(*Connection
);
499 return RPC_S_PROTOCOL_ERROR
;
502 if (count
< sizeof(response_hdr
->common
)) {
503 WARN("received invalid header\n");
504 RPCRT4_DestroyConnection(*Connection
);
505 return RPC_S_PROTOCOL_ERROR
;
508 response_hdr
= (RpcPktHdr
*)response
;
510 if (response_hdr
->common
.rpc_ver
!= RPC_VER_MAJOR
||
511 response_hdr
->common
.rpc_ver_minor
!= RPC_VER_MINOR
||
512 response_hdr
->common
.ptype
!= PKT_BIND_ACK
) {
513 WARN("invalid protocol version or rejection packet\n");
514 RPCRT4_DestroyConnection(*Connection
);
515 return RPC_S_PROTOCOL_ERROR
;
518 if (response_hdr
->bind_ack
.max_tsize
< RPC_MIN_PACKET_SIZE
) {
519 WARN("server doesn't allow large enough packets\n");
520 RPCRT4_DestroyConnection(*Connection
);
521 return RPC_S_PROTOCOL_ERROR
;
524 /* FIXME: do more checks? */
526 (*Connection
)->MaxTransmissionSize
= response_hdr
->bind_ack
.max_tsize
;
527 (*Connection
)->ActiveInterface
= *InterfaceId
;
533 RPC_STATUS
RPCRT4_CloseBinding(RpcBinding
* Binding
, RpcConnection
* Connection
)
535 TRACE("(Binding == ^%p)\n", Binding
);
536 if (!Connection
) return RPC_S_OK
;
537 if (Binding
->FromConn
== Connection
) return RPC_S_OK
;
538 return RPCRT4_DestroyConnection(Connection
);
541 /* utility functions for string composing and parsing */
542 static unsigned RPCRT4_strcopyA(LPSTR data
, LPCSTR src
)
544 unsigned len
= strlen(src
);
545 memcpy(data
, src
, len
*sizeof(CHAR
));
549 static unsigned RPCRT4_strcopyW(LPWSTR data
, LPCWSTR src
)
551 unsigned len
= strlenW(src
);
552 memcpy(data
, src
, len
*sizeof(WCHAR
));
556 static LPSTR
RPCRT4_strconcatA(LPSTR dst
, LPCSTR src
)
558 DWORD len
= strlen(dst
), slen
= strlen(src
);
559 LPSTR ndst
= HeapReAlloc(GetProcessHeap(), 0, dst
, (len
+slen
+2)*sizeof(CHAR
));
562 HeapFree(GetProcessHeap(), 0, dst
);
566 memcpy(ndst
+len
+1, src
, slen
+1);
570 static LPWSTR
RPCRT4_strconcatW(LPWSTR dst
, LPCWSTR src
)
572 DWORD len
= strlenW(dst
), slen
= strlenW(src
);
573 LPWSTR ndst
= HeapReAlloc(GetProcessHeap(), 0, dst
, (len
+slen
+2)*sizeof(WCHAR
));
576 HeapFree(GetProcessHeap(), 0, dst
);
580 memcpy(ndst
+len
+1, src
, (slen
+1)*sizeof(WCHAR
));
585 /***********************************************************************
586 * RpcStringBindingComposeA (RPCRT4.@)
588 RPC_STATUS WINAPI
RpcStringBindingComposeA(unsigned char *ObjUuid
, unsigned char *Protseq
,
589 unsigned char *NetworkAddr
, unsigned char *Endpoint
,
590 unsigned char *Options
, unsigned char** StringBinding
)
595 TRACE( "(%s,%s,%s,%s,%s,%p)\n",
596 debugstr_a( ObjUuid
), debugstr_a( Protseq
),
597 debugstr_a( NetworkAddr
), debugstr_a( Endpoint
),
598 debugstr_a( Options
), StringBinding
);
600 if (ObjUuid
&& *ObjUuid
) len
+= strlen(ObjUuid
) + 1;
601 if (Protseq
&& *Protseq
) len
+= strlen(Protseq
) + 1;
602 if (NetworkAddr
&& *NetworkAddr
) len
+= strlen(NetworkAddr
);
603 if (Endpoint
&& *Endpoint
) len
+= strlen(Endpoint
) + 2;
604 if (Options
&& *Options
) len
+= strlen(Options
) + 2;
606 data
= HeapAlloc(GetProcessHeap(), 0, len
);
607 *StringBinding
= data
;
609 if (ObjUuid
&& *ObjUuid
) {
610 data
+= RPCRT4_strcopyA(data
, ObjUuid
);
613 if (Protseq
&& *Protseq
) {
614 data
+= RPCRT4_strcopyA(data
, Protseq
);
617 if (NetworkAddr
&& *NetworkAddr
)
618 data
+= RPCRT4_strcopyA(data
, NetworkAddr
);
620 if ((Endpoint
&& *Endpoint
) ||
621 (Options
&& *Options
)) {
623 if (Endpoint
&& *Endpoint
) {
624 data
+= RPCRT4_strcopyA(data
, Endpoint
);
625 if (Options
&& *Options
) *data
++ = ',';
627 if (Options
&& *Options
) {
628 data
+= RPCRT4_strcopyA(data
, Options
);
637 /***********************************************************************
638 * RpcStringBindingComposeW (RPCRT4.@)
640 RPC_STATUS WINAPI
RpcStringBindingComposeW( LPWSTR ObjUuid
, LPWSTR Protseq
,
641 LPWSTR NetworkAddr
, LPWSTR Endpoint
,
642 LPWSTR Options
, LPWSTR
* StringBinding
)
647 TRACE("(%s,%s,%s,%s,%s,%p)\n",
648 debugstr_w( ObjUuid
), debugstr_w( Protseq
),
649 debugstr_w( NetworkAddr
), debugstr_w( Endpoint
),
650 debugstr_w( Options
), StringBinding
);
652 if (ObjUuid
&& *ObjUuid
) len
+= strlenW(ObjUuid
) + 1;
653 if (Protseq
&& *Protseq
) len
+= strlenW(Protseq
) + 1;
654 if (NetworkAddr
&& *NetworkAddr
) len
+= strlenW(NetworkAddr
);
655 if (Endpoint
&& *Endpoint
) len
+= strlenW(Endpoint
) + 2;
656 if (Options
&& *Options
) len
+= strlenW(Options
) + 2;
658 data
= HeapAlloc(GetProcessHeap(), 0, len
*sizeof(WCHAR
));
659 *StringBinding
= data
;
661 if (ObjUuid
&& *ObjUuid
) {
662 data
+= RPCRT4_strcopyW(data
, ObjUuid
);
665 if (Protseq
&& *Protseq
) {
666 data
+= RPCRT4_strcopyW(data
, Protseq
);
669 if (NetworkAddr
&& *NetworkAddr
) {
670 data
+= RPCRT4_strcopyW(data
, NetworkAddr
);
672 if ((Endpoint
&& *Endpoint
) ||
673 (Options
&& *Options
)) {
675 if (Endpoint
&& *Endpoint
) {
676 data
+= RPCRT4_strcopyW(data
, Endpoint
);
677 if (Options
&& *Options
) *data
++ = ',';
679 if (Options
&& *Options
) {
680 data
+= RPCRT4_strcopyW(data
, Options
);
690 /***********************************************************************
691 * RpcStringBindingParseA (RPCRT4.@)
693 RPC_STATUS WINAPI
RpcStringBindingParseA( unsigned char *StringBinding
, unsigned char **ObjUuid
,
694 unsigned char **Protseq
, unsigned char **NetworkAddr
,
695 unsigned char **Endpoint
, unsigned char **Options
)
698 static const char ep_opt
[] = "endpoint=";
700 TRACE("(%s,%p,%p,%p,%p,%p)\n", debugstr_a(StringBinding
),
701 ObjUuid
, Protseq
, NetworkAddr
, Endpoint
, Options
);
703 if (ObjUuid
) *ObjUuid
= NULL
;
704 if (Protseq
) *Protseq
= NULL
;
705 if (NetworkAddr
) *NetworkAddr
= NULL
;
706 if (Endpoint
) *Endpoint
= NULL
;
707 if (Options
) *Options
= NULL
;
709 data
= StringBinding
;
711 next
= strchr(data
, '@');
713 if (ObjUuid
) *ObjUuid
= RPCRT4_strndupA(data
, next
- data
);
717 next
= strchr(data
, ':');
719 if (Protseq
) *Protseq
= RPCRT4_strndupA(data
, next
- data
);
723 next
= strchr(data
, '[');
727 if (NetworkAddr
) *NetworkAddr
= RPCRT4_strndupA(data
, next
- data
);
729 close
= strchr(data
, ']');
730 if (!close
) goto fail
;
732 /* tokenize options */
733 while (data
< close
) {
734 next
= strchr(data
, ',');
735 if (!next
|| next
> close
) next
= close
;
736 /* FIXME: this is kind of inefficient */
737 opt
= RPCRT4_strndupA(data
, next
- data
);
741 next
= strchr(opt
, '=');
743 /* not an option, must be an endpoint */
744 if (*Endpoint
) goto fail
;
747 if (strncmp(opt
, ep_opt
, strlen(ep_opt
)) == 0) {
748 /* endpoint option */
749 if (*Endpoint
) goto fail
;
750 *Endpoint
= RPCRT4_strdupA(next
+1);
751 HeapFree(GetProcessHeap(), 0, opt
);
755 /* FIXME: this is kind of inefficient */
756 *Options
= RPCRT4_strconcatA(*Options
, opt
);
757 HeapFree(GetProcessHeap(), 0, opt
);
765 if (*data
) goto fail
;
767 else if (NetworkAddr
)
768 *NetworkAddr
= RPCRT4_strdupA(data
);
773 if (ObjUuid
) RpcStringFreeA((unsigned char**)ObjUuid
);
774 if (Protseq
) RpcStringFreeA((unsigned char**)Protseq
);
775 if (NetworkAddr
) RpcStringFreeA((unsigned char**)NetworkAddr
);
776 if (Endpoint
) RpcStringFreeA((unsigned char**)Endpoint
);
777 if (Options
) RpcStringFreeA((unsigned char**)Options
);
778 return RPC_S_INVALID_STRING_BINDING
;
781 /***********************************************************************
782 * RpcStringBindingParseW (RPCRT4.@)
784 RPC_STATUS WINAPI
RpcStringBindingParseW( LPWSTR StringBinding
, LPWSTR
*ObjUuid
,
785 LPWSTR
*Protseq
, LPWSTR
*NetworkAddr
,
786 LPWSTR
*Endpoint
, LPWSTR
*Options
)
789 static const WCHAR ep_opt
[] = {'e','n','d','p','o','i','n','t','=',0};
791 TRACE("(%s,%p,%p,%p,%p,%p)\n", debugstr_w(StringBinding
),
792 ObjUuid
, Protseq
, NetworkAddr
, Endpoint
, Options
);
794 if (ObjUuid
) *ObjUuid
= NULL
;
795 if (Protseq
) *Protseq
= NULL
;
796 if (NetworkAddr
) *NetworkAddr
= NULL
;
797 if (Endpoint
) *Endpoint
= NULL
;
798 if (Options
) *Options
= NULL
;
800 data
= StringBinding
;
802 next
= strchrW(data
, '@');
804 if (ObjUuid
) *ObjUuid
= RPCRT4_strndupW(data
, next
- data
);
808 next
= strchrW(data
, ':');
810 if (Protseq
) *Protseq
= RPCRT4_strndupW(data
, next
- data
);
814 next
= strchrW(data
, '[');
818 if (NetworkAddr
) *NetworkAddr
= RPCRT4_strndupW(data
, next
- data
);
820 close
= strchrW(data
, ']');
821 if (!close
) goto fail
;
823 /* tokenize options */
824 while (data
< close
) {
825 next
= strchrW(data
, ',');
826 if (!next
|| next
> close
) next
= close
;
827 /* FIXME: this is kind of inefficient */
828 opt
= RPCRT4_strndupW(data
, next
- data
);
832 next
= strchrW(opt
, '=');
834 /* not an option, must be an endpoint */
835 if (*Endpoint
) goto fail
;
838 if (strncmpW(opt
, ep_opt
, strlenW(ep_opt
)) == 0) {
839 /* endpoint option */
840 if (*Endpoint
) goto fail
;
841 *Endpoint
= RPCRT4_strdupW(next
+1);
842 HeapFree(GetProcessHeap(), 0, opt
);
846 /* FIXME: this is kind of inefficient */
847 *Options
= RPCRT4_strconcatW(*Options
, opt
);
848 HeapFree(GetProcessHeap(), 0, opt
);
856 if (*data
) goto fail
;
857 } else if (NetworkAddr
)
858 *NetworkAddr
= RPCRT4_strdupW(data
);
863 if (ObjUuid
) RpcStringFreeW(ObjUuid
);
864 if (Protseq
) RpcStringFreeW(Protseq
);
865 if (NetworkAddr
) RpcStringFreeW(NetworkAddr
);
866 if (Endpoint
) RpcStringFreeW(Endpoint
);
867 if (Options
) RpcStringFreeW(Options
);
868 return RPC_S_INVALID_STRING_BINDING
;
871 /***********************************************************************
872 * RpcBindingFree (RPCRT4.@)
874 RPC_STATUS WINAPI
RpcBindingFree( RPC_BINDING_HANDLE
* Binding
)
877 TRACE("(%p) = %p\n", Binding
, *Binding
);
878 status
= RPCRT4_DestroyBinding(*Binding
);
879 if (status
== RPC_S_OK
) *Binding
= 0;
883 /***********************************************************************
884 * RpcBindingVectorFree (RPCRT4.@)
886 RPC_STATUS WINAPI
RpcBindingVectorFree( RPC_BINDING_VECTOR
** BindingVector
)
891 TRACE("(%p)\n", BindingVector
);
892 for (c
=0; c
<(*BindingVector
)->Count
; c
++) {
893 status
= RpcBindingFree(&(*BindingVector
)->BindingH
[c
]);
895 HeapFree(GetProcessHeap(), 0, *BindingVector
);
896 *BindingVector
= NULL
;
900 /***********************************************************************
901 * RpcBindingInqObject (RPCRT4.@)
903 RPC_STATUS WINAPI
RpcBindingInqObject( RPC_BINDING_HANDLE Binding
, UUID
* ObjectUuid
)
905 RpcBinding
* bind
= (RpcBinding
*)Binding
;
907 TRACE("(%p,%p) = %s\n", Binding
, ObjectUuid
, debugstr_guid(&bind
->ObjectUuid
));
908 memcpy(ObjectUuid
, &bind
->ObjectUuid
, sizeof(UUID
));
912 /***********************************************************************
913 * RpcBindingSetObject (RPCRT4.@)
915 RPC_STATUS WINAPI
RpcBindingSetObject( RPC_BINDING_HANDLE Binding
, UUID
* ObjectUuid
)
917 RpcBinding
* bind
= (RpcBinding
*)Binding
;
919 TRACE("(%p,%s)\n", Binding
, debugstr_guid(ObjectUuid
));
920 if (bind
->server
) return RPC_S_WRONG_KIND_OF_BINDING
;
921 return RPCRT4_SetBindingObject(Binding
, ObjectUuid
);
924 /***********************************************************************
925 * RpcBindingFromStringBindingA (RPCRT4.@)
927 RPC_STATUS WINAPI
RpcBindingFromStringBindingA( unsigned char *StringBinding
, RPC_BINDING_HANDLE
* Binding
)
930 RpcBinding
* bind
= NULL
;
931 unsigned char *ObjectUuid
, *Protseq
, *NetworkAddr
, *Endpoint
, *Options
;
934 TRACE("(%s,%p)\n", debugstr_a(StringBinding
), Binding
);
936 ret
= RpcStringBindingParseA(StringBinding
, &ObjectUuid
, &Protseq
,
937 &NetworkAddr
, &Endpoint
, &Options
);
938 if (ret
!= RPC_S_OK
) return ret
;
940 ret
= UuidFromStringA(ObjectUuid
, &Uuid
);
943 ret
= RPCRT4_CreateBindingA(&bind
, FALSE
, Protseq
);
945 ret
= RPCRT4_SetBindingObject(bind
, &Uuid
);
947 ret
= RPCRT4_CompleteBindingA(bind
, NetworkAddr
, Endpoint
, Options
);
949 RpcStringFreeA((unsigned char**)&Options
);
950 RpcStringFreeA((unsigned char**)&Endpoint
);
951 RpcStringFreeA((unsigned char**)&NetworkAddr
);
952 RpcStringFreeA((unsigned char**)&Protseq
);
953 RpcStringFreeA((unsigned char**)&ObjectUuid
);
956 *Binding
= (RPC_BINDING_HANDLE
)bind
;
958 RPCRT4_DestroyBinding(bind
);
963 /***********************************************************************
964 * RpcBindingFromStringBindingW (RPCRT4.@)
966 RPC_STATUS WINAPI
RpcBindingFromStringBindingW( LPWSTR StringBinding
, RPC_BINDING_HANDLE
* Binding
)
969 RpcBinding
* bind
= NULL
;
970 LPWSTR ObjectUuid
, Protseq
, NetworkAddr
, Endpoint
, Options
;
973 TRACE("(%s,%p)\n", debugstr_w(StringBinding
), Binding
);
975 ret
= RpcStringBindingParseW(StringBinding
, &ObjectUuid
, &Protseq
,
976 &NetworkAddr
, &Endpoint
, &Options
);
977 if (ret
!= RPC_S_OK
) return ret
;
979 ret
= UuidFromStringW(ObjectUuid
, &Uuid
);
982 ret
= RPCRT4_CreateBindingW(&bind
, FALSE
, Protseq
);
984 ret
= RPCRT4_SetBindingObject(bind
, &Uuid
);
986 ret
= RPCRT4_CompleteBindingW(bind
, NetworkAddr
, Endpoint
, Options
);
988 RpcStringFreeW(&Options
);
989 RpcStringFreeW(&Endpoint
);
990 RpcStringFreeW(&NetworkAddr
);
991 RpcStringFreeW(&Protseq
);
992 RpcStringFreeW(&ObjectUuid
);
995 *Binding
= (RPC_BINDING_HANDLE
)bind
;
997 RPCRT4_DestroyBinding(bind
);
1002 /***********************************************************************
1003 * RpcBindingToStringBindingA (RPCRT4.@)
1005 RPC_STATUS WINAPI
RpcBindingToStringBindingA( RPC_BINDING_HANDLE Binding
, unsigned char** StringBinding
)
1008 RpcBinding
* bind
= (RpcBinding
*)Binding
;
1011 TRACE("(%p,%p)\n", Binding
, StringBinding
);
1013 ret
= UuidToStringA(&bind
->ObjectUuid
, (unsigned char**)&ObjectUuid
);
1014 if (ret
!= RPC_S_OK
) return ret
;
1016 ret
= RpcStringBindingComposeA(ObjectUuid
, bind
->Protseq
, bind
->NetworkAddr
,
1017 bind
->Endpoint
, NULL
, StringBinding
);
1019 RpcStringFreeA((unsigned char**)&ObjectUuid
);
1024 /***********************************************************************
1025 * RpcBindingToStringBindingW (RPCRT4.@)
1027 RPC_STATUS WINAPI
RpcBindingToStringBindingW( RPC_BINDING_HANDLE Binding
, LPWSTR
* StringBinding
)
1030 unsigned char *str
= NULL
;
1031 TRACE("(%p,%p)\n", Binding
, StringBinding
);
1032 ret
= RpcBindingToStringBindingA(Binding
, &str
);
1033 *StringBinding
= RPCRT4_strdupAtoW(str
);
1034 RpcStringFreeA((unsigned char**)&str
);
1038 /***********************************************************************
1039 * I_RpcBindingSetAsync (RPCRT4.@)
1041 * Exists in win9x and winNT, but with different number of arguments
1042 * (9x version has 3 arguments, NT has 2).
1044 RPC_STATUS WINAPI
I_RpcBindingSetAsync( RPC_BINDING_HANDLE Binding
, RPC_BLOCKING_FN BlockingFn
)
1046 RpcBinding
* bind
= (RpcBinding
*)Binding
;
1048 TRACE( "(%p,%p): stub\n", Binding
, BlockingFn
);
1050 bind
->BlockingFn
= BlockingFn
;
1055 /***********************************************************************
1056 * RpcNetworkIsProtseqValidA (RPCRT4.@)
1058 RPC_STATUS WINAPI
RpcNetworkIsProtseqValidA(unsigned char *protseq
) {
1059 UNICODE_STRING protseqW
;
1061 if (!protseq
) return RPC_S_INVALID_RPC_PROTSEQ
; /* ? */
1063 if (RtlCreateUnicodeStringFromAsciiz(&protseqW
, protseq
)) {
1064 RPC_STATUS ret
= RpcNetworkIsProtseqValidW(protseqW
.Buffer
);
1065 RtlFreeUnicodeString(&protseqW
);
1067 } else return RPC_S_OUT_OF_MEMORY
;
1070 /***********************************************************************
1071 * RpcNetworkIsProtseqValidW (RPCRT4.@)
1073 * Checks if the given protocol sequence is known by the RPC system.
1074 * If it is, returns RPC_S_OK, otherwise RPC_S_PROTSEQ_NOT_SUPPORTED.
1076 * We currently support:
1077 * ncalrpc local-only rpc over LPC (LPC is not really used)
1078 * ncacn_np rpc over named pipes
1080 RPC_STATUS WINAPI
RpcNetworkIsProtseqValidW(LPWSTR protseq
) {
1081 static const WCHAR protseqsW
[][15] = {
1082 {'n','c','a','l','r','p','c',0},
1083 {'n','c','a','c','n','_','n','p',0}
1085 static const int count
= sizeof(protseqsW
) / sizeof(protseqsW
[0]);
1088 if (!protseq
) return RPC_S_INVALID_RPC_PROTSEQ
; /* ? */
1090 for (i
= 0; i
< count
; i
++) {
1091 if (!strcmpW(protseq
, protseqsW
[i
])) return RPC_S_OK
;
1094 FIXME("Unknown protseq %s - we probably need to implement it one day\n", debugstr_w(protseq
));
1095 return RPC_S_PROTSEQ_NOT_SUPPORTED
;