/src/libreoffice/sal/osl/unx/pipe.cxx
Line | Count | Source |
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 <o3tl/safeint.hxx> |
21 | | #include <osl/pipe.h> |
22 | | #include <osl/diagnose.h> |
23 | | #include <osl/thread.h> |
24 | | #include <osl/interlck.h> |
25 | | #include <rtl/string.h> |
26 | | #include <rtl/ustring.h> |
27 | | #include <rtl/bootstrap.hxx> |
28 | | #include <sal/log.hxx> |
29 | | |
30 | | #include "sockimpl.hxx" |
31 | | #include "secimpl.hxx" |
32 | | #include "file_impl.hxx" |
33 | | #include "unixerrnostring.hxx" |
34 | | |
35 | | #include <cassert> |
36 | | #include <cstring> |
37 | | #include <fcntl.h> |
38 | | #include <sys/stat.h> |
39 | | #include <unistd.h> |
40 | | |
41 | | constexpr OString PIPEDEFAULTPATH = "/tmp"_ostr; |
42 | | constexpr OString PIPEALTERNATEPATH = "/var/tmp"_ostr; |
43 | | |
44 | | static oslPipe osl_psz_createPipe(const char *pszPipeName, oslPipeOptions Options, oslSecurity Security); |
45 | | |
46 | | struct |
47 | | { |
48 | | int errcode; |
49 | | oslPipeError error; |
50 | | } const 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 | | #ifdef ESOCKTNOSUPPORT |
56 | | { ESOCKTNOSUPPORT, osl_Pipe_E_NoProtocol }, /* Socket type not supported */ |
57 | | #endif |
58 | | { EPFNOSUPPORT, osl_Pipe_E_NoProtocol }, /* Protocol family not supported */ |
59 | | { EAFNOSUPPORT, osl_Pipe_E_NoProtocol }, /* Address family not supported by */ |
60 | | /* protocol family */ |
61 | | { ENETRESET, osl_Pipe_E_NetworkReset }, /* Network dropped connection because */ |
62 | | /* of reset */ |
63 | | { ECONNABORTED, osl_Pipe_E_ConnectionAbort }, /* Software caused connection abort */ |
64 | | { ECONNRESET, osl_Pipe_E_ConnectionReset }, /* Connection reset by peer */ |
65 | | { ENOBUFS, osl_Pipe_E_NoBufferSpace }, /* No buffer space available */ |
66 | | { ETIMEDOUT, osl_Pipe_E_TimedOut }, /* Connection timed out */ |
67 | | { ECONNREFUSED, osl_Pipe_E_ConnectionRefused }, /* Connection refused */ |
68 | | { -1, osl_Pipe_E_invalidError } |
69 | | }; |
70 | | |
71 | | static oslPipeError osl_PipeErrorFromNative(int nativeType) |
72 | 0 | { |
73 | 0 | int i = 0; |
74 | |
|
75 | 0 | while ((PipeError[i].error != osl_Pipe_E_invalidError) && |
76 | 0 | (PipeError[i].errcode != nativeType)) |
77 | 0 | { |
78 | 0 | i++; |
79 | 0 | } |
80 | |
|
81 | 0 | return PipeError[i].error; |
82 | 0 | } |
83 | | |
84 | | static oslPipe createPipeImpl() |
85 | 0 | { |
86 | 0 | oslPipe pPipeImpl = new oslPipeImpl; |
87 | |
|
88 | 0 | pPipeImpl->m_Socket = 0; |
89 | 0 | pPipeImpl->m_Name[0] = 0; |
90 | 0 | pPipeImpl->m_nRefCount = 1; |
91 | 0 | pPipeImpl->m_bClosed = false; |
92 | 0 | #if defined(CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT) |
93 | 0 | pPipeImpl->m_bIsInShutdown = false; |
94 | 0 | pPipeImpl->m_bIsAccepting = false; |
95 | 0 | #endif |
96 | |
|
97 | 0 | return pPipeImpl; |
98 | 0 | } |
99 | | |
100 | | static void destroyPipeImpl(oslPipe pImpl) |
101 | 0 | { |
102 | 0 | delete pImpl; |
103 | 0 | } |
104 | | |
105 | | oslPipe SAL_CALL osl_createPipe(rtl_uString *ustrPipeName, oslPipeOptions Options, oslSecurity Security) |
106 | 0 | { |
107 | 0 | oslPipe pPipe = nullptr; |
108 | 0 | rtl_String* strPipeName = nullptr; |
109 | |
|
110 | 0 | if (ustrPipeName) |
111 | 0 | { |
112 | 0 | rtl_uString2String(&strPipeName, |
113 | 0 | rtl_uString_getStr(ustrPipeName), |
114 | 0 | rtl_uString_getLength(ustrPipeName), |
115 | 0 | osl_getThreadTextEncoding(), |
116 | 0 | OUSTRING_TO_OSTRING_CVTFLAGS); |
117 | 0 | char* pszPipeName = rtl_string_getStr(strPipeName); |
118 | 0 | pPipe = osl_psz_createPipe(pszPipeName, Options, Security); |
119 | |
|
120 | 0 | if (strPipeName) |
121 | 0 | rtl_string_release(strPipeName); |
122 | 0 | } |
123 | |
|
124 | 0 | return pPipe; |
125 | |
|
126 | 0 | } |
127 | | |
128 | | static OString |
129 | | getBootstrapSocketPath() |
130 | 0 | { |
131 | 0 | OUString pValue; |
132 | |
|
133 | 0 | if (rtl::Bootstrap::get(u"OSL_SOCKET_PATH"_ustr, pValue)) |
134 | 0 | { |
135 | 0 | return OUStringToOString(pValue, RTL_TEXTENCODING_UTF8); |
136 | 0 | } |
137 | 0 | return ""_ostr; |
138 | 0 | } |
139 | | |
140 | | static oslPipe osl_psz_createPipe(const char *pszPipeName, oslPipeOptions Options, |
141 | | oslSecurity Security) |
142 | 0 | { |
143 | 0 | int Flags; |
144 | 0 | size_t len; |
145 | 0 | struct sockaddr_un addr; |
146 | |
|
147 | 0 | OString name; |
148 | 0 | oslPipe pPipe; |
149 | |
|
150 | 0 | if (access(PIPEDEFAULTPATH.getStr(), W_OK) == 0) |
151 | 0 | name = PIPEDEFAULTPATH; |
152 | 0 | else if (access(PIPEALTERNATEPATH.getStr(), W_OK) == 0) |
153 | 0 | name = PIPEALTERNATEPATH; |
154 | 0 | else { |
155 | 0 | name = getBootstrapSocketPath (); |
156 | 0 | } |
157 | |
|
158 | 0 | name += "/"; |
159 | |
|
160 | 0 | if (Security) |
161 | 0 | { |
162 | 0 | char Ident[256]; |
163 | |
|
164 | 0 | Ident[0] = '\0'; |
165 | |
|
166 | 0 | OSL_VERIFY(osl_psz_getUserIdent(Security, Ident, sizeof(Ident))); |
167 | |
|
168 | 0 | name += OString::Concat("OSL_PIPE_") + Ident + "_" + pszPipeName; |
169 | 0 | } |
170 | 0 | else |
171 | 0 | { |
172 | 0 | name += OString::Concat("OSL_PIPE_") + pszPipeName; |
173 | 0 | } |
174 | |
|
175 | 0 | if (o3tl::make_unsigned(name.getLength()) >= sizeof addr.sun_path) |
176 | 0 | { |
177 | 0 | SAL_WARN("sal.osl.pipe", "osl_createPipe: pipe name too long"); |
178 | 0 | return nullptr; |
179 | 0 | } |
180 | | |
181 | | /* alloc memory */ |
182 | 0 | pPipe = createPipeImpl(); |
183 | |
|
184 | 0 | if (!pPipe) |
185 | 0 | return nullptr; |
186 | | |
187 | | /* create socket */ |
188 | 0 | pPipe->m_Socket = socket(AF_UNIX, SOCK_STREAM, 0); |
189 | 0 | if (pPipe->m_Socket < 0) |
190 | 0 | { |
191 | 0 | SAL_WARN("sal.osl.pipe", "socket() failed: " << UnixErrnoString(errno)); |
192 | 0 | destroyPipeImpl(pPipe); |
193 | 0 | return nullptr; |
194 | 0 | } |
195 | | |
196 | | /* set close-on-exec flag */ |
197 | 0 | if ((Flags = fcntl(pPipe->m_Socket, F_GETFD, 0)) != -1) |
198 | 0 | { |
199 | 0 | Flags |= FD_CLOEXEC; |
200 | 0 | if (fcntl(pPipe->m_Socket, F_SETFD, Flags) == -1) |
201 | 0 | { |
202 | 0 | SAL_WARN("sal.osl.pipe", "fcntl() failed: " << UnixErrnoString(errno)); |
203 | 0 | } |
204 | 0 | } |
205 | | |
206 | 0 | memset(&addr, 0, sizeof(addr)); |
207 | |
|
208 | 0 | SAL_INFO("sal.osl.pipe", "new pipe on fd " << pPipe->m_Socket << " '" << name << "'"); |
209 | | |
210 | 0 | if (isForbidden(name, osl_File_OpenFlag_Create)) |
211 | 0 | { |
212 | 0 | close (pPipe->m_Socket); |
213 | 0 | destroyPipeImpl(pPipe); |
214 | 0 | return nullptr; |
215 | 0 | } |
216 | | |
217 | 0 | addr.sun_family = AF_UNIX; |
218 | 0 | strcpy(addr.sun_path, name.getStr()); |
219 | | #if defined(FREEBSD) |
220 | | len = SUN_LEN(&addr); |
221 | | #else |
222 | 0 | len = sizeof(addr); |
223 | 0 | #endif |
224 | |
|
225 | 0 | if (Options & osl_Pipe_CREATE) |
226 | 0 | { |
227 | 0 | struct stat status; |
228 | | |
229 | | /* check if there exists an orphan filesystem entry */ |
230 | 0 | if ((stat(name.getStr(), &status) == 0) && |
231 | 0 | (S_ISSOCK(status.st_mode) || S_ISFIFO(status.st_mode))) |
232 | 0 | { |
233 | 0 | if (connect(pPipe->m_Socket, reinterpret_cast< sockaddr* >(&addr), len) >= 0) |
234 | 0 | { |
235 | 0 | close (pPipe->m_Socket); |
236 | 0 | destroyPipeImpl(pPipe); |
237 | 0 | return nullptr; |
238 | 0 | } |
239 | | |
240 | 0 | unlink(name.getStr()); |
241 | 0 | } |
242 | | |
243 | | /* ok, fs clean */ |
244 | 0 | if (bind(pPipe->m_Socket, reinterpret_cast< sockaddr* >(&addr), len) < 0) |
245 | 0 | { |
246 | 0 | SAL_WARN("sal.osl.pipe", "bind() failed: " << UnixErrnoString(errno)); |
247 | 0 | close(pPipe->m_Socket); |
248 | 0 | destroyPipeImpl(pPipe); |
249 | 0 | return nullptr; |
250 | 0 | } |
251 | | |
252 | | /* Only give access to all if no security handle was specified, otherwise security |
253 | | depends on umask */ |
254 | | |
255 | 0 | if (!Security) |
256 | 0 | (void)chmod(name.getStr(),S_IRWXU | S_IRWXG |S_IRWXO); |
257 | |
|
258 | 0 | strcpy(pPipe->m_Name, name.getStr()); // safe, see check above |
259 | |
|
260 | 0 | if (listen(pPipe->m_Socket, 5) < 0) |
261 | 0 | { |
262 | 0 | SAL_WARN("sal.osl.pipe", "listen() failed: " << UnixErrnoString(errno)); |
263 | 0 | unlink(name.getStr()); /* remove filesystem entry */ |
264 | 0 | close(pPipe->m_Socket); |
265 | 0 | destroyPipeImpl(pPipe); |
266 | 0 | return nullptr; |
267 | 0 | } |
268 | | |
269 | 0 | return pPipe; |
270 | 0 | } |
271 | | |
272 | | /* osl_pipe_OPEN */ |
273 | 0 | if (access(name.getStr(), F_OK) != -1) |
274 | 0 | { |
275 | 0 | if (connect(pPipe->m_Socket, reinterpret_cast< sockaddr* >(&addr), len) >= 0) |
276 | 0 | return pPipe; |
277 | | |
278 | 0 | SAL_WARN("sal.osl.pipe", "connect() failed: " << UnixErrnoString(errno)); |
279 | 0 | } |
280 | | |
281 | 0 | close (pPipe->m_Socket); |
282 | 0 | destroyPipeImpl(pPipe); |
283 | 0 | return nullptr; |
284 | 0 | } |
285 | | |
286 | | void SAL_CALL osl_acquirePipe(oslPipe pPipe) |
287 | 0 | { |
288 | 0 | osl_atomic_increment(&(pPipe->m_nRefCount)); |
289 | 0 | } |
290 | | |
291 | | void SAL_CALL osl_releasePipe(oslPipe pPipe) |
292 | 0 | { |
293 | 0 | if (!pPipe) |
294 | 0 | return; |
295 | | |
296 | 0 | if (osl_atomic_decrement(&(pPipe->m_nRefCount)) == 0) |
297 | 0 | { |
298 | 0 | osl_closePipe(pPipe); |
299 | |
|
300 | 0 | destroyPipeImpl(pPipe); |
301 | 0 | } |
302 | 0 | } |
303 | | |
304 | | void SAL_CALL osl_closePipe(oslPipe pPipe) |
305 | 0 | { |
306 | 0 | int nRet; |
307 | 0 | int ConnFD; |
308 | |
|
309 | 0 | if (!pPipe) |
310 | 0 | return; |
311 | | |
312 | 0 | std::unique_lock aGuard(pPipe->m_Mutex); |
313 | |
|
314 | 0 | if (pPipe->m_bClosed) |
315 | 0 | return; |
316 | | |
317 | 0 | ConnFD = pPipe->m_Socket; |
318 | | |
319 | | /* Thread does not return from accept on linux, so |
320 | | connect to the accepting pipe |
321 | | */ |
322 | 0 | #if defined(CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT) |
323 | 0 | struct sockaddr_un addr; |
324 | |
|
325 | 0 | if (pPipe->m_bIsAccepting) |
326 | 0 | { |
327 | 0 | pPipe->m_bIsInShutdown = true; |
328 | 0 | pPipe->m_Socket = -1; |
329 | |
|
330 | 0 | int fd = socket(AF_UNIX, SOCK_STREAM, 0); |
331 | 0 | if (fd < 0) |
332 | 0 | { |
333 | 0 | SAL_WARN("sal.osl.pipe", "socket() failed: " << UnixErrnoString(errno)); |
334 | 0 | return; |
335 | 0 | } |
336 | | |
337 | 0 | memset(&addr, 0, sizeof(addr)); |
338 | |
|
339 | 0 | SAL_INFO("sal.osl.pipe", "osl_destroyPipe : Pipe Name '" << pPipe->m_Name << "'"); |
340 | | |
341 | 0 | addr.sun_family = AF_UNIX; |
342 | 0 | strcpy(addr.sun_path, pPipe->m_Name); // safe, as both are same size |
343 | |
|
344 | 0 | nRet = connect(fd, reinterpret_cast< sockaddr* >(&addr), sizeof(addr)); |
345 | 0 | if (nRet < 0) |
346 | 0 | SAL_WARN("sal.osl.pipe", "connect() failed: " << UnixErrnoString(errno)); |
347 | | |
348 | 0 | close(fd); |
349 | 0 | } |
350 | 0 | #endif /* CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT */ |
351 | | |
352 | 0 | nRet = shutdown(ConnFD, 2); |
353 | 0 | if (nRet < 0) |
354 | 0 | SAL_WARN("sal.osl.pipe", "shutdown() failed: " << UnixErrnoString(errno)); |
355 | | |
356 | 0 | nRet = close(ConnFD); |
357 | 0 | if (nRet < 0) |
358 | 0 | SAL_WARN("sal.osl.pipe", "close() failed: " << UnixErrnoString(errno)); |
359 | | |
360 | | /* remove filesystem entry */ |
361 | 0 | if (pPipe->m_Name[0] != '\0') |
362 | 0 | unlink(pPipe->m_Name); |
363 | |
|
364 | 0 | pPipe->m_bClosed = true; |
365 | 0 | } |
366 | | |
367 | | oslPipe SAL_CALL osl_acceptPipe(oslPipe pPipe) |
368 | 0 | { |
369 | 0 | int s; |
370 | 0 | oslPipe pAcceptedPipe; |
371 | |
|
372 | 0 | SAL_WARN_IF(!pPipe, "sal.osl.pipe", "invalid pipe"); |
373 | 0 | if (!pPipe) |
374 | 0 | return nullptr; |
375 | | |
376 | 0 | int socket; |
377 | 0 | { |
378 | | // don't hold lock while accepting, so it is possible to close a socket blocked in accept |
379 | 0 | std::unique_lock aGuard(pPipe->m_Mutex); |
380 | |
|
381 | 0 | assert(pPipe->m_Name[0] != '\0'); // you cannot have an empty pipe name |
382 | 0 | #if defined(CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT) |
383 | 0 | pPipe->m_bIsAccepting = true; |
384 | 0 | #endif |
385 | |
|
386 | 0 | socket = pPipe->m_Socket; |
387 | 0 | } |
388 | | |
389 | |
|
390 | 0 | s = accept(socket, nullptr, nullptr); |
391 | |
|
392 | 0 | std::unique_lock aGuard(pPipe->m_Mutex); |
393 | |
|
394 | 0 | #if defined(CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT) |
395 | 0 | pPipe->m_bIsAccepting = false; |
396 | 0 | #endif |
397 | |
|
398 | 0 | if (s < 0) |
399 | 0 | { |
400 | 0 | SAL_WARN("sal.osl.pipe", "accept() failed: " << UnixErrnoString(errno)); |
401 | 0 | return nullptr; |
402 | 0 | } |
403 | | |
404 | 0 | #if defined(CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT) |
405 | 0 | if (pPipe->m_bIsInShutdown) |
406 | 0 | { |
407 | 0 | close(s); |
408 | 0 | return nullptr; |
409 | 0 | } |
410 | 0 | #endif /* CLOSESOCKET_DOESNT_WAKE_UP_ACCEPT */ |
411 | | |
412 | | /* alloc memory */ |
413 | 0 | pAcceptedPipe = createPipeImpl(); |
414 | |
|
415 | 0 | assert(pAcceptedPipe); // should never be the case that an oslPipe cannot be initialized |
416 | 0 | if (!pAcceptedPipe) |
417 | 0 | { |
418 | 0 | close(s); |
419 | 0 | return nullptr; |
420 | 0 | } |
421 | | |
422 | | /* set close-on-exec flag */ |
423 | 0 | int flags; |
424 | 0 | if ((flags = fcntl(s, F_GETFD, 0)) >= 0) |
425 | 0 | { |
426 | 0 | flags |= FD_CLOEXEC; |
427 | 0 | if (fcntl(s, F_SETFD, flags) < 0) |
428 | 0 | SAL_WARN("sal.osl.pipe", "fcntl() failed: " << UnixErrnoString(errno)); |
429 | 0 | } |
430 | | |
431 | 0 | pAcceptedPipe->m_Socket = s; |
432 | |
|
433 | 0 | return pAcceptedPipe; |
434 | 0 | } |
435 | | |
436 | | sal_Int32 SAL_CALL osl_receivePipe(oslPipe pPipe, |
437 | | void* pBuffer, |
438 | | sal_Int32 BytesToRead) |
439 | 0 | { |
440 | 0 | SAL_WARN_IF(!pPipe, "sal.osl.pipe", "osl_receivePipe: invalid pipe"); |
441 | 0 | if (!pPipe) |
442 | 0 | { |
443 | 0 | SAL_WARN("sal.osl.pipe", "osl_receivePipe: Invalid socket"); |
444 | 0 | errno=EINVAL; |
445 | 0 | return -1; |
446 | 0 | } |
447 | | |
448 | 0 | int socket; |
449 | 0 | { |
450 | | // don't hold lock while receiving, so it is possible to close a socket blocked in recv |
451 | 0 | std::unique_lock aGuard(pPipe->m_Mutex); |
452 | 0 | socket = pPipe->m_Socket; |
453 | 0 | } |
454 | |
|
455 | 0 | sal_Int32 nRet = recv(socket, pBuffer, BytesToRead, 0); |
456 | |
|
457 | 0 | SAL_WARN_IF(nRet < 0, "sal.osl.pipe", "recv() failed: " << UnixErrnoString(errno)); |
458 | | |
459 | 0 | return nRet; |
460 | 0 | } |
461 | | |
462 | | sal_Int32 SAL_CALL osl_sendPipe(oslPipe pPipe, |
463 | | const void* pBuffer, |
464 | | sal_Int32 BytesToSend) |
465 | 0 | { |
466 | 0 | int nRet=0; |
467 | |
|
468 | 0 | SAL_WARN_IF(!pPipe, "sal.osl.pipe", "osl_sendPipe: invalid pipe"); |
469 | 0 | if (!pPipe) |
470 | 0 | { |
471 | 0 | SAL_WARN("sal.osl.pipe", "osl_sendPipe: Invalid socket"); |
472 | 0 | errno=EINVAL; |
473 | 0 | return -1; |
474 | 0 | } |
475 | | |
476 | 0 | int socket; |
477 | 0 | { |
478 | | // don't hold lock while sending, so it is possible to close a socket blocked in send |
479 | 0 | std::unique_lock aGuard(pPipe->m_Mutex); |
480 | 0 | socket = pPipe->m_Socket; |
481 | 0 | } |
482 | |
|
483 | 0 | nRet = send(socket, pBuffer, BytesToSend, 0); |
484 | |
|
485 | 0 | if (nRet <= 0) |
486 | 0 | SAL_WARN("sal.osl.pipe", "send() failed: " << UnixErrnoString(errno)); |
487 | | |
488 | 0 | return nRet; |
489 | 0 | } |
490 | | |
491 | | oslPipeError SAL_CALL osl_getLastPipeError(SAL_UNUSED_PARAMETER oslPipe) |
492 | 0 | { |
493 | 0 | return osl_PipeErrorFromNative(errno); |
494 | 0 | } |
495 | | |
496 | | sal_Int32 SAL_CALL osl_writePipe(oslPipe pPipe, const void *pBuffer, sal_Int32 n) |
497 | 0 | { |
498 | | /* loop until all desired bytes were send or an error occurred */ |
499 | 0 | sal_Int32 BytesSend = 0; |
500 | 0 | sal_Int32 BytesToSend = n; |
501 | |
|
502 | 0 | SAL_WARN_IF(!pPipe, "sal.osl.pipe", "osl_writePipe: invalid pipe"); // osl_sendPipe detects invalid pipe |
503 | 0 | while (BytesToSend > 0) |
504 | 0 | { |
505 | 0 | sal_Int32 RetVal = osl_sendPipe(pPipe, pBuffer, BytesToSend); |
506 | | /* error occurred? */ |
507 | 0 | if (RetVal <= 0) |
508 | 0 | break; |
509 | | |
510 | 0 | BytesToSend -= RetVal; |
511 | 0 | BytesSend += RetVal; |
512 | 0 | pBuffer= static_cast< char const* >(pBuffer) + RetVal; |
513 | 0 | } |
514 | |
|
515 | 0 | return BytesSend; |
516 | 0 | } |
517 | | |
518 | | sal_Int32 SAL_CALL osl_readPipe( oslPipe pPipe, void *pBuffer , sal_Int32 n ) |
519 | 0 | { |
520 | | /* loop until all desired bytes were read or an error occurred */ |
521 | 0 | sal_Int32 BytesRead = 0; |
522 | 0 | sal_Int32 BytesToRead = n; |
523 | |
|
524 | 0 | SAL_WARN_IF(!pPipe, "sal.osl.pipe", "osl_readPipe: invalid pipe"); // osl_receivePipe detects invalid pipe |
525 | 0 | while (BytesToRead > 0) |
526 | 0 | { |
527 | 0 | sal_Int32 RetVal = osl_receivePipe(pPipe, pBuffer, BytesToRead); |
528 | | /* error occurred? */ |
529 | 0 | if (RetVal <= 0) |
530 | 0 | break; |
531 | | |
532 | 0 | BytesToRead -= RetVal; |
533 | 0 | BytesRead += RetVal; |
534 | 0 | pBuffer= static_cast< char* >(pBuffer) + RetVal; |
535 | 0 | } |
536 | |
|
537 | 0 | return BytesRead; |
538 | 0 | } |
539 | | |
540 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |