Windows execmd: basic execm (question/response) test ok

This commit is contained in:
Jean-Francois Dockes 2015-09-09 15:39:14 +02:00
parent 592c3919d1
commit 91984f5513
2 changed files with 83 additions and 44 deletions

View file

@ -357,10 +357,10 @@ bool ExecCmd::Internal::preparePipes(bool has_input,HANDLE *hChildInput,
// now same procedure for input pipe
sa.bInheritHandle = FALSE;
HANDLE m_hInputWrite = CreateNamedPipe(
m_hInputWrite = CreateNamedPipe(
TEXT("\\\\.\\pipe\\instreamPipe"),
PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
PIPE_WAIT,
1, 4096, 4096, 0, &sa);
if (m_hInputWrite == INVALID_HANDLE_VALUE) {
printError("preparePipes: CreateNamedPipe(inputW)");
@ -584,10 +584,10 @@ static WaitResult Wait(HANDLE hdl, int timeout)
{
//HANDLE hdls[2] = { hdl, eQuit };
HANDLE hdls[1] = { hdl};
LOGDEB0(("ExecCmd::Wait()\n"));
LOGDEB1(("ExecCmd::Wait()\n"));
DWORD res = WaitForMultipleObjects(1, hdls, FALSE, timeout);
if (res == WAIT_OBJECT_0) {
LOGDEB0(("ExecCmd::Wait: returning Ok\n"));
LOGDEB1(("ExecCmd::Wait: returning Ok\n"));
return Ok;
} else if (res == (WAIT_OBJECT_0 + 1)) {
LOGDEB0(("ExecCmd::Wait: returning Quit\n"));
@ -604,11 +604,9 @@ static WaitResult Wait(HANDLE hdl, int timeout)
// Send data to the child.
int ExecCmd::send(const string& data)
{
DWORD dwWritten;
BOOL bSuccess = false;
bSuccess = WriteFile(m->m_hInputWrite, data.c_str(), (DWORD)data.size(),
NULL, &m->m_oInputWrite);
LOGDEB2(("ExecCmd::send: cnt %d\n", int(data.size())));
BOOL bSuccess = WriteFile(m->m_hInputWrite, data.c_str(),
(DWORD)data.size(), NULL, &m->m_oInputWrite);
DWORD err = GetLastError();
// TODO: some more decision, either the operation completes immediately
@ -621,10 +619,12 @@ int ExecCmd::send(const string& data)
}
WaitResult waitRes = Wait(m->m_oInputWrite.hEvent, m->m_timeoutMs);
DWORD dwWritten;
if (waitRes == Ok) {
if (!GetOverlappedResult(m->m_hInputWrite,
&m->m_oInputWrite, &dwWritten, TRUE)) {
err = GetLastError();
LOGERR(("ExecCmd::send: GetOverLappedResult: err %d\n", err));
return -1;
}
} else if (waitRes == Quit) {
@ -640,6 +640,7 @@ int ExecCmd::send(const string& data)
}
return -1;
}
LOGDEB2(("ExecCmd::send: returning %d\n", int(dwWritten)));
return dwWritten;
}
@ -651,10 +652,12 @@ int ExecCmd::send(const string& data)
// and write to cout in this programme
// Stop when there is no more data.
// @arg cnt count to read, -1 means read to end of data.
// 0 means read whatever comes back on the first read;
int ExecCmd::receive(string& data, int cnt)
{
LOGDEB1(("ExecCmd::receive: cnt %d\n", cnt));
int totread = 0;
LOGDEB(("ExecCmd::receive: cnt %d\n", cnt));
// If there is buffered data, use it (remains from a previous getline())
if (m->m_bufoffs < m->m_buf.size()) {
@ -663,7 +666,7 @@ int ExecCmd::receive(string& data, int cnt)
data.append(m->m_buf, m->m_bufoffs, toread);
m->m_bufoffs += toread;
totread += toread;
if (cnt > 0 && totread == cnt) {
if (cnt == 0 || (cnt > 0 && totread == cnt)) {
return cnt;
}
}
@ -699,7 +702,7 @@ int ExecCmd::receive(string& data, int cnt)
data.append(chBuf, dwRead);
if (m->m_advise)
m->m_advise->newData(dwRead);
LOGDEB(("ExecCmd::receive: got %d bytes\n", int(dwRead)));
LOGDEB1(("ExecCmd::recv: ReadFile: %d bytes\n", int(dwRead)));
}
} else if (waitRes == Quit) {
if (!CancelIo(m->m_hOutputRead)) {
@ -707,19 +710,23 @@ int ExecCmd::receive(string& data, int cnt)
}
break;
} else if (waitRes == Timeout) {
// We only want to cancel if m_advise says so here. Is the io still
// valid at this point ? Should we catch a possible exception to CancelIo?
if (m->m_advise)
m->m_advise->newData(0);
if (m->m_killRequest) {
LOGINFO(("ExecCmd::doexec: cancel request\n"));
if (!CancelIo(m->m_hOutputRead)) {
printError("CancelIo");
}
break;
}
// We only want to cancel if m_advise says so here. Is the
// io still valid at this point ? Should we catch a
// possible exception to CancelIo?
if (m->m_advise)
m->m_advise->newData(0);
if (m->m_killRequest) {
LOGINFO(("ExecCmd::doexec: cancel request\n"));
if (!CancelIo(m->m_hOutputRead)) {
printError("CancelIo");
}
break;
}
}
if (cnt == 0)
break;
}
LOGDEB1(("ExecCmd::receive: returning %d bytes\n", totread));
return totread;
}
@ -728,7 +735,7 @@ int ExecCmd::getline(string& data)
LOGDEB2(("ExecCmd::getline: cnt %d, timeo %d\n", cnt, timeo));
data.erase();
if (m->m_buf.empty()) {
m->m_buf.resize(4096);
m->m_buf.reserve(4096);
m->m_bufoffs = 0;
}
@ -740,21 +747,27 @@ int ExecCmd::getline(string& data)
for (; nn > 0;) {
nn--;
char c = m->m_buf[m->m_bufoffs++];
if (c == '\r')
continue;
data += c;
if (c == '\n') {
foundnl = true;
break;
}
}
if (foundnl)
if (foundnl) {
LOGDEB2(("ExecCmd::getline: ret: [%s]\n", data.c_str()));
return int(data.size());
}
// Read more
m->m_buf.erase();
if (receive(m->m_buf) < 0) {
if (receive(m->m_buf, 0) < 0) {
return -1;
}
if (m->m_buf.empty()) {
LOGDEB(("ExecCmd::getline: eof? ret: [%s]\n", data.c_str()));
return int(data.size());
}
m->m_bufoffs = 0;
@ -789,7 +802,30 @@ int ExecCmd::doexec(const string &cmd, const vector<string>& args,
return -1;
}
if (input) {
send(*input);
if (!input->empty()) {
if (send(*input) != input->size()) {
LOGERR(("ExecCmd::doexec: send failed\n"));
CloseHandle(m->m_hInputWrite);
m->m_hInputWrite = NULL;
return wait();
}
}
if (m->m_provide) {
for (;;) {
m->m_provide->newData();
if (input->empty()) {
CloseHandle(m->m_hInputWrite);
m->m_hInputWrite = NULL;
break;
}
if (send(*input) != input->size()) {
LOGERR(("ExecCmd::doexec: send failed\n"));
CloseHandle(m->m_hInputWrite);
m->m_hInputWrite = NULL;
break;
}
}
}
} else if (output) {
receive(*output);
}

View file

@ -19,10 +19,11 @@
using namespace std;
// Testing the rclexecm protocol outside of recoll. Here we use the
// rcldoc.py filter, you can try with rclaudio too, adjust the file arg
// accordingly
// rcldoc.py filter, you can try with rclaudio too, adjust the file
// arg accordingly. This simplified driver only really works with
// single-doc files (else it extracts only the first doc, usually the
// empty self-doc).
bool exercise_mhexecm(const string& cmdstr, const string& mimetype,
vector<string>& files)
{
@ -171,25 +172,26 @@ public:
// Data provider, used if the -i flag is set
class MEPv : public ExecCmdProvide {
public:
FILE *m_fp;
string *m_input;
int m_cnt;
MEPv(string *i)
: m_input(i)
{
m_fp = fopen("/etc/group", "r");
}
: m_input(i), m_cnt(0) {
}
~MEPv() {
if (m_fp)
fclose(m_fp);
}
void newData() {
char line[1024];
if (m_fp && fgets(line, 1024, m_fp)) {
m_input->assign((const char *)line);
if (m_cnt++ < 10) {
char num[30];
sprintf(num, "%d", m_cnt);
*m_input = string("This is an input chunk ") + string(num) +
string("\n");
} else {
m_input->erase();
}
}
void reset() {
m_cnt = 0;
}
};
@ -249,7 +251,7 @@ int main(int argc, char *argv[])
l.push_back(*argv++); argc--;
}
DebugLog::getdbl()->setloglevel(DEBINFO);
DebugLog::getdbl()->setloglevel(DEBDEB1);
DebugLog::setfilename("stderr");
#if 0
signal(SIGPIPE, SIG_IGN);
@ -302,8 +304,9 @@ int main(int argc, char *argv[])
}
int status = -1;
for (int i=0;i < 10000; i++) {
for (int i = 0; i < 1; i++) {
output.clear();
pv.reset();
try {
status = mexec.doexec(arg1, l, ip, op);
} catch (CancelExcept) {
@ -312,8 +315,8 @@ int main(int argc, char *argv[])
//fprintf(stderr, "Status: 0x%x\n", status);
if (op_flags & OPT_o) {
//cout << "data received: [" << output << "]\n";
cerr << "status " << status << " bytes received " <<
output.size() << endl;
cerr << "iter " << i << " status " <<
status << " bytes received " << output.size() << endl;
}
if (status)
break;