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