Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include "system.hxx"
21 :
22 : #include <osl/pipe.h>
23 : #include <osl/diagnose.h>
24 : #include <osl/thread.h>
25 : #include <osl/interlck.h>
26 : #include <rtl/string.h>
27 : #include <rtl/ustring.h>
28 : #include <rtl/bootstrap.h>
29 : #include <sal/log.hxx>
30 :
31 : #include "sockimpl.hxx"
32 : #include "secimpl.hxx"
33 :
34 : #define PIPEDEFAULTPATH "/tmp"
35 : #define PIPEALTERNATEPATH "/var/tmp"
36 :
37 : #define PIPENAMEMASK "OSL_PIPE_%s"
38 : #define SECPIPENAMEMASK "OSL_PIPE_%s_%s"
39 :
40 : oslPipe SAL_CALL osl_psz_createPipe(const sal_Char *pszPipeName, oslPipeOptions Options, oslSecurity Security);
41 :
42 : static struct
43 : {
44 : int errcode;
45 : oslPipeError error;
46 : } PipeError[]= {
47 : { 0, osl_Pipe_E_None }, /* no error */
48 : { EPROTOTYPE, osl_Pipe_E_NoProtocol }, /* Protocol wrong type for socket */
49 : { ENOPROTOOPT, osl_Pipe_E_NoProtocol }, /* Protocol not available */
50 : { EPROTONOSUPPORT, osl_Pipe_E_NoProtocol }, /* Protocol not supported */
51 : { ESOCKTNOSUPPORT, osl_Pipe_E_NoProtocol }, /* Socket type not supported */
52 : { EPFNOSUPPORT, osl_Pipe_E_NoProtocol }, /* Protocol family not supported */
53 : { EAFNOSUPPORT, osl_Pipe_E_NoProtocol }, /* Address family not supported by */
54 : /* protocol family */
55 : { ENETRESET, osl_Pipe_E_NetworkReset }, /* Network dropped connection because */
56 : /* of reset */
57 : { ECONNABORTED, osl_Pipe_E_ConnectionAbort }, /* Software caused connection abort */
58 : { ECONNRESET, osl_Pipe_E_ConnectionReset }, /* Connection reset by peer */
59 : { ENOBUFS, osl_Pipe_E_NoBufferSpace }, /* No buffer space available */
60 : { ETIMEDOUT, osl_Pipe_E_TimedOut }, /* Connection timed out */
61 : { ECONNREFUSED, osl_Pipe_E_ConnectionRefused }, /* Connection refused */
62 : { -1, osl_Pipe_E_invalidError }
63 : };
64 :
65 : /* reverse map */
66 185 : static oslPipeError osl_PipeErrorFromNative(int nativeType)
67 : {
68 185 : int i = 0;
69 :
70 2305 : while ((PipeError[i].error != osl_Pipe_E_invalidError) &&
71 1935 : (PipeError[i].errcode != nativeType)) i++;
72 :
73 185 : return PipeError[i].error;
74 : }
75 :
76 579 : oslPipe __osl_createPipeImpl()
77 : {
78 : oslPipe pPipeImpl;
79 :
80 579 : pPipeImpl = static_cast<oslPipe>(calloc(1, sizeof(struct oslPipeImpl)));
81 579 : if (pPipeImpl == NULL)
82 0 : return NULL;
83 579 : pPipeImpl->m_nRefCount =1;
84 579 : pPipeImpl->m_bClosed = false;
85 : #if defined(LINUX)
86 579 : pPipeImpl->m_bIsInShutdown = false;
87 579 : pPipeImpl->m_bIsAccepting = false;
88 : #endif
89 579 : return pPipeImpl;
90 : }
91 :
92 569 : void __osl_destroyPipeImpl(oslPipe pImpl)
93 : {
94 569 : if (pImpl != NULL)
95 569 : free(pImpl);
96 569 : }
97 :
98 515 : oslPipe SAL_CALL osl_createPipe(rtl_uString *ustrPipeName, oslPipeOptions Options, oslSecurity Security)
99 : {
100 515 : oslPipe pPipe=0;
101 515 : rtl_String* strPipeName=0;
102 :
103 515 : if ( ustrPipeName != 0 )
104 : {
105 : rtl_uString2String( &strPipeName,
106 515 : rtl_uString_getStr(ustrPipeName),
107 : rtl_uString_getLength(ustrPipeName),
108 515 : osl_getThreadTextEncoding(),
109 1030 : OUSTRING_TO_OSTRING_CVTFLAGS );
110 515 : sal_Char* pszPipeName = rtl_string_getStr(strPipeName);
111 515 : pPipe = osl_psz_createPipe(pszPipeName, Options, Security);
112 :
113 515 : if ( strPipeName != 0 )
114 : {
115 515 : rtl_string_release(strPipeName);
116 : }
117 : }
118 :
119 515 : return pPipe;
120 :
121 : }
122 :
123 : static bool
124 0 : cpyBootstrapSocketPath(sal_Char *name, size_t len)
125 : {
126 0 : bool bRet = false;
127 0 : rtl_uString *pName = 0, *pValue = 0;
128 :
129 0 : rtl_uString_newFromAscii(&pName, "OSL_SOCKET_PATH");
130 :
131 0 : if (rtl_bootstrap_get(pName, &pValue, NULL))
132 : {
133 0 : if (pValue && pValue->length > 0)
134 : {
135 0 : rtl_String *pStrValue = 0;
136 :
137 : rtl_uString2String(&pStrValue, pValue->buffer,
138 : pValue->length, RTL_TEXTENCODING_UTF8,
139 0 : OUSTRING_TO_OSTRING_CVTFLAGS);
140 0 : if (pStrValue)
141 : {
142 0 : if (pStrValue->length > 0)
143 : {
144 0 : size_t nCopy = (len-1 < (size_t)pStrValue->length) ? len-1 : (size_t)pStrValue->length;
145 0 : strncpy (name, pStrValue->buffer, nCopy);
146 0 : name[nCopy] = '\0';
147 0 : bRet = (size_t)pStrValue->length < len;
148 : }
149 0 : rtl_string_release(pStrValue);
150 : }
151 : }
152 0 : rtl_uString_release(pName);
153 : }
154 0 : return bRet;
155 : }
156 :
157 515 : oslPipe SAL_CALL osl_psz_createPipe(const sal_Char *pszPipeName, oslPipeOptions Options,
158 : oslSecurity Security)
159 : {
160 : int Flags;
161 : size_t len;
162 : struct sockaddr_un addr;
163 :
164 : sal_Char name[PATH_MAX + 1];
165 515 : size_t nNameLength = 0;
166 515 : bool bNameTooLong = false;
167 : oslPipe pPipe;
168 :
169 515 : if (access(PIPEDEFAULTPATH, R_OK|W_OK) == 0)
170 : {
171 515 : strncpy(name, PIPEDEFAULTPATH, sizeof(name));
172 : }
173 0 : else if (access(PIPEALTERNATEPATH, R_OK|W_OK) == 0)
174 : {
175 0 : strncpy(name, PIPEALTERNATEPATH, sizeof(name));
176 : }
177 0 : else if (!cpyBootstrapSocketPath (name, sizeof (name)))
178 : {
179 0 : return NULL;
180 : }
181 515 : name[sizeof(name) - 1] = '\0'; // ensure the string is NULL-terminated
182 515 : nNameLength = strlen(name);
183 515 : bNameTooLong = nNameLength > sizeof(name) - 2;
184 :
185 515 : if (!bNameTooLong)
186 : {
187 515 : size_t nRealLength = 0;
188 :
189 515 : strcat(name, "/");
190 515 : ++nNameLength;
191 :
192 515 : if (Security)
193 : {
194 : sal_Char Ident[256];
195 :
196 515 : Ident[0] = '\0';
197 :
198 515 : OSL_VERIFY(osl_psz_getUserIdent(Security, Ident, sizeof(Ident)));
199 :
200 515 : nRealLength = snprintf(&name[nNameLength], sizeof(name) - nNameLength, SECPIPENAMEMASK, Ident, pszPipeName);
201 : }
202 : else
203 : {
204 0 : nRealLength = snprintf(&name[nNameLength], sizeof(name) - nNameLength, PIPENAMEMASK, pszPipeName);
205 : }
206 :
207 515 : bNameTooLong = nRealLength > sizeof(name) - nNameLength - 1;
208 : }
209 :
210 515 : if (bNameTooLong)
211 : {
212 : SAL_WARN("sal.osl.pipe", "osl_createPipe: pipe name too long");
213 0 : return NULL;
214 : }
215 :
216 : /* alloc memory */
217 515 : pPipe = __osl_createPipeImpl();
218 :
219 515 : if (pPipe == NULL)
220 0 : return NULL;
221 :
222 : /* create socket */
223 515 : pPipe->m_Socket = socket(AF_UNIX, SOCK_STREAM, 0);
224 515 : if ( pPipe->m_Socket < 0 )
225 : {
226 : SAL_WARN("sal.osl.pipe", "socket() failed: " << strerror(errno));
227 0 : __osl_destroyPipeImpl(pPipe);
228 0 : return NULL;
229 : }
230 :
231 : /* set close-on-exec flag */
232 515 : if ((Flags = fcntl(pPipe->m_Socket, F_GETFD, 0)) != -1)
233 : {
234 515 : Flags |= FD_CLOEXEC;
235 515 : if (fcntl(pPipe->m_Socket, F_SETFD, Flags) == -1)
236 : {
237 : SAL_WARN("sal.osl.pipe", "fcntl() failed: " << strerror(errno));
238 : }
239 : }
240 :
241 515 : memset(&addr, 0, sizeof(addr));
242 :
243 : SAL_INFO("sal.osl.pipe", "new pipe on fd " << pPipe->m_Socket << " '" << name << "'");
244 :
245 515 : addr.sun_family = AF_UNIX;
246 515 : strncpy(addr.sun_path, name, sizeof(addr.sun_path) - 1);
247 : #if defined(FREEBSD)
248 : len = SUN_LEN(&addr);
249 : #else
250 515 : len = sizeof(addr);
251 : #endif
252 :
253 515 : if ( Options & osl_Pipe_CREATE )
254 : {
255 : struct stat status;
256 :
257 : /* check if there exists an orphan filesystem entry */
258 183 : if ( ( stat(name, &status) == 0) &&
259 2 : ( S_ISSOCK(status.st_mode) || S_ISFIFO(status.st_mode) ) )
260 : {
261 2 : if ( connect(pPipe->m_Socket, reinterpret_cast<sockaddr *>(&addr), len) >= 0 )
262 : {
263 0 : close (pPipe->m_Socket);
264 0 : __osl_destroyPipeImpl(pPipe);
265 0 : return NULL;
266 : }
267 :
268 2 : unlink(name);
269 : }
270 :
271 : /* ok, fs clean */
272 179 : if ( bind(pPipe->m_Socket, reinterpret_cast<sockaddr *>(&addr), len) < 0 )
273 : {
274 : SAL_WARN("sal.osl.pipe", "bind() failed: " << strerror(errno));
275 0 : close (pPipe->m_Socket);
276 0 : __osl_destroyPipeImpl(pPipe);
277 0 : return NULL;
278 : }
279 :
280 : /* Only give access to all if no security handle was specified, otherwise security
281 : depends on umask */
282 :
283 179 : if ( !Security )
284 0 : chmod(name,S_IRWXU | S_IRWXG |S_IRWXO);
285 :
286 179 : strncpy(pPipe->m_Name, name, sizeof(pPipe->m_Name) - 1);
287 :
288 179 : if ( listen(pPipe->m_Socket, 5) < 0 )
289 : {
290 : SAL_WARN("sal.osl.pipe", "listen() failed: " << strerror(errno));
291 : // coverity[toctou] cid#1255391 warns about unlink(name) after
292 : // stat(name, &status) above, but the intervening call to bind makes
293 : // those two clearly unrelated, as it would fail if name existed at
294 : // that point in time:
295 0 : unlink(name); /* remove filesystem entry */
296 0 : close (pPipe->m_Socket);
297 0 : __osl_destroyPipeImpl(pPipe);
298 0 : return NULL;
299 : }
300 :
301 179 : return pPipe;
302 : }
303 : else
304 : { /* osl_pipe_OPEN */
305 336 : if ( access(name, F_OK) != -1 )
306 : {
307 71 : if ( connect( pPipe->m_Socket, reinterpret_cast<sockaddr *>(&addr), len) >= 0 )
308 : {
309 71 : return pPipe;
310 : }
311 :
312 : SAL_WARN("sal.osl.pipe", "connect() failed: " << strerror(errno));
313 : }
314 :
315 265 : close (pPipe->m_Socket);
316 265 : __osl_destroyPipeImpl(pPipe);
317 265 : return NULL;
318 : }
319 : }
320 :
321 2056020 : void SAL_CALL osl_acquirePipe( oslPipe pPipe )
322 : {
323 2056020 : osl_atomic_increment( &(pPipe->m_nRefCount) );
324 2056020 : }
325 :
326 2056317 : void SAL_CALL osl_releasePipe( oslPipe pPipe )
327 : {
328 :
329 2056317 : if( 0 == pPipe )
330 2056317 : return;
331 :
332 2056317 : if( 0 == osl_atomic_decrement( &(pPipe->m_nRefCount) ) )
333 : {
334 304 : if( ! pPipe->m_bClosed )
335 1 : osl_closePipe( pPipe );
336 :
337 304 : __osl_destroyPipeImpl( pPipe );
338 : }
339 : }
340 :
341 424 : void SAL_CALL osl_closePipe( oslPipe pPipe )
342 : {
343 : int nRet;
344 : int ConnFD;
345 :
346 424 : if( ! pPipe )
347 : {
348 119 : return;
349 : }
350 :
351 422 : if( pPipe->m_bClosed )
352 : {
353 115 : return;
354 : }
355 :
356 307 : ConnFD = pPipe->m_Socket;
357 :
358 : /*
359 : Thread does not return from accept on linux, so
360 : connect to the accepting pipe
361 : */
362 : #if defined(LINUX)
363 : struct sockaddr_un addr;
364 :
365 307 : if ( pPipe->m_bIsAccepting )
366 : {
367 178 : pPipe->m_bIsInShutdown = true;
368 178 : pPipe->m_Socket = -1;
369 178 : int fd = socket(AF_UNIX, SOCK_STREAM, 0);
370 178 : if ( fd < 0 )
371 : {
372 : SAL_WARN("sal.osl.pipe", "socket() failed: " << strerror(errno));
373 0 : return;
374 : }
375 178 : memset(&addr, 0, sizeof(addr));
376 :
377 : SAL_INFO("sal.osl.pipe", "osl_destroyPipe : Pipe Name '" << pPipe->m_Name << "'");
378 :
379 178 : addr.sun_family = AF_UNIX;
380 178 : strncpy(addr.sun_path, pPipe->m_Name, sizeof(addr.sun_path) - 1);
381 178 : size_t len = sizeof(addr);
382 :
383 178 : nRet = connect( fd, reinterpret_cast<sockaddr *>(&addr), len);
384 178 : if ( nRet < 0 )
385 : {
386 : SAL_WARN("sal.osl.pipe", "connect() failed: " << strerror(errno));
387 : }
388 178 : close(fd);
389 : }
390 : #endif /* LINUX */
391 :
392 307 : nRet = shutdown(ConnFD, 2);
393 307 : if ( nRet < 0 )
394 : {
395 : SAL_WARN("sal.osl.pipe", "shutdown() failed: " << strerror(errno));
396 : }
397 :
398 307 : nRet = close(ConnFD);
399 307 : if ( nRet < 0 )
400 : {
401 : SAL_WARN("sal.osl.pipe", "close() failed: " << strerror(errno));
402 : }
403 : /* remove filesystem entry */
404 307 : if ( strlen(pPipe->m_Name) > 0 )
405 : {
406 179 : unlink(pPipe->m_Name);
407 : }
408 307 : pPipe->m_bClosed = true;
409 : }
410 :
411 242 : oslPipe SAL_CALL osl_acceptPipe(oslPipe pPipe)
412 : {
413 : int s;
414 : oslPipe pAcceptedPipe;
415 :
416 : OSL_ASSERT(pPipe);
417 242 : if ( pPipe == 0 )
418 : {
419 0 : return NULL;
420 : }
421 :
422 : OSL_ASSERT(strlen(pPipe->m_Name) > 0);
423 :
424 : #if defined(LINUX)
425 242 : pPipe->m_bIsAccepting = true;
426 : #endif
427 :
428 242 : s = accept(pPipe->m_Socket, NULL, NULL);
429 :
430 : #if defined(LINUX)
431 242 : pPipe->m_bIsAccepting = false;
432 : #endif
433 :
434 242 : if (s < 0)
435 : {
436 : SAL_WARN("sal.osl.pipe", "accept() failed: " << strerror(errno));
437 0 : return NULL;
438 : }
439 :
440 : #if defined(LINUX)
441 242 : if ( pPipe->m_bIsInShutdown )
442 : {
443 178 : close(s);
444 178 : return NULL;
445 : }
446 : #endif /* LINUX */
447 : else
448 : {
449 : /* alloc memory */
450 64 : pAcceptedPipe = __osl_createPipeImpl();
451 :
452 : OSL_ASSERT(pAcceptedPipe);
453 64 : if(pAcceptedPipe==NULL)
454 : {
455 0 : close(s);
456 0 : return NULL;
457 : }
458 :
459 : /* set close-on-exec flag */
460 : int flags;
461 64 : if (!((flags = fcntl(s, F_GETFD, 0)) < 0))
462 : {
463 64 : flags |= FD_CLOEXEC;
464 64 : if (fcntl(s, F_SETFD, flags) < 0)
465 : {
466 : SAL_WARN("sal.osl.pipe", "fcntl() failed: " << strerror(errno));
467 : }
468 : }
469 :
470 64 : pAcceptedPipe->m_Socket = s;
471 : }
472 :
473 64 : return pAcceptedPipe;
474 : }
475 :
476 3334567 : sal_Int32 SAL_CALL osl_receivePipe(oslPipe pPipe,
477 : void* pBuffer,
478 : sal_Int32 BytesToRead)
479 : {
480 3334567 : int nRet = 0;
481 :
482 : OSL_ASSERT(pPipe);
483 :
484 3334567 : if ( pPipe == 0 )
485 : {
486 : SAL_WARN("sal.osl.pipe", "osl_receivePipe: Invalid socket");
487 0 : errno=EINVAL;
488 0 : return -1;
489 : }
490 :
491 : nRet = recv(pPipe->m_Socket,
492 : pBuffer,
493 3334567 : BytesToRead, 0);
494 :
495 3334565 : if ( nRet < 0 )
496 : {
497 : SAL_WARN("sal.osl.pipe", "recv() failed: " << strerror(errno));
498 : }
499 :
500 3334565 : return nRet;
501 : }
502 :
503 2720766 : sal_Int32 SAL_CALL osl_sendPipe(oslPipe pPipe,
504 : const void* pBuffer,
505 : sal_Int32 BytesToSend)
506 : {
507 2720766 : int nRet=0;
508 :
509 : OSL_ASSERT(pPipe);
510 :
511 2720766 : if ( pPipe == 0 )
512 : {
513 : SAL_WARN("sal.osl.pipe", "osl_sendPipe: Invalid socket");
514 0 : errno=EINVAL;
515 0 : return -1;
516 : }
517 :
518 : nRet = send(pPipe->m_Socket,
519 : pBuffer,
520 2720766 : BytesToSend, 0);
521 :
522 2720766 : if ( nRet <= 0 )
523 : {
524 : SAL_WARN("sal.osl.pipe", "send() failed: " << strerror(errno));
525 : }
526 :
527 2720766 : return nRet;
528 : }
529 :
530 185 : oslPipeError SAL_CALL osl_getLastPipeError(oslPipe pPipe)
531 : {
532 : (void) pPipe; /* unused */
533 185 : return osl_PipeErrorFromNative(errno);
534 : }
535 :
536 2720766 : sal_Int32 SAL_CALL osl_writePipe( oslPipe pPipe, const void *pBuffer , sal_Int32 n )
537 : {
538 : /* loop until all desired bytes were send or an error occurred */
539 2720766 : sal_Int32 BytesSend= 0;
540 2720766 : sal_Int32 BytesToSend= n;
541 :
542 : OSL_ASSERT(pPipe);
543 8162298 : while (BytesToSend > 0)
544 : {
545 : sal_Int32 RetVal;
546 :
547 2720766 : RetVal= osl_sendPipe(pPipe, pBuffer, BytesToSend);
548 :
549 : /* error occurred? */
550 2720766 : if(RetVal <= 0)
551 : {
552 0 : break;
553 : }
554 :
555 2720766 : BytesToSend -= RetVal;
556 2720766 : BytesSend += RetVal;
557 2720766 : pBuffer= static_cast<sal_Char const *>(pBuffer) + RetVal;
558 : }
559 :
560 2720766 : return BytesSend;
561 : }
562 :
563 2589541 : sal_Int32 SAL_CALL osl_readPipe( oslPipe pPipe, void *pBuffer , sal_Int32 n )
564 : {
565 : /* loop until all desired bytes were read or an error occurred */
566 2589541 : sal_Int32 BytesRead= 0;
567 2589541 : sal_Int32 BytesToRead= n;
568 :
569 : OSL_ASSERT( pPipe );
570 8513328 : while (BytesToRead > 0)
571 : {
572 : sal_Int32 RetVal;
573 3334567 : RetVal= osl_receivePipe(pPipe, pBuffer, BytesToRead);
574 :
575 : /* error occurred? */
576 3334565 : if(RetVal <= 0)
577 : {
578 319 : break;
579 : }
580 :
581 3334246 : BytesToRead -= RetVal;
582 3334246 : BytesRead += RetVal;
583 3334246 : pBuffer= static_cast<sal_Char*>(pBuffer) + RetVal;
584 : }
585 2589539 : return BytesRead;
586 : }
587 :
588 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|