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