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