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.h"
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 :
30 : #include "sockimpl.h"
31 :
32 : #define PIPEDEFAULTPATH "/tmp"
33 : #define PIPEALTERNATEPATH "/var/tmp"
34 :
35 : #define PIPENAMEMASK "OSL_PIPE_%s"
36 : #define SECPIPENAMEMASK "OSL_PIPE_%s_%s"
37 :
38 : sal_Bool SAL_CALL osl_psz_getUserIdent(oslSecurity Security, sal_Char *pszIdent, sal_uInt32 nMax);
39 : oslPipe SAL_CALL osl_psz_createPipe(const sal_Char *pszPipeName, oslPipeOptions Options, oslSecurity Security);
40 :
41 :
42 : /*****************************************************************************/
43 : /* enum oslPipeError */
44 : /*****************************************************************************/
45 :
46 : static struct
47 : {
48 : int errcode;
49 : oslPipeError error;
50 : } PipeError[]= {
51 : { 0, osl_Pipe_E_None }, /* no error */
52 : { EPROTOTYPE, osl_Pipe_E_NoProtocol }, /* Protocol wrong type for socket */
53 : { ENOPROTOOPT, osl_Pipe_E_NoProtocol }, /* Protocol not available */
54 : { EPROTONOSUPPORT, osl_Pipe_E_NoProtocol }, /* Protocol not supported */
55 : { ESOCKTNOSUPPORT, osl_Pipe_E_NoProtocol }, /* Socket type not supported */
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 }
67 : };
68 :
69 :
70 : /* map */
71 : /* mfe: NOT USED
72 : static int osl_NativeFromPipeError(oslPipeError errorCode)
73 : {
74 : int i = 0;
75 :
76 : while ((PipeError[i].error != osl_Pipe_E_invalidError) &&
77 : (PipeError[i].error != errorCode)) i++;
78 :
79 : return PipeError[i].errcode;
80 :
81 : }
82 : */
83 :
84 : /* reverse map */
85 57 : static oslPipeError osl_PipeErrorFromNative(int nativeType)
86 : {
87 57 : int i = 0;
88 :
89 1396 : while ((PipeError[i].error != osl_Pipe_E_invalidError) &&
90 1282 : (PipeError[i].errcode != nativeType)) i++;
91 :
92 57 : return PipeError[i].error;
93 : }
94 :
95 :
96 : /* macros */
97 : #define ERROR_TO_NATIVE(x) osl_NativeFromPipeError(x)
98 : #define ERROR_FROM_NATIVE(y) osl_PipeErrorFromNative(y)
99 :
100 :
101 : /*****************************************************************************/
102 : /* osl_create/destroy-PipeImpl */
103 : /*****************************************************************************/
104 :
105 21048 : oslPipe __osl_createPipeImpl()
106 : {
107 : oslPipe pPipeImpl;
108 :
109 21048 : pPipeImpl = (oslPipe)calloc(1, sizeof(struct oslPipeImpl));
110 21048 : pPipeImpl->m_nRefCount =1;
111 21048 : pPipeImpl->m_bClosed = sal_False;
112 : #if defined(LINUX)
113 21048 : pPipeImpl->m_bIsInShutdown = sal_False;
114 21048 : pPipeImpl->m_bIsAccepting = sal_False;
115 : #endif
116 21048 : return pPipeImpl;
117 : }
118 :
119 21048 : void __osl_destroyPipeImpl(oslPipe pImpl)
120 : {
121 21048 : if (pImpl != NULL)
122 21048 : free(pImpl);
123 21048 : }
124 :
125 :
126 : /*****************************************************************************/
127 : /* osl_createPipe */
128 : /*****************************************************************************/
129 21040 : oslPipe SAL_CALL osl_createPipe(rtl_uString *ustrPipeName, oslPipeOptions Options, oslSecurity Security)
130 : {
131 21040 : oslPipe pPipe=0;
132 21040 : rtl_String* strPipeName=0;
133 21040 : sal_Char* pszPipeName=0;
134 :
135 21040 : if ( ustrPipeName != 0 )
136 : {
137 42080 : rtl_uString2String( &strPipeName,
138 21040 : rtl_uString_getStr(ustrPipeName),
139 : rtl_uString_getLength(ustrPipeName),
140 21040 : osl_getThreadTextEncoding(),
141 : OUSTRING_TO_OSTRING_CVTFLAGS );
142 21040 : pszPipeName = rtl_string_getStr(strPipeName);
143 21040 : pPipe = osl_psz_createPipe(pszPipeName, Options, Security);
144 :
145 21040 : if ( strPipeName != 0 )
146 : {
147 21040 : rtl_string_release(strPipeName);
148 : }
149 : }
150 :
151 21040 : return pPipe;
152 :
153 : }
154 :
155 : static sal_Bool
156 0 : cpyBootstrapSocketPath(sal_Char *name, size_t len)
157 : {
158 0 : sal_Bool bRet = sal_False;
159 0 : rtl_uString *pName = 0, *pValue = 0;
160 :
161 0 : rtl_uString_newFromAscii(&pName, "OSL_SOCKET_PATH");
162 :
163 0 : if (rtl_bootstrap_get(pName, &pValue, NULL))
164 : {
165 0 : rtl_String *pStrValue = 0;
166 0 : if (pValue && pValue->length > 0)
167 : {
168 0 : rtl_uString2String(&pStrValue, pValue->buffer,
169 0 : pValue->length, RTL_TEXTENCODING_UTF8,
170 : OUSTRING_TO_OSTRING_CVTFLAGS);
171 0 : if (pStrValue && pStrValue->length > 0)
172 : {
173 0 : size_t nCopy = (len-1 < (size_t)pStrValue->length) ? len-1 : (size_t)pStrValue->length;
174 0 : strncpy (name, pStrValue->buffer, nCopy);
175 0 : name[nCopy] = '\0';
176 0 : bRet = (size_t)pStrValue->length < len;
177 : }
178 0 : rtl_string_release(pStrValue);
179 : }
180 0 : rtl_uString_release(pName);
181 : }
182 0 : return bRet;
183 : }
184 :
185 21040 : oslPipe SAL_CALL osl_psz_createPipe(const sal_Char *pszPipeName, oslPipeOptions Options,
186 : oslSecurity Security)
187 : {
188 : int Flags;
189 : size_t len;
190 : struct sockaddr_un addr;
191 :
192 : sal_Char name[PATH_MAX + 1];
193 21040 : size_t nNameLength = 0;
194 21040 : int bNameTooLong = 0;
195 : oslPipe pPipe;
196 :
197 21040 : if (access(PIPEDEFAULTPATH, R_OK|W_OK) == 0)
198 : {
199 21040 : strncpy(name, PIPEDEFAULTPATH, sizeof(name));
200 : }
201 0 : else if (access(PIPEALTERNATEPATH, R_OK|W_OK) == 0)
202 : {
203 0 : strncpy(name, PIPEALTERNATEPATH, sizeof(name));
204 : }
205 0 : else if (!cpyBootstrapSocketPath (name, sizeof (name)))
206 : {
207 0 : return NULL;
208 : }
209 21040 : name[sizeof(name) - 1] = '\0'; // ensure the string is NULL-terminated
210 21040 : nNameLength = strlen(name);
211 21040 : bNameTooLong = nNameLength > sizeof(name) - 2;
212 :
213 21040 : if (!bNameTooLong)
214 : {
215 21040 : size_t nRealLength = 0;
216 :
217 21040 : strcat(name, "/");
218 21040 : ++nNameLength;
219 :
220 21040 : if (Security)
221 : {
222 : sal_Char Ident[256];
223 :
224 21040 : Ident[0] = '\0';
225 :
226 21040 : OSL_VERIFY(osl_psz_getUserIdent(Security, Ident, sizeof(Ident)));
227 :
228 21040 : nRealLength = snprintf(&name[nNameLength], sizeof(name) - nNameLength, SECPIPENAMEMASK, Ident, pszPipeName);
229 : }
230 : else
231 : {
232 0 : nRealLength = snprintf(&name[nNameLength], sizeof(name) - nNameLength, PIPENAMEMASK, pszPipeName);
233 : }
234 :
235 21040 : bNameTooLong = nRealLength > sizeof(name) - nNameLength - 1;
236 : }
237 :
238 21040 : if (bNameTooLong)
239 : {
240 : OSL_TRACE("osl_createPipe: pipe name too long");
241 0 : return NULL;
242 : }
243 :
244 : /* alloc memory */
245 21040 : pPipe= __osl_createPipeImpl();
246 :
247 : /* create socket */
248 21040 : pPipe->m_Socket = socket(AF_UNIX, SOCK_STREAM, 0);
249 21040 : if ( pPipe->m_Socket < 0 )
250 : {
251 : OSL_TRACE("osl_createPipe socket failed. Errno: %d; %s",errno, strerror(errno));
252 0 : __osl_destroyPipeImpl(pPipe);
253 0 : return NULL;
254 : }
255 :
256 : /* OSL_TRACE("osl_createPipe : new Pipe on fd %i\n",pPipe->m_Socket);*/
257 :
258 : /* set close-on-exec flag */
259 21040 : if ((Flags = fcntl(pPipe->m_Socket, F_GETFD, 0)) != -1)
260 : {
261 21040 : Flags |= FD_CLOEXEC;
262 21040 : if (fcntl(pPipe->m_Socket, F_SETFD, Flags) == -1)
263 : {
264 : OSL_TRACE("osl_createPipe failed changing socket flags. Errno: %d; %s",errno,strerror(errno));
265 : }
266 : }
267 :
268 21040 : memset(&addr, 0, sizeof(addr));
269 :
270 : OSL_TRACE("osl_createPipe : Pipe Name '%s'",name);
271 :
272 21040 : addr.sun_family = AF_UNIX;
273 21040 : strncpy(addr.sun_path, name, sizeof(addr.sun_path) - 1);
274 : #if defined(FREEBSD)
275 : len = SUN_LEN(&addr);
276 : #else
277 21040 : len = sizeof(addr);
278 : #endif
279 :
280 21040 : if ( Options & osl_Pipe_CREATE )
281 : {
282 : struct stat status;
283 :
284 : /* check if there exists an orphan filesystem entry */
285 21 : if ( ( stat(name, &status) == 0) &&
286 5 : ( S_ISSOCK(status.st_mode) || S_ISFIFO(status.st_mode) ) )
287 : {
288 5 : if ( connect(pPipe->m_Socket,(struct sockaddr *)&addr,len) >= 0 )
289 : {
290 : OSL_TRACE("osl_createPipe : Pipe already in use. Errno: %d; %s",errno,strerror(errno));
291 0 : close (pPipe->m_Socket);
292 0 : __osl_destroyPipeImpl(pPipe);
293 0 : return NULL;
294 : }
295 :
296 5 : unlink(name);
297 : }
298 :
299 : /* ok, fs clean */
300 16 : if ( bind(pPipe->m_Socket, (struct sockaddr *)&addr, len) < 0 )
301 : {
302 : OSL_TRACE("osl_createPipe : failed to bind socket. Errno: %d; %s",errno,strerror(errno));
303 0 : close (pPipe->m_Socket);
304 0 : __osl_destroyPipeImpl(pPipe);
305 0 : return NULL;
306 : }
307 :
308 : /* Only give access to all if no security handle was specified, otherwise security
309 : depends on umask */
310 :
311 16 : if ( !Security )
312 0 : chmod(name,S_IRWXU | S_IRWXG |S_IRWXO);
313 :
314 :
315 16 : strncpy(pPipe->m_Name, name, sizeof(pPipe->m_Name) - 1);
316 :
317 16 : if ( listen(pPipe->m_Socket, 5) < 0 )
318 : {
319 : OSL_TRACE("osl_createPipe failed to listen. Errno: %d; %s",errno,strerror(errno));
320 0 : unlink(name); /* remove filesystem entry */
321 0 : close (pPipe->m_Socket);
322 0 : __osl_destroyPipeImpl(pPipe);
323 0 : return NULL;
324 : }
325 :
326 16 : return (pPipe);
327 : }
328 : else
329 : { /* osl_pipe_OPEN */
330 21024 : if ( access(name, F_OK) != -1 )
331 : {
332 34 : if ( connect( pPipe->m_Socket, (struct sockaddr *)&addr, len) >= 0 )
333 : {
334 34 : return (pPipe);
335 : }
336 :
337 : OSL_TRACE("osl_createPipe failed to connect. Errno: %d; %s",errno,strerror(errno));
338 : }
339 :
340 20990 : close (pPipe->m_Socket);
341 20990 : __osl_destroyPipeImpl(pPipe);
342 20990 : return NULL;
343 : }
344 : }
345 :
346 61069 : void SAL_CALL osl_acquirePipe( oslPipe pPipe )
347 : {
348 61069 : osl_atomic_increment( &(pPipe->m_nRefCount) );
349 61069 : }
350 :
351 61127 : void SAL_CALL osl_releasePipe( oslPipe pPipe )
352 : {
353 :
354 61127 : if( 0 == pPipe )
355 61127 : return;
356 :
357 61127 : if( 0 == osl_atomic_decrement( &(pPipe->m_nRefCount) ) )
358 : {
359 58 : if( ! pPipe->m_bClosed )
360 0 : osl_closePipe( pPipe );
361 :
362 58 : __osl_destroyPipeImpl( pPipe );
363 : }
364 : }
365 :
366 66 : void SAL_CALL osl_closePipe( oslPipe pPipe )
367 : {
368 : int nRet;
369 : #if defined(LINUX)
370 : size_t len;
371 : struct sockaddr_un addr;
372 : int fd;
373 : #endif
374 : int ConnFD;
375 :
376 66 : if( ! pPipe )
377 : {
378 : return;
379 : }
380 :
381 66 : if( pPipe->m_bClosed )
382 : {
383 : return;
384 : }
385 :
386 58 : ConnFD = pPipe->m_Socket;
387 :
388 : /*
389 : Thread does not return from accept on linux, so
390 : connect to the accepting pipe
391 : */
392 : #if defined(LINUX)
393 58 : if ( pPipe->m_bIsAccepting )
394 : {
395 16 : pPipe->m_bIsInShutdown = sal_True;
396 16 : pPipe->m_Socket = -1;
397 16 : fd = socket(AF_UNIX, SOCK_STREAM, 0);
398 16 : memset(&addr, 0, sizeof(addr));
399 :
400 : OSL_TRACE("osl_destroyPipe : Pipe Name '%s'",pPipe->m_Name);
401 :
402 16 : addr.sun_family = AF_UNIX;
403 16 : strncpy(addr.sun_path, pPipe->m_Name, sizeof(addr.sun_path) - 1);
404 16 : len = sizeof(addr);
405 :
406 16 : nRet = connect( fd, (struct sockaddr *)&addr, len);
407 : if ( nRet < 0 )
408 : {
409 : OSL_TRACE("connect in osl_destroyPipe failed with error: %s", strerror(errno));
410 : }
411 16 : close(fd);
412 : }
413 : #endif /* LINUX */
414 :
415 :
416 58 : nRet = shutdown(ConnFD, 2);
417 : if ( nRet < 0 )
418 : {
419 : OSL_TRACE("shutdown in destroyPipe failed : '%s'",strerror(errno));
420 : }
421 :
422 58 : nRet = close(ConnFD);
423 : if ( nRet < 0 )
424 : {
425 : OSL_TRACE("close in destroyPipe failed : '%s'",strerror(errno));
426 : }
427 : /* remove filesystem entry */
428 58 : if ( strlen(pPipe->m_Name) > 0 )
429 : {
430 16 : unlink(pPipe->m_Name);
431 : }
432 58 : pPipe->m_bClosed = sal_True;
433 :
434 : /* OSL_TRACE("Out osl_destroyPipe"); */
435 : }
436 :
437 :
438 : /*****************************************************************************/
439 : /* osl_acceptPipe */
440 : /*****************************************************************************/
441 24 : oslPipe SAL_CALL osl_acceptPipe(oslPipe pPipe)
442 : {
443 : int s, flags;
444 : oslPipe pAcceptedPipe;
445 :
446 : OSL_ASSERT(pPipe);
447 24 : if ( pPipe == 0 )
448 : {
449 0 : return NULL;
450 : }
451 :
452 : OSL_ASSERT(strlen(pPipe->m_Name) > 0);
453 :
454 : #if defined(LINUX)
455 24 : pPipe->m_bIsAccepting = sal_True;
456 : #endif
457 :
458 24 : s = accept(pPipe->m_Socket, NULL, NULL);
459 :
460 : #if defined(LINUX)
461 24 : pPipe->m_bIsAccepting = sal_False;
462 : #endif
463 :
464 24 : if (s < 0)
465 : {
466 : OSL_TRACE("osl_acceptPipe : accept error '%s'", strerror(errno));
467 0 : return NULL;
468 : }
469 :
470 : #if defined(LINUX)
471 24 : if ( pPipe->m_bIsInShutdown )
472 : {
473 16 : close(s);
474 16 : return NULL;
475 : }
476 : #endif /* LINUX */
477 : else
478 : {
479 : /* alloc memory */
480 8 : pAcceptedPipe= __osl_createPipeImpl();
481 :
482 : OSL_ASSERT(pAcceptedPipe);
483 8 : if(pAcceptedPipe==NULL)
484 : {
485 0 : close(s);
486 0 : return NULL;
487 : }
488 :
489 : /* set close-on-exec flag */
490 8 : if (!((flags = fcntl(s, F_GETFD, 0)) < 0))
491 : {
492 8 : flags |= FD_CLOEXEC;
493 8 : if (fcntl(s, F_SETFD, flags) < 0)
494 : {
495 : OSL_TRACE("osl_acceptPipe: error changing socket flags. "
496 : "Errno: %d; %s",errno,strerror(errno));
497 : }
498 : }
499 :
500 8 : pAcceptedPipe->m_Socket = s;
501 : }
502 :
503 8 : return pAcceptedPipe;
504 : }
505 :
506 : /*****************************************************************************/
507 : /* osl_receivePipe */
508 : /*****************************************************************************/
509 67735 : sal_Int32 SAL_CALL osl_receivePipe(oslPipe pPipe,
510 : void* pBuffer,
511 : sal_Int32 BytesToRead)
512 : {
513 67735 : int nRet = 0;
514 :
515 : OSL_ASSERT(pPipe);
516 :
517 67735 : if ( pPipe == 0 )
518 : {
519 : OSL_TRACE("osl_receivePipe : Invalid socket");
520 0 : errno=EINVAL;
521 0 : return -1;
522 : }
523 :
524 67735 : nRet = recv(pPipe->m_Socket,
525 : (sal_Char*)pBuffer,
526 : BytesToRead, 0);
527 :
528 : if ( nRet < 0 )
529 : {
530 : OSL_TRACE("osl_receivePipe failed : %i '%s'",nRet,strerror(errno));
531 : }
532 :
533 67735 : return nRet;
534 : }
535 :
536 :
537 : /*****************************************************************************/
538 : /* osl_sendPipe */
539 : /*****************************************************************************/
540 67600 : sal_Int32 SAL_CALL osl_sendPipe(oslPipe pPipe,
541 : const void* pBuffer,
542 : sal_Int32 BytesToSend)
543 : {
544 67600 : int nRet=0;
545 :
546 : OSL_ASSERT(pPipe);
547 :
548 67600 : if ( pPipe == 0 )
549 : {
550 : OSL_TRACE("osl_sendPipe : Invalid socket");
551 0 : errno=EINVAL;
552 0 : return -1;
553 : }
554 :
555 67600 : nRet = send(pPipe->m_Socket,
556 : (sal_Char*)pBuffer,
557 : BytesToSend, 0);
558 :
559 :
560 : if ( nRet <= 0 )
561 : {
562 : OSL_TRACE("osl_sendPipe failed : %i '%s'",nRet,strerror(errno));
563 : }
564 :
565 67600 : return nRet;
566 : }
567 :
568 :
569 : /*****************************************************************************/
570 : /* osl_getLastPipeError */
571 : /*****************************************************************************/
572 57 : oslPipeError SAL_CALL osl_getLastPipeError(oslPipe pPipe)
573 : {
574 : (void) pPipe; /* unused */
575 57 : return ERROR_FROM_NATIVE(errno);
576 : }
577 :
578 :
579 67600 : sal_Int32 SAL_CALL osl_writePipe( oslPipe pPipe, const void *pBuffer , sal_Int32 n )
580 : {
581 : /* loop until all desired bytes were send or an error occurred */
582 67600 : sal_Int32 BytesSend= 0;
583 67600 : sal_Int32 BytesToSend= n;
584 :
585 : OSL_ASSERT(pPipe);
586 202800 : while (BytesToSend > 0)
587 : {
588 : sal_Int32 RetVal;
589 :
590 67600 : RetVal= osl_sendPipe(pPipe, pBuffer, BytesToSend);
591 :
592 : /* error occurred? */
593 67600 : if(RetVal <= 0)
594 : {
595 0 : break;
596 : }
597 :
598 67600 : BytesToSend -= RetVal;
599 67600 : BytesSend += RetVal;
600 67600 : pBuffer= (sal_Char*)pBuffer + RetVal;
601 : }
602 :
603 67600 : return BytesSend;
604 : }
605 :
606 65031 : sal_Int32 SAL_CALL osl_readPipe( oslPipe pPipe, void *pBuffer , sal_Int32 n )
607 : {
608 : /* loop until all desired bytes were read or an error occurred */
609 65031 : sal_Int32 BytesRead= 0;
610 65031 : sal_Int32 BytesToRead= n;
611 :
612 : OSL_ASSERT( pPipe );
613 197653 : while (BytesToRead > 0)
614 : {
615 : sal_Int32 RetVal;
616 67735 : RetVal= osl_receivePipe(pPipe, pBuffer, BytesToRead);
617 :
618 : /* error occurred? */
619 67735 : if(RetVal <= 0)
620 : {
621 144 : break;
622 : }
623 :
624 67591 : BytesToRead -= RetVal;
625 67591 : BytesRead += RetVal;
626 67591 : pBuffer= (sal_Char*)pBuffer + RetVal;
627 : }
628 65031 : return BytesRead;
629 : }
630 :
631 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|