4 * Copyright 2001 Ove Kåven, TransGaming Technologies
5 * Copyright 2003 Mike Hearn
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
36 #include "wine/unicode.h"
40 #include "wine/debug.h"
42 #include "rpc_binding.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
46 static RpcConnection
* conn_cache
;
48 static CRITICAL_SECTION conn_cache_cs
;
49 static CRITICAL_SECTION_DEBUG critsect_debug
=
52 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
53 0, 0, { 0, (DWORD
)(__FILE__
": conn_cache_cs") }
55 static CRITICAL_SECTION conn_cache_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
57 LPSTR
RPCRT4_strndupA(LPCSTR src
, INT slen
)
61 if (!src
) return NULL
;
62 if (slen
== -1) slen
= strlen(src
);
64 s
= HeapAlloc(GetProcessHeap(), 0, len
+1);
70 LPSTR
RPCRT4_strdupWtoA(LPWSTR src
)
74 if (!src
) return NULL
;
75 len
= WideCharToMultiByte(CP_ACP
, 0, src
, -1, NULL
, 0, NULL
, NULL
);
76 s
= HeapAlloc(GetProcessHeap(), 0, len
);
77 WideCharToMultiByte(CP_ACP
, 0, src
, -1, s
, len
, NULL
, NULL
);
81 LPWSTR
RPCRT4_strdupAtoW(LPSTR src
)
85 if (!src
) return NULL
;
86 len
= MultiByteToWideChar(CP_ACP
, 0, src
, -1, NULL
, 0);
87 s
= HeapAlloc(GetProcessHeap(), 0, len
*sizeof(WCHAR
));
88 MultiByteToWideChar(CP_ACP
, 0, src
, -1, s
, len
);
92 LPWSTR
RPCRT4_strndupW(LPWSTR src
, INT slen
)
96 if (!src
) return NULL
;
97 if (slen
== -1) slen
= strlenW(src
);
99 s
= HeapAlloc(GetProcessHeap(), 0, (len
+1)*sizeof(WCHAR
));
100 memcpy(s
, src
, len
*sizeof(WCHAR
));
105 void RPCRT4_strfree(LPSTR src
)
107 if (src
) HeapFree(GetProcessHeap(), 0, src
);
110 RPC_STATUS
RPCRT4_CreateConnection(RpcConnection
** Connection
, BOOL server
, LPSTR Protseq
, LPSTR NetworkAddr
, LPSTR Endpoint
, LPSTR NetworkOptions
, RpcBinding
* Binding
)
112 RpcConnection
* NewConnection
;
114 NewConnection
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(RpcConnection
));
115 NewConnection
->server
= server
;
116 NewConnection
->Protseq
= RPCRT4_strdupA(Protseq
);
117 NewConnection
->NetworkAddr
= RPCRT4_strdupA(NetworkAddr
);
118 NewConnection
->Endpoint
= RPCRT4_strdupA(Endpoint
);
119 NewConnection
->Used
= Binding
;
121 EnterCriticalSection(&conn_cache_cs
);
122 NewConnection
->Next
= conn_cache
;
123 conn_cache
= NewConnection
;
124 LeaveCriticalSection(&conn_cache_cs
);
126 TRACE("connection: %p\n", NewConnection
);
127 *Connection
= NewConnection
;
132 RPC_STATUS
RPCRT4_DestroyConnection(RpcConnection
* Connection
)
134 RpcConnection
* PrevConnection
;
136 TRACE("connection: %p\n", Connection
);
137 if (Connection
->Used
) ERR("connection is still in use\n");
139 EnterCriticalSection(&conn_cache_cs
);
140 PrevConnection
= conn_cache
;
141 if (PrevConnection
== Connection
) {
142 conn_cache
= Connection
->Next
;
144 while (PrevConnection
&& PrevConnection
->Next
!= Connection
)
145 PrevConnection
= PrevConnection
->Next
;
146 if (PrevConnection
) PrevConnection
->Next
= Connection
->Next
;
148 LeaveCriticalSection(&conn_cache_cs
);
150 RPCRT4_CloseConnection(Connection
);
151 RPCRT4_strfree(Connection
->Endpoint
);
152 RPCRT4_strfree(Connection
->NetworkAddr
);
153 RPCRT4_strfree(Connection
->Protseq
);
154 HeapFree(GetProcessHeap(), 0, Connection
);
158 RPC_STATUS
RPCRT4_GetConnection(RpcConnection
** Connection
, BOOL server
, LPSTR Protseq
, LPSTR NetworkAddr
, LPSTR Endpoint
, LPSTR NetworkOptions
, RpcBinding
* Binding
)
160 RpcConnection
* NewConnection
;
163 EnterCriticalSection(&conn_cache_cs
);
164 for (NewConnection
= conn_cache
; NewConnection
; NewConnection
= NewConnection
->Next
) {
165 if (NewConnection
->Used
) continue;
166 if (NewConnection
->server
!= server
) continue;
167 if (Protseq
&& strcmp(NewConnection
->Protseq
, Protseq
)) continue;
168 if (NetworkAddr
&& strcmp(NewConnection
->NetworkAddr
, NetworkAddr
)) continue;
169 if (Endpoint
&& strcmp(NewConnection
->Endpoint
, Endpoint
)) continue;
170 /* this connection fits the bill */
171 NewConnection
->Used
= Binding
;
174 LeaveCriticalSection(&conn_cache_cs
);
176 TRACE("cached connection: %p\n", NewConnection
);
177 *Connection
= NewConnection
;
181 return RPCRT4_CreateConnection(Connection
, server
, Protseq
, NetworkAddr
, Endpoint
, NetworkOptions
, Binding
);
184 RPC_STATUS
RPCRT4_ReleaseConnection(RpcConnection
* Connection
)
186 TRACE("connection: %p\n", Connection
);
187 Connection
->Used
= NULL
;
188 if (!Connection
->server
) {
189 /* cache the open connection for reuse later */
190 /* FIXME: we should probably clean the cache someday */
193 return RPCRT4_DestroyConnection(Connection
);
196 RPC_STATUS
RPCRT4_OpenConnection(RpcConnection
* Connection
)
198 TRACE("(Connection == ^%p)\n", Connection
);
199 if (!Connection
->conn
) {
200 if (Connection
->server
) { /* server */
201 /* protseq=ncalrpc: supposed to use NT LPC ports,
202 * but we'll implement it with named pipes for now */
203 if (strcmp(Connection
->Protseq
, "ncalrpc") == 0) {
204 static LPCSTR prefix
= "\\\\.\\pipe\\lrpc\\";
206 pname
= HeapAlloc(GetProcessHeap(), 0, strlen(prefix
) + strlen(Connection
->Endpoint
) + 1);
207 strcat(strcpy(pname
, prefix
), Connection
->Endpoint
);
208 TRACE("listening on %s\n", pname
);
209 Connection
->conn
= CreateNamedPipeA(pname
, PIPE_ACCESS_DUPLEX
| FILE_FLAG_OVERLAPPED
,
210 0, PIPE_UNLIMITED_INSTANCES
, 0, 0, 5000, NULL
);
211 HeapFree(GetProcessHeap(), 0, pname
);
212 memset(&Connection
->ovl
, 0, sizeof(Connection
->ovl
));
213 Connection
->ovl
.hEvent
= CreateEventA(NULL
, TRUE
, FALSE
, NULL
);
214 if (!ConnectNamedPipe(Connection
->conn
, &Connection
->ovl
)) {
215 WARN("Couldn't ConnectNamedPipe (error was %ld)\n", GetLastError());
216 if (GetLastError() == ERROR_PIPE_CONNECTED
) {
217 SetEvent(Connection
->ovl
.hEvent
);
220 return RPC_S_SERVER_UNAVAILABLE
;
223 /* protseq=ncacn_np: named pipes */
224 else if (strcmp(Connection
->Protseq
, "ncacn_np") == 0) {
225 static LPCSTR prefix
= "\\\\.";
227 pname
= HeapAlloc(GetProcessHeap(), 0, strlen(prefix
) + strlen(Connection
->Endpoint
) + 1);
228 strcat(strcpy(pname
, prefix
), Connection
->Endpoint
);
229 TRACE("listening on %s\n", pname
);
230 Connection
->conn
= CreateNamedPipeA(pname
, PIPE_ACCESS_DUPLEX
| FILE_FLAG_OVERLAPPED
,
231 0, PIPE_UNLIMITED_INSTANCES
, 0, 0, 5000, NULL
);
232 HeapFree(GetProcessHeap(), 0, pname
);
233 memset(&Connection
->ovl
, 0, sizeof(Connection
->ovl
));
234 Connection
->ovl
.hEvent
= CreateEventA(NULL
, TRUE
, FALSE
, NULL
);
235 if (!ConnectNamedPipe(Connection
->conn
, &Connection
->ovl
)) {
236 WARN("Couldn't ConnectNamedPipe (error was %ld)\n", GetLastError());
237 if (GetLastError() == ERROR_PIPE_CONNECTED
) {
238 SetEvent(Connection
->ovl
.hEvent
);
241 return RPC_S_SERVER_UNAVAILABLE
;
245 ERR("protseq %s not supported\n", Connection
->Protseq
);
246 return RPC_S_PROTSEQ_NOT_SUPPORTED
;
250 /* protseq=ncalrpc: supposed to use NT LPC ports,
251 * but we'll implement it with named pipes for now */
252 if (strcmp(Connection
->Protseq
, "ncalrpc") == 0) {
253 static LPCSTR prefix
= "\\\\.\\pipe\\lrpc\\";
258 pname
= HeapAlloc(GetProcessHeap(), 0, strlen(prefix
) + strlen(Connection
->Endpoint
) + 1);
259 strcat(strcpy(pname
, prefix
), Connection
->Endpoint
);
260 TRACE("connecting to %s\n", pname
);
262 if (WaitNamedPipeA(pname
, NMPWAIT_WAIT_FOREVER
)) {
263 conn
= CreateFileA(pname
, GENERIC_READ
|GENERIC_WRITE
, 0, NULL
,
264 OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, 0);
265 if (conn
!= INVALID_HANDLE_VALUE
) break;
266 err
= GetLastError();
267 if (err
== ERROR_PIPE_BUSY
) continue;
268 TRACE("connection failed, error=%lx\n", err
);
269 HeapFree(GetProcessHeap(), 0, pname
);
270 return RPC_S_SERVER_TOO_BUSY
;
272 err
= GetLastError();
273 TRACE("connection failed, error=%lx\n", err
);
274 HeapFree(GetProcessHeap(), 0, pname
);
275 return RPC_S_SERVER_UNAVAILABLE
;
280 HeapFree(GetProcessHeap(), 0, pname
);
281 memset(&Connection
->ovl
, 0, sizeof(Connection
->ovl
));
282 Connection
->ovl
.hEvent
= CreateEventA(NULL
, TRUE
, FALSE
, NULL
);
283 Connection
->conn
= conn
;
285 /* protseq=ncacn_np: named pipes */
286 else if (strcmp(Connection
->Protseq
, "ncacn_np") == 0) {
287 static LPCSTR prefix
= "\\\\.";
292 pname
= HeapAlloc(GetProcessHeap(), 0, strlen(prefix
) + strlen(Connection
->Endpoint
) + 1);
293 strcat(strcpy(pname
, prefix
), Connection
->Endpoint
);
294 TRACE("connecting to %s\n", pname
);
295 conn
= CreateFileA(pname
, GENERIC_READ
|GENERIC_WRITE
, 0, NULL
,
296 OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, 0);
297 if (conn
== INVALID_HANDLE_VALUE
) {
298 err
= GetLastError();
299 /* we don't need to handle ERROR_PIPE_BUSY here,
300 * the doc says that it is returned to the app */
301 TRACE("connection failed, error=%lx\n", err
);
302 HeapFree(GetProcessHeap(), 0, pname
);
303 if (err
== ERROR_PIPE_BUSY
)
304 return RPC_S_SERVER_TOO_BUSY
;
306 return RPC_S_SERVER_UNAVAILABLE
;
310 HeapFree(GetProcessHeap(), 0, pname
);
311 memset(&Connection
->ovl
, 0, sizeof(Connection
->ovl
));
312 Connection
->ovl
.hEvent
= CreateEventA(NULL
, TRUE
, FALSE
, NULL
);
313 Connection
->conn
= conn
;
315 ERR("protseq %s not supported\n", Connection
->Protseq
);
316 return RPC_S_PROTSEQ_NOT_SUPPORTED
;
323 RPC_STATUS
RPCRT4_CloseConnection(RpcConnection
* Connection
)
325 TRACE("(Connection == ^%p)\n", Connection
);
326 if (Connection
->conn
) {
327 CancelIo(Connection
->conn
);
328 CloseHandle(Connection
->conn
);
329 Connection
->conn
= 0;
331 if (Connection
->ovl
.hEvent
) {
332 CloseHandle(Connection
->ovl
.hEvent
);
333 Connection
->ovl
.hEvent
= 0;
338 RPC_STATUS
RPCRT4_SpawnConnection(RpcConnection
** Connection
, RpcConnection
* OldConnection
)
340 RpcConnection
* NewConnection
;
341 RPC_STATUS err
= RPCRT4_CreateConnection(&NewConnection
, OldConnection
->server
, OldConnection
->Protseq
,
342 OldConnection
->NetworkAddr
, OldConnection
->Endpoint
, NULL
, NULL
);
343 if (err
== RPC_S_OK
) {
344 /* because of the way named pipes work, we'll transfer the connected pipe
345 * to the child, then reopen the server binding to continue listening */
346 NewConnection
->conn
= OldConnection
->conn
;
347 NewConnection
->ovl
= OldConnection
->ovl
;
348 OldConnection
->conn
= 0;
349 memset(&OldConnection
->ovl
, 0, sizeof(OldConnection
->ovl
));
350 *Connection
= NewConnection
;
351 RPCRT4_OpenConnection(OldConnection
);
356 RPC_STATUS
RPCRT4_AllocBinding(RpcBinding
** Binding
, BOOL server
)
358 RpcBinding
* NewBinding
;
360 NewBinding
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(RpcBinding
));
361 NewBinding
->refs
= 1;
362 NewBinding
->server
= server
;
364 *Binding
= NewBinding
;
369 RPC_STATUS
RPCRT4_CreateBindingA(RpcBinding
** Binding
, BOOL server
, LPSTR Protseq
)
371 RpcBinding
* NewBinding
;
373 RPCRT4_AllocBinding(&NewBinding
, server
);
374 NewBinding
->Protseq
= RPCRT4_strdupA(Protseq
);
376 TRACE("binding: %p\n", NewBinding
);
377 *Binding
= NewBinding
;
382 RPC_STATUS
RPCRT4_CreateBindingW(RpcBinding
** Binding
, BOOL server
, LPWSTR Protseq
)
384 RpcBinding
* NewBinding
;
386 RPCRT4_AllocBinding(&NewBinding
, server
);
387 NewBinding
->Protseq
= RPCRT4_strdupWtoA(Protseq
);
389 TRACE("binding: %p\n", NewBinding
);
390 *Binding
= NewBinding
;
395 RPC_STATUS
RPCRT4_CompleteBindingA(RpcBinding
* Binding
, LPSTR NetworkAddr
, LPSTR Endpoint
, LPSTR NetworkOptions
)
397 TRACE("(RpcBinding == ^%p, NetworkAddr == \"%s\", EndPoint == \"%s\", NetworkOptions == \"%s\")\n", Binding
,
398 debugstr_a(NetworkAddr
), debugstr_a(Endpoint
), debugstr_a(NetworkOptions
));
400 RPCRT4_strfree(Binding
->NetworkAddr
);
401 Binding
->NetworkAddr
= RPCRT4_strdupA(NetworkAddr
);
402 RPCRT4_strfree(Binding
->Endpoint
);
404 Binding
->Endpoint
= RPCRT4_strdupA(Endpoint
);
406 Binding
->Endpoint
= RPCRT4_strdupA("");
408 if (!Binding
->Endpoint
) ERR("out of memory?\n");
413 RPC_STATUS
RPCRT4_CompleteBindingW(RpcBinding
* Binding
, LPWSTR NetworkAddr
, LPWSTR Endpoint
, LPWSTR NetworkOptions
)
415 TRACE("(RpcBinding == ^%p, NetworkAddr == \"%s\", EndPoint == \"%s\", NetworkOptions == \"%s\")\n", Binding
,
416 debugstr_w(NetworkAddr
), debugstr_w(Endpoint
), debugstr_w(NetworkOptions
));
418 RPCRT4_strfree(Binding
->NetworkAddr
);
419 Binding
->NetworkAddr
= RPCRT4_strdupWtoA(NetworkAddr
);
420 RPCRT4_strfree(Binding
->Endpoint
);
422 Binding
->Endpoint
= RPCRT4_strdupWtoA(Endpoint
);
424 Binding
->Endpoint
= RPCRT4_strdupA("");
426 if (!Binding
->Endpoint
) ERR("out of memory?\n");
431 RPC_STATUS
RPCRT4_ResolveBinding(RpcBinding
* Binding
, LPSTR Endpoint
)
433 TRACE("(RpcBinding == ^%p, EndPoint == \"%s\"\n", Binding
, Endpoint
);
435 RPCRT4_strfree(Binding
->Endpoint
);
436 Binding
->Endpoint
= RPCRT4_strdupA(Endpoint
);
441 RPC_STATUS
RPCRT4_SetBindingObject(RpcBinding
* Binding
, UUID
* ObjectUuid
)
443 TRACE("(*RpcBinding == ^%p, UUID == %s)\n", Binding
, debugstr_guid(ObjectUuid
));
444 if (ObjectUuid
) memcpy(&Binding
->ObjectUuid
, ObjectUuid
, sizeof(UUID
));
445 else UuidCreateNil(&Binding
->ObjectUuid
);
449 RPC_STATUS
RPCRT4_MakeBinding(RpcBinding
** Binding
, RpcConnection
* Connection
)
451 RpcBinding
* NewBinding
;
452 TRACE("(*RpcBinding == ^%p, Connection == ^%p)\n", *Binding
, Connection
);
454 RPCRT4_AllocBinding(&NewBinding
, Connection
->server
);
455 NewBinding
->Protseq
= RPCRT4_strdupA(Connection
->Protseq
);
456 NewBinding
->NetworkAddr
= RPCRT4_strdupA(Connection
->NetworkAddr
);
457 NewBinding
->Endpoint
= RPCRT4_strdupA(Connection
->Endpoint
);
458 NewBinding
->FromConn
= Connection
;
460 TRACE("binding: %p\n", NewBinding
);
461 *Binding
= NewBinding
;
466 RPC_STATUS
RPCRT4_ExportBinding(RpcBinding
** Binding
, RpcBinding
* OldBinding
)
468 InterlockedIncrement(&OldBinding
->refs
);
469 *Binding
= OldBinding
;
473 RPC_STATUS
RPCRT4_DestroyBinding(RpcBinding
* Binding
)
475 if (InterlockedDecrement(&Binding
->refs
))
478 TRACE("binding: %p\n", Binding
);
479 /* FIXME: release connections */
480 RPCRT4_strfree(Binding
->Endpoint
);
481 RPCRT4_strfree(Binding
->NetworkAddr
);
482 RPCRT4_strfree(Binding
->Protseq
);
483 HeapFree(GetProcessHeap(), 0, Binding
);
487 RPC_STATUS
RPCRT4_OpenBinding(RpcBinding
* Binding
, RpcConnection
** Connection
)
489 RpcConnection
* NewConnection
;
490 TRACE("(Binding == ^%p)\n", Binding
);
491 if (Binding
->FromConn
) {
492 *Connection
= Binding
->FromConn
;
496 RPCRT4_GetConnection(&NewConnection
, Binding
->server
, Binding
->Protseq
, Binding
->NetworkAddr
, Binding
->Endpoint
, NULL
, Binding
);
497 *Connection
= NewConnection
;
498 return RPCRT4_OpenConnection(NewConnection
);
501 RPC_STATUS
RPCRT4_CloseBinding(RpcBinding
* Binding
, RpcConnection
* Connection
)
503 TRACE("(Binding == ^%p)\n", Binding
);
504 if (!Connection
) return RPC_S_OK
;
505 if (Binding
->FromConn
== Connection
) return RPC_S_OK
;
506 return RPCRT4_ReleaseConnection(Connection
);
509 /* utility functions for string composing and parsing */
510 static unsigned RPCRT4_strcopyA(LPSTR data
, LPCSTR src
)
512 unsigned len
= strlen(src
);
513 memcpy(data
, src
, len
*sizeof(CHAR
));
517 static unsigned RPCRT4_strcopyW(LPWSTR data
, LPCWSTR src
)
519 unsigned len
= strlenW(src
);
520 memcpy(data
, src
, len
*sizeof(WCHAR
));
524 static LPSTR
RPCRT4_strconcatA(LPSTR dst
, LPCSTR src
)
526 DWORD len
= strlen(dst
), slen
= strlen(src
);
527 LPSTR ndst
= HeapReAlloc(GetProcessHeap(), 0, dst
, (len
+slen
+2)*sizeof(CHAR
));
530 HeapFree(GetProcessHeap(), 0, dst
);
534 memcpy(ndst
+len
+1, src
, slen
+1);
538 static LPWSTR
RPCRT4_strconcatW(LPWSTR dst
, LPCWSTR src
)
540 DWORD len
= strlenW(dst
), slen
= strlenW(src
);
541 LPWSTR ndst
= HeapReAlloc(GetProcessHeap(), 0, dst
, (len
+slen
+2)*sizeof(WCHAR
));
544 HeapFree(GetProcessHeap(), 0, dst
);
548 memcpy(ndst
+len
+1, src
, (slen
+1)*sizeof(WCHAR
));
553 /***********************************************************************
554 * RpcStringBindingComposeA (RPCRT4.@)
556 RPC_STATUS WINAPI
RpcStringBindingComposeA( LPSTR ObjUuid
, LPSTR Protseq
,
557 LPSTR NetworkAddr
, LPSTR Endpoint
,
558 LPSTR Options
, LPSTR
* StringBinding
)
563 TRACE( "(%s,%s,%s,%s,%s,%p)\n",
564 debugstr_a( ObjUuid
), debugstr_a( Protseq
),
565 debugstr_a( NetworkAddr
), debugstr_a( Endpoint
),
566 debugstr_a( Options
), StringBinding
);
568 if (ObjUuid
&& *ObjUuid
) len
+= strlen(ObjUuid
) + 1;
569 if (Protseq
&& *Protseq
) len
+= strlen(Protseq
) + 1;
570 if (NetworkAddr
&& *NetworkAddr
) len
+= strlen(NetworkAddr
);
571 if (Endpoint
&& *Endpoint
) len
+= strlen(Endpoint
) + 2;
572 if (Options
&& *Options
) len
+= strlen(Options
) + 2;
574 data
= HeapAlloc(GetProcessHeap(), 0, len
);
575 *StringBinding
= data
;
577 if (ObjUuid
&& *ObjUuid
) {
578 data
+= RPCRT4_strcopyA(data
, ObjUuid
);
581 if (Protseq
&& *Protseq
) {
582 data
+= RPCRT4_strcopyA(data
, Protseq
);
585 if (NetworkAddr
&& *NetworkAddr
)
586 data
+= RPCRT4_strcopyA(data
, NetworkAddr
);
588 if ((Endpoint
&& *Endpoint
) ||
589 (Options
&& *Options
)) {
591 if (Endpoint
&& *Endpoint
) {
592 data
+= RPCRT4_strcopyA(data
, Endpoint
);
593 if (Options
&& *Options
) *data
++ = ',';
595 if (Options
&& *Options
) {
596 data
+= RPCRT4_strcopyA(data
, Options
);
605 /***********************************************************************
606 * RpcStringBindingComposeW (RPCRT4.@)
608 RPC_STATUS WINAPI
RpcStringBindingComposeW( LPWSTR ObjUuid
, LPWSTR Protseq
,
609 LPWSTR NetworkAddr
, LPWSTR Endpoint
,
610 LPWSTR Options
, LPWSTR
* StringBinding
)
615 TRACE("(%s,%s,%s,%s,%s,%p)\n",
616 debugstr_w( ObjUuid
), debugstr_w( Protseq
),
617 debugstr_w( NetworkAddr
), debugstr_w( Endpoint
),
618 debugstr_w( Options
), StringBinding
);
620 if (ObjUuid
&& *ObjUuid
) len
+= strlenW(ObjUuid
) + 1;
621 if (Protseq
&& *Protseq
) len
+= strlenW(Protseq
) + 1;
622 if (NetworkAddr
&& *NetworkAddr
) len
+= strlenW(NetworkAddr
);
623 if (Endpoint
&& *Endpoint
) len
+= strlenW(Endpoint
) + 2;
624 if (Options
&& *Options
) len
+= strlenW(Options
) + 2;
626 data
= HeapAlloc(GetProcessHeap(), 0, len
*sizeof(WCHAR
));
627 *StringBinding
= data
;
629 if (ObjUuid
&& *ObjUuid
) {
630 data
+= RPCRT4_strcopyW(data
, ObjUuid
);
633 if (Protseq
&& *Protseq
) {
634 data
+= RPCRT4_strcopyW(data
, Protseq
);
637 if (NetworkAddr
&& *NetworkAddr
) {
638 data
+= RPCRT4_strcopyW(data
, NetworkAddr
);
640 if ((Endpoint
&& *Endpoint
) ||
641 (Options
&& *Options
)) {
643 if (Endpoint
&& *Endpoint
) {
644 data
+= RPCRT4_strcopyW(data
, Endpoint
);
645 if (Options
&& *Options
) *data
++ = ',';
647 if (Options
&& *Options
) {
648 data
+= RPCRT4_strcopyW(data
, Options
);
658 /***********************************************************************
659 * RpcStringBindingParseA (RPCRT4.@)
661 RPC_STATUS WINAPI
RpcStringBindingParseA( LPSTR StringBinding
, LPSTR
*ObjUuid
,
662 LPSTR
*Protseq
, LPSTR
*NetworkAddr
,
663 LPSTR
*Endpoint
, LPSTR
*Options
)
666 static const char ep_opt
[] = "endpoint=";
668 TRACE("(%s,%p,%p,%p,%p,%p)\n", debugstr_a(StringBinding
),
669 ObjUuid
, Protseq
, NetworkAddr
, Endpoint
, Options
);
671 if (ObjUuid
) *ObjUuid
= NULL
;
672 if (Protseq
) *Protseq
= NULL
;
673 if (NetworkAddr
) *NetworkAddr
= NULL
;
674 if (Endpoint
) *Endpoint
= NULL
;
675 if (Options
) *Options
= NULL
;
677 data
= StringBinding
;
679 next
= strchr(data
, '@');
681 if (ObjUuid
) *ObjUuid
= RPCRT4_strndupA(data
, next
- data
);
685 next
= strchr(data
, ':');
687 if (Protseq
) *Protseq
= RPCRT4_strndupA(data
, next
- data
);
691 next
= strchr(data
, '[');
695 if (NetworkAddr
) *NetworkAddr
= RPCRT4_strndupA(data
, next
- data
);
697 close
= strchr(data
, ']');
698 if (!close
) goto fail
;
700 /* tokenize options */
701 while (data
< close
) {
702 next
= strchr(data
, ',');
703 if (!next
|| next
> close
) next
= close
;
704 /* FIXME: this is kind of inefficient */
705 opt
= RPCRT4_strndupA(data
, next
- data
);
709 next
= strchr(opt
, '=');
711 /* not an option, must be an endpoint */
712 if (*Endpoint
) goto fail
;
715 if (strncmp(opt
, ep_opt
, strlen(ep_opt
)) == 0) {
716 /* endpoint option */
717 if (*Endpoint
) goto fail
;
718 *Endpoint
= RPCRT4_strdupA(next
+1);
719 HeapFree(GetProcessHeap(), 0, opt
);
723 /* FIXME: this is kind of inefficient */
724 *Options
= RPCRT4_strconcatA(*Options
, opt
);
725 HeapFree(GetProcessHeap(), 0, opt
);
733 if (*data
) goto fail
;
735 else if (NetworkAddr
)
736 *NetworkAddr
= RPCRT4_strdupA(data
);
741 if (ObjUuid
) RpcStringFreeA((unsigned char**)ObjUuid
);
742 if (Protseq
) RpcStringFreeA((unsigned char**)Protseq
);
743 if (NetworkAddr
) RpcStringFreeA((unsigned char**)NetworkAddr
);
744 if (Endpoint
) RpcStringFreeA((unsigned char**)Endpoint
);
745 if (Options
) RpcStringFreeA((unsigned char**)Options
);
746 return RPC_S_INVALID_STRING_BINDING
;
749 /***********************************************************************
750 * RpcStringBindingParseW (RPCRT4.@)
752 RPC_STATUS WINAPI
RpcStringBindingParseW( LPWSTR StringBinding
, LPWSTR
*ObjUuid
,
753 LPWSTR
*Protseq
, LPWSTR
*NetworkAddr
,
754 LPWSTR
*Endpoint
, LPWSTR
*Options
)
757 static const WCHAR ep_opt
[] = {'e','n','d','p','o','i','n','t','=',0};
759 TRACE("(%s,%p,%p,%p,%p,%p)\n", debugstr_w(StringBinding
),
760 ObjUuid
, Protseq
, NetworkAddr
, Endpoint
, Options
);
762 if (ObjUuid
) *ObjUuid
= NULL
;
763 if (Protseq
) *Protseq
= NULL
;
764 if (NetworkAddr
) *NetworkAddr
= NULL
;
765 if (Endpoint
) *Endpoint
= NULL
;
766 if (Options
) *Options
= NULL
;
768 data
= StringBinding
;
770 next
= strchrW(data
, '@');
772 if (ObjUuid
) *ObjUuid
= RPCRT4_strndupW(data
, next
- data
);
776 next
= strchrW(data
, ':');
778 if (Protseq
) *Protseq
= RPCRT4_strndupW(data
, next
- data
);
782 next
= strchrW(data
, '[');
786 if (NetworkAddr
) *NetworkAddr
= RPCRT4_strndupW(data
, next
- data
);
788 close
= strchrW(data
, ']');
789 if (!close
) goto fail
;
791 /* tokenize options */
792 while (data
< close
) {
793 next
= strchrW(data
, ',');
794 if (!next
|| next
> close
) next
= close
;
795 /* FIXME: this is kind of inefficient */
796 opt
= RPCRT4_strndupW(data
, next
- data
);
800 next
= strchrW(opt
, '=');
802 /* not an option, must be an endpoint */
803 if (*Endpoint
) goto fail
;
806 if (strncmpW(opt
, ep_opt
, strlenW(ep_opt
)) == 0) {
807 /* endpoint option */
808 if (*Endpoint
) goto fail
;
809 *Endpoint
= RPCRT4_strdupW(next
+1);
810 HeapFree(GetProcessHeap(), 0, opt
);
814 /* FIXME: this is kind of inefficient */
815 *Options
= RPCRT4_strconcatW(*Options
, opt
);
816 HeapFree(GetProcessHeap(), 0, opt
);
824 if (*data
) goto fail
;
825 } else if (NetworkAddr
)
826 *NetworkAddr
= RPCRT4_strdupW(data
);
831 if (ObjUuid
) RpcStringFreeW(ObjUuid
);
832 if (Protseq
) RpcStringFreeW(Protseq
);
833 if (NetworkAddr
) RpcStringFreeW(NetworkAddr
);
834 if (Endpoint
) RpcStringFreeW(Endpoint
);
835 if (Options
) RpcStringFreeW(Options
);
836 return RPC_S_INVALID_STRING_BINDING
;
839 /***********************************************************************
840 * RpcBindingFree (RPCRT4.@)
842 RPC_STATUS WINAPI
RpcBindingFree( RPC_BINDING_HANDLE
* Binding
)
845 TRACE("(%p) = %p\n", Binding
, *Binding
);
846 status
= RPCRT4_DestroyBinding(*Binding
);
847 if (status
== RPC_S_OK
) *Binding
= 0;
851 /***********************************************************************
852 * RpcBindingVectorFree (RPCRT4.@)
854 RPC_STATUS WINAPI
RpcBindingVectorFree( RPC_BINDING_VECTOR
** BindingVector
)
859 TRACE("(%p)\n", BindingVector
);
860 for (c
=0; c
<(*BindingVector
)->Count
; c
++) {
861 status
= RpcBindingFree(&(*BindingVector
)->BindingH
[c
]);
863 HeapFree(GetProcessHeap(), 0, *BindingVector
);
864 *BindingVector
= NULL
;
868 /***********************************************************************
869 * RpcBindingInqObject (RPCRT4.@)
871 RPC_STATUS WINAPI
RpcBindingInqObject( RPC_BINDING_HANDLE Binding
, UUID
* ObjectUuid
)
873 RpcBinding
* bind
= (RpcBinding
*)Binding
;
875 TRACE("(%p,%p) = %s\n", Binding
, ObjectUuid
, debugstr_guid(&bind
->ObjectUuid
));
876 memcpy(ObjectUuid
, &bind
->ObjectUuid
, sizeof(UUID
));
880 /***********************************************************************
881 * RpcBindingSetObject (RPCRT4.@)
883 RPC_STATUS WINAPI
RpcBindingSetObject( RPC_BINDING_HANDLE Binding
, UUID
* ObjectUuid
)
885 RpcBinding
* bind
= (RpcBinding
*)Binding
;
887 TRACE("(%p,%s)\n", Binding
, debugstr_guid(ObjectUuid
));
888 if (bind
->server
) return RPC_S_WRONG_KIND_OF_BINDING
;
889 return RPCRT4_SetBindingObject(Binding
, ObjectUuid
);
892 /***********************************************************************
893 * RpcBindingFromStringBindingA (RPCRT4.@)
895 RPC_STATUS WINAPI
RpcBindingFromStringBindingA( LPSTR StringBinding
, RPC_BINDING_HANDLE
* Binding
)
898 RpcBinding
* bind
= NULL
;
899 LPSTR ObjectUuid
, Protseq
, NetworkAddr
, Endpoint
, Options
;
902 TRACE("(%s,%p)\n", debugstr_a(StringBinding
), Binding
);
904 ret
= RpcStringBindingParseA(StringBinding
, &ObjectUuid
, &Protseq
,
905 &NetworkAddr
, &Endpoint
, &Options
);
906 if (ret
!= RPC_S_OK
) return ret
;
908 ret
= UuidFromStringA(ObjectUuid
, &Uuid
);
911 ret
= RPCRT4_CreateBindingA(&bind
, FALSE
, Protseq
);
913 ret
= RPCRT4_SetBindingObject(bind
, &Uuid
);
915 ret
= RPCRT4_CompleteBindingA(bind
, NetworkAddr
, Endpoint
, Options
);
917 RpcStringFreeA((unsigned char**)&Options
);
918 RpcStringFreeA((unsigned char**)&Endpoint
);
919 RpcStringFreeA((unsigned char**)&NetworkAddr
);
920 RpcStringFreeA((unsigned char**)&Protseq
);
921 RpcStringFreeA((unsigned char**)&ObjectUuid
);
924 *Binding
= (RPC_BINDING_HANDLE
)bind
;
926 RPCRT4_DestroyBinding(bind
);
931 /***********************************************************************
932 * RpcBindingFromStringBindingW (RPCRT4.@)
934 RPC_STATUS WINAPI
RpcBindingFromStringBindingW( LPWSTR StringBinding
, RPC_BINDING_HANDLE
* Binding
)
937 RpcBinding
* bind
= NULL
;
938 LPWSTR ObjectUuid
, Protseq
, NetworkAddr
, Endpoint
, Options
;
941 TRACE("(%s,%p)\n", debugstr_w(StringBinding
), Binding
);
943 ret
= RpcStringBindingParseW(StringBinding
, &ObjectUuid
, &Protseq
,
944 &NetworkAddr
, &Endpoint
, &Options
);
945 if (ret
!= RPC_S_OK
) return ret
;
947 ret
= UuidFromStringW(ObjectUuid
, &Uuid
);
950 ret
= RPCRT4_CreateBindingW(&bind
, FALSE
, Protseq
);
952 ret
= RPCRT4_SetBindingObject(bind
, &Uuid
);
954 ret
= RPCRT4_CompleteBindingW(bind
, NetworkAddr
, Endpoint
, Options
);
956 RpcStringFreeW(&Options
);
957 RpcStringFreeW(&Endpoint
);
958 RpcStringFreeW(&NetworkAddr
);
959 RpcStringFreeW(&Protseq
);
960 RpcStringFreeW(&ObjectUuid
);
963 *Binding
= (RPC_BINDING_HANDLE
)bind
;
965 RPCRT4_DestroyBinding(bind
);
970 /***********************************************************************
971 * RpcBindingToStringBindingA (RPCRT4.@)
973 RPC_STATUS WINAPI
RpcBindingToStringBindingA( RPC_BINDING_HANDLE Binding
, LPSTR
* StringBinding
)
976 RpcBinding
* bind
= (RpcBinding
*)Binding
;
979 TRACE("(%p,%p)\n", Binding
, StringBinding
);
981 ret
= UuidToStringA(&bind
->ObjectUuid
, (unsigned char**)&ObjectUuid
);
982 if (ret
!= RPC_S_OK
) return ret
;
984 ret
= RpcStringBindingComposeA(ObjectUuid
, bind
->Protseq
, bind
->NetworkAddr
,
985 bind
->Endpoint
, NULL
, StringBinding
);
987 RpcStringFreeA((unsigned char**)&ObjectUuid
);
992 /***********************************************************************
993 * RpcBindingToStringBindingW (RPCRT4.@)
995 RPC_STATUS WINAPI
RpcBindingToStringBindingW( RPC_BINDING_HANDLE Binding
, LPWSTR
* StringBinding
)
999 TRACE("(%p,%p)\n", Binding
, StringBinding
);
1000 ret
= RpcBindingToStringBindingA(Binding
, &str
);
1001 *StringBinding
= RPCRT4_strdupAtoW(str
);
1002 RpcStringFreeA((unsigned char**)&str
);
1006 /***********************************************************************
1007 * I_RpcBindingSetAsync (RPCRT4.@)
1009 * Exists in win9x and winNT, but with different number of arguments
1010 * (9x version has 3 arguments, NT has 2).
1012 RPC_STATUS WINAPI
I_RpcBindingSetAsync( RPC_BINDING_HANDLE Binding
, RPC_BLOCKING_FN BlockingFn
)
1014 RpcBinding
* bind
= (RpcBinding
*)Binding
;
1016 TRACE( "(%p,%p): stub\n", Binding
, BlockingFn
);
1018 bind
->BlockingFn
= BlockingFn
;
1023 /***********************************************************************
1024 * RpcNetworkIsProtSeqValidA (RPCRT4.@)
1026 RPC_STATUS RPC_ENTRY
RpcNetworkIsProtSeqValidA(unsigned char *protseq
) {
1027 UNICODE_STRING protseqW
;
1029 if (!protseq
) return RPC_S_INVALID_RPC_PROTSEQ
; /* ? */
1031 if (RtlCreateUnicodeStringFromAsciiz(&protseqW
, protseq
)) {
1032 RPC_STATUS ret
= RpcNetworkIsProtSeqValidW(protseqW
.Buffer
);
1033 RtlFreeUnicodeString(&protseqW
);
1035 } else return RPC_S_OUT_OF_MEMORY
;
1038 /***********************************************************************
1039 * RpcNetworkIsProtSeqValidW (RPCRT4.@)
1041 * Checks if the given protocol sequence is known by the RPC system.
1042 * If it is, returns RPC_S_OK, otherwise RPC_S_PROTSEQ_NOT_SUPPORTED.
1044 * We currently support:
1045 * ncalrpc local-only rpc over LPC (LPC is not really used)
1046 * ncacn_np rpc over named pipes
1048 RPC_STATUS RPC_ENTRY
RpcNetworkIsProtSeqValidW(LPWSTR protseq
) {
1049 static const WCHAR protseqsW
[][15] = {
1050 {'n','c','a','l','r','p','c',0},
1051 {'n','c','a','c','n','_','n','p',0}
1053 static const int count
= sizeof(protseqsW
) / sizeof(protseqsW
[0]);
1056 if (!protseq
) return RPC_S_INVALID_RPC_PROTSEQ
; /* ? */
1058 for (i
= 0; i
< count
; i
++) {
1059 if (!strcmpW(protseq
, protseqsW
[i
])) return RPC_S_OK
;
1062 FIXME("Unknown protseq %s - we probably need to implement it one day\n", debugstr_w(protseq
));
1063 return RPC_S_PROTSEQ_NOT_SUPPORTED
;