File indexing completed on 2024-12-08 07:21:05

0001 /*
0002  * Copyright (C) 2003-2007  Justin Karneges <justin@affinix.com>
0003  *
0004  * This library is free software; you can redistribute it and/or
0005  * modify it under the terms of the GNU Lesser General Public
0006  * License as published by the Free Software Foundation; either
0007  * version 2.1 of the License, or (at your option) any later version.
0008  *
0009  * This library is distributed in the hope that it will be useful,
0010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012  * Lesser General Public License for more details.
0013  *
0014  * You should have received a copy of the GNU Lesser General Public
0015  * License along with this library; if not, write to the Free Software
0016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
0017  * 02110-1301  USA
0018  *
0019  */
0020 
0021 // Note: if we ever enable the threaded backend, we need to protect:
0022 //   QPipeDevice read and bytesAvailable
0023 //   QPipeEnd finalize
0024 
0025 // Note: we never use the return value for QPipeWriter::stop, but I don't
0026 //   think this matters much
0027 
0028 #include "qpipe.h"
0029 
0030 #include <climits>
0031 #include <cstdlib>
0032 
0033 // sorry, i've added this dependency for now, but it's easy enough to take
0034 //   with you if you want qpipe independent of qca
0035 #include "qca_safeobj.h"
0036 
0037 #ifdef Q_OS_WIN
0038 #include <QMutex>
0039 #include <QTextCodec>
0040 #include <QTextDecoder>
0041 #include <QTextEncoder>
0042 #include <QThread>
0043 #include <QWaitCondition>
0044 #else
0045 #include <QMutex>
0046 #endif
0047 
0048 #ifdef Q_OS_UNIX
0049 #include <cerrno>
0050 #include <csignal>
0051 #include <fcntl.h>
0052 #include <sys/ioctl.h>
0053 #include <unistd.h>
0054 #ifdef HAVE_SYS_FILIO_H
0055 #include <sys/filio.h>
0056 #endif
0057 #endif
0058 
0059 #define USE_POLL
0060 
0061 #define CONSOLE_CHAREXPAND 5
0062 #define PIPEWRITER_POLL 1000
0063 #define PIPEREADER_POLL 100
0064 #define PIPEWRITER_BLOCK 8192
0065 #define PIPEEND_BLOCK 8192
0066 #define PIPEEND_READBUF 16384
0067 #define PIPEEND_READBUF_SEC 1024
0068 
0069 namespace QCA {
0070 
0071 #ifdef Q_OS_UNIX
0072 // adapted from qt
0073 Q_GLOBAL_STATIC(QMutex, ign_mutex)
0074 static bool ign_sigpipe = false;
0075 
0076 static void ignore_sigpipe()
0077 {
0078     // Set to ignore SIGPIPE once only.
0079     QMutexLocker locker(ign_mutex());
0080     if (!ign_sigpipe) {
0081         ign_sigpipe = true;
0082         struct sigaction noaction;
0083         memset(&noaction, 0, sizeof(noaction));
0084         noaction.sa_handler = SIG_IGN;
0085         sigaction(SIGPIPE, &noaction, nullptr);
0086     }
0087 }
0088 #endif
0089 
0090 #ifdef Q_OS_WIN
0091 static int pipe_dword_cap_to_int(DWORD dw)
0092 {
0093     if (sizeof(int) <= sizeof(DWORD))
0094         return (int)((dw > INT_MAX) ? INT_MAX : dw);
0095     else
0096         return (int)dw;
0097 }
0098 
0099 static bool pipe_dword_overflows_int(DWORD dw)
0100 {
0101     if (sizeof(int) <= sizeof(DWORD))
0102         return (dw > INT_MAX) ? true : false;
0103     else
0104         return false;
0105 }
0106 #endif
0107 
0108 #ifdef Q_OS_UNIX
0109 static int pipe_size_t_cap_to_int(size_t size)
0110 {
0111     if (sizeof(int) <= sizeof(size_t))
0112         return (int)((size > INT_MAX) ? INT_MAX : size);
0113     else // maybe silly..  can int ever be larger than size_t?
0114         return (int)size;
0115 }
0116 #endif
0117 
0118 static bool pipe_set_blocking(Q_PIPE_ID pipe, bool b)
0119 {
0120 #ifdef Q_OS_WIN
0121     DWORD flags = 0;
0122     if (!b)
0123         flags |= PIPE_NOWAIT;
0124     if (!SetNamedPipeHandleState(pipe, &flags, NULL, NULL))
0125         return false;
0126     return true;
0127 #endif
0128 #ifdef Q_OS_UNIX
0129     int flags = fcntl(pipe, F_GETFL);
0130     if (!b)
0131         flags |= O_NONBLOCK;
0132     else
0133         flags &= ~O_NONBLOCK;
0134     if (fcntl(pipe, F_SETFL, flags) == -1)
0135         return false;
0136     return true;
0137 #endif
0138 }
0139 
0140 // on windows, the pipe is closed and the new pipe is returned in newPipe
0141 static bool pipe_set_inheritable(Q_PIPE_ID pipe, bool b, Q_PIPE_ID *newPipe = nullptr)
0142 {
0143 #ifdef Q_OS_WIN
0144     // windows is required to accept a new pipe id
0145     if (!newPipe)
0146         return false;
0147     HANDLE h;
0148     if (!DuplicateHandle(GetCurrentProcess(), pipe, GetCurrentProcess(), &h, 0, b, DUPLICATE_SAME_ACCESS))
0149         return false;
0150     *newPipe = h;
0151     return true;
0152 #endif
0153 #ifdef Q_OS_UNIX
0154     if (newPipe)
0155         *newPipe = pipe;
0156     int flags = fcntl(pipe, F_GETFD);
0157     if (!b)
0158         flags |= FD_CLOEXEC;
0159     else
0160         flags &= ~FD_CLOEXEC;
0161     if (fcntl(pipe, F_SETFD, flags) == -1)
0162         return false;
0163     return true;
0164 #endif
0165 }
0166 
0167 // returns number of bytes available
0168 static int pipe_read_avail(Q_PIPE_ID pipe)
0169 {
0170     int bytesAvail = 0;
0171 #ifdef Q_OS_WIN
0172     DWORD i = 0;
0173     if (PeekNamedPipe(pipe, 0, 0, 0, &i, 0))
0174         bytesAvail = pipe_dword_cap_to_int(i);
0175 #endif
0176 #ifdef Q_OS_UNIX
0177     size_t nbytes = 0;
0178     if (ioctl(pipe, FIONREAD, (char *)&nbytes) >= 0)
0179         bytesAvail = pipe_size_t_cap_to_int(nbytes);
0180 #endif
0181     return bytesAvail;
0182 }
0183 
0184 // returns number of bytes actually read, no more than 'max'.
0185 // -1 on error.  0 means no data, NOT EOF.
0186 // note: even though this function looks like it can return data and EOF
0187 //       at the same time, it never actually does.
0188 static int pipe_read(Q_PIPE_ID pipe, char *data, int max, bool *eof)
0189 {
0190     int bytesRead = 0;
0191     if (eof)
0192         *eof = false;
0193     if (max < 1)
0194         return 0;
0195 #ifdef Q_OS_WIN
0196     DWORD maxread = max;
0197     DWORD r       = 0;
0198     if (!ReadFile(pipe, data, maxread, &r, 0)) {
0199         const DWORD err = GetLastError();
0200         if (err == ERROR_HANDLE_EOF) {
0201             if (eof)
0202                 *eof = true;
0203         } else if (err == ERROR_NO_DATA) {
0204             r = 0;
0205         } else
0206             return -1;
0207     }
0208     bytesRead = (int)r; // safe to cast, since 'max' is signed
0209 #endif
0210 #ifdef Q_OS_UNIX
0211     int r   = 0;
0212     int ret = read(pipe, data, max);
0213     if (ret == -1) {
0214         if (errno != EAGAIN)
0215             return -1;
0216     } else if (ret == 0) {
0217         if (eof)
0218             *eof = true;
0219     } else
0220         r = ret;
0221 
0222     bytesRead = r;
0223 #endif
0224     return bytesRead;
0225 }
0226 
0227 // returns number of bytes actually written.
0228 // for blocking pipes, this should always be 'size'.
0229 // -1 on error.
0230 static int pipe_write(Q_PIPE_ID pipe, const char *data, int size)
0231 {
0232 #ifdef Q_OS_WIN
0233     DWORD written;
0234     if (!WriteFile(pipe, data, size, &written, 0))
0235         return -1;
0236     return (int)written; // safe to cast, since 'size' is signed
0237 #endif
0238 #ifdef Q_OS_UNIX
0239     ignore_sigpipe();
0240     int r   = 0;
0241     int ret = write(pipe, data, size);
0242     if (ret == -1) {
0243         if (errno != EAGAIN)
0244             return -1;
0245     } else
0246         r = ret;
0247     return r;
0248 #endif
0249 }
0250 
0251 // Windows Console functions
0252 
0253 #ifdef Q_OS_WIN
0254 
0255 static bool pipe_is_a_console(Q_PIPE_ID pipe)
0256 {
0257     DWORD mode;
0258     if (GetConsoleMode(pipe, &mode))
0259         return true;
0260     return false;
0261 }
0262 
0263 // returns the number of keypress events in the console input queue,
0264 //   or -1 if there is an error (don't forget this!!)
0265 static int pipe_read_avail_console(Q_PIPE_ID pipe)
0266 {
0267     DWORD         count, i;
0268     INPUT_RECORD *rec;
0269     int           n, icount, total;
0270 
0271     // how many events are there?
0272     if (!GetNumberOfConsoleInputEvents(pipe, &count))
0273         return -1;
0274 
0275     // peek them all
0276     rec = (INPUT_RECORD *)malloc(count * sizeof(INPUT_RECORD));
0277     BOOL ret;
0278     ret = PeekConsoleInputW(pipe, rec, count, &i);
0279     if (!ret) {
0280         free(rec);
0281         return -1;
0282     }
0283 
0284     icount = pipe_dword_cap_to_int(i); // process only the amount returned
0285 
0286     // see which ones are normal keypress events
0287     total = 0;
0288     for (n = 0; n < icount; ++n) {
0289         if (rec[n].EventType == KEY_EVENT) {
0290             KEY_EVENT_RECORD *ke = &rec[n].Event.KeyEvent;
0291             if (ke->bKeyDown && ke->uChar.AsciiChar != 0)
0292                 total += ke->wRepeatCount;
0293         }
0294     }
0295 
0296     free(rec);
0297     return total;
0298 }
0299 
0300 // pass dec to keep a long-running decoder, else 0
0301 static int pipe_read_console(Q_PIPE_ID pipe, ushort *data, int max, bool *eof, QTextDecoder *dec = 0)
0302 {
0303     int  n, size, count;
0304     bool own_decoder;
0305 
0306     if (eof)
0307         *eof = false;
0308     if (max < 1)
0309         return 0;
0310 
0311     count = pipe_read_avail_console(pipe);
0312     if (count == -1)
0313         return -1;
0314     if (count == 0)
0315         return 0;
0316 
0317     if (dec) {
0318         own_decoder = false;
0319     } else {
0320         dec         = 0;
0321         own_decoder = true;
0322     }
0323 
0324     size = 0;
0325     for (n = 0; n < count && size < max; ++n) {
0326         bool    use_uni = true;
0327         quint16 uni     = 0;
0328         quint8  ansi    = 0;
0329 
0330         BOOL  ret;
0331         DWORD i;
0332         ret = ReadConsoleW(pipe, &uni, 1, &i, NULL);
0333         if (!ret) {
0334             // if the first read is an error, then report error
0335             if (n == 0) {
0336                 delete dec;
0337                 return -1;
0338             }
0339             // if we have some data, don't count this as an error.
0340             //   we'll probably get it again next time around...
0341             else
0342                 break;
0343         }
0344 
0345         QString substr;
0346         if (use_uni)
0347             substr = QChar(uni);
0348         else
0349             substr = dec->toUnicode((const char *)&ansi, 1);
0350 
0351         for (int k = 0; k < substr.length() && size < max; ++k) {
0352             QChar c = substr[k];
0353             if (c == QChar(0x1A)) // EOF?
0354             {
0355                 if (eof)
0356                     *eof = true;
0357                 break;
0358             }
0359             data[size++] = substr[k].unicode();
0360         }
0361     }
0362     if (own_decoder)
0363         delete dec;
0364 
0365     return size;
0366 }
0367 
0368 static int pipe_write_console(Q_PIPE_ID pipe, const ushort *data, int size)
0369 {
0370     DWORD i;
0371     BOOL  ret;
0372     ret = WriteConsoleW(pipe, data, size, &i, NULL);
0373     if (!ret)
0374         return -1;
0375     return (int)i; // safe to cast since 'size' is signed
0376 }
0377 #endif
0378 
0379 #ifdef Q_OS_WIN
0380 
0381 // Here is the multi-backend stuff for windows.  QPipeWriter and QPipeReader
0382 //   define a common interface, and then subclasses (like QPipeWriterThread)
0383 //   are used by QPipeDevice.  The base classes inherit from QThread, even
0384 //   if threads aren't used, so that I can define signals without dealing
0385 //   with multiple QObject inheritance in the thread subclasses (it is also
0386 //   possible that I'm missing something obvious and don't need to do this).
0387 
0388 // Note:
0389 //   QPipeWriterThread and QPipeReaderThread require the pipes to be in
0390 //     blocking mode.  QPipeWriterPoll and QPipeReaderPoll require the pipes
0391 //     to be in non-blocking mode.
0392 
0393 //----------------------------------------------------------------------------
0394 // QPipeWriter
0395 //----------------------------------------------------------------------------
0396 class QPipeWriter : public QThread
0397 {
0398     Q_OBJECT
0399 public:
0400     QPipeWriter(QObject *parent = nullptr)
0401         : QThread(parent)
0402     {
0403     }
0404 
0405     virtual ~QPipeWriter()
0406     {
0407     }
0408 
0409     // start
0410     virtual void start() = 0;
0411 
0412     // stop, and return number of bytes written so far
0413     virtual int stop() = 0;
0414 
0415     // data pointer needs to remain until canWrite is emitted
0416     virtual int write(const char *data, int size) = 0;
0417 
0418 Q_SIGNALS:
0419     // result values:
0420     //   =   0 : success
0421     //   =  -1 : error
0422     void canWrite(int result, int bytesWritten);
0423 
0424 protected:
0425     virtual void run()
0426     {
0427         // implement a default to satisfy the polling subclass
0428     }
0429 };
0430 
0431 //----------------------------------------------------------------------------
0432 // QPipeReader
0433 //----------------------------------------------------------------------------
0434 class QPipeReader : public QThread
0435 {
0436     Q_OBJECT
0437 public:
0438     QPipeReader(QObject *parent = nullptr)
0439         : QThread(parent)
0440     {
0441     }
0442 
0443     virtual ~QPipeReader()
0444     {
0445     }
0446 
0447     // start
0448     virtual void start() = 0;
0449 
0450     // to be called after every read
0451     virtual void resume() = 0;
0452 
0453 Q_SIGNALS:
0454     // result values:
0455     //  >=  0 : readAhead
0456     //   = -1 : atEnd
0457     //   = -2 : atError
0458     //   = -3 : data available, but no readAhead
0459     void canRead(int result);
0460 
0461 protected:
0462     virtual void run()
0463     {
0464         // implement a default to satisfy the polling subclass
0465     }
0466 };
0467 
0468 //----------------------------------------------------------------------------
0469 // QPipeWriterThread
0470 //----------------------------------------------------------------------------
0471 class QPipeWriterThread : public QPipeWriter
0472 {
0473     Q_OBJECT
0474 public:
0475     Q_PIPE_ID      pipe;
0476     QMutex         m;
0477     QWaitCondition w;
0478     bool           do_quit;
0479     const char    *data;
0480     int            size;
0481 
0482     QPipeWriterThread(Q_PIPE_ID id, QObject *parent = nullptr)
0483         : QPipeWriter(parent)
0484     {
0485         do_quit = false;
0486         data    = 0;
0487         connect(this, &QPipeWriterThread::canWrite_p, this, &QPipeWriterThread::canWrite);
0488         DuplicateHandle(GetCurrentProcess(), id, GetCurrentProcess(), &pipe, 0, false, DUPLICATE_SAME_ACCESS);
0489     }
0490 
0491     virtual ~QPipeWriterThread()
0492     {
0493         stop();
0494         CloseHandle(pipe);
0495     }
0496 
0497     virtual void start()
0498     {
0499         pipe_set_blocking(pipe, true);
0500         QThread::start();
0501     }
0502 
0503     virtual int stop()
0504     {
0505         if (isRunning()) {
0506             m.lock();
0507             do_quit = true;
0508             w.wakeOne();
0509             m.unlock();
0510             if (!wait(100))
0511                 terminate();
0512             do_quit = false;
0513             data    = 0;
0514         }
0515         return size;
0516     }
0517 
0518     virtual int write(const char *_data, int _size)
0519     {
0520         if (!isRunning())
0521             return -1;
0522 
0523         QMutexLocker locker(&m);
0524         if (data)
0525             return 0;
0526 
0527         data = _data;
0528         size = _size;
0529         w.wakeOne();
0530         return _size;
0531     }
0532 
0533 protected:
0534     virtual void run()
0535     {
0536         while (1) {
0537             m.lock();
0538 
0539             while (!data && !do_quit)
0540                 w.wait(&m);
0541 
0542             if (do_quit) {
0543                 m.unlock();
0544                 break;
0545             }
0546 
0547             const char *p   = data;
0548             int         len = size;
0549 
0550             m.unlock();
0551 
0552             int ret = internalWrite(p, len);
0553 
0554             m.lock();
0555             data = 0;
0556             size = ret;
0557             m.unlock();
0558 
0559             emit canWrite_p(ret < len ? -1 : 0, ret);
0560         }
0561     }
0562 
0563 private:
0564     // attempts to write len bytes.  value returned is number of bytes written.
0565     //   any return value less than len means a write error was encountered
0566     int internalWrite(const char *p, int len)
0567     {
0568         int total = 0;
0569         while (total < len) {
0570             m.lock();
0571             if (do_quit) {
0572                 m.unlock();
0573                 return 0;
0574             }
0575             m.unlock();
0576 
0577             int ret = pipe_write(pipe, p + total, qMin(PIPEWRITER_BLOCK, len - total));
0578             if (ret == -1) {
0579                 // from qt, don't know why
0580                 if (GetLastError() == 0xE8) // NT_STATUS_INVALID_USER_BUFFER
0581                 {
0582                     // give the os a rest
0583                     msleep(100);
0584                     continue;
0585                 }
0586 
0587                 // on any other error, end thread
0588                 return total;
0589             }
0590             total += ret;
0591         }
0592         return total;
0593     }
0594 
0595 Q_SIGNALS:
0596     void canWrite_p(int result, int bytesWritten);
0597 };
0598 
0599 //----------------------------------------------------------------------------
0600 // QPipeWriterPoll
0601 //----------------------------------------------------------------------------
0602 class QPipeWriterPoll : public QPipeWriter
0603 {
0604     Q_OBJECT
0605 public:
0606     Q_PIPE_ID   pipe;
0607     const char *data;
0608     int         size;
0609     SafeTimer   timer;
0610     int         total;
0611 
0612     QPipeWriterPoll(Q_PIPE_ID id, QObject *parent = nullptr)
0613         : QPipeWriter(parent)
0614         , timer(this)
0615     {
0616         pipe = id;
0617         data = 0;
0618         connect(&timer, &SafeTimer::timeout, this, &QPipeWriterPoll::tryNextWrite);
0619     }
0620 
0621     virtual ~QPipeWriterPoll()
0622     {
0623     }
0624 
0625     virtual void start()
0626     {
0627         pipe_set_blocking(pipe, false);
0628     }
0629 
0630     // return number of bytes written
0631     virtual int stop()
0632     {
0633         timer.stop();
0634         data = 0;
0635         return total;
0636     }
0637 
0638     // data pointer needs to remain until canWrite is emitted
0639     virtual int write(const char *_data, int _size)
0640     {
0641         total = 0;
0642         data  = _data;
0643         size  = _size;
0644         timer.start(0); // write at next event loop
0645         return _size;
0646     }
0647 
0648 private Q_SLOTS:
0649     void tryNextWrite()
0650     {
0651         int  written = pipe_write(pipe, data + total, size - total);
0652         bool error   = false;
0653         if (written == -1) {
0654             error   = true;
0655             written = 0; // no bytes written on error
0656 
0657             // from qt, they don't count it as fatal
0658             if (GetLastError() == 0xE8) // NT_STATUS_INVALID_USER_BUFFER
0659                 error = false;
0660         }
0661 
0662         total += written;
0663         if (error || total == size) {
0664             timer.stop();
0665             data = 0;
0666             emit canWrite(error ? -1 : 0, total);
0667             return;
0668         }
0669 
0670         timer.setInterval(PIPEWRITER_POLL);
0671     }
0672 };
0673 
0674 //----------------------------------------------------------------------------
0675 // QPipeReaderThread
0676 //----------------------------------------------------------------------------
0677 class QPipeReaderThread : public QPipeReader
0678 {
0679     Q_OBJECT
0680 public:
0681     Q_PIPE_ID      pipe;
0682     QMutex         m;
0683     QWaitCondition w;
0684     bool           do_quit, active;
0685 
0686     QPipeReaderThread(Q_PIPE_ID id, QObject *parent = nullptr)
0687         : QPipeReader(parent)
0688     {
0689         do_quit = false;
0690         active  = true;
0691         connect(this, &QPipeReaderThread::canRead_p, this, &QPipeReaderThread::canRead);
0692         DuplicateHandle(GetCurrentProcess(), id, GetCurrentProcess(), &pipe, 0, false, DUPLICATE_SAME_ACCESS);
0693     }
0694 
0695     virtual ~QPipeReaderThread()
0696     {
0697         if (isRunning()) {
0698             m.lock();
0699             do_quit = true;
0700             w.wakeOne();
0701             m.unlock();
0702             if (!wait(100))
0703                 terminate();
0704         }
0705         CloseHandle(pipe);
0706     }
0707 
0708     virtual void start()
0709     {
0710         pipe_set_blocking(pipe, true);
0711         QThread::start();
0712     }
0713 
0714     virtual void resume()
0715     {
0716         QMutexLocker locker(&m);
0717         pipe_set_blocking(pipe, true);
0718         active = true;
0719         w.wakeOne();
0720     }
0721 
0722 protected:
0723     virtual void run()
0724     {
0725         while (1) {
0726             m.lock();
0727 
0728             while (!active && !do_quit)
0729                 w.wait(&m);
0730 
0731             if (do_quit) {
0732                 m.unlock();
0733                 break;
0734             }
0735 
0736             m.unlock();
0737 
0738             while (1) {
0739                 unsigned char c;
0740                 bool          done;
0741                 int           ret = pipe_read(pipe, (char *)&c, 1, &done);
0742                 if (done || ret != 0) // eof, error, or data?
0743                 {
0744                     int result;
0745 
0746                     if (done) // we got EOF?
0747                         result = -1;
0748                     else if (ret == -1) // we got an error?
0749                         result = -2;
0750                     else if (ret >= 1) // we got some data??  queue it
0751                         result = c;
0752                     else // will never happen
0753                         result = -2;
0754 
0755                     m.lock();
0756                     active = false;
0757                     pipe_set_blocking(pipe, false);
0758                     m.unlock();
0759 
0760                     emit canRead_p(result);
0761                     break;
0762                 }
0763             }
0764         }
0765     }
0766 
0767 Q_SIGNALS:
0768     void canRead_p(int result);
0769 };
0770 
0771 //----------------------------------------------------------------------------
0772 // QPipeReaderPoll
0773 //----------------------------------------------------------------------------
0774 class QPipeReaderPoll : public QPipeReader
0775 {
0776     Q_OBJECT
0777 public:
0778     Q_PIPE_ID pipe;
0779     SafeTimer timer;
0780     bool      consoleMode;
0781 
0782     QPipeReaderPoll(Q_PIPE_ID id, QObject *parent = nullptr)
0783         : QPipeReader(parent)
0784         , timer(this)
0785     {
0786         pipe = id;
0787         connect(&timer, &SafeTimer::timeout, this, &QPipeReaderPoll::tryRead);
0788     }
0789 
0790     virtual ~QPipeReaderPoll()
0791     {
0792     }
0793 
0794     virtual void start()
0795     {
0796         pipe_set_blocking(pipe, false);
0797         consoleMode = pipe_is_a_console(pipe);
0798         resume();
0799     }
0800 
0801     virtual void resume()
0802     {
0803         timer.start(0);
0804     }
0805 
0806 private Q_SLOTS:
0807     void tryRead()
0808     {
0809         if (consoleMode)
0810             tryReadConsole();
0811         else
0812             tryReadPipe();
0813     }
0814 
0815 private:
0816     void tryReadPipe()
0817     {
0818         // is there data available for reading?  if so, signal.
0819         int bytes = pipe_read_avail(pipe);
0820         if (bytes > 0) {
0821             timer.stop();
0822             emit canRead(-3); // no readAhead
0823             return;
0824         }
0825 
0826         // no data available?  probe for EOF/error
0827         unsigned char c;
0828         bool          done;
0829         int           ret = pipe_read(pipe, (char *)&c, 1, &done);
0830         if (done || ret != 0) // eof, error, or data?
0831         {
0832             int result;
0833 
0834             if (done) // we got EOF?
0835                 result = -1;
0836             else if (ret == -1) // we got an error?
0837                 result = -2;
0838             else if (ret >= 1) // we got some data??  queue it
0839                 result = c;
0840             else // will never happen
0841                 result = -2;
0842 
0843             timer.stop();
0844             emit canRead(result);
0845             return;
0846         }
0847 
0848         timer.setInterval(PIPEREADER_POLL);
0849     }
0850 
0851     void tryReadConsole()
0852     {
0853         // is there data available for reading?  if so, signal.
0854         int count = pipe_read_avail_console(pipe);
0855         if (count > 0) {
0856             timer.stop();
0857             emit canRead(-3); // no readAhead
0858             return;
0859         }
0860 
0861         timer.setInterval(PIPEREADER_POLL);
0862     }
0863 };
0864 
0865 // end of windows pipe writer/reader implementations
0866 
0867 #endif
0868 
0869 //----------------------------------------------------------------------------
0870 // QPipeDevice
0871 //----------------------------------------------------------------------------
0872 class QPipeDevice::Private : public QObject
0873 {
0874     Q_OBJECT
0875 public:
0876     QPipeDevice      *q;
0877     Q_PIPE_ID         pipe;
0878     QPipeDevice::Type type;
0879     bool              enabled;
0880     bool              blockReadNotify;
0881     bool              canWrite;
0882     int               writeResult;
0883     int               lastTaken, lastWritten;
0884 
0885 #ifdef Q_OS_WIN
0886     bool          atEnd, atError, forceNotify;
0887     int           readAhead;
0888     SafeTimer    *readTimer;
0889     QTextDecoder *dec;
0890     bool          consoleMode;
0891     QPipeWriter  *pipeWriter;
0892     QPipeReader  *pipeReader;
0893 #endif
0894 #ifdef Q_OS_UNIX
0895     SafeSocketNotifier *sn_read, *sn_write;
0896 #endif
0897 
0898     Private(QPipeDevice *_q)
0899         : QObject(_q)
0900         , q(_q)
0901         , pipe(INVALID_Q_PIPE_ID)
0902     {
0903 #ifdef Q_OS_WIN
0904         readTimer  = 0;
0905         pipeWriter = 0;
0906         pipeReader = 0;
0907         dec        = 0;
0908 #endif
0909 #ifdef Q_OS_UNIX
0910         sn_read  = nullptr;
0911         sn_write = nullptr;
0912 #endif
0913     }
0914 
0915     ~Private() override
0916     {
0917         reset();
0918     }
0919 
0920     void reset()
0921     {
0922 #ifdef Q_OS_WIN
0923         atEnd       = false;
0924         atError     = false;
0925         forceNotify = false;
0926         readAhead   = -1;
0927         delete readTimer;
0928         readTimer = 0;
0929         delete pipeWriter;
0930         pipeWriter = 0;
0931         delete pipeReader;
0932         pipeReader = 0;
0933         delete dec;
0934         dec         = 0;
0935         consoleMode = false;
0936 #endif
0937 #ifdef Q_OS_UNIX
0938         delete sn_read;
0939         sn_read = nullptr;
0940         delete sn_write;
0941         sn_write = nullptr;
0942 #endif
0943         if (pipe != INVALID_Q_PIPE_ID) {
0944 #ifdef Q_OS_WIN
0945             CloseHandle(pipe);
0946 #endif
0947 #ifdef Q_OS_UNIX
0948             ::close(pipe);
0949 #endif
0950             pipe = INVALID_Q_PIPE_ID;
0951         }
0952 
0953         enabled         = false;
0954         blockReadNotify = false;
0955         canWrite        = true;
0956         writeResult     = -1;
0957     }
0958 
0959     void setup(Q_PIPE_ID id, QPipeDevice::Type _type)
0960     {
0961         pipe = id;
0962         type = _type;
0963     }
0964 
0965     void enable()
0966     {
0967         if (enabled)
0968             return;
0969 
0970         enabled = true;
0971 
0972         if (type == QPipeDevice::Read) {
0973 #ifdef Q_OS_WIN
0974             // for windows, the blocking mode is chosen by the QPipeReader
0975 
0976             // console might need a decoder
0977             if (consoleMode) {
0978                 dec = 0;
0979             }
0980 
0981             // pipe reader
0982 #ifdef USE_POLL
0983             pipeReader = new QPipeReaderPoll(pipe, this);
0984 #else
0985             // console always polls, no matter what
0986             if (consoleMode)
0987                 pipeReader = new QPipeReaderPoll(pipe, this);
0988             else
0989                 pipeReader = new QPipeReaderThread(pipe, this);
0990 #endif
0991             connect(pipeReader, &QPipeReader::canRead, this, &Private::pr_canRead);
0992             pipeReader->start();
0993 
0994             // polling timer
0995             readTimer = new SafeTimer(this);
0996             connect(readTimer, &SafeTimer::timeout, this, &Private::t_timeout);
0997 
0998             // updated: now that we have pipeReader, this no longer
0999             //   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:
1024     void t_timeout()
1025     {
1026 #ifdef Q_OS_WIN
1027         if (blockReadNotify)
1028             return;
1029 
1030         // were we forced to notify?  this can happen if we want to
1031         //   spread out results across two reads.  whatever caused
1032         //   the forceNotify already knows what to do, so all we do
1033         //   is signal.
1034         if (forceNotify) {
1035             forceNotify     = false;
1036             blockReadNotify = true;
1037             emit q->notify();
1038             return;
1039         }
1040 #endif
1041     }
1042 
1043     void pw_canWrite(int result, int bytesWritten)
1044     {
1045 #ifdef Q_OS_WIN
1046         if (result == 0) {
1047             writeResult = 0;
1048             lastWritten = lastTaken; // success means all bytes
1049         } else {
1050             writeResult = -1;
1051             lastWritten = bytesWritten;
1052         }
1053 
1054         canWrite = true;
1055         emit q->notify();
1056 #else
1057         Q_UNUSED(result);
1058         Q_UNUSED(bytesWritten);
1059 #endif
1060     }
1061 
1062     void pr_canRead(int result)
1063     {
1064 #ifdef Q_OS_WIN
1065         blockReadNotify = true;
1066         if (result == -1)
1067             atEnd = true;
1068         else if (result == -2)
1069             atError = true;
1070         else if (result != -3)
1071             readAhead = result;
1072         emit q->notify();
1073 #else
1074         Q_UNUSED(result);
1075 #endif
1076     }
1077 
1078     void sn_read_activated()
1079     {
1080 #ifdef Q_OS_UNIX
1081         if (blockReadNotify)
1082             return;
1083 
1084         blockReadNotify = true;
1085         emit q->notify();
1086 #endif
1087     }
1088 
1089     void sn_write_activated()
1090     {
1091 #ifdef Q_OS_UNIX
1092         writeResult = 0;
1093         lastWritten = lastTaken;
1094 
1095         canWrite = true;
1096         sn_write->setEnabled(false);
1097         emit q->notify();
1098 #endif
1099     }
1100 };
1101 
1102 QPipeDevice::QPipeDevice(QObject *parent)
1103     : QObject(parent)
1104 {
1105     d = new Private(this);
1106 }
1107 
1108 QPipeDevice::~QPipeDevice()
1109 {
1110     delete d;
1111 }
1112 
1113 QPipeDevice::Type QPipeDevice::type() const
1114 {
1115     return d->type;
1116 }
1117 
1118 bool QPipeDevice::isValid() const
1119 {
1120     return (d->pipe != INVALID_Q_PIPE_ID);
1121 }
1122 
1123 Q_PIPE_ID QPipeDevice::id() const
1124 {
1125     return d->pipe;
1126 }
1127 
1128 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 
1140 void QPipeDevice::take(Q_PIPE_ID id, Type t)
1141 {
1142     close();
1143     d->setup(id, t);
1144 }
1145 
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 
1154 void QPipeDevice::close()
1155 {
1156     d->reset();
1157 }
1158 
1159 void QPipeDevice::release()
1160 {
1161     d->pipe = INVALID_Q_PIPE_ID;
1162     d->reset();
1163 }
1164 
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 
1185 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 
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 
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 
1414 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 
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 
1477     void reset(ResetMode mode)
1478     {
1479         pipe.close();
1480         readTrigger.stop();
1481         writeTrigger.stop();
1482         closeTrigger.stop();
1483         writeErrorTrigger.stop();
1484         canRead     = false;
1485         activeWrite = false;
1486         lastWrite   = 0;
1487         closeLater  = false;
1488         closing     = false;
1489         curWrite.clear();
1490 #ifdef QPIPE_SECURE
1491         secure = false;
1492         sec_curWrite.clear();
1493 #endif
1494 
1495         if (mode >= ResetSessionAndData) {
1496             buf.clear();
1497 #ifdef QPIPE_SECURE
1498             sec_buf.clear();
1499 #endif
1500         }
1501     }
1502 
1503     void setup(Q_PIPE_ID id, QPipeDevice::Type _type)
1504     {
1505         type = _type;
1506 #ifdef Q_OS_WIN
1507         consoleMode = pipe_is_a_console(id);
1508 #endif
1509         pipe.take(id, type);
1510     }
1511 
1512     int pendingSize() const
1513     {
1514 #ifdef QPIPE_SECURE
1515         if (secure)
1516             return sec_buf.size();
1517         else
1518 #endif
1519             return buf.size();
1520     }
1521 
1522     int pendingFreeSize() const
1523     {
1524 #ifdef QPIPE_SECURE
1525         if (secure)
1526             return qMax(PIPEEND_READBUF_SEC - sec_buf.size(), 0);
1527         else
1528 #endif
1529             return qMax(PIPEEND_READBUF - buf.size(), 0);
1530     }
1531 
1532     void appendArray(QByteArray *a, const QByteArray &b)
1533     {
1534         (*a) += b;
1535     }
1536 
1537 #ifdef QPIPE_SECURE
1538     void appendArray(SecureArray *a, const SecureArray &b)
1539     {
1540         a->append(b);
1541     }
1542 #endif
1543 
1544     void takeArray(QByteArray *a, int len)
1545     {
1546         char     *p       = a->data();
1547         const int newsize = a->size() - len;
1548         memmove(p, p + len, newsize);
1549         a->resize(newsize);
1550     }
1551 
1552 #ifdef QPIPE_SECURE
1553     void takeArray(SecureArray *a, int len)
1554     {
1555         char     *p       = a->data();
1556         const int newsize = a->size() - len;
1557         memmove(p, p + len, newsize);
1558         a->resize(newsize);
1559     }
1560 #endif
1561 
1562     void setupNextRead()
1563     {
1564         if (pipe.isValid() && canRead) {
1565             canRead = false;
1566             readTrigger.start(0);
1567         }
1568     }
1569 
1570     void setupNextWrite()
1571     {
1572         if (!activeWrite) {
1573             activeWrite = true;
1574             writeTrigger.start(0);
1575         }
1576     }
1577 
1578     QByteArray read(QByteArray *buf, int bytes)
1579     {
1580         QByteArray a;
1581         if (bytes == -1 || bytes > buf->size()) {
1582             a = *buf;
1583         } else {
1584             a.resize(bytes);
1585             memcpy(a.data(), buf->data(), a.size());
1586         }
1587 
1588         takeArray(buf, a.size());
1589         setupNextRead();
1590         return a;
1591     }
1592 
1593     void write(QByteArray *buf, const QByteArray &a)
1594     {
1595         appendArray(buf, a);
1596         setupNextWrite();
1597     }
1598 
1599 #ifdef QPIPE_SECURE
1600     SecureArray readSecure(SecureArray *buf, int bytes)
1601     {
1602         SecureArray a;
1603         if (bytes == -1 || bytes > buf->size()) {
1604             a = *buf;
1605         } else {
1606             a.resize(bytes);
1607             memcpy(a.data(), buf->data(), a.size());
1608         }
1609 
1610         takeArray(buf, a.size());
1611         setupNextRead();
1612         return a;
1613     }
1614 
1615     void writeSecure(SecureArray *buf, const SecureArray &a)
1616     {
1617         appendArray(buf, a);
1618         setupNextWrite();
1619     }
1620 #endif
1621 
1622 public Q_SLOTS:
1623     void pipe_notify()
1624     {
1625         if (pipe.type() == QPipeDevice::Read) {
1626             doRead();
1627         } else {
1628             int x;
1629             int writeResult = pipe.writeResult(&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 
1675     void doRead()
1676     {
1677         doReadActual(true);
1678     }
1679 
1680     void doReadActual(bool sigs)
1681     {
1682         const int left = pendingFreeSize();
1683         if (left == 0) {
1684             canRead = true;
1685             return;
1686         }
1687 
1688         int max;
1689 #ifdef Q_OS_WIN
1690         if (consoleMode) {
1691             // need a minimum amount for console
1692             if (left < CONSOLE_CHAREXPAND) {
1693                 canRead = true;
1694                 return;
1695             }
1696 
1697             // don't use pipe.bytesAvailable() for console mode,
1698             //   as it is somewhat bogus.  fortunately, there is
1699             //   no problem with overreading from the console.
1700             max = qMin(left, 32);
1701         } else
1702 #endif
1703         {
1704             max = qMin(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 
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 
1769     void doClose()
1770     {
1771         reset(ResetSession);
1772         emit q->closed();
1773     }
1774 
1775     void doWriteError()
1776     {
1777         reset(ResetSession);
1778         emit q->error(QPipeEnd::ErrorBroken);
1779     }
1780 };
1781 
1782 QPipeEnd::QPipeEnd(QObject *parent)
1783     : QObject(parent)
1784 {
1785     d = new Private(this);
1786 }
1787 
1788 QPipeEnd::~QPipeEnd()
1789 {
1790     delete d;
1791 }
1792 
1793 void QPipeEnd::reset()
1794 {
1795     d->reset(ResetAll);
1796 }
1797 
1798 QPipeDevice::Type QPipeEnd::type() const
1799 {
1800     return d->pipe.type();
1801 }
1802 
1803 bool QPipeEnd::isValid() const
1804 {
1805     return d->pipe.isValid();
1806 }
1807 
1808 Q_PIPE_ID QPipeEnd::id() const
1809 {
1810     return d->pipe.id();
1811 }
1812 
1813 int QPipeEnd::idAsInt() const
1814 {
1815     return d->pipe.idAsInt();
1816 }
1817 
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
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 
1843 void QPipeEnd::enable()
1844 {
1845     d->pipe.enable();
1846 }
1847 
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 
1861 void QPipeEnd::release()
1862 {
1863     if (!isValid())
1864         return;
1865 
1866     d->pipe.release();
1867     d->reset(ResetSession);
1868 }
1869 
1870 bool QPipeEnd::setInheritable(bool enabled)
1871 {
1872     return d->pipe.setInheritable(enabled);
1873 }
1874 
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 
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 
1896 int QPipeEnd::bytesAvailable() const
1897 {
1898     return d->pendingSize();
1899 }
1900 
1901 int QPipeEnd::bytesToWrite() const
1902 {
1903     return d->pendingSize();
1904 }
1905 
1906 QByteArray QPipeEnd::read(int bytes)
1907 {
1908     return d->read(&d->buf, bytes);
1909 }
1910 
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
1928 SecureArray QPipeEnd::readSecure(int bytes)
1929 {
1930     return d->readSecure(&d->sec_buf, bytes);
1931 }
1932 
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 
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
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 //----------------------------------------------------------------------------
1975 QPipe::QPipe(QObject *parent)
1976     : i(parent)
1977     , o(parent)
1978 {
1979 }
1980 
1981 QPipe::~QPipe()
1982 {
1983 }
1984 
1985 void QPipe::reset()
1986 {
1987     i.reset();
1988     o.reset();
1989 }
1990 
1991 #ifdef QPIPE_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"