We now have a current svn snapshot of libqxt in our contrib dir, and
[quassel.git] / src / contrib / libqxt-2007-10-24 / src / network / qxtnamedpipe_win.cpp
1 #include <windows.h>
2 #include <io.h>
3 #include <QSocketNotifier>
4 #include <QByteArray>
5 #include "qxtnamedpipe.h"
6
7 #define BUFSIZE 4096
8 #define PIPE_TIMEOUT  (120*1000) /*120 seconds*/
9
10 #include "qxtnamedpipe_win_p.h"
11
12 void QxtNamedPipePrivate::bytesAvailable()
13 {
14     char chBuf[BUFSIZE];
15     bool fSuccess = false;
16     DWORD cbRead = 0;
17
18     do
19     {
20         // Read from the pipe.
21
22         memset((void *)chBuf,0,BUFSIZE*sizeof(char));
23
24         fSuccess = ReadFile(
25                        this->win32Handle,      // pipe handle
26                        chBuf,                  // buffer to receive reply
27                        BUFSIZE*sizeof(char),  // size of buffer
28                        &cbRead,                // number of bytes read
29                        NULL);                  // not overlapped
30
31         if (! fSuccess && GetLastError() != ERROR_MORE_DATA)
32             break;
33
34         this->readBuffer.append(QByteArray(chBuf,cbRead));
35
36     }
37     while (!fSuccess);  // repeat loop if ERROR_MORE_DATA
38
39     emit readyRead();
40 }
41
42 QxtNamedPipe::QxtNamedPipe(const QString& name, QObject* parent) : QIODevice(parent)
43 {
44     QXT_INIT_PRIVATE(QxtNamedPipe);
45     qxt_d().pipeName = name;
46     qxt_d().win32Handle = INVALID_HANDLE_VALUE;
47     qxt_d().fd = -1;
48     qxt_d().serverMode = false;
49     qxt_d().notify = 0;
50
51 }
52
53 bool QxtNamedPipe::open(QIODevice::OpenMode mode)
54 {
55     int m = PIPE_ACCESS_DUPLEX;
56     int m_client = GENERIC_READ | GENERIC_WRITE;
57
58     if (!(mode & QIODevice::ReadOnly))
59     {
60         m = PIPE_ACCESS_OUTBOUND;
61         m_client = GENERIC_WRITE;
62     }
63     else if (!(mode & QIODevice::WriteOnly))
64     {
65         m = PIPE_ACCESS_INBOUND;
66         m_client = GENERIC_READ;
67     }
68
69     QString pipePrefix("\\\\.\\pipe\\");
70
71     // first try to open in client mode
72     qxt_d().win32Handle  = CreateFileA(qPrintable(pipePrefix+qxt_d().pipeName),   // pipe name
73                                        m_client,                      // read and write access
74                                        0,                             // no sharing
75                                        NULL,                          // default security attributes
76                                        OPEN_EXISTING ,                // opens a pipe
77                                        0,                             // default attributes
78                                        NULL);                         // no template file
79
80     //if we have no success create the pipe and open it
81     if (qxt_d().win32Handle == NULL || qxt_d().win32Handle == INVALID_HANDLE_VALUE)
82     {
83         qxt_d().win32Handle  =   CreateNamedPipeA(qPrintable(pipePrefix+qxt_d().pipeName),        //pipe Name must be \\.\pipe\userdefinedname
84                                  m,                                //read/write mode
85                                  PIPE_NOWAIT,                      //don't block
86                                  1,                                //max number of instances 1
87                                  BUFSIZE,                          //ouput buffer size allocate as needed
88                                  BUFSIZE,                          //input buffer size allocate as needed
89                                  PIPE_TIMEOUT,                     //default timeout value
90                                  NULL);                            //security attributes
91         if (qxt_d().win32Handle != NULL && qxt_d().win32Handle != INVALID_HANDLE_VALUE)
92             qxt_d().serverMode = true;
93     }
94     else
95     {
96         qxt_d().serverMode = false;
97
98         DWORD pipeMode = PIPE_NOWAIT;
99         SetNamedPipeHandleState(
100             qxt_d().win32Handle,    // pipe handle
101             &pipeMode,              // new pipe mode
102             NULL,                   // don't set maximum bytes
103             NULL);                  // don't set maximum time
104
105     }
106
107
108     if (qxt_d().win32Handle != NULL && qxt_d().win32Handle != INVALID_HANDLE_VALUE)
109     {
110         qxt_d().fd = _open_osfhandle((long)qxt_d().win32Handle,0); //FIXME that is not x64 compatible
111         setOpenMode ( mode);
112
113         if (!qxt_d().notify)
114             qxt_d().notify = new QSocketNotifier(qxt_d().fd,QSocketNotifier::Read,this);
115
116         qxt_d().notify->setEnabled(true);
117         connect(qxt_d().notify,SIGNAL(activated(int)),&qxt_d(),SLOT(bytesAvailable()));
118         connect(&qxt_d(),SIGNAL(readyRead()),this,SIGNAL(readyRead()));
119
120         return true;
121     }
122     else
123     {
124         return false;
125     }
126 }
127
128 bool QxtNamedPipe::open(const QString& name, QIODevice::OpenMode mode)
129 {
130     qxt_d().pipeName = name;
131     return QxtNamedPipe::open(mode);
132 }
133
134 void QxtNamedPipe::close()
135 {
136     if (qxt_d().win32Handle != NULL && qxt_d().win32Handle != INVALID_HANDLE_VALUE)
137     {
138         FlushFileBuffers(qxt_d().win32Handle);
139         if (qxt_d().serverMode)
140         {
141             DisconnectNamedPipe(qxt_d().win32Handle);
142         }
143
144         qxt_d().notify->setEnabled(false);
145         delete qxt_d().notify;
146         qxt_d().notify = 0;
147         qxt_d().readBuffer.clear();
148
149         //this will close native and C handle
150         _close(qxt_d().fd);
151         qxt_d().win32Handle = INVALID_HANDLE_VALUE;
152         qxt_d().fd = -1;
153     }
154     setOpenMode(QIODevice::NotOpen);
155 }
156
157 QByteArray QxtNamedPipe::readAvailableBytes()
158 {
159     char ch;
160     QByteArray rv;
161     while (getChar(&ch)) rv += ch;
162     return rv;
163 }
164
165 qint64 QxtNamedPipe::bytesAvailable () const
166 {
167     return qxt_d().readBuffer.size();
168 }
169
170 qint64 QxtNamedPipe::readData ( char * data, qint64 maxSize )
171 {
172     qint64 toRead = qxt_d().readBuffer.size() < maxSize ? qxt_d().readBuffer.size() : maxSize;
173
174     memcpy(data,qxt_d().readBuffer.data(),toRead);
175     qxt_d().readBuffer.remove(0,toRead);
176
177     return toRead;
178
179 }
180
181 qint64 QxtNamedPipe::writeData ( const char * data, qint64 maxSize )
182 {
183     DWORD bytesWritten = 0;
184
185     bool fSuccess = WriteFile(
186                         qxt_d().win32Handle,    // pipe handle
187                         data,                   // message
188                         maxSize,                // message length
189                         &bytesWritten,          // bytes written
190                         NULL);                  // not overlapped
191     if (!fSuccess)
192     {
193         return -1;
194     }
195     return bytesWritten;
196 }
197
198 bool QxtNamedPipe::isSequential () const
199 {
200     return true;
201 }
202