tdf#130857 qt weld: Delete unused image label object
[LibreOffice.git] / sal / osl / w32 / pipe.cxx
blobc94441e6362abf20d7ac346265cba6302cd997dd
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 struct oslPipeImpl
41 oslInterlockedCount m_Reference;
42 HANDLE m_File;
43 HANDLE m_NamedObject;
44 PSECURITY_ATTRIBUTES m_Security;
45 HANDLE m_ReadEvent;
46 HANDLE m_WriteEvent;
47 HANDLE m_AcceptEvent;
48 rtl_uString* m_Name;
49 oslPipeError m_Error;
50 bool m_bClosed;
53 static oslPipe osl_createPipeImpl(void)
55 oslPipe pPipe;
57 pPipe = static_cast< oslPipe >(rtl_allocateZeroMemory(sizeof(struct oslPipeImpl)));
59 pPipe->m_bClosed = false;
60 pPipe->m_Reference = 0;
61 pPipe->m_Name = nullptr;
62 pPipe->m_File = INVALID_HANDLE_VALUE;
63 pPipe->m_NamedObject = nullptr;
65 pPipe->m_ReadEvent = CreateEventW(nullptr, TRUE, FALSE, nullptr);
66 pPipe->m_WriteEvent = CreateEventW(nullptr, TRUE, FALSE, nullptr);
67 pPipe->m_AcceptEvent = CreateEventW(nullptr, TRUE, FALSE, nullptr);
69 return pPipe;
72 static void osl_destroyPipeImpl(oslPipe pPipe)
74 if (!pPipe)
75 return;
77 if (pPipe->m_NamedObject)
78 CloseHandle(pPipe->m_NamedObject);
80 if (pPipe->m_Security)
82 free(pPipe->m_Security->lpSecurityDescriptor);
83 free(pPipe->m_Security);
86 CloseHandle(pPipe->m_ReadEvent);
87 CloseHandle(pPipe->m_WriteEvent);
88 CloseHandle(pPipe->m_AcceptEvent);
90 if (pPipe->m_Name)
91 rtl_uString_release(pPipe->m_Name);
93 free(pPipe);
96 oslPipe SAL_CALL osl_createPipe(rtl_uString *strPipeName, oslPipeOptions Options,
97 oslSecurity Security)
99 rtl_uString* name = nullptr;
100 rtl_uString* path = nullptr;
101 rtl_uString* temp = nullptr;
102 oslPipe pPipe;
104 PSECURITY_ATTRIBUTES pSecAttr = nullptr;
106 rtl_uString_newFromAscii(&path, PIPESYSTEM);
107 rtl_uString_newFromAscii(&name, PIPEPREFIX);
109 if (Security)
111 rtl_uString *Ident = nullptr;
112 rtl_uString *Delim = nullptr;
114 OSL_VERIFY(osl_getUserIdent(Security, &Ident));
115 rtl_uString_newFromAscii(&Delim, "_");
117 rtl_uString_newConcat(&temp, name, Ident);
118 rtl_uString_newConcat(&name, temp, Delim);
120 rtl_uString_release(Ident);
121 rtl_uString_release(Delim);
123 else
125 if (Options & osl_Pipe_CREATE)
127 PSECURITY_DESCRIPTOR pSecDesc;
129 pSecDesc = static_cast< PSECURITY_DESCRIPTOR >(malloc(SECURITY_DESCRIPTOR_MIN_LENGTH));
130 assert(pSecDesc); // Don't handle OOM conditions
132 /* add a NULL disc. ACL to the security descriptor */
133 OSL_VERIFY(InitializeSecurityDescriptor(pSecDesc, SECURITY_DESCRIPTOR_REVISION));
134 OSL_VERIFY(SetSecurityDescriptorDacl(pSecDesc, TRUE, nullptr, FALSE));
136 pSecAttr = static_cast< PSECURITY_ATTRIBUTES >(malloc(sizeof(SECURITY_ATTRIBUTES)));
137 assert(pSecAttr); // Don't handle OOM conditions
138 pSecAttr->nLength = sizeof(SECURITY_ATTRIBUTES);
139 pSecAttr->lpSecurityDescriptor = pSecDesc;
140 pSecAttr->bInheritHandle = TRUE;
144 rtl_uString_assign(&temp, name);
145 rtl_uString_newConcat(&name, temp, strPipeName);
147 /* alloc memory */
148 pPipe = osl_createPipeImpl();
150 assert(pPipe); // if osl_createPipeImpl() cannot init. a new pipe, this is a failure
152 osl_atomic_increment(&(pPipe->m_Reference));
154 /* build system pipe name */
155 rtl_uString_assign(&temp, path);
156 rtl_uString_newConcat(&path, temp, name);
157 rtl_uString_release(temp);
158 temp = nullptr;
160 if (Options & osl_Pipe_CREATE)
162 SetLastError(ERROR_SUCCESS);
164 pPipe->m_NamedObject = CreateMutexW(nullptr, FALSE, o3tl::toW(name->buffer));
166 if (pPipe->m_NamedObject)
168 if (GetLastError() != ERROR_ALREADY_EXISTS)
170 pPipe->m_Security = pSecAttr;
171 rtl_uString_assign(&pPipe->m_Name, name);
173 /* try to open system pipe */
174 pPipe->m_File = CreateNamedPipeW(
175 o3tl::toW(path->buffer),
176 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
177 PIPE_WAIT | PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
178 PIPE_UNLIMITED_INSTANCES,
179 4096, 4096,
180 NMPWAIT_WAIT_FOREVER,
181 pPipe->m_Security);
183 if (pPipe->m_File != INVALID_HANDLE_VALUE)
185 rtl_uString_release( name );
186 rtl_uString_release( path );
188 return pPipe;
191 else
193 CloseHandle(pPipe->m_NamedObject);
194 pPipe->m_NamedObject = nullptr;
198 else
200 bool bPipeAvailable;
204 /* free instance should be available first */
205 bPipeAvailable = WaitNamedPipeW(o3tl::toW(path->buffer), NMPWAIT_WAIT_FOREVER);
207 /* first try to open system pipe */
208 if (bPipeAvailable)
210 pPipe->m_File = CreateFileW(
211 o3tl::toW(path->buffer),
212 GENERIC_READ|GENERIC_WRITE,
213 FILE_SHARE_READ | FILE_SHARE_WRITE,
214 nullptr,
215 OPEN_EXISTING,
216 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
217 nullptr);
219 if (pPipe->m_File != INVALID_HANDLE_VALUE)
221 // We got it !
222 rtl_uString_release(name);
223 rtl_uString_release(path);
225 // We should try to transfer our privilege to become foreground process
226 // to the other process, so that it may show popups (otherwise, they might
227 // be blocked by SPI_GETFOREGROUNDLOCKTIMEOUT setting -
228 // see SystemParametersInfo function at MSDN
229 ULONG ServerProcessId = 0;
230 if (GetNamedPipeServerProcessId(pPipe->m_File, &ServerProcessId))
231 AllowSetForegroundWindow(ServerProcessId);
233 return pPipe;
235 else
237 // Pipe instance maybe caught by another client -> try again
240 } while (bPipeAvailable);
243 /* if we reach here something went wrong */
244 osl_destroyPipeImpl(pPipe);
246 return nullptr;
249 void SAL_CALL osl_acquirePipe(oslPipe pPipe)
251 osl_atomic_increment(&(pPipe->m_Reference));
254 void SAL_CALL osl_releasePipe(oslPipe pPipe)
256 if (!pPipe)
257 return;
259 if (osl_atomic_decrement(&(pPipe->m_Reference)) == 0)
261 if (!pPipe->m_bClosed)
262 osl_closePipe(pPipe);
264 osl_destroyPipeImpl(pPipe);
268 void SAL_CALL osl_closePipe(oslPipe pPipe)
270 if (pPipe && !pPipe->m_bClosed)
272 pPipe->m_bClosed = true;
273 /* if we have a system pipe close it */
274 if (pPipe->m_File != INVALID_HANDLE_VALUE)
276 DisconnectNamedPipe(pPipe->m_File);
277 CloseHandle(pPipe->m_File);
282 oslPipe SAL_CALL osl_acceptPipe(oslPipe pPipe)
284 oslPipe pAcceptedPipe = nullptr;
286 OVERLAPPED os = {};
288 DWORD nBytesTransferred;
289 rtl_uString* path = nullptr;
290 rtl_uString* temp = nullptr;
292 SAL_WARN_IF(!pPipe, "sal.osl.pipe", "osl_acceptPipe: invalid pipe");
293 if (!pPipe)
294 return nullptr;
296 SAL_WARN_IF(pPipe->m_File == INVALID_HANDLE_VALUE, "sal.osl.pipe", "osl_acceptPipe: invalid handle");
298 os.hEvent = pPipe->m_AcceptEvent;
299 ResetEvent(pPipe->m_AcceptEvent);
301 if (!ConnectNamedPipe(pPipe->m_File, &os))
303 switch (GetLastError())
305 case ERROR_PIPE_CONNECTED: // Client already connected to pipe
306 case ERROR_NO_DATA: // Client was connected but has already closed pipe end
307 // should only appear in nonblocking mode but in fact does
308 // in blocking asynchronous mode.
309 break;
310 case ERROR_PIPE_LISTENING: // Only for nonblocking mode but see ERROR_NO_DATA
311 case ERROR_IO_PENDING: // This is normal if not client is connected yet
312 case ERROR_MORE_DATA: // Should not happen
313 // blocking call to accept
314 if( !GetOverlappedResult(pPipe->m_File, &os, &nBytesTransferred, TRUE))
316 // Possible error could be that between ConnectNamedPipe and
317 // GetOverlappedResult a connect took place.
319 switch (GetLastError())
321 case ERROR_PIPE_CONNECTED: // Pipe was already connected
322 case ERROR_NO_DATA: // Pipe was connected but client has already closed -> ver fast client ;-)
323 break; // Everything's fine !!!
324 default:
325 // Something went wrong
326 return nullptr;
329 break;
330 default: // All other error say that somethings going wrong.
331 return nullptr;
335 pAcceptedPipe = osl_createPipeImpl();
336 assert(pAcceptedPipe); // should never be the case that an oslPipe cannot be initialized
338 osl_atomic_increment(&(pAcceptedPipe->m_Reference));
339 rtl_uString_assign(&pAcceptedPipe->m_Name, pPipe->m_Name);
340 pAcceptedPipe->m_File = pPipe->m_File;
342 rtl_uString_newFromAscii(&temp, PIPESYSTEM);
343 rtl_uString_newConcat(&path, temp, pPipe->m_Name);
344 rtl_uString_release(temp);
346 // prepare for next accept
347 pPipe->m_File =
348 CreateNamedPipeW(o3tl::toW(path->buffer),
349 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
350 PIPE_WAIT | PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
351 PIPE_UNLIMITED_INSTANCES,
352 4096, 4096,
353 NMPWAIT_WAIT_FOREVER,
354 pAcceptedPipe->m_Security);
355 rtl_uString_release(path);
357 return pAcceptedPipe;
360 sal_Int32 SAL_CALL osl_receivePipe(oslPipe pPipe,
361 void* pBuffer,
362 sal_Int32 BytesToRead)
364 DWORD nBytes;
365 OVERLAPPED os = {};
367 assert(pPipe);
369 os.hEvent = pPipe->m_ReadEvent;
371 ResetEvent(pPipe->m_ReadEvent);
373 if (!ReadFile(pPipe->m_File, pBuffer, BytesToRead, &nBytes, &os) &&
374 ((GetLastError() != ERROR_IO_PENDING) ||
375 !GetOverlappedResult(pPipe->m_File, &os, &nBytes, TRUE)))
377 DWORD lastError = GetLastError();
379 if (lastError == ERROR_MORE_DATA)
381 nBytes = BytesToRead;
383 else
385 if (lastError == ERROR_PIPE_NOT_CONNECTED)
386 nBytes = 0;
387 else
388 nBytes = DWORD(-1);
390 pPipe->m_Error = osl_Pipe_E_ConnectionAbort;
394 return nBytes;
397 sal_Int32 SAL_CALL osl_sendPipe(oslPipe pPipe,
398 const void* pBuffer,
399 sal_Int32 BytesToSend)
401 DWORD nBytes;
402 OVERLAPPED os = {};
404 assert(pPipe);
406 os.hEvent = pPipe->m_WriteEvent;
407 ResetEvent(pPipe->m_WriteEvent);
409 if (!WriteFile(pPipe->m_File, pBuffer, BytesToSend, &nBytes, &os) &&
410 ((GetLastError() != ERROR_IO_PENDING) ||
411 !GetOverlappedResult(pPipe->m_File, &os, &nBytes, TRUE)))
413 if (GetLastError() == ERROR_PIPE_NOT_CONNECTED)
414 nBytes = 0;
415 else
416 nBytes = DWORD(-1);
418 pPipe->m_Error = osl_Pipe_E_ConnectionAbort;
421 return nBytes;
424 sal_Int32 SAL_CALL osl_writePipe(oslPipe pPipe, const void *pBuffer , sal_Int32 n)
426 /* loop until all desired bytes were send or an error occurred */
427 sal_Int32 BytesSend = 0;
428 sal_Int32 BytesToSend = n;
430 SAL_WARN_IF(!pPipe, "sal.osl.pipe", "osl_writePipe: invalid pipe");
431 while (BytesToSend > 0)
433 sal_Int32 RetVal;
435 RetVal= osl_sendPipe(pPipe, pBuffer, BytesToSend);
437 /* error occurred? */
438 if (RetVal <= 0)
439 break;
441 BytesToSend -= RetVal;
442 BytesSend += RetVal;
443 pBuffer= static_cast< char const* >(pBuffer) + RetVal;
446 return BytesSend;
449 sal_Int32 SAL_CALL osl_readPipe(oslPipe pPipe, void *pBuffer, sal_Int32 n)
451 /* loop until all desired bytes were read or an error occurred */
452 sal_Int32 BytesRead = 0;
453 sal_Int32 BytesToRead = n;
455 SAL_WARN_IF(!pPipe, "sal.osl.pipe", "osl_readPipe: invalid pipe");
456 while (BytesToRead > 0)
458 sal_Int32 RetVal;
459 RetVal= osl_receivePipe(pPipe, pBuffer, BytesToRead);
461 /* error occurred? */
462 if(RetVal <= 0)
463 break;
465 BytesToRead -= RetVal;
466 BytesRead += RetVal;
467 pBuffer= static_cast< char* >(pBuffer) + RetVal;
469 return BytesRead;
472 oslPipeError SAL_CALL osl_getLastPipeError(oslPipe pPipe)
474 oslPipeError Error;
476 if (pPipe)
478 Error = pPipe->m_Error;
479 pPipe->m_Error = osl_Pipe_E_None;
481 else
483 Error = osl_Pipe_E_NotFound;
486 return Error;
489 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */