1/*
2 * Copyright (C) 2003-2007 Justin Karneges <justin@affinix.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301 USA
18 *
19 */
20
21// Note: if we ever enable the threaded backend, we need to protect:
22// QPipeDevice read and bytesAvailable
23// QPipeEnd finalize
24
25// Note: we never use the return value for QPipeWriter::stop, but I don't
26// think this matters much
27
28#include "qpipe.h"
29
30#include <climits>
31#include <cstdlib>
32
33// sorry, i've added this dependency for now, but it's easy enough to take
34// with you if you want qpipe independent of qca
35#include "qca_safeobj.h"
36
37#ifdef Q_OS_WIN
38#include <QMutex>
39#include <QTextCodec>
40#include <QTextDecoder>
41#include <QTextEncoder>
42#include <QThread>
43#include <QWaitCondition>
44#else
45#include <QMutex>
46#endif
47
48#ifdef Q_OS_UNIX
49#include <cerrno>
50#include <csignal>
51#include <fcntl.h>
52#include <sys/ioctl.h>
53#include <unistd.h>
54#ifdef HAVE_SYS_FILIO_H
55#include <sys/filio.h>
56#endif
57#endif
58
59#define USE_POLL
60
61#define CONSOLE_CHAREXPAND 5
62#define PIPEWRITER_POLL 1000
63#define PIPEREADER_POLL 100
64#define PIPEWRITER_BLOCK 8192
65#define PIPEEND_BLOCK 8192
66#define PIPEEND_READBUF 16384
67#define PIPEEND_READBUF_SEC 1024
68
69namespace QCA {
70
71#ifdef Q_OS_UNIX
72// adapted from qt
73Q_GLOBAL_STATIC(QMutex, ign_mutex)
74static bool ign_sigpipe = false;
75
76static void ignore_sigpipe()
77{
78 // Set to ignore SIGPIPE once only.
79 QMutexLocker locker(ign_mutex());
80 if (!ign_sigpipe) {
81 ign_sigpipe = true;
82 struct sigaction noaction;
83 memset(s: &noaction, c: 0, n: sizeof(noaction));
84 noaction.sa_handler = SIG_IGN;
85 sigaction(SIGPIPE, act: &noaction, oact: nullptr);
86 }
87}
88#endif
89
90#ifdef Q_OS_WIN
91static int pipe_dword_cap_to_int(DWORD dw)
92{
93 if (sizeof(int) <= sizeof(DWORD))
94 return (int)((dw > INT_MAX) ? INT_MAX : dw);
95 else
96 return (int)dw;
97}
98
99static bool pipe_dword_overflows_int(DWORD dw)
100{
101 if (sizeof(int) <= sizeof(DWORD))
102 return (dw > INT_MAX) ? true : false;
103 else
104 return false;
105}
106#endif
107
108#ifdef Q_OS_UNIX
109static int pipe_size_t_cap_to_int(size_t size)
110{
111 if (sizeof(int) <= sizeof(size_t))
112 return (int)((size > INT_MAX) ? INT_MAX : size);
113 else // maybe silly.. can int ever be larger than size_t?
114 return (int)size;
115}
116#endif
117
118static bool pipe_set_blocking(Q_PIPE_ID pipe, bool b)
119{
120#ifdef Q_OS_WIN
121 DWORD flags = 0;
122 if (!b)
123 flags |= PIPE_NOWAIT;
124 if (!SetNamedPipeHandleState(pipe, &flags, NULL, NULL))
125 return false;
126 return true;
127#endif
128#ifdef Q_OS_UNIX
129 int flags = fcntl(fd: pipe, F_GETFL);
130 if (!b)
131 flags |= O_NONBLOCK;
132 else
133 flags &= ~O_NONBLOCK;
134 if (fcntl(fd: pipe, F_SETFL, flags) == -1)
135 return false;
136 return true;
137#endif
138}
139
140// on windows, the pipe is closed and the new pipe is returned in newPipe
141static bool pipe_set_inheritable(Q_PIPE_ID pipe, bool b, Q_PIPE_ID *newPipe = nullptr)
142{
143#ifdef Q_OS_WIN
144 // windows is required to accept a new pipe id
145 if (!newPipe)
146 return false;
147 HANDLE h;
148 if (!DuplicateHandle(GetCurrentProcess(), pipe, GetCurrentProcess(), &h, 0, b, DUPLICATE_SAME_ACCESS))
149 return false;
150 *newPipe = h;
151 return true;
152#endif
153#ifdef Q_OS_UNIX
154 if (newPipe)
155 *newPipe = pipe;
156 int flags = fcntl(fd: pipe, F_GETFD);
157 if (!b)
158 flags |= FD_CLOEXEC;
159 else
160 flags &= ~FD_CLOEXEC;
161 if (fcntl(fd: pipe, F_SETFD, flags) == -1)
162 return false;
163 return true;
164#endif
165}
166
167// returns number of bytes available
168static int pipe_read_avail(Q_PIPE_ID pipe)
169{
170 int bytesAvail = 0;
171#ifdef Q_OS_WIN
172 DWORD i = 0;
173 if (PeekNamedPipe(pipe, 0, 0, 0, &i, 0))
174 bytesAvail = pipe_dword_cap_to_int(i);
175#endif
176#ifdef Q_OS_UNIX
177 size_t nbytes = 0;
178 if (ioctl(fd: pipe, FIONREAD, (char *)&nbytes) >= 0)
179 bytesAvail = pipe_size_t_cap_to_int(size: nbytes);
180#endif
181 return bytesAvail;
182}
183
184// returns number of bytes actually read, no more than 'max'.
185// -1 on error. 0 means no data, NOT EOF.
186// note: even though this function looks like it can return data and EOF
187// at the same time, it never actually does.
188static int pipe_read(Q_PIPE_ID pipe, char *data, int max, bool *eof)
189{
190 int bytesRead = 0;
191 if (eof)
192 *eof = false;
193 if (max < 1)
194 return 0;
195#ifdef Q_OS_WIN
196 DWORD maxread = max;
197 DWORD r = 0;
198 if (!ReadFile(pipe, data, maxread, &r, 0)) {
199 const DWORD err = GetLastError();
200 if (err == ERROR_HANDLE_EOF) {
201 if (eof)
202 *eof = true;
203 } else if (err == ERROR_NO_DATA) {
204 r = 0;
205 } else
206 return -1;
207 }
208 bytesRead = (int)r; // safe to cast, since 'max' is signed
209#endif
210#ifdef Q_OS_UNIX
211 int r = 0;
212 int ret = read(fd: pipe, buf: data, nbytes: max);
213 if (ret == -1) {
214 if (errno != EAGAIN)
215 return -1;
216 } else if (ret == 0) {
217 if (eof)
218 *eof = true;
219 } else
220 r = ret;
221
222 bytesRead = r;
223#endif
224 return bytesRead;
225}
226
227// returns number of bytes actually written.
228// for blocking pipes, this should always be 'size'.
229// -1 on error.
230static int pipe_write(Q_PIPE_ID pipe, const char *data, int size)
231{
232#ifdef Q_OS_WIN
233 DWORD written;
234 if (!WriteFile(pipe, data, size, &written, 0))
235 return -1;
236 return (int)written; // safe to cast, since 'size' is signed
237#endif
238#ifdef Q_OS_UNIX
239 ignore_sigpipe();
240 int r = 0;
241 int ret = write(fd: pipe, buf: data, n: size);
242 if (ret == -1) {
243 if (errno != EAGAIN)
244 return -1;
245 } else
246 r = ret;
247 return r;
248#endif
249}
250
251// Windows Console functions
252
253#ifdef Q_OS_WIN
254
255static bool pipe_is_a_console(Q_PIPE_ID pipe)
256{
257 DWORD mode;
258 if (GetConsoleMode(pipe, &mode))
259 return true;
260 return false;
261}
262
263// returns the number of keypress events in the console input queue,
264// or -1 if there is an error (don't forget this!!)
265static int pipe_read_avail_console(Q_PIPE_ID pipe)
266{
267 DWORD count, i;
268 INPUT_RECORD *rec;
269 int n, icount, total;
270
271 // how many events are there?
272 if (!GetNumberOfConsoleInputEvents(pipe, &count))
273 return -1;
274
275 // peek them all
276 rec = (INPUT_RECORD *)malloc(count * sizeof(INPUT_RECORD));
277 BOOL ret;
278 ret = PeekConsoleInputW(pipe, rec, count, &i);
279 if (!ret) {
280 free(rec);
281 return -1;
282 }
283
284 icount = pipe_dword_cap_to_int(i); // process only the amount returned
285
286 // see which ones are normal keypress events
287 total = 0;
288 for (n = 0; n < icount; ++n) {
289 if (rec[n].EventType == KEY_EVENT) {
290 KEY_EVENT_RECORD *ke = &rec[n].Event.KeyEvent;
291 if (ke->bKeyDown && ke->uChar.AsciiChar != 0)
292 total += ke->wRepeatCount;
293 }
294 }
295
296 free(rec);
297 return total;
298}
299
300// pass dec to keep a long-running decoder, else 0
301static int pipe_read_console(Q_PIPE_ID pipe, ushort *data, int max, bool *eof, QTextDecoder *dec = 0)
302{
303 int n, size, count;
304 bool own_decoder;
305
306 if (eof)
307 *eof = false;
308 if (max < 1)
309 return 0;
310
311 count = pipe_read_avail_console(pipe);
312 if (count == -1)
313 return -1;
314 if (count == 0)
315 return 0;
316
317 if (dec) {
318 own_decoder = false;
319 } else {
320 dec = 0;
321 own_decoder = true;
322 }
323
324 size = 0;
325 for (n = 0; n < count && size < max; ++n) {
326 bool use_uni = true;
327 quint16 uni = 0;
328 quint8 ansi = 0;
329
330 BOOL ret;
331 DWORD i;
332 ret = ReadConsoleW(pipe, &uni, 1, &i, NULL);
333 if (!ret) {
334 // if the first read is an error, then report error
335 if (n == 0) {
336 delete dec;
337 return -1;
338 }
339 // if we have some data, don't count this as an error.
340 // we'll probably get it again next time around...
341 else
342 break;
343 }
344
345 QString substr;
346 if (use_uni)
347 substr = QChar(uni);
348 else
349 substr = dec->toUnicode((const char *)&ansi, 1);
350
351 for (int k = 0; k < substr.length() && size < max; ++k) {
352 QChar c = substr[k];
353 if (c == QChar(0x1A)) // EOF?
354 {
355 if (eof)
356 *eof = true;
357 break;
358 }
359 data[size++] = substr[k].unicode();
360 }
361 }
362 if (own_decoder)
363 delete dec;
364
365 return size;
366}
367
368static int pipe_write_console(Q_PIPE_ID pipe, const ushort *data, int size)
369{
370 DWORD i;
371 BOOL ret;
372 ret = WriteConsoleW(pipe, data, size, &i, NULL);
373 if (!ret)
374 return -1;
375 return (int)i; // safe to cast since 'size' is signed
376}
377#endif
378
379#ifdef Q_OS_WIN
380
381// Here is the multi-backend stuff for windows. QPipeWriter and QPipeReader
382// define a common interface, and then subclasses (like QPipeWriterThread)
383// are used by QPipeDevice. The base classes inherit from QThread, even
384// if threads aren't used, so that I can define signals without dealing
385// with multiple QObject inheritance in the thread subclasses (it is also
386// possible that I'm missing something obvious and don't need to do this).
387
388// Note:
389// QPipeWriterThread and QPipeReaderThread require the pipes to be in
390// blocking mode. QPipeWriterPoll and QPipeReaderPoll require the pipes
391// to be in non-blocking mode.
392
393//----------------------------------------------------------------------------
394// QPipeWriter
395//----------------------------------------------------------------------------
396class QPipeWriter : public QThread
397{
398 Q_OBJECT
399public:
400 QPipeWriter(QObject *parent = nullptr)
401 : QThread(parent)
402 {
403 }
404
405 virtual ~QPipeWriter()
406 {
407 }
408
409 // start
410 virtual void start() = 0;
411
412 // stop, and return number of bytes written so far
413 virtual int stop() = 0;
414
415 // data pointer needs to remain until canWrite is emitted
416 virtual int write(const char *data, int size) = 0;
417
418Q_SIGNALS:
419 // result values:
420 // = 0 : success
421 // = -1 : error
422 void canWrite(int result, int bytesWritten);
423
424protected:
425 virtual void run()
426 {
427 // implement a default to satisfy the polling subclass
428 }
429};
430
431//----------------------------------------------------------------------------
432// QPipeReader
433//----------------------------------------------------------------------------
434class QPipeReader : public QThread
435{
436 Q_OBJECT
437public:
438 QPipeReader(QObject *parent = nullptr)
439 : QThread(parent)
440 {
441 }
442
443 virtual ~QPipeReader()
444 {
445 }
446
447 // start
448 virtual void start() = 0;
449
450 // to be called after every read
451 virtual void resume() = 0;
452
453Q_SIGNALS:
454 // result values:
455 // >= 0 : readAhead
456 // = -1 : atEnd
457 // = -2 : atError
458 // = -3 : data available, but no readAhead
459 void canRead(int result);
460
461protected:
462 virtual void run()
463 {
464 // implement a default to satisfy the polling subclass
465 }
466};
467
468//----------------------------------------------------------------------------
469// QPipeWriterThread
470//----------------------------------------------------------------------------
471class QPipeWriterThread : public QPipeWriter
472{
473 Q_OBJECT
474public:
475 Q_PIPE_ID pipe;
476 QMutex m;
477 QWaitCondition w;
478 bool do_quit;
479 const char *data;
480 int size;
481
482 QPipeWriterThread(Q_PIPE_ID id, QObject *parent = nullptr)
483 : QPipeWriter(parent)
484 {
485 do_quit = false;
486 data = 0;
487 connect(this, &QPipeWriterThread::canWrite_p, this, &QPipeWriterThread::canWrite);
488 DuplicateHandle(GetCurrentProcess(), id, GetCurrentProcess(), &pipe, 0, false, DUPLICATE_SAME_ACCESS);
489 }
490
491 virtual ~QPipeWriterThread()
492 {
493 stop();
494 CloseHandle(pipe);
495 }
496
497 virtual void start()
498 {
499 pipe_set_blocking(pipe, true);
500 QThread::start();
501 }
502
503 virtual int stop()
504 {
505 if (isRunning()) {
506 m.lock();
507 do_quit = true;
508 w.wakeOne();
509 m.unlock();
510 if (!wait(100))
511 terminate();
512 do_quit = false;
513 data = 0;
514 }
515 return size;
516 }
517
518 virtual int write(const char *_data, int _size)
519 {
520 if (!isRunning())
521 return -1;
522
523 QMutexLocker locker(&m);
524 if (data)
525 return 0;
526
527 data = _data;
528 size = _size;
529 w.wakeOne();
530 return _size;
531 }
532
533protected:
534 virtual void run()
535 {
536 while (1) {
537 m.lock();
538
539 while (!data && !do_quit)
540 w.wait(&m);
541
542 if (do_quit) {
543 m.unlock();
544 break;
545 }
546
547 const char *p = data;
548 int len = size;
549
550 m.unlock();
551
552 int ret = internalWrite(p, len);
553
554 m.lock();
555 data = 0;
556 size = ret;
557 m.unlock();
558
559 emit canWrite_p(ret < len ? -1 : 0, ret);
560 }
561 }
562
563private:
564 // attempts to write len bytes. value returned is number of bytes written.
565 // any return value less than len means a write error was encountered
566 int internalWrite(const char *p, int len)
567 {
568 int total = 0;
569 while (total < len) {
570 m.lock();
571 if (do_quit) {
572 m.unlock();
573 return 0;
574 }
575 m.unlock();
576
577 int ret = pipe_write(pipe, p + total, qMin(PIPEWRITER_BLOCK, len - total));
578 if (ret == -1) {
579 // from qt, don't know why
580 if (GetLastError() == 0xE8) // NT_STATUS_INVALID_USER_BUFFER
581 {
582 // give the os a rest
583 msleep(100);
584 continue;
585 }
586
587 // on any other error, end thread
588 return total;
589 }
590 total += ret;
591 }
592 return total;
593 }
594
595Q_SIGNALS:
596 void canWrite_p(int result, int bytesWritten);
597};
598
599//----------------------------------------------------------------------------
600// QPipeWriterPoll
601//----------------------------------------------------------------------------
602class QPipeWriterPoll : public QPipeWriter
603{
604 Q_OBJECT
605public:
606 Q_PIPE_ID pipe;
607 const char *data;
608 int size;
609 SafeTimer timer;
610 int total;
611
612 QPipeWriterPoll(Q_PIPE_ID id, QObject *parent = nullptr)
613 : QPipeWriter(parent)
614 , timer(this)
615 {
616 pipe = id;
617 data = 0;
618 connect(&timer, &SafeTimer::timeout, this, &QPipeWriterPoll::tryNextWrite);
619 }
620
621 virtual ~QPipeWriterPoll()
622 {
623 }
624
625 virtual void start()
626 {
627 pipe_set_blocking(pipe, false);
628 }
629
630 // return number of bytes written
631 virtual int stop()
632 {
633 timer.stop();
634 data = 0;
635 return total;
636 }
637
638 // data pointer needs to remain until canWrite is emitted
639 virtual int write(const char *_data, int _size)
640 {
641 total = 0;
642 data = _data;
643 size = _size;
644 timer.start(0); // write at next event loop
645 return _size;
646 }
647
648private Q_SLOTS:
649 void tryNextWrite()
650 {
651 int written = pipe_write(pipe, data + total, size - total);
652 bool error = false;
653 if (written == -1) {
654 error = true;
655 written = 0; // no bytes written on error
656
657 // from qt, they don't count it as fatal
658 if (GetLastError() == 0xE8) // NT_STATUS_INVALID_USER_BUFFER
659 error = false;
660 }
661
662 total += written;
663 if (error || total == size) {
664 timer.stop();
665 data = 0;
666 emit canWrite(error ? -1 : 0, total);
667 return;
668 }
669
670 timer.setInterval(PIPEWRITER_POLL);
671 }
672};
673
674//----------------------------------------------------------------------------
675// QPipeReaderThread
676//----------------------------------------------------------------------------
677class QPipeReaderThread : public QPipeReader
678{
679 Q_OBJECT
680public:
681 Q_PIPE_ID pipe;
682 QMutex m;
683 QWaitCondition w;
684 bool do_quit, active;
685
686 QPipeReaderThread(Q_PIPE_ID id, QObject *parent = nullptr)
687 : QPipeReader(parent)
688 {
689 do_quit = false;
690 active = true;
691 connect(this, &QPipeReaderThread::canRead_p, this, &QPipeReaderThread::canRead);
692 DuplicateHandle(GetCurrentProcess(), id, GetCurrentProcess(), &pipe, 0, false, DUPLICATE_SAME_ACCESS);
693 }
694
695 virtual ~QPipeReaderThread()
696 {
697 if (isRunning()) {
698 m.lock();
699 do_quit = true;
700 w.wakeOne();
701 m.unlock();
702 if (!wait(100))
703 terminate();
704 }
705 CloseHandle(pipe);
706 }
707
708 virtual void start()
709 {
710 pipe_set_blocking(pipe, true);
711 QThread::start();
712 }
713
714 virtual void resume()
715 {
716 QMutexLocker locker(&m);
717 pipe_set_blocking(pipe, true);
718 active = true;
719 w.wakeOne();
720 }
721
722protected:
723 virtual void run()
724 {
725 while (1) {
726 m.lock();
727
728 while (!active && !do_quit)
729 w.wait(&m);
730
731 if (do_quit) {
732 m.unlock();
733 break;
734 }
735
736 m.unlock();
737
738 while (1) {
739 unsigned char c;
740 bool done;
741 int ret = pipe_read(pipe, (char *)&c, 1, &done);
742 if (done || ret != 0) // eof, error, or data?
743 {
744 int result;
745
746 if (done) // we got EOF?
747 result = -1;
748 else if (ret == -1) // we got an error?
749 result = -2;
750 else if (ret >= 1) // we got some data?? queue it
751 result = c;
752 else // will never happen
753 result = -2;
754
755 m.lock();
756 active = false;
757 pipe_set_blocking(pipe, false);
758 m.unlock();
759
760 emit canRead_p(result);
761 break;
762 }
763 }
764 }
765 }
766
767Q_SIGNALS:
768 void canRead_p(int result);
769};
770
771//----------------------------------------------------------------------------
772// QPipeReaderPoll
773//----------------------------------------------------------------------------
774class QPipeReaderPoll : public QPipeReader
775{
776 Q_OBJECT
777public:
778 Q_PIPE_ID pipe;
779 SafeTimer timer;
780 bool consoleMode;
781
782 QPipeReaderPoll(Q_PIPE_ID id, QObject *parent = nullptr)
783 : QPipeReader(parent)
784 , timer(this)
785 {
786 pipe = id;
787 connect(&timer, &SafeTimer::timeout, this, &QPipeReaderPoll::tryRead);
788 }
789
790 virtual ~QPipeReaderPoll()
791 {
792 }
793
794 virtual void start()
795 {
796 pipe_set_blocking(pipe, false);
797 consoleMode = pipe_is_a_console(pipe);
798 resume();
799 }
800
801 virtual void resume()
802 {
803 timer.start(0);
804 }
805
806private Q_SLOTS:
807 void tryRead()
808 {
809 if (consoleMode)
810 tryReadConsole();
811 else
812 tryReadPipe();
813 }
814
815private:
816 void tryReadPipe()
817 {
818 // is there data available for reading? if so, signal.
819 int bytes = pipe_read_avail(pipe);
820 if (bytes > 0) {
821 timer.stop();
822 emit canRead(-3); // no readAhead
823 return;
824 }
825
826 // no data available? probe for EOF/error
827 unsigned char c;
828 bool done;
829 int ret = pipe_read(pipe, (char *)&c, 1, &done);
830 if (done || ret != 0) // eof, error, or data?
831 {
832 int result;
833
834 if (done) // we got EOF?
835 result = -1;
836 else if (ret == -1) // we got an error?
837 result = -2;
838 else if (ret >= 1) // we got some data?? queue it
839 result = c;
840 else // will never happen
841 result = -2;
842
843 timer.stop();
844 emit canRead(result);
845 return;
846 }
847
848 timer.setInterval(PIPEREADER_POLL);
849 }
850
851 void tryReadConsole()
852 {
853 // is there data available for reading? if so, signal.
854 int count = pipe_read_avail_console(pipe);
855 if (count > 0) {
856 timer.stop();
857 emit canRead(-3); // no readAhead
858 return;
859 }
860
861 timer.setInterval(PIPEREADER_POLL);
862 }
863};
864
865// end of windows pipe writer/reader implementations
866
867#endif
868
869//----------------------------------------------------------------------------
870// QPipeDevice
871//----------------------------------------------------------------------------
872class QPipeDevice::Private : public QObject
873{
874 Q_OBJECT
875public:
876 QPipeDevice *q;
877 Q_PIPE_ID pipe;
878 QPipeDevice::Type type;
879 bool enabled;
880 bool blockReadNotify;
881 bool canWrite;
882 int writeResult;
883 int lastTaken, lastWritten;
884
885#ifdef Q_OS_WIN
886 bool atEnd, atError, forceNotify;
887 int readAhead;
888 SafeTimer *readTimer;
889 QTextDecoder *dec;
890 bool consoleMode;
891 QPipeWriter *pipeWriter;
892 QPipeReader *pipeReader;
893#endif
894#ifdef Q_OS_UNIX
895 SafeSocketNotifier *sn_read, *sn_write;
896#endif
897
898 Private(QPipeDevice *_q)
899 : QObject(_q)
900 , q(_q)
901 , pipe(INVALID_Q_PIPE_ID)
902 {
903#ifdef Q_OS_WIN
904 readTimer = 0;
905 pipeWriter = 0;
906 pipeReader = 0;
907 dec = 0;
908#endif
909#ifdef Q_OS_UNIX
910 sn_read = nullptr;
911 sn_write = nullptr;
912#endif
913 }
914
915 ~Private() override
916 {
917 reset();
918 }
919
920 void reset()
921 {
922#ifdef Q_OS_WIN
923 atEnd = false;
924 atError = false;
925 forceNotify = false;
926 readAhead = -1;
927 delete readTimer;
928 readTimer = 0;
929 delete pipeWriter;
930 pipeWriter = 0;
931 delete pipeReader;
932 pipeReader = 0;
933 delete dec;
934 dec = 0;
935 consoleMode = false;
936#endif
937#ifdef Q_OS_UNIX
938 delete sn_read;
939 sn_read = nullptr;
940 delete sn_write;
941 sn_write = nullptr;
942#endif
943 if (pipe != INVALID_Q_PIPE_ID) {
944#ifdef Q_OS_WIN
945 CloseHandle(pipe);
946#endif
947#ifdef Q_OS_UNIX
948 ::close(fd: pipe);
949#endif
950 pipe = INVALID_Q_PIPE_ID;
951 }
952
953 enabled = false;
954 blockReadNotify = false;
955 canWrite = true;
956 writeResult = -1;
957 }
958
959 void setup(Q_PIPE_ID id, QPipeDevice::Type _type)
960 {
961 pipe = id;
962 type = _type;
963 }
964
965 void enable()
966 {
967 if (enabled)
968 return;
969
970 enabled = true;
971
972 if (type == QPipeDevice::Read) {
973#ifdef Q_OS_WIN
974 // for windows, the blocking mode is chosen by the QPipeReader
975
976 // console might need a decoder
977 if (consoleMode) {
978 dec = 0;
979 }
980
981 // pipe reader
982#ifdef USE_POLL
983 pipeReader = new QPipeReaderPoll(pipe, this);
984#else
985 // console always polls, no matter what
986 if (consoleMode)
987 pipeReader = new QPipeReaderPoll(pipe, this);
988 else
989 pipeReader = new QPipeReaderThread(pipe, this);
990#endif
991 connect(pipeReader, &QPipeReader::canRead, this, &Private::pr_canRead);
992 pipeReader->start();
993
994 // polling timer
995 readTimer = new SafeTimer(this);
996 connect(readTimer, &SafeTimer::timeout, this, &Private::t_timeout);
997
998 // updated: now that we have pipeReader, this no longer
999 // polls for data. it only does delayed singleshot
1000 // notifications.
1001 readTimer->setSingleShot(true);
1002#endif
1003#ifdef Q_OS_UNIX
1004 pipe_set_blocking(pipe, b: false);
1005
1006 // socket notifier
1007 sn_read = new SafeSocketNotifier(pipe, QSocketNotifier::Read, this);
1008 connect(sender: sn_read, signal: &SafeSocketNotifier::activated, context: this, slot: &Private::sn_read_activated);
1009#endif
1010 } else {
1011 // for windows, the blocking mode is chosen by the QPipeWriter
1012#ifdef Q_OS_UNIX
1013 pipe_set_blocking(pipe, b: false);
1014
1015 // socket notifier
1016 sn_write = new SafeSocketNotifier(pipe, QSocketNotifier::Write, this);
1017 connect(sender: sn_write, signal: &SafeSocketNotifier::activated, context: this, slot: &Private::sn_write_activated);
1018 sn_write->setEnabled(false);
1019#endif
1020 }
1021 }
1022
1023public Q_SLOTS:
1024 void t_timeout()
1025 {
1026#ifdef Q_OS_WIN
1027 if (blockReadNotify)
1028 return;
1029
1030 // were we forced to notify? this can happen if we want to
1031 // spread out results across two reads. whatever caused
1032 // the forceNotify already knows what to do, so all we do
1033 // is signal.
1034 if (forceNotify) {
1035 forceNotify = false;
1036 blockReadNotify = true;
1037 emit q->notify();
1038 return;
1039 }
1040#endif
1041 }
1042
1043 void pw_canWrite(int result, int bytesWritten)
1044 {
1045#ifdef Q_OS_WIN
1046 if (result == 0) {
1047 writeResult = 0;
1048 lastWritten = lastTaken; // success means all bytes
1049 } else {
1050 writeResult = -1;
1051 lastWritten = bytesWritten;
1052 }
1053
1054 canWrite = true;
1055 emit q->notify();
1056#else
1057 Q_UNUSED(result);
1058 Q_UNUSED(bytesWritten);
1059#endif
1060 }
1061
1062 void pr_canRead(int result)
1063 {
1064#ifdef Q_OS_WIN
1065 blockReadNotify = true;
1066 if (result == -1)
1067 atEnd = true;
1068 else if (result == -2)
1069 atError = true;
1070 else if (result != -3)
1071 readAhead = result;
1072 emit q->notify();
1073#else
1074 Q_UNUSED(result);
1075#endif
1076 }
1077
1078 void sn_read_activated()
1079 {
1080#ifdef Q_OS_UNIX
1081 if (blockReadNotify)
1082 return;
1083
1084 blockReadNotify = true;
1085 emit q->notify();
1086#endif
1087 }
1088
1089 void sn_write_activated()
1090 {
1091#ifdef Q_OS_UNIX
1092 writeResult = 0;
1093 lastWritten = lastTaken;
1094
1095 canWrite = true;
1096 sn_write->setEnabled(false);
1097 emit q->notify();
1098#endif
1099 }
1100};
1101
1102QPipeDevice::QPipeDevice(QObject *parent)
1103 : QObject(parent)
1104{
1105 d = new Private(this);
1106}
1107
1108QPipeDevice::~QPipeDevice()
1109{
1110 delete d;
1111}
1112
1113QPipeDevice::Type QPipeDevice::type() const
1114{
1115 return d->type;
1116}
1117
1118bool QPipeDevice::isValid() const
1119{
1120 return (d->pipe != INVALID_Q_PIPE_ID);
1121}
1122
1123Q_PIPE_ID QPipeDevice::id() const
1124{
1125 return d->pipe;
1126}
1127
1128int QPipeDevice::idAsInt() const
1129{
1130#ifdef Q_OS_WIN
1131 DWORD dw;
1132 memcpy(&dw, &d->pipe, sizeof(DWORD));
1133 return (int)dw; // FIXME? assumes handle value fits in signed int
1134#endif
1135#ifdef Q_OS_UNIX
1136 return d->pipe;
1137#endif
1138}
1139
1140void QPipeDevice::take(Q_PIPE_ID id, Type t)
1141{
1142 close();
1143 d->setup(id, type: t);
1144}
1145
1146void QPipeDevice::enable()
1147{
1148#ifdef Q_OS_WIN
1149 d->consoleMode = pipe_is_a_console(d->pipe);
1150#endif
1151 d->enable();
1152}
1153
1154void QPipeDevice::close()
1155{
1156 d->reset();
1157}
1158
1159void QPipeDevice::release()
1160{
1161 d->pipe = INVALID_Q_PIPE_ID;
1162 d->reset();
1163}
1164
1165bool QPipeDevice::setInheritable(bool enabled)
1166{
1167#ifdef Q_OS_WIN
1168 Q_PIPE_ID newPipe;
1169 if (!pipe_set_inheritable(d->pipe, enabled, &newPipe))
1170 return false;
1171 d->pipe = newPipe;
1172#ifdef USE_POLL
1173 if (d->pipeReader)
1174 static_cast<QPipeReaderPoll *>(d->pipeReader)->pipe = d->pipe;
1175 if (d->pipeWriter)
1176 static_cast<QPipeWriterPoll *>(d->pipeWriter)->pipe = d->pipe;
1177#endif
1178 return true;
1179#endif
1180#ifdef Q_OS_UNIX
1181 return pipe_set_inheritable(pipe: d->pipe, b: enabled, newPipe: nullptr);
1182#endif
1183}
1184
1185int QPipeDevice::bytesAvailable() const
1186{
1187 int n;
1188#ifdef Q_OS_WIN
1189 if (d->consoleMode)
1190 n = pipe_read_avail_console(d->pipe);
1191 else
1192 n = pipe_read_avail(d->pipe);
1193 if (d->readAhead != -1)
1194 ++n;
1195#else
1196 n = pipe_read_avail(pipe: d->pipe);
1197#endif
1198 return n;
1199}
1200
1201int QPipeDevice::read(char *data, int maxsize)
1202{
1203 if (d->type != QPipeDevice::Read)
1204 return -1;
1205
1206 // must read at least 1 byte
1207 if (maxsize < 1)
1208 return -1;
1209
1210#ifdef Q_OS_WIN
1211 // for windows console:
1212 // the number of bytes in utf8 can exceed the number of actual
1213 // characters it represents. to be safe, we'll assume that
1214 // utf8 could outnumber characters X:1. this does mean that
1215 // the maxsize parameter needs to be at least X to do
1216 // anything. (X = CONSOLE_CHAREXPAND)
1217 if (d->consoleMode && maxsize < CONSOLE_CHAREXPAND)
1218 return -1;
1219
1220 // for resuming the pipeReader
1221 bool wasBlocked = d->blockReadNotify;
1222#endif
1223
1224 d->blockReadNotify = false;
1225
1226#ifdef Q_OS_WIN
1227 // predetermined results
1228 if (d->atEnd) {
1229 close();
1230 return 0;
1231 }
1232 if (d->atError) {
1233 close();
1234 return -1;
1235 }
1236
1237 int offset = 0;
1238 int size = maxsize;
1239
1240 // prepend readAhead if we have it
1241 if (d->readAhead != -1) {
1242 unsigned char c = (unsigned char)d->readAhead;
1243 d->readAhead = -1;
1244 memcpy(&data[0], &c, 1);
1245 ++offset;
1246 --size;
1247
1248 // readAhead was enough data for the caller?
1249 if (size == 0) {
1250 if (wasBlocked)
1251 d->pipeReader->resume();
1252 return offset;
1253 }
1254 }
1255
1256 // read from the pipe now
1257 bool done;
1258 int ret;
1259 if (d->consoleMode) {
1260 // read a fraction of the number of characters as requested,
1261 // to guarantee the result fits
1262 int num = size / CONSOLE_CHAREXPAND;
1263
1264#ifdef QPIPE_SECURE
1265 SecureArray destbuf(num * sizeof(ushort), 0);
1266#else
1267 QByteArray destbuf(num * sizeof(ushort), 0);
1268#endif
1269 ushort *dest = (ushort *)destbuf.data();
1270
1271 ret = pipe_read_console(d->pipe, dest, num, &done, d->dec);
1272 if (ret != -1) {
1273 // for security, encode one character at a time without
1274 // performing a QString conversion of the whole thing
1275 QTextCodec *codec = QTextCodec::codecForMib(106);
1276 QTextCodec::ConverterState cstate(QTextCodec::IgnoreHeader);
1277 int at = 0;
1278 for (int n = 0; n < ret; ++n) {
1279 QChar c(dest[n]);
1280 QByteArray out = codec->fromUnicode(&c, 1, &cstate);
1281 memcpy(data + offset + at, out.data(), out.size());
1282 at += out.size();
1283 }
1284 ret = at; // change ret to actual bytes
1285 }
1286 } else
1287 ret = pipe_read(d->pipe, data + offset, size, &done);
1288 if (done || ret == -1) // eof or error
1289 {
1290 // did we already have some data? if so, defer the eof/error
1291 if (offset) {
1292 d->forceNotify = true;
1293 if (done)
1294 d->atEnd = true;
1295 else
1296 d->atError = true;
1297
1298 // readTimer is a singleshot, so we have to start it
1299 // for forceNotify to work
1300 d->readTimer->start();
1301 }
1302 // otherwise, bail
1303 else {
1304 close();
1305 if (done)
1306 return 0;
1307 else
1308 return -1;
1309 }
1310 } else
1311 offset += ret;
1312
1313 // pipe still active? resume the pipeReader
1314 if (wasBlocked && !d->atEnd && !d->atError)
1315 d->pipeReader->resume();
1316
1317 // no data means error
1318 if (offset == 0)
1319 return -1;
1320
1321 return offset;
1322#endif
1323#ifdef Q_OS_UNIX
1324 bool done;
1325 int r = pipe_read(pipe: d->pipe, data, max: maxsize, eof: &done);
1326 if (done) {
1327 close();
1328 return 0;
1329 }
1330 if (r == -1) {
1331 close();
1332 return -1;
1333 }
1334
1335 // no data means error
1336 if (r == 0)
1337 return -1;
1338
1339 return r;
1340#endif
1341}
1342
1343int QPipeDevice::write(const char *data, int size)
1344{
1345 if (d->type != QPipeDevice::Write)
1346 return -1;
1347
1348 // allowed to write?
1349 if (!d->canWrite)
1350 return -1;
1351
1352 // if size is zero, don't bother
1353 if (size == 0)
1354 return 0;
1355
1356 int r;
1357#ifdef Q_OS_WIN
1358 if (!d->pipeWriter) {
1359#ifdef USE_POLL
1360 d->pipeWriter = new QPipeWriterPoll(d->pipe, d);
1361#else
1362 // console always polls, no matter what
1363 if (d->consoleMode)
1364 d->pipeWriter = new QPipeReaderPoll(d->pipe, d);
1365 else
1366 d->pipeWriter = new QPipeWriterThread(d->pipe, d);
1367#endif
1368 connect(d->pipeWriter, &QPipeWriter::canWrite, d, &Private::pw_canWrite);
1369 d->pipeWriter->start();
1370 }
1371
1372 if (d->consoleMode) {
1373 // Note: we convert to QString here, but it should not be a
1374 // security issue (see pipe_write_console comment above)
1375
1376 // for console, just write direct. we won't use pipewriter
1377 QString out = QString::fromUtf8(QByteArray(data, size));
1378 r = pipe_write_console(d->pipe, out.utf16(), out.length());
1379 if (r == -1)
1380 return -1;
1381
1382 // convert characters to bytes
1383 r = out.mid(0, r).toUtf8().size();
1384
1385 // simulate. we invoke the signal of pipewriter rather than our
1386 // own slot, so that the invoke can be cancelled.
1387 d->canWrite = false;
1388 QMetaObject::invokeMethod(d->pipeWriter, "canWrite", Qt::QueuedConnection, Q_ARG(int, 0), Q_ARG(int, r));
1389 } else {
1390 d->canWrite = false;
1391 r = d->pipeWriter->write(data, size);
1392 }
1393
1394 d->lastTaken = r;
1395 if (r == -1) {
1396 close();
1397 return -1;
1398 }
1399#endif
1400#ifdef Q_OS_UNIX
1401 r = pipe_write(pipe: d->pipe, data, size);
1402 d->lastTaken = r;
1403 if (r == -1) {
1404 close();
1405 return -1;
1406 }
1407
1408 d->canWrite = false;
1409 d->sn_write->setEnabled(true);
1410#endif
1411 return r;
1412}
1413
1414int QPipeDevice::writeResult(int *written) const
1415{
1416 if (written)
1417 *written = d->lastWritten;
1418 return d->writeResult;
1419}
1420
1421//----------------------------------------------------------------------------
1422// QPipeEnd
1423//----------------------------------------------------------------------------
1424enum ResetMode
1425{
1426 ResetSession = 0,
1427 ResetSessionAndData = 1,
1428 ResetAll = 2
1429};
1430
1431class QPipeEnd::Private : public QObject
1432{
1433 Q_OBJECT
1434public:
1435 QPipeEnd *q;
1436 QPipeDevice pipe;
1437 QPipeDevice::Type type;
1438 QByteArray buf;
1439 QByteArray curWrite;
1440
1441#ifdef Q_OS_WIN
1442 bool consoleMode;
1443#endif
1444
1445#ifdef QPIPE_SECURE
1446 bool secure;
1447 SecureArray sec_buf;
1448 SecureArray sec_curWrite;
1449#endif
1450 SafeTimer readTrigger, writeTrigger, closeTrigger, writeErrorTrigger;
1451 bool canRead, activeWrite;
1452 int lastWrite;
1453 bool closeLater;
1454 bool closing;
1455
1456 Private(QPipeEnd *_q)
1457 : QObject(_q)
1458 , q(_q)
1459 , pipe(this)
1460 , readTrigger(this)
1461 , writeTrigger(this)
1462 , closeTrigger(this)
1463 , writeErrorTrigger(this)
1464 {
1465 readTrigger.setSingleShot(true);
1466 writeTrigger.setSingleShot(true);
1467 closeTrigger.setSingleShot(true);
1468 writeErrorTrigger.setSingleShot(true);
1469 connect(sender: &pipe, signal: &QPipeDevice::notify, context: this, slot: &Private::pipe_notify);
1470 connect(sender: &readTrigger, signal: &SafeTimer::timeout, context: this, slot: &Private::doRead);
1471 connect(sender: &writeTrigger, signal: &SafeTimer::timeout, context: this, slot: &Private::doWrite);
1472 connect(sender: &closeTrigger, signal: &SafeTimer::timeout, context: this, slot: &Private::doClose);
1473 connect(sender: &writeErrorTrigger, signal: &SafeTimer::timeout, context: this, slot: &Private::doWriteError);
1474 reset(mode: ResetSessionAndData);
1475 }
1476
1477 void reset(ResetMode mode)
1478 {
1479 pipe.close();
1480 readTrigger.stop();
1481 writeTrigger.stop();
1482 closeTrigger.stop();
1483 writeErrorTrigger.stop();
1484 canRead = false;
1485 activeWrite = false;
1486 lastWrite = 0;
1487 closeLater = false;
1488 closing = false;
1489 curWrite.clear();
1490#ifdef QPIPE_SECURE
1491 secure = false;
1492 sec_curWrite.clear();
1493#endif
1494
1495 if (mode >= ResetSessionAndData) {
1496 buf.clear();
1497#ifdef QPIPE_SECURE
1498 sec_buf.clear();
1499#endif
1500 }
1501 }
1502
1503 void setup(Q_PIPE_ID id, QPipeDevice::Type _type)
1504 {
1505 type = _type;
1506#ifdef Q_OS_WIN
1507 consoleMode = pipe_is_a_console(id);
1508#endif
1509 pipe.take(id, t: type);
1510 }
1511
1512 int pendingSize() const
1513 {
1514#ifdef QPIPE_SECURE
1515 if (secure)
1516 return sec_buf.size();
1517 else
1518#endif
1519 return buf.size();
1520 }
1521
1522 int pendingFreeSize() const
1523 {
1524#ifdef QPIPE_SECURE
1525 if (secure)
1526 return qMax(PIPEEND_READBUF_SEC - sec_buf.size(), b: 0);
1527 else
1528#endif
1529 return qMax(PIPEEND_READBUF - buf.size(), b: 0);
1530 }
1531
1532 void appendArray(QByteArray *a, const QByteArray &b)
1533 {
1534 (*a) += b;
1535 }
1536
1537#ifdef QPIPE_SECURE
1538 void appendArray(SecureArray *a, const SecureArray &b)
1539 {
1540 a->append(a: b);
1541 }
1542#endif
1543
1544 void takeArray(QByteArray *a, int len)
1545 {
1546 char *p = a->data();
1547 const int newsize = a->size() - len;
1548 memmove(dest: p, src: p + len, n: newsize);
1549 a->resize(size: newsize);
1550 }
1551
1552#ifdef QPIPE_SECURE
1553 void takeArray(SecureArray *a, int len)
1554 {
1555 char *p = a->data();
1556 const int newsize = a->size() - len;
1557 memmove(dest: p, src: p + len, n: newsize);
1558 a->resize(size: newsize);
1559 }
1560#endif
1561
1562 void setupNextRead()
1563 {
1564 if (pipe.isValid() && canRead) {
1565 canRead = false;
1566 readTrigger.start(msec: 0);
1567 }
1568 }
1569
1570 void setupNextWrite()
1571 {
1572 if (!activeWrite) {
1573 activeWrite = true;
1574 writeTrigger.start(msec: 0);
1575 }
1576 }
1577
1578 QByteArray read(QByteArray *buf, int bytes)
1579 {
1580 QByteArray a;
1581 if (bytes == -1 || bytes > buf->size()) {
1582 a = *buf;
1583 } else {
1584 a.resize(size: bytes);
1585 memcpy(dest: a.data(), src: buf->data(), n: a.size());
1586 }
1587
1588 takeArray(a: buf, len: a.size());
1589 setupNextRead();
1590 return a;
1591 }
1592
1593 void write(QByteArray *buf, const QByteArray &a)
1594 {
1595 appendArray(a: buf, b: a);
1596 setupNextWrite();
1597 }
1598
1599#ifdef QPIPE_SECURE
1600 SecureArray readSecure(SecureArray *buf, int bytes)
1601 {
1602 SecureArray a;
1603 if (bytes == -1 || bytes > buf->size()) {
1604 a = *buf;
1605 } else {
1606 a.resize(size: bytes);
1607 memcpy(dest: a.data(), src: buf->data(), n: a.size());
1608 }
1609
1610 takeArray(a: buf, len: a.size());
1611 setupNextRead();
1612 return a;
1613 }
1614
1615 void writeSecure(SecureArray *buf, const SecureArray &a)
1616 {
1617 appendArray(a: buf, b: a);
1618 setupNextWrite();
1619 }
1620#endif
1621
1622public Q_SLOTS:
1623 void pipe_notify()
1624 {
1625 if (pipe.type() == QPipeDevice::Read) {
1626 doRead();
1627 } else {
1628 int x;
1629 int writeResult = pipe.writeResult(written: &x);
1630 if (writeResult == -1)
1631 lastWrite = x; // if error, we may have written less bytes
1632
1633 // remove what we just wrote
1634 bool moreData = false;
1635#ifdef QPIPE_SECURE
1636 if (secure) {
1637 takeArray(a: &sec_buf, len: lastWrite);
1638 moreData = !sec_buf.isEmpty();
1639 } else
1640#endif
1641 {
1642 takeArray(a: &buf, len: lastWrite);
1643 moreData = !buf.isEmpty();
1644 }
1645
1646#ifdef QPIPE_SECURE
1647 sec_curWrite.clear();
1648#endif
1649 curWrite.clear();
1650
1651 x = lastWrite;
1652 lastWrite = 0;
1653
1654 if (writeResult == 0) {
1655 // more to write? do it
1656 if (moreData) {
1657 writeTrigger.start(msec: 0);
1658 }
1659 // done with all writing
1660 else {
1661 activeWrite = false;
1662 if (closeLater) {
1663 closeLater = false;
1664 closeTrigger.start(msec: 0);
1665 }
1666 }
1667 } else
1668 writeErrorTrigger.start();
1669
1670 if (x > 0)
1671 emit q->bytesWritten(bytes: x);
1672 }
1673 }
1674
1675 void doRead()
1676 {
1677 doReadActual(sigs: true);
1678 }
1679
1680 void doReadActual(bool sigs)
1681 {
1682 const int left = pendingFreeSize();
1683 if (left == 0) {
1684 canRead = true;
1685 return;
1686 }
1687
1688 int max;
1689#ifdef Q_OS_WIN
1690 if (consoleMode) {
1691 // need a minimum amount for console
1692 if (left < CONSOLE_CHAREXPAND) {
1693 canRead = true;
1694 return;
1695 }
1696
1697 // don't use pipe.bytesAvailable() for console mode,
1698 // as it is somewhat bogus. fortunately, there is
1699 // no problem with overreading from the console.
1700 max = qMin(left, 32);
1701 } else
1702#endif
1703 {
1704 max = qMin(a: left, b: pipe.bytesAvailable());
1705 }
1706
1707 int ret;
1708#ifdef QPIPE_SECURE
1709 if (secure) {
1710 SecureArray a(max);
1711 ret = pipe.read(data: a.data(), maxsize: a.size());
1712 if (ret >= 1) {
1713 a.resize(size: ret);
1714 sec_buf.append(a);
1715 }
1716 } else
1717#endif
1718 {
1719 QByteArray a(max, 0);
1720 ret = pipe.read(data: a.data(), maxsize: a.size());
1721 if (ret >= 1) {
1722 a.resize(size: ret);
1723 buf += a;
1724 }
1725 }
1726
1727 if (ret < 1) {
1728 reset(mode: ResetSession);
1729 if (sigs) {
1730 if (ret == 0)
1731 emit q->error(e: QPipeEnd::ErrorEOF);
1732 else
1733 emit q->error(e: QPipeEnd::ErrorBroken);
1734 }
1735 return;
1736 }
1737
1738 if (sigs)
1739 emit q->readyRead();
1740 }
1741
1742 void doWrite()
1743 {
1744 int ret;
1745#ifdef QPIPE_SECURE
1746 if (secure) {
1747 sec_curWrite.resize(size: qMin(PIPEEND_BLOCK, b: sec_buf.size()));
1748 memcpy(dest: sec_curWrite.data(), src: sec_buf.data(), n: sec_curWrite.size());
1749
1750 ret = pipe.write(data: sec_curWrite.data(), size: sec_curWrite.size());
1751 } else
1752#endif
1753 {
1754 curWrite.resize(size: qMin(PIPEEND_BLOCK, b: buf.size()));
1755 memcpy(dest: curWrite.data(), src: buf.data(), n: curWrite.size());
1756
1757 ret = pipe.write(data: curWrite.data(), size: curWrite.size());
1758 }
1759
1760 if (ret == -1) {
1761 reset(mode: ResetSession);
1762 emit q->error(e: QPipeEnd::ErrorBroken);
1763 return;
1764 }
1765
1766 lastWrite = ret;
1767 }
1768
1769 void doClose()
1770 {
1771 reset(mode: ResetSession);
1772 emit q->closed();
1773 }
1774
1775 void doWriteError()
1776 {
1777 reset(mode: ResetSession);
1778 emit q->error(e: QPipeEnd::ErrorBroken);
1779 }
1780};
1781
1782QPipeEnd::QPipeEnd(QObject *parent)
1783 : QObject(parent)
1784{
1785 d = new Private(this);
1786}
1787
1788QPipeEnd::~QPipeEnd()
1789{
1790 delete d;
1791}
1792
1793void QPipeEnd::reset()
1794{
1795 d->reset(mode: ResetAll);
1796}
1797
1798QPipeDevice::Type QPipeEnd::type() const
1799{
1800 return d->pipe.type();
1801}
1802
1803bool QPipeEnd::isValid() const
1804{
1805 return d->pipe.isValid();
1806}
1807
1808Q_PIPE_ID QPipeEnd::id() const
1809{
1810 return d->pipe.id();
1811}
1812
1813int QPipeEnd::idAsInt() const
1814{
1815 return d->pipe.idAsInt();
1816}
1817
1818void QPipeEnd::take(Q_PIPE_ID id, QPipeDevice::Type t)
1819{
1820 reset();
1821 d->setup(id, type: t);
1822}
1823
1824#ifdef QPIPE_SECURE
1825void QPipeEnd::setSecurityEnabled(bool secure)
1826{
1827 // no change
1828 if (d->secure == secure)
1829 return;
1830
1831 if (secure) {
1832 d->sec_buf = d->buf;
1833 d->buf.clear();
1834 } else {
1835 d->buf = d->sec_buf.toByteArray();
1836 d->sec_buf.clear();
1837 }
1838
1839 d->secure = secure;
1840}
1841#endif
1842
1843void QPipeEnd::enable()
1844{
1845 d->pipe.enable();
1846}
1847
1848void QPipeEnd::close()
1849{
1850 if (!isValid() || d->closing)
1851 return;
1852
1853 d->closing = true;
1854
1855 if (d->activeWrite)
1856 d->closeLater = true;
1857 else
1858 d->closeTrigger.start(msec: 0);
1859}
1860
1861void QPipeEnd::release()
1862{
1863 if (!isValid())
1864 return;
1865
1866 d->pipe.release();
1867 d->reset(mode: ResetSession);
1868}
1869
1870bool QPipeEnd::setInheritable(bool enabled)
1871{
1872 return d->pipe.setInheritable(enabled);
1873}
1874
1875void QPipeEnd::finalize()
1876{
1877 if (!isValid())
1878 return;
1879
1880 if (d->pipe.bytesAvailable())
1881 d->doReadActual(sigs: false);
1882 d->reset(mode: ResetSession);
1883}
1884
1885void QPipeEnd::finalizeAndRelease()
1886{
1887 if (!isValid())
1888 return;
1889
1890 if (d->pipe.bytesAvailable())
1891 d->doReadActual(sigs: false);
1892 d->pipe.release();
1893 d->reset(mode: ResetSession);
1894}
1895
1896int QPipeEnd::bytesAvailable() const
1897{
1898 return d->pendingSize();
1899}
1900
1901int QPipeEnd::bytesToWrite() const
1902{
1903 return d->pendingSize();
1904}
1905
1906QByteArray QPipeEnd::read(int bytes)
1907{
1908 return d->read(buf: &d->buf, bytes);
1909}
1910
1911void QPipeEnd::write(const QByteArray &buf)
1912{
1913 if (!isValid() || d->closing)
1914 return;
1915
1916 if (buf.isEmpty())
1917 return;
1918
1919#ifdef QPIPE_SECURE
1920 if (d->secure) // call writeSecure() instead
1921 return;
1922#endif
1923
1924 d->write(buf: &d->buf, a: buf);
1925}
1926
1927#ifdef QPIPE_SECURE
1928SecureArray QPipeEnd::readSecure(int bytes)
1929{
1930 return d->readSecure(buf: &d->sec_buf, bytes);
1931}
1932
1933void QPipeEnd::writeSecure(const SecureArray &buf)
1934{
1935 if (!isValid() || d->closing)
1936 return;
1937
1938 if (buf.isEmpty())
1939 return;
1940
1941 if (!d->secure) // call write() instead
1942 return;
1943
1944 d->writeSecure(buf: &d->sec_buf, a: buf);
1945}
1946#endif
1947
1948QByteArray QPipeEnd::takeBytesToWrite()
1949{
1950 // only call this on inactive sessions
1951 if (isValid())
1952 return QByteArray();
1953
1954 QByteArray a = d->buf;
1955 d->buf.clear();
1956 return a;
1957}
1958
1959#ifdef QPIPE_SECURE
1960SecureArray QPipeEnd::takeBytesToWriteSecure()
1961{
1962 // only call this on inactive sessions
1963 if (isValid())
1964 return SecureArray();
1965
1966 SecureArray a = d->sec_buf;
1967 d->sec_buf.clear();
1968 return a;
1969}
1970#endif
1971
1972//----------------------------------------------------------------------------
1973// QPipe
1974//----------------------------------------------------------------------------
1975QPipe::QPipe(QObject *parent)
1976 : i(parent)
1977 , o(parent)
1978{
1979}
1980
1981QPipe::~QPipe()
1982{
1983}
1984
1985void QPipe::reset()
1986{
1987 i.reset();
1988 o.reset();
1989}
1990
1991#ifdef QPIPE_SECURE
1992bool QPipe::create(bool secure)
1993#else
1994bool QPipe::create()
1995#endif
1996{
1997 reset();
1998
1999#ifdef Q_OS_WIN
2000 SECURITY_ATTRIBUTES secAttr;
2001 memset(&secAttr, 0, sizeof secAttr);
2002 secAttr.nLength = sizeof secAttr;
2003 secAttr.bInheritHandle = false;
2004
2005 HANDLE r, w;
2006 if (!CreatePipe(&r, &w, &secAttr, 0))
2007 return false;
2008 i.take(r, QPipeDevice::Read);
2009 o.take(w, QPipeDevice::Write);
2010#endif
2011
2012#ifdef Q_OS_UNIX
2013 int p[2];
2014 if (pipe(pipedes: p) == -1)
2015 return false;
2016 if (!pipe_set_inheritable(pipe: p[0], b: false, newPipe: nullptr) || !pipe_set_inheritable(pipe: p[1], b: false, newPipe: nullptr)) {
2017 close(fd: p[0]);
2018 close(fd: p[1]);
2019 return false;
2020 }
2021 i.take(id: p[0], t: QPipeDevice::Read);
2022 o.take(id: p[1], t: QPipeDevice::Write);
2023#endif
2024
2025#ifdef QPIPE_SECURE
2026 i.setSecurityEnabled(secure);
2027 o.setSecurityEnabled(secure);
2028#endif
2029
2030 return true;
2031}
2032
2033}
2034
2035#include "qpipe.moc"
2036

source code of qca/src/support/qpipe.cpp