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