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
69 namespace QCA {
70
71 #ifdef Q_OS_UNIX
72 // adapted from qt
73 Q_GLOBAL_STATIC(QMutex, ign_mutex)
74 static bool ign_sigpipe = false;
75
ignore_sigpipe()76 static 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(&noaction, 0, sizeof(noaction));
84 noaction.sa_handler = SIG_IGN;
85 sigaction(SIGPIPE, &noaction, nullptr);
86 }
87 }
88 #endif
89
90 #ifdef Q_OS_WIN
pipe_dword_cap_to_int(DWORD dw)91 static 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
pipe_dword_overflows_int(DWORD dw)99 static 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
pipe_size_t_cap_to_int(size_t size)109 static 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
pipe_set_blocking(Q_PIPE_ID pipe,bool b)118 static 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(pipe, F_GETFL);
130 if (!b)
131 flags |= O_NONBLOCK;
132 else
133 flags &= ~O_NONBLOCK;
134 if (fcntl(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
pipe_set_inheritable(Q_PIPE_ID pipe,bool b,Q_PIPE_ID * newPipe=nullptr)141 static 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(pipe, F_GETFD);
157 if (!b)
158 flags |= FD_CLOEXEC;
159 else
160 flags &= ~FD_CLOEXEC;
161 if (fcntl(pipe, F_SETFD, flags) == -1)
162 return false;
163 return true;
164 #endif
165 }
166
167 // returns number of bytes available
pipe_read_avail(Q_PIPE_ID pipe)168 static 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(pipe, FIONREAD, (char *)&nbytes) >= 0)
179 bytesAvail = pipe_size_t_cap_to_int(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.
pipe_read(Q_PIPE_ID pipe,char * data,int max,bool * eof)188 static 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(pipe, data, 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.
pipe_write(Q_PIPE_ID pipe,const char * data,int size)230 static 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(pipe, data, 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
pipe_is_a_console(Q_PIPE_ID pipe)255 static 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!!)
pipe_read_avail_console(Q_PIPE_ID pipe)265 static 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
pipe_read_console(Q_PIPE_ID pipe,ushort * data,int max,bool * eof,QTextDecoder * dec=0)301 static 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
pipe_write_console(Q_PIPE_ID pipe,const ushort * data,int size)368 static 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 //----------------------------------------------------------------------------
396 class QPipeWriter : public QThread
397 {
398 Q_OBJECT
399 public:
QPipeWriter(QObject * parent=nullptr)400 QPipeWriter(QObject *parent = nullptr)
401 : QThread(parent)
402 {
403 }
404
~QPipeWriter()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
418 Q_SIGNALS:
419 // result values:
420 // = 0 : success
421 // = -1 : error
422 void canWrite(int result, int bytesWritten);
423
424 protected:
run()425 virtual void run()
426 {
427 // implement a default to satisfy the polling subclass
428 }
429 };
430
431 //----------------------------------------------------------------------------
432 // QPipeReader
433 //----------------------------------------------------------------------------
434 class QPipeReader : public QThread
435 {
436 Q_OBJECT
437 public:
QPipeReader(QObject * parent=nullptr)438 QPipeReader(QObject *parent = nullptr)
439 : QThread(parent)
440 {
441 }
442
~QPipeReader()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
453 Q_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
461 protected:
run()462 virtual void run()
463 {
464 // implement a default to satisfy the polling subclass
465 }
466 };
467
468 //----------------------------------------------------------------------------
469 // QPipeWriterThread
470 //----------------------------------------------------------------------------
471 class QPipeWriterThread : public QPipeWriter
472 {
473 Q_OBJECT
474 public:
475 Q_PIPE_ID pipe;
476 QMutex m;
477 QWaitCondition w;
478 bool do_quit;
479 const char * data;
480 int size;
481
QPipeWriterThread(Q_PIPE_ID id,QObject * parent=nullptr)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
~QPipeWriterThread()491 virtual ~QPipeWriterThread()
492 {
493 stop();
494 CloseHandle(pipe);
495 }
496
start()497 virtual void start()
498 {
499 pipe_set_blocking(pipe, true);
500 QThread::start();
501 }
502
stop()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
write(const char * _data,int _size)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
533 protected:
run()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
563 private:
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
internalWrite(const char * p,int len)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
595 Q_SIGNALS:
596 void canWrite_p(int result, int bytesWritten);
597 };
598
599 //----------------------------------------------------------------------------
600 // QPipeWriterPoll
601 //----------------------------------------------------------------------------
602 class QPipeWriterPoll : public QPipeWriter
603 {
604 Q_OBJECT
605 public:
606 Q_PIPE_ID pipe;
607 const char *data;
608 int size;
609 SafeTimer timer;
610 int total;
611
QPipeWriterPoll(Q_PIPE_ID id,QObject * parent=nullptr)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
~QPipeWriterPoll()621 virtual ~QPipeWriterPoll()
622 {
623 }
624
start()625 virtual void start()
626 {
627 pipe_set_blocking(pipe, false);
628 }
629
630 // return number of bytes written
stop()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
write(const char * _data,int _size)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
648 private Q_SLOTS:
tryNextWrite()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 //----------------------------------------------------------------------------
677 class QPipeReaderThread : public QPipeReader
678 {
679 Q_OBJECT
680 public:
681 Q_PIPE_ID pipe;
682 QMutex m;
683 QWaitCondition w;
684 bool do_quit, active;
685
QPipeReaderThread(Q_PIPE_ID id,QObject * parent=nullptr)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
~QPipeReaderThread()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
start()708 virtual void start()
709 {
710 pipe_set_blocking(pipe, true);
711 QThread::start();
712 }
713
resume()714 virtual void resume()
715 {
716 QMutexLocker locker(&m);
717 pipe_set_blocking(pipe, true);
718 active = true;
719 w.wakeOne();
720 }
721
722 protected:
run()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
767 Q_SIGNALS:
768 void canRead_p(int result);
769 };
770
771 //----------------------------------------------------------------------------
772 // QPipeReaderPoll
773 //----------------------------------------------------------------------------
774 class QPipeReaderPoll : public QPipeReader
775 {
776 Q_OBJECT
777 public:
778 Q_PIPE_ID pipe;
779 SafeTimer timer;
780 bool consoleMode;
781
QPipeReaderPoll(Q_PIPE_ID id,QObject * parent=nullptr)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
~QPipeReaderPoll()790 virtual ~QPipeReaderPoll()
791 {
792 }
793
start()794 virtual void start()
795 {
796 pipe_set_blocking(pipe, false);
797 consoleMode = pipe_is_a_console(pipe);
798 resume();
799 }
800
resume()801 virtual void resume()
802 {
803 timer.start(0);
804 }
805
806 private Q_SLOTS:
tryRead()807 void tryRead()
808 {
809 if (consoleMode)
810 tryReadConsole();
811 else
812 tryReadPipe();
813 }
814
815 private:
tryReadPipe()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
tryReadConsole()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 //----------------------------------------------------------------------------
872 class QPipeDevice::Private : public QObject
873 {
874 Q_OBJECT
875 public:
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
Private(QPipeDevice * _q)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
~Private()915 ~Private() override
916 {
917 reset();
918 }
919
reset()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(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
setup(Q_PIPE_ID id,QPipeDevice::Type _type)959 void setup(Q_PIPE_ID id, QPipeDevice::Type _type)
960 {
961 pipe = id;
962 type = _type;
963 }
964
enable()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, false);
1005
1006 // socket notifier
1007 sn_read = new SafeSocketNotifier(pipe, QSocketNotifier::Read, this);
1008 connect(sn_read, &SafeSocketNotifier::activated, this, &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, false);
1014
1015 // socket notifier
1016 sn_write = new SafeSocketNotifier(pipe, QSocketNotifier::Write, this);
1017 connect(sn_write, &SafeSocketNotifier::activated, this, &Private::sn_write_activated);
1018 sn_write->setEnabled(false);
1019 #endif
1020 }
1021 }
1022
1023 public Q_SLOTS:
t_timeout()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
pw_canWrite(int result,int bytesWritten)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
pr_canRead(int result)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
sn_read_activated(int)1078 void sn_read_activated(int)
1079 {
1080 #ifdef Q_OS_UNIX
1081 if (blockReadNotify)
1082 return;
1083
1084 blockReadNotify = true;
1085 emit q->notify();
1086 #endif
1087 }
1088
sn_write_activated(int)1089 void sn_write_activated(int)
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
QPipeDevice(QObject * parent)1102 QPipeDevice::QPipeDevice(QObject *parent)
1103 : QObject(parent)
1104 {
1105 d = new Private(this);
1106 }
1107
~QPipeDevice()1108 QPipeDevice::~QPipeDevice()
1109 {
1110 delete d;
1111 }
1112
type() const1113 QPipeDevice::Type QPipeDevice::type() const
1114 {
1115 return d->type;
1116 }
1117
isValid() const1118 bool QPipeDevice::isValid() const
1119 {
1120 return (d->pipe != INVALID_Q_PIPE_ID);
1121 }
1122
id() const1123 Q_PIPE_ID QPipeDevice::id() const
1124 {
1125 return d->pipe;
1126 }
1127
idAsInt() const1128 int 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
take(Q_PIPE_ID id,Type t)1140 void QPipeDevice::take(Q_PIPE_ID id, Type t)
1141 {
1142 close();
1143 d->setup(id, t);
1144 }
1145
enable()1146 void QPipeDevice::enable()
1147 {
1148 #ifdef Q_OS_WIN
1149 d->consoleMode = pipe_is_a_console(d->pipe);
1150 #endif
1151 d->enable();
1152 }
1153
close()1154 void QPipeDevice::close()
1155 {
1156 d->reset();
1157 }
1158
release()1159 void QPipeDevice::release()
1160 {
1161 d->pipe = INVALID_Q_PIPE_ID;
1162 d->reset();
1163 }
1164
setInheritable(bool enabled)1165 bool 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(d->pipe, enabled, nullptr);
1182 #endif
1183 }
1184
bytesAvailable() const1185 int 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(d->pipe);
1197 #endif
1198 return n;
1199 }
1200
read(char * data,int maxsize)1201 int 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(d->pipe, data, maxsize, &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
write(const char * data,int size)1343 int 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(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
writeResult(int * written) const1414 int QPipeDevice::writeResult(int *written) const
1415 {
1416 if (written)
1417 *written = d->lastWritten;
1418 return d->writeResult;
1419 }
1420
1421 //----------------------------------------------------------------------------
1422 // QPipeEnd
1423 //----------------------------------------------------------------------------
1424 enum ResetMode
1425 {
1426 ResetSession = 0,
1427 ResetSessionAndData = 1,
1428 ResetAll = 2
1429 };
1430
1431 class QPipeEnd::Private : public QObject
1432 {
1433 Q_OBJECT
1434 public:
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
Private(QPipeEnd * _q)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(&pipe, &QPipeDevice::notify, this, &Private::pipe_notify);
1470 connect(&readTrigger, &SafeTimer::timeout, this, &Private::doRead);
1471 connect(&writeTrigger, &SafeTimer::timeout, this, &Private::doWrite);
1472 connect(&closeTrigger, &SafeTimer::timeout, this, &Private::doClose);
1473 connect(&writeErrorTrigger, &SafeTimer::timeout, this, &Private::doWriteError);
1474 reset(ResetSessionAndData);
1475 }
1476
reset(ResetMode mode)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
setup(Q_PIPE_ID id,QPipeDevice::Type _type)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, type);
1510 }
1511
pendingSize() const1512 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
pendingFreeSize() const1522 int pendingFreeSize() const
1523 {
1524 #ifdef QPIPE_SECURE
1525 if (secure)
1526 return qMax(PIPEEND_READBUF_SEC - sec_buf.size(), 0);
1527 else
1528 #endif
1529 return qMax(PIPEEND_READBUF - buf.size(), 0);
1530 }
1531
appendArray(QByteArray * a,const QByteArray & b)1532 void appendArray(QByteArray *a, const QByteArray &b)
1533 {
1534 (*a) += b;
1535 }
1536
1537 #ifdef QPIPE_SECURE
appendArray(SecureArray * a,const SecureArray & b)1538 void appendArray(SecureArray *a, const SecureArray &b)
1539 {
1540 a->append(b);
1541 }
1542 #endif
1543
takeArray(QByteArray * a,int len)1544 void takeArray(QByteArray *a, int len)
1545 {
1546 char * p = a->data();
1547 const int newsize = a->size() - len;
1548 memmove(p, p + len, newsize);
1549 a->resize(newsize);
1550 }
1551
1552 #ifdef QPIPE_SECURE
takeArray(SecureArray * a,int len)1553 void takeArray(SecureArray *a, int len)
1554 {
1555 char * p = a->data();
1556 const int newsize = a->size() - len;
1557 memmove(p, p + len, newsize);
1558 a->resize(newsize);
1559 }
1560 #endif
1561
setupNextRead()1562 void setupNextRead()
1563 {
1564 if (pipe.isValid() && canRead) {
1565 canRead = false;
1566 readTrigger.start(0);
1567 }
1568 }
1569
setupNextWrite()1570 void setupNextWrite()
1571 {
1572 if (!activeWrite) {
1573 activeWrite = true;
1574 writeTrigger.start(0);
1575 }
1576 }
1577
read(QByteArray * buf,int bytes)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(bytes);
1585 memcpy(a.data(), buf->data(), a.size());
1586 }
1587
1588 takeArray(buf, a.size());
1589 setupNextRead();
1590 return a;
1591 }
1592
write(QByteArray * buf,const QByteArray & a)1593 void write(QByteArray *buf, const QByteArray &a)
1594 {
1595 appendArray(buf, a);
1596 setupNextWrite();
1597 }
1598
1599 #ifdef QPIPE_SECURE
readSecure(SecureArray * buf,int bytes)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(bytes);
1607 memcpy(a.data(), buf->data(), a.size());
1608 }
1609
1610 takeArray(buf, a.size());
1611 setupNextRead();
1612 return a;
1613 }
1614
writeSecure(SecureArray * buf,const SecureArray & a)1615 void writeSecure(SecureArray *buf, const SecureArray &a)
1616 {
1617 appendArray(buf, a);
1618 setupNextWrite();
1619 }
1620 #endif
1621
1622 public Q_SLOTS:
pipe_notify()1623 void pipe_notify()
1624 {
1625 if (pipe.type() == QPipeDevice::Read) {
1626 doRead();
1627 } else {
1628 int x;
1629 int writeResult = pipe.writeResult(&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(&sec_buf, lastWrite);
1638 moreData = !sec_buf.isEmpty();
1639 } else
1640 #endif
1641 {
1642 takeArray(&buf, 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(0);
1658 }
1659 // done with all writing
1660 else {
1661 activeWrite = false;
1662 if (closeLater) {
1663 closeLater = false;
1664 closeTrigger.start(0);
1665 }
1666 }
1667 } else
1668 writeErrorTrigger.start();
1669
1670 if (x > 0)
1671 emit q->bytesWritten(x);
1672 }
1673 }
1674
doRead()1675 void doRead()
1676 {
1677 doReadActual(true);
1678 }
1679
doReadActual(bool sigs)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(left, pipe.bytesAvailable());
1705 }
1706
1707 int ret;
1708 #ifdef QPIPE_SECURE
1709 if (secure) {
1710 SecureArray a(max);
1711 ret = pipe.read(a.data(), a.size());
1712 if (ret >= 1) {
1713 a.resize(ret);
1714 sec_buf.append(a);
1715 }
1716 } else
1717 #endif
1718 {
1719 QByteArray a(max, 0);
1720 ret = pipe.read(a.data(), a.size());
1721 if (ret >= 1) {
1722 a.resize(ret);
1723 buf += a;
1724 }
1725 }
1726
1727 if (ret < 1) {
1728 reset(ResetSession);
1729 if (sigs) {
1730 if (ret == 0)
1731 emit q->error(QPipeEnd::ErrorEOF);
1732 else
1733 emit q->error(QPipeEnd::ErrorBroken);
1734 }
1735 return;
1736 }
1737
1738 if (sigs)
1739 emit q->readyRead();
1740 }
1741
doWrite()1742 void doWrite()
1743 {
1744 int ret;
1745 #ifdef QPIPE_SECURE
1746 if (secure) {
1747 sec_curWrite.resize(qMin(PIPEEND_BLOCK, sec_buf.size()));
1748 memcpy(sec_curWrite.data(), sec_buf.data(), sec_curWrite.size());
1749
1750 ret = pipe.write(sec_curWrite.data(), sec_curWrite.size());
1751 } else
1752 #endif
1753 {
1754 curWrite.resize(qMin(PIPEEND_BLOCK, buf.size()));
1755 memcpy(curWrite.data(), buf.data(), curWrite.size());
1756
1757 ret = pipe.write(curWrite.data(), curWrite.size());
1758 }
1759
1760 if (ret == -1) {
1761 reset(ResetSession);
1762 emit q->error(QPipeEnd::ErrorBroken);
1763 return;
1764 }
1765
1766 lastWrite = ret;
1767 }
1768
doClose()1769 void doClose()
1770 {
1771 reset(ResetSession);
1772 emit q->closed();
1773 }
1774
doWriteError()1775 void doWriteError()
1776 {
1777 reset(ResetSession);
1778 emit q->error(QPipeEnd::ErrorBroken);
1779 }
1780 };
1781
QPipeEnd(QObject * parent)1782 QPipeEnd::QPipeEnd(QObject *parent)
1783 : QObject(parent)
1784 {
1785 d = new Private(this);
1786 }
1787
~QPipeEnd()1788 QPipeEnd::~QPipeEnd()
1789 {
1790 delete d;
1791 }
1792
reset()1793 void QPipeEnd::reset()
1794 {
1795 d->reset(ResetAll);
1796 }
1797
type() const1798 QPipeDevice::Type QPipeEnd::type() const
1799 {
1800 return d->pipe.type();
1801 }
1802
isValid() const1803 bool QPipeEnd::isValid() const
1804 {
1805 return d->pipe.isValid();
1806 }
1807
id() const1808 Q_PIPE_ID QPipeEnd::id() const
1809 {
1810 return d->pipe.id();
1811 }
1812
idAsInt() const1813 int QPipeEnd::idAsInt() const
1814 {
1815 return d->pipe.idAsInt();
1816 }
1817
take(Q_PIPE_ID id,QPipeDevice::Type t)1818 void QPipeEnd::take(Q_PIPE_ID id, QPipeDevice::Type t)
1819 {
1820 reset();
1821 d->setup(id, t);
1822 }
1823
1824 #ifdef QPIPE_SECURE
setSecurityEnabled(bool secure)1825 void 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
enable()1843 void QPipeEnd::enable()
1844 {
1845 d->pipe.enable();
1846 }
1847
close()1848 void 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(0);
1859 }
1860
release()1861 void QPipeEnd::release()
1862 {
1863 if (!isValid())
1864 return;
1865
1866 d->pipe.release();
1867 d->reset(ResetSession);
1868 }
1869
setInheritable(bool enabled)1870 bool QPipeEnd::setInheritable(bool enabled)
1871 {
1872 return d->pipe.setInheritable(enabled);
1873 }
1874
finalize()1875 void QPipeEnd::finalize()
1876 {
1877 if (!isValid())
1878 return;
1879
1880 if (d->pipe.bytesAvailable())
1881 d->doReadActual(false);
1882 d->reset(ResetSession);
1883 }
1884
finalizeAndRelease()1885 void QPipeEnd::finalizeAndRelease()
1886 {
1887 if (!isValid())
1888 return;
1889
1890 if (d->pipe.bytesAvailable())
1891 d->doReadActual(false);
1892 d->pipe.release();
1893 d->reset(ResetSession);
1894 }
1895
bytesAvailable() const1896 int QPipeEnd::bytesAvailable() const
1897 {
1898 return d->pendingSize();
1899 }
1900
bytesToWrite() const1901 int QPipeEnd::bytesToWrite() const
1902 {
1903 return d->pendingSize();
1904 }
1905
read(int bytes)1906 QByteArray QPipeEnd::read(int bytes)
1907 {
1908 return d->read(&d->buf, bytes);
1909 }
1910
write(const QByteArray & buf)1911 void 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(&d->buf, buf);
1925 }
1926
1927 #ifdef QPIPE_SECURE
readSecure(int bytes)1928 SecureArray QPipeEnd::readSecure(int bytes)
1929 {
1930 return d->readSecure(&d->sec_buf, bytes);
1931 }
1932
writeSecure(const SecureArray & buf)1933 void 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(&d->sec_buf, buf);
1945 }
1946 #endif
1947
takeBytesToWrite()1948 QByteArray 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
takeBytesToWriteSecure()1960 SecureArray 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 //----------------------------------------------------------------------------
QPipe(QObject * parent)1975 QPipe::QPipe(QObject *parent)
1976 : i(parent)
1977 , o(parent)
1978 {
1979 }
1980
~QPipe()1981 QPipe::~QPipe()
1982 {
1983 }
1984
reset()1985 void QPipe::reset()
1986 {
1987 i.reset();
1988 o.reset();
1989 }
1990
1991 #ifdef QPIPE_SECURE
create(bool secure)1992 bool QPipe::create(bool secure)
1993 #else
1994 bool 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(p) == -1)
2015 return false;
2016 if (!pipe_set_inheritable(p[0], false, nullptr) || !pipe_set_inheritable(p[1], false, nullptr)) {
2017 close(p[0]);
2018 close(p[1]);
2019 return false;
2020 }
2021 i.take(p[0], QPipeDevice::Read);
2022 o.take(p[1], 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