lok: vcl: fix multiple floatwin removal case more robustly.
[LibreOffice.git] / sal / osl / w32 / pipe.cxx
blob2e469b93e8c52d0c3014525221cf35a0293e67ca
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "system.h"
22 #include <osl/pipe.h>
23 #include <osl/diagnose.h>
24 #include <osl/thread.h>
25 #include <osl/mutex.h>
26 #include <osl/conditn.h>
27 #include <osl/interlck.h>
28 #include <osl/process.h>
29 #include <rtl/alloc.h>
30 #include <sal/log.hxx>
31 #include <o3tl/char16_t2wchar_t.hxx>
33 #include <cassert>
34 #include <string.h>
36 #define PIPESYSTEM "\\\\.\\pipe\\"
37 #define PIPEPREFIX "OSL_PIPE_"
39 typedef struct
41 sal_uInt32 m_Size;
42 sal_uInt32 m_ReadPos;
43 sal_uInt32 m_WritePos;
44 BYTE m_Data[1];
46 } oslPipeBuffer;
48 struct oslPipeImpl
50 oslInterlockedCount m_Reference;
51 HANDLE m_File;
52 HANDLE m_NamedObject;
53 PSECURITY_ATTRIBUTES m_Security;
54 HANDLE m_ReadEvent;
55 HANDLE m_WriteEvent;
56 HANDLE m_AcceptEvent;
57 rtl_uString* m_Name;
58 oslPipeError m_Error;
59 bool m_bClosed;
62 static oslPipe osl_createPipeImpl(void)
64 oslPipe pPipe;
66 pPipe = static_cast< oslPipe >(rtl_allocateZeroMemory(sizeof(struct oslPipeImpl)));
68 pPipe->m_bClosed = false;
69 pPipe->m_Reference = 0;
70 pPipe->m_Name = nullptr;
71 pPipe->m_File = INVALID_HANDLE_VALUE;
72 pPipe->m_NamedObject = nullptr;
74 pPipe->m_ReadEvent = CreateEventW(nullptr, TRUE, FALSE, nullptr);
75 pPipe->m_WriteEvent = CreateEventW(nullptr, TRUE, FALSE, nullptr);
76 pPipe->m_AcceptEvent = CreateEventW(nullptr, TRUE, FALSE, nullptr);
78 return pPipe;
81 static void osl_destroyPipeImpl(oslPipe pPipe)
83 if (pPipe)
85 if (pPipe->m_NamedObject)
86 CloseHandle(pPipe->m_NamedObject);
88 if (pPipe->m_Security)
90 free(pPipe->m_Security->lpSecurityDescriptor);
91 free(pPipe->m_Security);
94 CloseHandle(pPipe->m_ReadEvent);
95 CloseHandle(pPipe->m_WriteEvent);
96 CloseHandle(pPipe->m_AcceptEvent);
98 if (pPipe->m_Name)
99 rtl_uString_release(pPipe->m_Name);
101 free(pPipe);
105 oslPipe SAL_CALL osl_createPipe(rtl_uString *strPipeName, oslPipeOptions Options,
106 oslSecurity Security)
108 rtl_uString* name = nullptr;
109 rtl_uString* path = nullptr;
110 rtl_uString* temp = nullptr;
111 oslPipe pPipe;
113 PSECURITY_ATTRIBUTES pSecAttr = nullptr;
115 rtl_uString_newFromAscii(&path, PIPESYSTEM);
116 rtl_uString_newFromAscii(&name, PIPEPREFIX);
118 if (Security)
120 rtl_uString *Ident = nullptr;
121 rtl_uString *Delim = nullptr;
123 OSL_VERIFY(osl_getUserIdent(Security, &Ident));
124 rtl_uString_newFromAscii(&Delim, "_");
126 rtl_uString_newConcat(&temp, name, Ident);
127 rtl_uString_newConcat(&name, temp, Delim);
129 rtl_uString_release(Ident);
130 rtl_uString_release(Delim);
132 else
134 if (Options & osl_Pipe_CREATE)
136 PSECURITY_DESCRIPTOR pSecDesc;
138 pSecDesc = static_cast< PSECURITY_DESCRIPTOR >(malloc(SECURITY_DESCRIPTOR_MIN_LENGTH));
140 /* add a NULL disc. ACL to the security descriptor */
141 OSL_VERIFY(InitializeSecurityDescriptor(pSecDesc, SECURITY_DESCRIPTOR_REVISION));
142 OSL_VERIFY(SetSecurityDescriptorDacl(pSecDesc, TRUE, nullptr, FALSE));
144 pSecAttr = static_cast< PSECURITY_ATTRIBUTES >(malloc(sizeof(SECURITY_ATTRIBUTES)));
145 pSecAttr->nLength = sizeof(SECURITY_ATTRIBUTES);
146 pSecAttr->lpSecurityDescriptor = pSecDesc;
147 pSecAttr->bInheritHandle = TRUE;
151 rtl_uString_assign(&temp, name);
152 rtl_uString_newConcat(&name, temp, strPipeName);
154 /* alloc memory */
155 pPipe = osl_createPipeImpl();
157 assert(pPipe); // if osl_createPipeImpl() cannot init. a new pipe, this is a failure
159 osl_atomic_increment(&(pPipe->m_Reference));
161 /* build system pipe name */
162 rtl_uString_assign(&temp, path);
163 rtl_uString_newConcat(&path, temp, name);
164 rtl_uString_release(temp);
165 temp = nullptr;
167 if (Options & osl_Pipe_CREATE)
169 SetLastError(ERROR_SUCCESS);
171 pPipe->m_NamedObject = CreateMutexW(nullptr, FALSE, o3tl::toW(name->buffer));
173 if (pPipe->m_NamedObject)
175 if (GetLastError() != ERROR_ALREADY_EXISTS)
177 pPipe->m_Security = pSecAttr;
178 rtl_uString_assign(&pPipe->m_Name, name);
180 /* try to open system pipe */
181 pPipe->m_File = CreateNamedPipeW(
182 o3tl::toW(path->buffer),
183 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
184 PIPE_WAIT | PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
185 PIPE_UNLIMITED_INSTANCES,
186 4096, 4096,
187 NMPWAIT_WAIT_FOREVER,
188 pPipe->m_Security);
190 if (pPipe->m_File != INVALID_HANDLE_VALUE)
192 rtl_uString_release( name );
193 rtl_uString_release( path );
195 return pPipe;
198 else
200 CloseHandle(pPipe->m_NamedObject);
201 pPipe->m_NamedObject = nullptr;
205 else
207 BOOL bPipeAvailable;
211 /* free instance should be available first */
212 bPipeAvailable = WaitNamedPipeW(o3tl::toW(path->buffer), NMPWAIT_WAIT_FOREVER);
214 /* first try to open system pipe */
215 if (bPipeAvailable)
217 pPipe->m_File = CreateFileW(
218 o3tl::toW(path->buffer),
219 GENERIC_READ|GENERIC_WRITE,
220 FILE_SHARE_READ | FILE_SHARE_WRITE,
221 nullptr,
222 OPEN_EXISTING,
223 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
224 nullptr);
226 if (pPipe->m_File != INVALID_HANDLE_VALUE)
228 // We got it !
229 rtl_uString_release(name);
230 rtl_uString_release(path);
232 // We should try to transfer our privilege to become foreground process
233 // to the other process, so that it may show popups (otherwise, they might
234 // be blocked by SPI_GETFOREGROUNDLOCKTIMEOUT setting -
235 // see SystemParametersInfo function at MSDN
236 ULONG ServerProcessId = 0;
237 if (GetNamedPipeServerProcessId(pPipe->m_File, &ServerProcessId))
238 AllowSetForegroundWindow(ServerProcessId);
240 return pPipe;
242 else
244 // Pipe instance maybe caught by another client -> try again
247 } while (bPipeAvailable);
250 /* if we reach here something went wrong */
251 osl_destroyPipeImpl(pPipe);
253 return nullptr;
256 void SAL_CALL osl_acquirePipe(oslPipe pPipe)
258 osl_atomic_increment(&(pPipe->m_Reference));
261 void SAL_CALL osl_releasePipe(oslPipe pPipe)
263 if (!pPipe)
264 return;
266 if (osl_atomic_decrement(&(pPipe->m_Reference)) == 0)
268 if (!pPipe->m_bClosed)
269 osl_closePipe(pPipe);
271 osl_destroyPipeImpl(pPipe);
275 void SAL_CALL osl_closePipe(oslPipe pPipe)
277 if (pPipe && !pPipe->m_bClosed)
279 pPipe->m_bClosed = true;
280 /* if we have a system pipe close it */
281 if (pPipe->m_File != INVALID_HANDLE_VALUE)
283 DisconnectNamedPipe(pPipe->m_File);
284 CloseHandle(pPipe->m_File);
289 oslPipe SAL_CALL osl_acceptPipe(oslPipe pPipe)
291 oslPipe pAcceptedPipe = nullptr;
293 OVERLAPPED os;
295 DWORD nBytesTransfered;
296 rtl_uString* path = nullptr;
297 rtl_uString* temp = nullptr;
299 SAL_WARN_IF(!pPipe, "sal.osl.pipe", "osl_acceptPipe: invalid pipe");
300 if (!pPipe)
301 return nullptr;
303 SAL_WARN_IF(pPipe->m_File == INVALID_HANDLE_VALUE, "sal.osl.pipe", "osl_acceptPipe: invalid handle");
305 memset(&os, 0, sizeof(OVERLAPPED));
306 os.hEvent = pPipe->m_AcceptEvent;
307 ResetEvent(pPipe->m_AcceptEvent);
309 if (!ConnectNamedPipe(pPipe->m_File, &os))
311 switch (GetLastError())
313 case ERROR_PIPE_CONNECTED: // Client already connected to pipe
314 case ERROR_NO_DATA: // Client was connected but has already closed pipe end
315 // should only appear in nonblocking mode but in fact does
316 // in blocking asynchronous mode.
317 break;
318 case ERROR_PIPE_LISTENING: // Only for nonblocking mode but see ERROR_NO_DATA
319 case ERROR_IO_PENDING: // This is normal if not client is connected yet
320 case ERROR_MORE_DATA: // Should not happen
321 // blocking call to accept
322 if( !GetOverlappedResult(pPipe->m_File, &os, &nBytesTransfered, TRUE))
324 // Possible error could be that between ConnectNamedPipe and
325 // GetOverlappedResult a connect took place.
327 switch (GetLastError())
329 case ERROR_PIPE_CONNECTED: // Pipe was already connected
330 case ERROR_NO_DATA: // Pipe was connected but client has already closed -> ver fast client ;-)
331 break; // Everything's fine !!!
332 default:
333 // Something went wrong
334 return nullptr;
337 break;
338 default: // All other error say that somethings going wrong.
339 return nullptr;
343 pAcceptedPipe = osl_createPipeImpl();
344 assert(pAcceptedPipe); // should never be the case that an oslPipe cannot be initialized
346 osl_atomic_increment(&(pAcceptedPipe->m_Reference));
347 rtl_uString_assign(&pAcceptedPipe->m_Name, pPipe->m_Name);
348 pAcceptedPipe->m_File = pPipe->m_File;
350 rtl_uString_newFromAscii(&temp, PIPESYSTEM);
351 rtl_uString_newConcat(&path, temp, pPipe->m_Name);
352 rtl_uString_release(temp);
354 // prepare for next accept
355 pPipe->m_File =
356 CreateNamedPipeW(o3tl::toW(path->buffer),
357 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
358 PIPE_WAIT | PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
359 PIPE_UNLIMITED_INSTANCES,
360 4096, 4096,
361 NMPWAIT_WAIT_FOREVER,
362 pAcceptedPipe->m_Security);
363 rtl_uString_release(path);
365 return pAcceptedPipe;
368 sal_Int32 SAL_CALL osl_receivePipe(oslPipe pPipe,
369 void* pBuffer,
370 sal_Int32 BytesToRead)
372 DWORD nBytes;
373 OVERLAPPED os;
375 assert(pPipe);
377 memset(&os, 0, sizeof(OVERLAPPED));
378 os.hEvent = pPipe->m_ReadEvent;
380 ResetEvent(pPipe->m_ReadEvent);
382 if (!ReadFile(pPipe->m_File, pBuffer, BytesToRead, &nBytes, &os) &&
383 ((GetLastError() != ERROR_IO_PENDING) ||
384 !GetOverlappedResult(pPipe->m_File, &os, &nBytes, TRUE)))
386 DWORD lastError = GetLastError();
388 if (lastError == ERROR_MORE_DATA)
390 nBytes = BytesToRead;
392 else
394 if (lastError == ERROR_PIPE_NOT_CONNECTED)
395 nBytes = 0;
396 else
397 nBytes = DWORD(-1);
399 pPipe->m_Error = osl_Pipe_E_ConnectionAbort;
403 return nBytes;
406 sal_Int32 SAL_CALL osl_sendPipe(oslPipe pPipe,
407 const void* pBuffer,
408 sal_Int32 BytesToSend)
410 DWORD nBytes;
411 OVERLAPPED os;
413 assert(pPipe);
415 memset(&os, 0, sizeof(OVERLAPPED));
416 os.hEvent = pPipe->m_WriteEvent;
417 ResetEvent(pPipe->m_WriteEvent);
419 if (!WriteFile(pPipe->m_File, pBuffer, BytesToSend, &nBytes, &os) &&
420 ((GetLastError() != ERROR_IO_PENDING) ||
421 !GetOverlappedResult(pPipe->m_File, &os, &nBytes, TRUE)))
423 if (GetLastError() == ERROR_PIPE_NOT_CONNECTED)
424 nBytes = 0;
425 else
426 nBytes = DWORD(-1);
428 pPipe->m_Error = osl_Pipe_E_ConnectionAbort;
431 return nBytes;
434 sal_Int32 SAL_CALL osl_writePipe(oslPipe pPipe, const void *pBuffer , sal_Int32 n)
436 /* loop until all desired bytes were send or an error occurred */
437 sal_Int32 BytesSend = 0;
438 sal_Int32 BytesToSend = n;
440 SAL_WARN_IF(!pPipe, "sal.osl.pipe", "osl_writePipe: invalid pipe");
441 while (BytesToSend > 0)
443 sal_Int32 RetVal;
445 RetVal= osl_sendPipe(pPipe, pBuffer, BytesToSend);
447 /* error occurred? */
448 if (RetVal <= 0)
449 break;
451 BytesToSend -= RetVal;
452 BytesSend += RetVal;
453 pBuffer= static_cast< sal_Char const* >(pBuffer) + RetVal;
456 return BytesSend;
459 sal_Int32 SAL_CALL osl_readPipe(oslPipe pPipe, void *pBuffer, sal_Int32 n)
461 /* loop until all desired bytes were read or an error occurred */
462 sal_Int32 BytesRead = 0;
463 sal_Int32 BytesToRead = n;
465 SAL_WARN_IF(!pPipe, "sal.osl.pipe", "osl_readPipe: invalid pipe");
466 while (BytesToRead > 0)
468 sal_Int32 RetVal;
469 RetVal= osl_receivePipe(pPipe, pBuffer, BytesToRead);
471 /* error occurred? */
472 if(RetVal <= 0)
473 break;
475 BytesToRead -= RetVal;
476 BytesRead += RetVal;
477 pBuffer= static_cast< sal_Char* >(pBuffer) + RetVal;
479 return BytesRead;
482 oslPipeError SAL_CALL osl_getLastPipeError(oslPipe pPipe)
484 oslPipeError Error;
486 if (pPipe)
488 Error = pPipe->m_Error;
489 pPipe->m_Error = osl_Pipe_E_None;
491 else
493 Error = osl_Pipe_E_NotFound;
496 return Error;
499 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */