comparison vamp-server/simple-server.cpp @ 138:b01dac674beb

Discard stdout output that occurs in between our own outputs (e.g. from plugin)
author Chris Cannam <c.cannam@qmul.ac.uk>
date Thu, 12 Jan 2017 08:49:26 +0000
parents 9da826f812cb
children 807a0a43096e
comparison
equal deleted inserted replaced
137:1902e6db5b61 138:b01dac674beb
55 #else 55 #else
56 #include <unistd.h> 56 #include <unistd.h>
57 static int pid = getpid(); 57 static int pid = getpid();
58 #endif 58 #endif
59 59
60 // for _setmode stuff 60 // for _setmode stuff and _dup
61 #ifdef _WIN32 61 #ifdef _WIN32
62 #include <io.h> 62 #include <io.h>
63 #include <fcntl.h> 63 #include <fcntl.h>
64 #endif
65
66 // for dup, open etc
67 #ifndef _WIN32
68 #include <fcntl.h>
69 #include <unistd.h>
64 #endif 70 #endif
65 71
66 using namespace std; 72 using namespace std;
67 using namespace json11; 73 using namespace json11;
68 using namespace piper_vamp; 74 using namespace piper_vamp;
102 else exit(2); 108 else exit(2);
103 } 109 }
104 110
105 static CountingPluginHandleMapper mapper; 111 static CountingPluginHandleMapper mapper;
106 112
113 // We write our output to stdout, but want to ensure that the plugin
114 // doesn't write anything itself. To do this we open a null file
115 // descriptor and dup2() it into place of stdout in the gaps between
116 // our own output activity.
117
118 static int normalFd = -1;
119 static int suspendedFd = -1;
120
121 static void initFds(bool binary)
122 {
123 #ifdef _WIN32
124 if (binary) {
125 int result = _setmode(0, _O_BINARY);
126 if (result == -1) {
127 throw runtime_error("Failed to set binary mode on stdin");
128 }
129 result = _setmode(1, _O_BINARY);
130 if (result == -1) {
131 throw runtime_error("Failed to set binary mode on stdout");
132 }
133 }
134 normalFd = _dup(1);
135 suspendedFd = _open("NUL", _O_WRONLY);
136 #else
137 normalFd = dup(1);
138 suspendedFd = open("/dev/null", O_WRONLY);
139 #endif
140
141 if (normalFd < 0 || suspendedFd < 0) {
142 throw runtime_error("Failed to initialise fds for stdio suspend/resume");
143 }
144 }
145
146 static void suspendOutput()
147 {
148 #ifdef _WIN32
149 _dup2(suspendedFd, 1);
150 #else
151 dup2(suspendedFd, 1);
152 #endif
153 }
154
155 static void resumeOutput()
156 {
157 #ifdef _WIN32
158 _dup2(normalFd, 1);
159 #else
160 dup2(normalFd, 1);
161 #endif
162 }
163
107 static RequestOrResponse::RpcId 164 static RequestOrResponse::RpcId
108 readId(const piper::RpcRequest::Reader &r) 165 readId(const piper::RpcRequest::Reader &r)
109 { 166 {
110 int number; 167 int number;
111 string tag; 168 string tag;
274 break; 331 break;
275 case RRType::NotValid: 332 case RRType::NotValid:
276 break; 333 break;
277 } 334 }
278 } 335 }
279 336
280 cout << j.dump() << endl; 337 cout << j.dump() << endl;
281 } 338 }
282 339
283 void 340 void
284 writeExceptionJson(const std::exception &e, RRType type) 341 writeExceptionJson(const exception &e, RRType type)
285 { 342 {
286 Json j = VampJson::fromError(e.what(), type, Json()); 343 Json j = VampJson::fromError(e.what(), type, Json());
287 cout << j.dump() << endl; 344 cout << j.dump() << endl;
288 } 345 }
289 346
370 427
371 writeMessageToFd(1, message); 428 writeMessageToFd(1, message);
372 } 429 }
373 430
374 void 431 void
375 writeExceptionCapnp(const std::exception &e, RRType type) 432 writeExceptionCapnp(const exception &e, RRType type)
376 { 433 {
377 capnp::MallocMessageBuilder message; 434 capnp::MallocMessageBuilder message;
378 piper::RpcResponse::Builder builder = message.initRoot<piper::RpcResponse>(); 435 piper::RpcResponse::Builder builder = message.initRoot<piper::RpcResponse>();
379 VampnProto::buildRpcResponse_Exception(builder, e, type); 436 VampnProto::buildRpcResponse_Exception(builder, e, type);
380 437
504 } 561 }
505 562
506 void 563 void
507 writeResponse(string format, RequestOrResponse &rr) 564 writeResponse(string format, RequestOrResponse &rr)
508 { 565 {
566 resumeOutput();
509 if (format == "capnp") { 567 if (format == "capnp") {
510 writeResponseCapnp(rr); 568 writeResponseCapnp(rr);
511 } else if (format == "json") { 569 } else if (format == "json") {
512 writeResponseJson(rr, false); 570 writeResponseJson(rr, false);
513 } else { 571 } else {
514 throw runtime_error("unknown output format \"" + format + "\""); 572 throw runtime_error("unknown output format \"" + format + "\"");
515 } 573 }
574 suspendOutput();
516 } 575 }
517 576
518 void 577 void
519 writeException(string format, const std::exception &e, RRType type) 578 writeException(string format, const exception &e, RRType type)
520 { 579 {
580 resumeOutput();
521 if (format == "capnp") { 581 if (format == "capnp") {
522 writeExceptionCapnp(e, type); 582 writeExceptionCapnp(e, type);
523 } else if (format == "json") { 583 } else if (format == "json") {
524 writeExceptionJson(e, type); 584 writeExceptionJson(e, type);
525 } else { 585 } else {
526 throw runtime_error("unknown output format \"" + format + "\""); 586 throw runtime_error("unknown output format \"" + format + "\"");
527 } 587 }
588 suspendOutput();
528 } 589 }
529 590
530 int main(int argc, char **argv) 591 int main(int argc, char **argv)
531 { 592 {
532 if (argc != 2 && argc != 3) { 593 if (argc != 2 && argc != 3) {
561 622
562 if (format != "capnp" && format != "json") { 623 if (format != "capnp" && format != "json") {
563 usage(); 624 usage();
564 } 625 }
565 626
566 #ifdef _WIN32 627 try {
567 if (format == "capnp") { 628 initFds(format == "capnp");
568 int result = _setmode(_fileno(stdin), _O_BINARY); 629 } catch (exception &e) {
569 if (result == -1) { 630 cerr << "ERROR: " << e.what() << endl;
570 cerr << "Failed to set binary mode on stdin, necessary for capnp format" << endl; 631 exit(1);
571 exit(1); 632 }
572 } 633
573 result = _setmode(_fileno(stdout), _O_BINARY); 634 suspendOutput();
574 if (result == -1) {
575 cerr << "Failed to set binary mode on stdout, necessary for capnp format" << endl;
576 exit(1);
577 }
578 }
579 #endif
580 635
581 if (debug) { 636 if (debug) {
582 cerr << myname << " " << pid << ": waiting for format: " << format << endl; 637 cerr << myname << " " << pid << ": waiting for format: " << format << endl;
583 } 638 }
584 639
585 while (true) { 640 while (true) {
586 641
587 RequestOrResponse request; 642 RequestOrResponse request;
588 643
589 try { 644 try {
625 } 680 }
626 mapper.removePlugin(h); 681 mapper.removePlugin(h);
627 delete request.finishRequest.plugin; 682 delete request.finishRequest.plugin;
628 } 683 }
629 684
630 } catch (std::exception &e) { 685 } catch (exception &e) {
631 686
632 if (debug) { 687 if (debug) {
633 cerr << myname << " " << pid << ": error: " << e.what() << endl; 688 cerr << myname << " " << pid << ": error: " << e.what() << endl;
634 } 689 }
635 690