curl: remove curl-7.26.0_win-proxy.patch
[LibreOffice.git] / sal / osl / unx / pipe.cxx
blobd903bdd2f2de39da37bb03b45ae65ada8a04a975
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.hxx"
22 #include <o3tl/safeint.hxx>
23 #include <osl/pipe.h>
24 #include <osl/diagnose.h>
25 #include <osl/thread.h>
26 #include <osl/interlck.h>
27 #include <rtl/string.h>
28 #include <rtl/ustring.h>
29 #include <rtl/bootstrap.hxx>
30 #include <sal/log.hxx>
32 #include "sockimpl.hxx"
33 #include "secimpl.hxx"
34 #include "unixerrnostring.hxx"
36 #include <cassert>
37 #include <cstring>
39 #define PIPEDEFAULTPATH "/tmp"
40 #define PIPEALTERNATEPATH "/var/tmp"
42 static oslPipe osl_psz_createPipe(const char *pszPipeName, oslPipeOptions Options, oslSecurity Security);
44 struct
46 int errcode;
47 oslPipeError error;
48 } const PipeError[]= {
49 { 0, osl_Pipe_E_None }, /* no error */
50 { EPROTOTYPE, osl_Pipe_E_NoProtocol }, /* Protocol wrong type for socket */
51 { ENOPROTOOPT, osl_Pipe_E_NoProtocol }, /* Protocol not available */
52 { EPROTONOSUPPORT, osl_Pipe_E_NoProtocol }, /* Protocol not supported */
53 #ifdef ESOCKTNOSUPPORT
54 { ESOCKTNOSUPPORT, osl_Pipe_E_NoProtocol }, /* Socket type not supported */
55 #endif
56 { EPFNOSUPPORT, osl_Pipe_E_NoProtocol }, /* Protocol family not supported */
57 { EAFNOSUPPORT, osl_Pipe_E_NoProtocol }, /* Address family not supported by */
58 /* protocol family */
59 { ENETRESET, osl_Pipe_E_NetworkReset }, /* Network dropped connection because */
60 /* of reset */
61 { ECONNABORTED, osl_Pipe_E_ConnectionAbort }, /* Software caused connection abort */
62 { ECONNRESET, osl_Pipe_E_ConnectionReset }, /* Connection reset by peer */
63 { ENOBUFS, osl_Pipe_E_NoBufferSpace }, /* No buffer space available */
64 { ETIMEDOUT, osl_Pipe_E_TimedOut }, /* Connection timed out */
65 { ECONNREFUSED, osl_Pipe_E_ConnectionRefused }, /* Connection refused */
66 { -1, osl_Pipe_E_invalidError }
69 static oslPipeError osl_PipeErrorFromNative(int nativeType)
71 int i = 0;
73 while ((PipeError[i].error != osl_Pipe_E_invalidError) &&
74 (PipeError[i].errcode != nativeType))
76 i++;
79 return PipeError[i].error;
82 static oslPipe createPipeImpl()
84 oslPipe pPipeImpl;
86 pPipeImpl = static_cast< oslPipe >(calloc(1, sizeof(struct oslPipeImpl)));
87 if (!pPipeImpl)
88 return nullptr;
90 pPipeImpl->m_nRefCount = 1;
91 pPipeImpl->m_bClosed = false;
92 #if defined(CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT)
93 pPipeImpl->m_bIsInShutdown = false;
94 pPipeImpl->m_bIsAccepting = false;
95 #endif
97 return pPipeImpl;
100 static void destroyPipeImpl(oslPipe pImpl)
102 if (pImpl)
103 free(pImpl);
106 oslPipe SAL_CALL osl_createPipe(rtl_uString *ustrPipeName, oslPipeOptions Options, oslSecurity Security)
108 oslPipe pPipe = nullptr;
109 rtl_String* strPipeName = nullptr;
111 if (ustrPipeName)
113 rtl_uString2String(&strPipeName,
114 rtl_uString_getStr(ustrPipeName),
115 rtl_uString_getLength(ustrPipeName),
116 osl_getThreadTextEncoding(),
117 OUSTRING_TO_OSTRING_CVTFLAGS);
118 char* pszPipeName = rtl_string_getStr(strPipeName);
119 pPipe = osl_psz_createPipe(pszPipeName, Options, Security);
121 if (strPipeName)
122 rtl_string_release(strPipeName);
125 return pPipe;
129 static OString
130 getBootstrapSocketPath()
132 OUString pValue;
134 if (rtl::Bootstrap::get("OSL_SOCKET_PATH", pValue))
136 return OUStringToOString(pValue, RTL_TEXTENCODING_UTF8);
138 return "";
141 static oslPipe osl_psz_createPipe(const char *pszPipeName, oslPipeOptions Options,
142 oslSecurity Security)
144 int Flags;
145 size_t len;
146 struct sockaddr_un addr;
148 OString name;
149 oslPipe pPipe;
151 if (access(PIPEDEFAULTPATH, W_OK) == 0)
152 name = PIPEDEFAULTPATH;
153 else if (access(PIPEALTERNATEPATH, W_OK) == 0)
154 name = PIPEALTERNATEPATH;
155 else {
156 name = getBootstrapSocketPath ();
159 name += "/";
161 if (Security)
163 char Ident[256];
165 Ident[0] = '\0';
167 OSL_VERIFY(osl_psz_getUserIdent(Security, Ident, sizeof(Ident)));
169 name += OString::Concat("OSL_PIPE_") + Ident + "_" + pszPipeName;
171 else
173 name += OString::Concat("OSL_PIPE_") + pszPipeName;
176 if (o3tl::make_unsigned(name.getLength()) >= sizeof addr.sun_path)
178 SAL_WARN("sal.osl.pipe", "osl_createPipe: pipe name too long");
179 return nullptr;
182 /* alloc memory */
183 pPipe = createPipeImpl();
185 if (!pPipe)
186 return nullptr;
188 /* create socket */
189 pPipe->m_Socket = socket(AF_UNIX, SOCK_STREAM, 0);
190 if (pPipe->m_Socket < 0)
192 SAL_WARN("sal.osl.pipe", "socket() failed: " << UnixErrnoString(errno));
193 destroyPipeImpl(pPipe);
194 return nullptr;
197 /* set close-on-exec flag */
198 if ((Flags = fcntl(pPipe->m_Socket, F_GETFD, 0)) != -1)
200 Flags |= FD_CLOEXEC;
201 if (fcntl(pPipe->m_Socket, F_SETFD, Flags) == -1)
203 SAL_WARN("sal.osl.pipe", "fcntl() failed: " << UnixErrnoString(errno));
207 memset(&addr, 0, sizeof(addr));
209 SAL_INFO("sal.osl.pipe", "new pipe on fd " << pPipe->m_Socket << " '" << name << "'");
211 addr.sun_family = AF_UNIX;
212 // coverity[fixed_size_dest : FALSE] - safe, see check above
213 strcpy(addr.sun_path, name.getStr());
214 #if defined(FREEBSD)
215 len = SUN_LEN(&addr);
216 #else
217 len = sizeof(addr);
218 #endif
220 if (Options & osl_Pipe_CREATE)
222 struct stat status;
224 /* check if there exists an orphan filesystem entry */
225 if ((stat(name.getStr(), &status) == 0) &&
226 (S_ISSOCK(status.st_mode) || S_ISFIFO(status.st_mode)))
228 if (connect(pPipe->m_Socket, reinterpret_cast< sockaddr* >(&addr), len) >= 0)
230 close (pPipe->m_Socket);
231 destroyPipeImpl(pPipe);
232 return nullptr;
235 unlink(name.getStr());
238 /* ok, fs clean */
239 if (bind(pPipe->m_Socket, reinterpret_cast< sockaddr* >(&addr), len) < 0)
241 SAL_WARN("sal.osl.pipe", "bind() failed: " << UnixErrnoString(errno));
242 close(pPipe->m_Socket);
243 destroyPipeImpl(pPipe);
244 return nullptr;
247 /* Only give access to all if no security handle was specified, otherwise security
248 depends on umask */
250 if (!Security)
251 (void)chmod(name.getStr(),S_IRWXU | S_IRWXG |S_IRWXO);
253 strcpy(pPipe->m_Name, name.getStr()); // safe, see check above
255 if (listen(pPipe->m_Socket, 5) < 0)
257 SAL_WARN("sal.osl.pipe", "listen() failed: " << UnixErrnoString(errno));
258 // cid#1255391 warns about unlink(name) after stat(name, &status)
259 // above, but the intervening call to bind makes those two clearly
260 // unrelated, as it would fail if name existed at that point in
261 // time:
262 // coverity[toctou] - this is bogus
263 unlink(name.getStr()); /* remove filesystem entry */
264 close(pPipe->m_Socket);
265 destroyPipeImpl(pPipe);
266 return nullptr;
269 return pPipe;
272 /* osl_pipe_OPEN */
273 if (access(name.getStr(), F_OK) != -1)
275 if (connect(pPipe->m_Socket, reinterpret_cast< sockaddr* >(&addr), len) >= 0)
276 return pPipe;
278 SAL_WARN("sal.osl.pipe", "connect() failed: " << UnixErrnoString(errno));
281 close (pPipe->m_Socket);
282 destroyPipeImpl(pPipe);
283 return nullptr;
286 void SAL_CALL osl_acquirePipe(oslPipe pPipe)
288 osl_atomic_increment(&(pPipe->m_nRefCount));
291 void SAL_CALL osl_releasePipe(oslPipe pPipe)
293 if (!pPipe)
294 return;
296 if (osl_atomic_decrement(&(pPipe->m_nRefCount)) == 0)
298 if (!pPipe->m_bClosed)
299 osl_closePipe(pPipe);
301 destroyPipeImpl(pPipe);
305 void SAL_CALL osl_closePipe(oslPipe pPipe)
307 int nRet;
308 int ConnFD;
310 if (!pPipe)
311 return;
313 if (pPipe->m_bClosed)
314 return;
316 ConnFD = pPipe->m_Socket;
318 /* Thread does not return from accept on linux, so
319 connect to the accepting pipe
321 #if defined(CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT)
322 struct sockaddr_un addr;
324 if (pPipe->m_bIsAccepting)
326 pPipe->m_bIsInShutdown = true;
327 pPipe->m_Socket = -1;
329 int fd = socket(AF_UNIX, SOCK_STREAM, 0);
330 if (fd < 0)
332 SAL_WARN("sal.osl.pipe", "socket() failed: " << UnixErrnoString(errno));
333 return;
336 memset(&addr, 0, sizeof(addr));
338 SAL_INFO("sal.osl.pipe", "osl_destroyPipe : Pipe Name '" << pPipe->m_Name << "'");
340 addr.sun_family = AF_UNIX;
341 strcpy(addr.sun_path, pPipe->m_Name); // safe, as both are same size
343 nRet = connect(fd, reinterpret_cast< sockaddr* >(&addr), sizeof(addr));
344 if (nRet < 0)
345 SAL_WARN("sal.osl.pipe", "connect() failed: " << UnixErrnoString(errno));
347 close(fd);
349 #endif /* CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT */
351 nRet = shutdown(ConnFD, 2);
352 if (nRet < 0)
353 SAL_WARN("sal.osl.pipe", "shutdown() failed: " << UnixErrnoString(errno));
355 nRet = close(ConnFD);
356 if (nRet < 0)
357 SAL_WARN("sal.osl.pipe", "close() failed: " << UnixErrnoString(errno));
359 /* remove filesystem entry */
360 if (pPipe->m_Name[0] != '\0')
361 unlink(pPipe->m_Name);
363 pPipe->m_bClosed = true;
366 oslPipe SAL_CALL osl_acceptPipe(oslPipe pPipe)
368 int s;
369 oslPipe pAcceptedPipe;
371 SAL_WARN_IF(!pPipe, "sal.osl.pipe", "invalid pipe");
372 if (!pPipe)
373 return nullptr;
375 assert(pPipe->m_Name[0] != '\0'); // you cannot have an empty pipe name
377 #if defined(CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT)
378 pPipe->m_bIsAccepting = true;
379 #endif
381 s = accept(pPipe->m_Socket, nullptr, nullptr);
383 #if defined(CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT)
384 pPipe->m_bIsAccepting = false;
385 #endif
387 if (s < 0)
389 SAL_WARN("sal.osl.pipe", "accept() failed: " << UnixErrnoString(errno));
390 return nullptr;
393 #if defined(CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT)
394 if (pPipe->m_bIsInShutdown)
396 close(s);
397 return nullptr;
399 #endif /* CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT */
401 /* alloc memory */
402 pAcceptedPipe = createPipeImpl();
404 assert(pAcceptedPipe); // should never be the case that an oslPipe cannot be initialized
405 if (!pAcceptedPipe)
407 close(s);
408 return nullptr;
411 /* set close-on-exec flag */
412 int flags;
413 if ((flags = fcntl(s, F_GETFD, 0)) >= 0)
415 flags |= FD_CLOEXEC;
416 if (fcntl(s, F_SETFD, flags) < 0)
417 SAL_WARN("sal.osl.pipe", "fcntl() failed: " << UnixErrnoString(errno));
420 pAcceptedPipe->m_Socket = s;
422 return pAcceptedPipe;
425 sal_Int32 SAL_CALL osl_receivePipe(oslPipe pPipe,
426 void* pBuffer,
427 sal_Int32 BytesToRead)
429 int nRet = 0;
431 SAL_WARN_IF(!pPipe, "sal.osl.pipe", "osl_receivePipe: invalid pipe");
432 if (!pPipe)
434 SAL_WARN("sal.osl.pipe", "osl_receivePipe: Invalid socket");
435 errno=EINVAL;
436 return -1;
439 nRet = recv(pPipe->m_Socket, pBuffer, BytesToRead, 0);
441 if (nRet < 0)
442 SAL_WARN("sal.osl.pipe", "recv() failed: " << UnixErrnoString(errno));
444 return nRet;
447 sal_Int32 SAL_CALL osl_sendPipe(oslPipe pPipe,
448 const void* pBuffer,
449 sal_Int32 BytesToSend)
451 int nRet=0;
453 SAL_WARN_IF(!pPipe, "sal.osl.pipe", "osl_sendPipe: invalid pipe");
454 if (!pPipe)
456 SAL_WARN("sal.osl.pipe", "osl_sendPipe: Invalid socket");
457 errno=EINVAL;
458 return -1;
461 nRet = send(pPipe->m_Socket, pBuffer, BytesToSend, 0);
463 if (nRet <= 0)
464 SAL_WARN("sal.osl.pipe", "send() failed: " << UnixErrnoString(errno));
466 return nRet;
469 oslPipeError SAL_CALL osl_getLastPipeError(SAL_UNUSED_PARAMETER oslPipe)
471 return osl_PipeErrorFromNative(errno);
474 sal_Int32 SAL_CALL osl_writePipe(oslPipe pPipe, const void *pBuffer, sal_Int32 n)
476 /* loop until all desired bytes were send or an error occurred */
477 sal_Int32 BytesSend = 0;
478 sal_Int32 BytesToSend = n;
480 SAL_WARN_IF(!pPipe, "sal.osl.pipe", "osl_writePipe: invalid pipe"); // osl_sendPipe detects invalid pipe
481 while (BytesToSend > 0)
483 sal_Int32 RetVal;
485 RetVal= osl_sendPipe(pPipe, pBuffer, BytesToSend);
487 /* error occurred? */
488 if (RetVal <= 0)
489 break;
491 BytesToSend -= RetVal;
492 BytesSend += RetVal;
493 pBuffer= static_cast< char const* >(pBuffer) + RetVal;
496 return BytesSend;
499 sal_Int32 SAL_CALL osl_readPipe( oslPipe pPipe, void *pBuffer , sal_Int32 n )
501 /* loop until all desired bytes were read or an error occurred */
502 sal_Int32 BytesRead = 0;
503 sal_Int32 BytesToRead = n;
505 SAL_WARN_IF(!pPipe, "sal.osl.pipe", "osl_readPipe: invalid pipe"); // osl_receivePipe detects invalid pipe
506 while (BytesToRead > 0)
508 sal_Int32 RetVal;
509 RetVal= osl_receivePipe(pPipe, pBuffer, BytesToRead);
511 /* error occurred? */
512 if (RetVal <= 0)
513 break;
515 BytesToRead -= RetVal;
516 BytesRead += RetVal;
517 pBuffer= static_cast< char* >(pBuffer) + RetVal;
520 return BytesRead;
523 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */