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 0 : static oslPipeError osl_PipeErrorFromNative(int nativeType)
80 : {
81 0 : int i = 0;
82 :
83 0 : while ((PipeError[i].error != osl_Pipe_E_invalidError) &&
84 0 : (PipeError[i].errcode != nativeType)) i++;
85 :
86 0 : return PipeError[i].error;
87 : }
88 :
89 : /* macros */
90 : #define ERROR_FROM_NATIVE(y) osl_PipeErrorFromNative(y)
91 :
92 2 : oslPipe __osl_createPipeImpl()
93 : {
94 : oslPipe pPipeImpl;
95 :
96 2 : pPipeImpl = (oslPipe)calloc(1, sizeof(struct oslPipeImpl));
97 2 : if (pPipeImpl == NULL)
98 0 : return NULL;
99 2 : pPipeImpl->m_nRefCount =1;
100 2 : pPipeImpl->m_bClosed = sal_False;
101 : #if defined(LINUX)
102 2 : pPipeImpl->m_bIsInShutdown = sal_False;
103 2 : pPipeImpl->m_bIsAccepting = sal_False;
104 : #endif
105 2 : return pPipeImpl;
106 : }
107 :
108 2 : void __osl_destroyPipeImpl(oslPipe pImpl)
109 : {
110 2 : if (pImpl != NULL)
111 2 : free(pImpl);
112 2 : }
113 :
114 2 : oslPipe SAL_CALL osl_createPipe(rtl_uString *ustrPipeName, oslPipeOptions Options, oslSecurity Security)
115 : {
116 2 : oslPipe pPipe=0;
117 2 : rtl_String* strPipeName=0;
118 2 : sal_Char* pszPipeName=0;
119 :
120 2 : if ( ustrPipeName != 0 )
121 : {
122 4 : rtl_uString2String( &strPipeName,
123 2 : rtl_uString_getStr(ustrPipeName),
124 : rtl_uString_getLength(ustrPipeName),
125 2 : osl_getThreadTextEncoding(),
126 : OUSTRING_TO_OSTRING_CVTFLAGS );
127 2 : pszPipeName = rtl_string_getStr(strPipeName);
128 2 : pPipe = osl_psz_createPipe(pszPipeName, Options, Security);
129 :
130 2 : if ( strPipeName != 0 )
131 : {
132 2 : rtl_string_release(strPipeName);
133 : }
134 : }
135 :
136 2 : 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 2 : 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 2 : size_t nNameLength = 0;
179 2 : int bNameTooLong = 0;
180 : oslPipe pPipe;
181 :
182 2 : if (access(PIPEDEFAULTPATH, R_OK|W_OK) == 0)
183 : {
184 2 : 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 2 : name[sizeof(name) - 1] = '\0'; // ensure the string is NULL-terminated
195 2 : nNameLength = strlen(name);
196 2 : bNameTooLong = nNameLength > sizeof(name) - 2;
197 :
198 2 : if (!bNameTooLong)
199 : {
200 2 : size_t nRealLength = 0;
201 :
202 2 : strcat(name, "/");
203 2 : ++nNameLength;
204 :
205 2 : if (Security)
206 : {
207 : sal_Char Ident[256];
208 :
209 2 : Ident[0] = '\0';
210 :
211 2 : OSL_VERIFY(osl_psz_getUserIdent(Security, Ident, sizeof(Ident)));
212 :
213 2 : 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 2 : bNameTooLong = nRealLength > sizeof(name) - nNameLength - 1;
221 : }
222 :
223 2 : if (bNameTooLong)
224 : {
225 : OSL_TRACE("osl_createPipe: pipe name too long");
226 0 : return NULL;
227 : }
228 :
229 : /* alloc memory */
230 2 : pPipe = __osl_createPipeImpl();
231 :
232 2 : if (pPipe == NULL)
233 : {
234 : OSL_TRACE("__osl_createPipe socket failed");
235 0 : return NULL;
236 : }
237 :
238 : /* create socket */
239 2 : pPipe->m_Socket = socket(AF_UNIX, SOCK_STREAM, 0);
240 2 : 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 2 : if ((Flags = fcntl(pPipe->m_Socket, F_GETFD, 0)) != -1)
251 : {
252 2 : Flags |= FD_CLOEXEC;
253 2 : 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 2 : memset(&addr, 0, sizeof(addr));
260 :
261 : OSL_TRACE("osl_createPipe : Pipe Name '%s'",name);
262 :
263 2 : addr.sun_family = AF_UNIX;
264 2 : strncpy(addr.sun_path, name, sizeof(addr.sun_path) - 1);
265 : #if defined(FREEBSD)
266 : len = SUN_LEN(&addr);
267 : #else
268 2 : len = sizeof(addr);
269 : #endif
270 :
271 2 : if ( Options & osl_Pipe_CREATE )
272 : {
273 : struct stat status;
274 :
275 : /* check if there exists an orphan filesystem entry */
276 2 : if ( ( stat(name, &status) == 0) &&
277 1 : ( S_ISSOCK(status.st_mode) || S_ISFIFO(status.st_mode) ) )
278 : {
279 1 : 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 1 : close (pPipe->m_Socket);
283 1 : __osl_destroyPipeImpl(pPipe);
284 1 : return NULL;
285 : }
286 :
287 0 : unlink(name);
288 : }
289 :
290 : /* ok, fs clean */
291 0 : 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 0 : if ( !Security )
303 0 : chmod(name,S_IRWXU | S_IRWXG |S_IRWXO);
304 :
305 0 : strncpy(pPipe->m_Name, name, sizeof(pPipe->m_Name) - 1);
306 :
307 0 : 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 0 : return (pPipe);
317 : }
318 : else
319 : { /* osl_pipe_OPEN */
320 1 : if ( access(name, F_OK) != -1 )
321 : {
322 1 : if ( connect( pPipe->m_Socket, (struct sockaddr *)&addr, len) >= 0 )
323 : {
324 1 : return (pPipe);
325 : }
326 :
327 : OSL_TRACE("osl_createPipe failed to connect. Errno: %d; %s",errno,strerror(errno));
328 : }
329 :
330 0 : close (pPipe->m_Socket);
331 0 : __osl_destroyPipeImpl(pPipe);
332 0 : return NULL;
333 : }
334 : }
335 :
336 3 : void SAL_CALL osl_acquirePipe( oslPipe pPipe )
337 : {
338 3 : osl_atomic_increment( &(pPipe->m_nRefCount) );
339 3 : }
340 :
341 4 : void SAL_CALL osl_releasePipe( oslPipe pPipe )
342 : {
343 :
344 4 : if( 0 == pPipe )
345 4 : return;
346 :
347 4 : if( 0 == osl_atomic_decrement( &(pPipe->m_nRefCount) ) )
348 : {
349 1 : if( ! pPipe->m_bClosed )
350 0 : osl_closePipe( pPipe );
351 :
352 1 : __osl_destroyPipeImpl( pPipe );
353 : }
354 : }
355 :
356 1 : 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 1 : if( ! pPipe )
367 : {
368 0 : return;
369 : }
370 :
371 1 : if( pPipe->m_bClosed )
372 : {
373 0 : return;
374 : }
375 :
376 1 : 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 1 : if ( pPipe->m_bIsAccepting )
384 : {
385 0 : pPipe->m_bIsInShutdown = sal_True;
386 0 : pPipe->m_Socket = -1;
387 0 : fd = socket(AF_UNIX, SOCK_STREAM, 0);
388 0 : if ( fd < 0 )
389 : {
390 : OSL_TRACE("socket in osl_destroyPipe failed with error: %s", strerror(errno));
391 0 : return;
392 : }
393 0 : memset(&addr, 0, sizeof(addr));
394 :
395 : OSL_TRACE("osl_destroyPipe : Pipe Name '%s'",pPipe->m_Name);
396 :
397 0 : addr.sun_family = AF_UNIX;
398 0 : strncpy(addr.sun_path, pPipe->m_Name, sizeof(addr.sun_path) - 1);
399 0 : len = sizeof(addr);
400 :
401 0 : 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 0 : close(fd);
407 : }
408 : #endif /* LINUX */
409 :
410 1 : nRet = shutdown(ConnFD, 2);
411 : if ( nRet < 0 )
412 : {
413 : OSL_TRACE("shutdown in destroyPipe failed : '%s'",strerror(errno));
414 : }
415 :
416 1 : nRet = close(ConnFD);
417 : if ( nRet < 0 )
418 : {
419 : OSL_TRACE("close in destroyPipe failed : '%s'",strerror(errno));
420 : }
421 : /* remove filesystem entry */
422 1 : if ( strlen(pPipe->m_Name) > 0 )
423 : {
424 0 : unlink(pPipe->m_Name);
425 : }
426 1 : pPipe->m_bClosed = sal_True;
427 :
428 : /* OSL_TRACE("Out osl_destroyPipe"); */
429 : }
430 :
431 0 : oslPipe SAL_CALL osl_acceptPipe(oslPipe pPipe)
432 : {
433 : int s, flags;
434 : oslPipe pAcceptedPipe;
435 :
436 : OSL_ASSERT(pPipe);
437 0 : if ( pPipe == 0 )
438 : {
439 0 : return NULL;
440 : }
441 :
442 : OSL_ASSERT(strlen(pPipe->m_Name) > 0);
443 :
444 : #if defined(LINUX)
445 0 : pPipe->m_bIsAccepting = sal_True;
446 : #endif
447 :
448 0 : s = accept(pPipe->m_Socket, NULL, NULL);
449 :
450 : #if defined(LINUX)
451 0 : pPipe->m_bIsAccepting = sal_False;
452 : #endif
453 :
454 0 : 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 0 : if ( pPipe->m_bIsInShutdown )
462 : {
463 0 : close(s);
464 0 : return NULL;
465 : }
466 : #endif /* LINUX */
467 : else
468 : {
469 : /* alloc memory */
470 0 : pAcceptedPipe = __osl_createPipeImpl();
471 :
472 : OSL_ASSERT(pAcceptedPipe);
473 0 : if(pAcceptedPipe==NULL)
474 : {
475 0 : close(s);
476 0 : return NULL;
477 : }
478 :
479 : /* set close-on-exec flag */
480 0 : if (!((flags = fcntl(s, F_GETFD, 0)) < 0))
481 : {
482 0 : flags |= FD_CLOEXEC;
483 0 : 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 0 : pAcceptedPipe->m_Socket = s;
491 : }
492 :
493 0 : return pAcceptedPipe;
494 : }
495 :
496 2 : sal_Int32 SAL_CALL osl_receivePipe(oslPipe pPipe,
497 : void* pBuffer,
498 : sal_Int32 BytesToRead)
499 : {
500 2 : int nRet = 0;
501 :
502 : OSL_ASSERT(pPipe);
503 :
504 2 : if ( pPipe == 0 )
505 : {
506 : OSL_TRACE("osl_receivePipe : Invalid socket");
507 0 : errno=EINVAL;
508 0 : return -1;
509 : }
510 :
511 2 : 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 2 : return nRet;
521 : }
522 :
523 1 : sal_Int32 SAL_CALL osl_sendPipe(oslPipe pPipe,
524 : const void* pBuffer,
525 : sal_Int32 BytesToSend)
526 : {
527 1 : int nRet=0;
528 :
529 : OSL_ASSERT(pPipe);
530 :
531 1 : if ( pPipe == 0 )
532 : {
533 : OSL_TRACE("osl_sendPipe : Invalid socket");
534 0 : errno=EINVAL;
535 0 : return -1;
536 : }
537 :
538 1 : 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 1 : return nRet;
548 : }
549 :
550 0 : oslPipeError SAL_CALL osl_getLastPipeError(oslPipe pPipe)
551 : {
552 : (void) pPipe; /* unused */
553 0 : return ERROR_FROM_NATIVE(errno);
554 : }
555 :
556 1 : 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 1 : sal_Int32 BytesSend= 0;
560 1 : sal_Int32 BytesToSend= n;
561 :
562 : OSL_ASSERT(pPipe);
563 3 : while (BytesToSend > 0)
564 : {
565 : sal_Int32 RetVal;
566 :
567 1 : RetVal= osl_sendPipe(pPipe, pBuffer, BytesToSend);
568 :
569 : /* error occurred? */
570 1 : if(RetVal <= 0)
571 : {
572 0 : break;
573 : }
574 :
575 1 : BytesToSend -= RetVal;
576 1 : BytesSend += RetVal;
577 1 : pBuffer= (sal_Char*)pBuffer + RetVal;
578 : }
579 :
580 1 : return BytesSend;
581 : }
582 :
583 0 : 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 0 : sal_Int32 BytesRead= 0;
587 0 : sal_Int32 BytesToRead= n;
588 :
589 : OSL_ASSERT( pPipe );
590 0 : while (BytesToRead > 0)
591 : {
592 : sal_Int32 RetVal;
593 0 : RetVal= osl_receivePipe(pPipe, pBuffer, BytesToRead);
594 :
595 : /* error occurred? */
596 0 : if(RetVal <= 0)
597 : {
598 0 : break;
599 : }
600 :
601 0 : BytesToRead -= RetVal;
602 0 : BytesRead += RetVal;
603 0 : pBuffer= (sal_Char*)pBuffer + RetVal;
604 : }
605 0 : return BytesRead;
606 : }
607 :
608 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|