1 /*******************************************************************************
2 * Copyright (c) 2000-2015 Ericsson Telecom AB
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
9 * Zoltan Janos Szabo (Ericsson) - initial architecture design and implementation
10 * Roland Gecse (Ericsson) - initial architecture design
11 * Akos Cserveni (Ericsson) - Basic AST in compiler, semantic checking
12 * Gabor Szalai (Ericsson) – RAW and TEXT codecs
13 * Matyas Forstner (Ericsson) - ASN.1 extension of the compiler and BER/CER/DER codecs
14 * Kristof Szabados (Ericsson) - Eclipse Designer, Executor, Titanium UIs
15 * Szabolcs Beres (Ericsson) - Eclipse LogViewer
16 * Ferenc Kovacs (Ericsson) – log interfaces, big number support, subtype checking
17 * Csaba Raduly (Ericsson) – ASN.1 additions, XML encoder/decoder
18 * Adam Delic (Ericsson) – template restrictions, try&catch, support of pre-processor directives in Eclipse
19 * Krisztian Pandi (Ericsson) – import of imports
20 * Peter Dimitrov (Ericsson)- maintenance
21 * Balazs Andor Zalanyi (Ericsson) – code splitting
22 * Gabor Szalai (Ericsson) – RAW encoding/decoding
23 * Jeno Attila Balasko (Ericsson) – tests
24 * Csaba Feher (Ericsson) – epoll support
25 * Tamas Buti (Ericsson)- maintenance
26 * Matyas Ormandi (Ericsson) - maintenance
27 * Botond Baranyi (Ericsson) - JSON encoder
28 * Arpad Lovassy (Ericsson) - Java Executor API
29 * Laszlo Baji (Ericsson) - maintenance
30 * Marton Godar (Ericsson) - xsd2ttcn converter
31 *******************************************************************************/
33 // File: PIPEasp_PT.cc
34 // Description: Source code of PIPE testport implementation
36 // Prodnr: CNL 113 334
37 // Updated: 2008-06-03
38 // Contact: http://ttcn.ericsson.se
42 #include "PIPEasp_PT.hh"
43 #include <signal.h> //kill
44 #include <unistd.h> //pipe
45 #include <errno.h> //errno
46 #include <ctype.h> //isspace
47 #include <sys/select.h> //FD_ZERO
48 #include <stdio.h> // sys_errlist
49 #include <sys/types.h> //wait
50 #include <sys/wait.h> //wait
53 #define PIPE_BUF_SIZE 655536
56 namespace PIPEasp__PortType
{
58 PIPEasp__PT::PIPEasp__PT(const char *par_port_name
)
59 : PIPEasp__PT_BASE(par_port_name
)
61 , processExecuting(false)
64 , processPid(-1) // pid of the process currently executing
65 , processStdin(-1) // fd of stdin of the process
66 , processStdout(-1) // fd of stdout of the process
67 , processStderr(-1) // fd of stderr of the process
68 , processExitCode(0) // exit code of the process
71 stdout_buffer
.clear();
72 stderr_buffer
.clear();
75 PIPEasp__PT::~PIPEasp__PT()
80 void PIPEasp__PT::set_parameter(const char * /*parameter_name*/,
81 const char * /*parameter_value*/)
83 // no config parameters
86 void PIPEasp__PT::Event_Handler(const fd_set
*read_fds
,
87 const fd_set
* /*write_fds*/, const fd_set
* /*error_fds*/,
88 double /*time_since_last_call*/)
90 log("PIPEasp__PT::Event_Handler called");
91 if (processStdout
!= -1 && FD_ISSET(processStdout
, read_fds
)) {
92 if (!processExecuting
) {
93 TTCN_warning("Unexpected message from stdout, no command is executing");
95 log("Incoming stdout message received from process");
101 nBytes
= PIPE_BUF_SIZE
;
102 unsigned char* buffer
;
103 size_t end_len
= nBytes
;
104 stdout_buffer
.get_end(buffer
, end_len
);
105 r
= read(processStdout
,buffer
,(int)nBytes
);
107 log("ttcn_pipe_port: read problem on stdout.\n");
108 // close the pipe and remove it from event handler
109 close(processStdout
);
110 FD_CLR(processStdout
, &readfds
);
111 Install_Handler(&readfds
, NULL
, NULL
, 0.0);
114 // check if stderr is closed:
115 if (processStderr
== -1) {
117 log("Child might have died.");
122 log("incoming stdout %ld bytes\n", r
);
123 stdout_buffer
.increase_length(r
);
128 if (processStderr
!= -1 && FD_ISSET(processStderr
, read_fds
)) {
129 if (!processExecuting
) {
130 TTCN_warning("Unexpected message from stderr, no command is executing");
132 log("Incoming stderr message received from process");
138 nBytes
= PIPE_BUF_SIZE
;
139 unsigned char* buffer
;
140 size_t end_len
= nBytes
;
141 stderr_buffer
.get_end(buffer
, end_len
);
142 r
= read(processStderr
,buffer
,(int)nBytes
);
144 log("ttcn_pipe_port: read problem on stderr.\n");
145 // close the pipe and remove it from event handler
146 close(processStderr
);
147 FD_CLR(processStderr
, &readfds
);
148 Install_Handler(&readfds
, NULL
, NULL
, 0.0);
151 // check if stdout is closed:
152 if (processStdout
== -1) {
154 log("Child might have died.");
159 log("incoming stderr %ld bytes\n", r
);
160 stderr_buffer
.increase_length(r
);
167 void PIPEasp__PT::user_map(const char * /*system_port*/)
172 void PIPEasp__PT::user_unmap(const char * /*system_port*/)
177 void PIPEasp__PT::user_start()
182 void PIPEasp__PT::user_stop()
187 /*************************************
188 * Specific outgoing_send functions
189 *************************************/
190 void PIPEasp__PT::outgoing_send(const PIPEasp__Types::ASP__PExecute
& send_par
) {
191 log("PIPEasp__PT::outgoing_send_PExecute called");
192 // disable sendStdout, sendStderr until process exits
193 if (processExecuting
) {
194 sendError("Pipe Test Port: Command already executing");
195 TTCN_Logger::begin_event(TTCN_DEBUG
);
196 TTCN_Logger::log_event("PIPE test port (%s): Command already executing. Following ASP is ignored: ", get_name());
198 TTCN_Logger::end_event();
201 PIPEasp__Types::ASP__PExecuteBackground message_PExecuteBackground
;
203 message_PExecuteBackground
.command() = send_par
.command();
204 outgoing_send(message_PExecuteBackground
);
206 PIPEasp__Types::ASP__PStdin message_PStdin
;
207 message_PStdin
.stdin_() = send_par
.stdin_();
208 outgoing_send(message_PStdin
);
211 // closing stdin pipe:
212 outgoing_send(PIPEasp__Types::ASP__PEndOfInput());
214 log("PIPEasp__PT::outgoing_send_PExecute exited");
217 void PIPEasp__PT::outgoing_send(const PIPEasp__Types::ASP__PExecuteBinary
& send_par
) {
218 log("PIPEasp__PT::outgoing_send_PExecuteBinary called");
219 // disable sendStdout, sendStderr until process exits
220 if (processExecuting
) {
221 sendError("Pipe Test Port: Command already executing");
222 TTCN_Logger::begin_event(TTCN_DEBUG
);
223 TTCN_Logger::log_event("PIPE test port (%s): Command already executing. Following ASP is ignored: ", get_name());
225 TTCN_Logger::end_event();
228 PIPEasp__Types::ASP__PExecuteBackground message_PExecuteBackground
;
230 message_PExecuteBackground
.command() = send_par
.command();
231 outgoing_send(message_PExecuteBackground
);
233 PIPEasp__Types::ASP__PStdinBinary message_PStdinBinary
;
234 message_PStdinBinary
.stdin_() = send_par
.stdin_();
235 outgoing_send(message_PStdinBinary
);
238 // closing stdin pipe:
239 outgoing_send(PIPEasp__Types::ASP__PEndOfInput());
241 log("PIPEasp__PT::outgoing_send_PExecuteBinary exited");
244 void PIPEasp__PT::outgoing_send(const PIPEasp__Types::ASP__PExecuteBackground
& send_par
) {
245 log("PIPEasp__PT::outgoing_send_PExecuteBackground called");
247 if (processExecuting
) {
248 log("Process already executing. Cannot start new process.");
249 sendError("Pipe Test Port: Command already executing");
250 TTCN_Logger::begin_event(TTCN_DEBUG
);
251 TTCN_Logger::log_event("PIPE test port (%s): Command already executing. Following ASP is ignored: ", get_name());
253 TTCN_Logger::end_event();
254 log("PIPEasp__PT::outgoing_send_PExecuteBackground exited");
258 // creating pipes for process
263 if (pipe(pipesStdin
) != 0) {
264 sendError("Pipe Test Port: Cannot create stdin pipe");
265 log("PIPEasp__PT::outgoing_send_PExecuteBackground exited");
268 if (pipe(pipesStdout
) != 0) {
269 sendError("Pipe Test Port: Cannot create stdout pipe");
270 log("PIPEasp__PT::outgoing_send_PExecuteBackground exited");
273 if (pipe(pipesStderr
) != 0) {
274 sendError("Pipe Test Port: Cannot create stderr pipe");
275 log("PIPEasp__PT::outgoing_send_PExecuteBackground exited");
279 processStdin
= pipesStdin
[1];
280 processStdout
= pipesStdout
[0];
281 processStderr
= pipesStderr
[0];
284 if (processPid
< 0) {
290 close(pipesStdin
[0]);
291 close(pipesStdout
[1]);
292 close(pipesStderr
[1]);
295 close(processStdout
);
296 close(processStderr
);
298 sendError("Pipe Test Port: Cannot fork");
300 else if (processPid
== 0) {
306 // close the parent end of the pipes
308 close(processStdout
);
309 close(processStderr
);
311 /*// set these to the other end of the pipe
312 processStdin = pipesStdin[0];
313 processStdout = pipesStdout[1];
314 processStderr = pipesStderr[1];*/
317 // redirect pipeStdin to stdin
318 r
= dup2(pipesStdin
[0], 0);
320 TTCN_error("Cannot redirect stdin");
324 // redirect pipeStdout to stdout
325 r
= dup2(pipesStdout
[1], 1);
327 TTCN_error("Cannot redirect stdout");
331 // redirect pipeStderr to stderr
332 r
= dup2(pipesStderr
[1], 2);
334 TTCN_error("Cannot redirect stderr");
338 processExitCode
= execCommand((const char*)send_par
.command());
340 // There is a problem executing the command
347 close(pipesStdin
[0]);
348 close(pipesStdout
[1]);
349 close(pipesStderr
[1]);
351 exit(processExitCode
); // end of child process
359 log("Process started with pid: %d", processPid
);
360 // close child end of the pipes
361 close(pipesStdin
[0]);
362 close(pipesStdout
[1]);
363 close(pipesStderr
[1]);
366 processExecuting
= true;
368 // install handler for the process pipes:
369 //FD_SET(processStdin, &readfds);
370 FD_SET(processStdout
, &readfds
);
371 FD_SET(processStderr
, &readfds
);
373 Install_Handler(&readfds
, NULL
, NULL
, 0.0);
376 log("PIPEasp__PT::outgoing_send_PExecuteBackground exited");
379 void PIPEasp__PT::outgoing_send(const PIPEasp__Types::ASP__PStdin
& send_par
) {
381 log("PIPEasp__PT::outgoing_send_PStdin called");
383 if (!processExecuting
) {
384 sendError("Pipe Test Port: No command executing");
387 if (disableSend
) { // process was started with PExecute(Binary)
388 sendError("Pipe Test Port: PStdin is not sent: current process is not started with PExecuteBackground!");
392 log("will now write to stdin: '%s'",
393 (const char*)(send_par
.stdin_()+((lineMode
)?"\n":"")));
395 (const char*)(send_par
.stdin_()+((lineMode
)?"\n":"")),
396 send_par
.stdin_().lengthof()+((lineMode
)?1:0));
398 log("PIPEasp__PT::outgoing_send_PStdin exited");
401 void PIPEasp__PT::outgoing_send(const PIPEasp__Types::ASP__PStdinBinary
& send_par
) {
402 log("PIPEasp__PT::outgoing_send_PStdinBinary called");
404 if (!processExecuting
) {
405 sendError("Pipe Test Port: No command executing");
408 if (disableSend
) { // process was started with PExecute(Binary)
409 sendError("Pipe Test Port: PStdinBinary is not sent: current process is not started with PExecuteBackground!");
413 TTCN_Logger::begin_event(TTCN_DEBUG
);
414 TTCN_Logger::log_event("PIPE test port (%s): will now write binary data to stdin: ", get_name());
415 send_par
.stdin_().log();
416 TTCN_Logger::end_event();
419 (const char*)(const unsigned char*)(send_par
.stdin_()),
420 send_par
.stdin_().lengthof());
421 log("PIPEasp__PT::outgoing_send_PStdinBinary exited");
424 void PIPEasp__PT::outgoing_send(const PIPEasp__Types::ASP__PKill
& send_par
) {
425 log("PIPEasp__PT::outgoing_send_PKill called");
426 if (!processExecuting
) {
427 // no process is running
428 log("No process executing.");
429 sendError("Pipe Test Port: No command executing");
430 log("PIPEasp__PT::outgoing_send_PKill exited");
434 int signo
= (int)send_par
.signal();
435 if (signo
<1 || signo
>31) {
436 // signo out of range;
437 log("Signo out of range.");
439 "Pipe Test port: Signal number should be "
441 log("PIPEasp__PT::outgoing_send_PKill exited");
445 log("Killing process %d, signo: %d", processPid
, signo
);
446 int r
= kill(processPid
, signo
);
447 log("Kill process returned %d", r
);
448 log("PIPEasp__PT::outgoing_send_PKill exited");
451 void PIPEasp__PT::outgoing_send(const PIPEasp__Types::ASP__PLineMode
& send_par
) {
452 log("PIPEasp__PT::outgoing_send_PLineMode called");
453 lineMode
= (bool)send_par
.lineMode();
454 log("LineMode is set to %s", (lineMode
)?"TRUE":"FALSE");
455 log("PIPEasp__PT::outgoing_send_PLineMode exited");
458 void PIPEasp__PT::outgoing_send(const PIPEasp__Types::ASP__PEndOfInput
& /*send_par*/) {
459 log("PIPEasp__PT::outgoing_send_PEndOfInput called");
464 log("PIPEasp__PT::outgoing_send_PEndOfInput exited");
467 /********************************
468 * Execute the given command
469 * returns the exitcode of the process
470 *********************************/
471 int PIPEasp__PT::execCommand(const char* command
) {
472 log("PIPEasp__PT::execCommand called");
473 log("Executing command: %s", command
);
475 // with this it is not possible to access the pid of the process
476 //return system(command);
481 CHARSTRING
temp(0, ""); // empty string
482 for (int i
= 0; command
[i
] != 0; i
++) {
483 if (isspace(command
[i
])) {
484 argv
[argc
++] = strdup(temp
);
485 log("command argument added: %s", (const char*)temp
);
486 while (command
[i
] != '0' && isspace(command
[i
])) i
++;
490 temp
= temp
+ CHARSTRING(1, command
+i
);
495 argv
[argc
++] = strdup(temp
);
496 log("command argument added: %s", (const char*)temp
);
499 argv
[argc
++] = (char*)NULL
;
501 log("execCommand(%s,%d)\n", argv
[0], argc
);
502 execvp(argv
[0],argv
);
504 fprintf(stderr
,"Error executing command %s (%d): %s\n",
505 argv
[0], errno
, strerror(errno
));
511 /***********************************
512 * if the the child process died, gets
513 * the exit code and sends it to TTCN
514 * should be called when stdout/err are closed
515 ************************************/
516 void PIPEasp__PT::handle_childDeath() {
517 log("Getting process status for pid %d...", processPid
);
518 processExitCode
= 0; // reset the exitcode
519 int pid
= wait(&processExitCode
);
520 //waitpid(processPid,&processExitCode, 0);
521 if (pid
!=processPid
) {
522 log("other child died with pid: %d, exit code: %d", pid
, processExitCode
);
526 log("Child process exit status is: %d", processExitCode
);
527 // send code to TTCN:
529 // send result to TTCN
532 // removing fd-s installed for the process:
533 Uninstall_Handler(); // no handler is needed
537 //FD_CLR(processStdin, &readfds);
538 FD_CLR(processStdout, &readfds);
539 FD_CLR(processStderr, &readfds);
540 Install_Handler(&readfds, NULL, NULL, 0.0);
545 //close(processStdout); // already closed
546 //close(processStderr); // already closed
549 //processStdout = -1;
550 //processStderr = -1;
552 processExecuting
= false;
556 /***************************
557 * Send stdout msg to TTCN
558 ***************************/
559 void PIPEasp__PT::sendStdout() {
560 if (disableSend
) return;
562 PIPEasp__Types::ASP__PStdout message_PStdout
;
563 PIPEasp__Types::ASP__PStdoutBinary message_PStdoutBinary
;
564 if (lineMode
&& !binaryMode
) {
565 // send complete lines from buffer
566 const unsigned char* pos
= stdout_buffer
.get_read_data();
567 for(unsigned int i
=0; i
<stdout_buffer
.get_read_len(); i
++) {
569 if (pos
[i
] != '\n') {
574 // length of data is i (+1 is for \n and is not sent)
575 message_PStdout
.stdout_() = CHARSTRING(i
, (const char*)pos
);
578 incoming_message(message_PStdout
);
580 // remove the complete line from buffer,
581 // also set i and pos to the beginning of buffer
582 stdout_buffer
.set_pos(i
+1);
585 pos
= stdout_buffer
.get_read_data();
588 // lineMode false or binaryMode true
590 message_PStdoutBinary
.stdout_() =
591 OCTETSTRING(stdout_buffer
.get_read_len(), stdout_buffer
.get_read_data());
592 stdout_buffer
.clear();
593 incoming_message(message_PStdoutBinary
);
596 message_PStdout
.stdout_() =
597 CHARSTRING(stdout_buffer
.get_read_len(), (const char*)stdout_buffer
.get_read_data());
598 stdout_buffer
.clear();
599 incoming_message(message_PStdout
);
601 // incoming_message(message);
606 /***************************
607 * Send stderr msg to TTCN
608 ***************************/
609 void PIPEasp__PT::sendStderr() {
610 if (disableSend
) return;
612 PIPEasp__Types::ASP__PStderr message_PStderr
;
613 PIPEasp__Types::ASP__PStderrBinary message_PStderrBinary
;
614 if (lineMode
&& !binaryMode
) {
615 // send complete lines from buffer
616 const unsigned char* pos
= stderr_buffer
.get_read_data();
617 for(unsigned int i
=0; i
<stderr_buffer
.get_read_len(); i
++) {
619 if (pos
[i
] != '\n') {
624 // length of data is i (+1 is for \n and is not sent)
625 message_PStderr
.stderr_() = CHARSTRING(i
, (const char*)pos
);
628 incoming_message(message_PStderr
);
630 // remove the complete line from buffer,
631 // also set i and pos to the beginning of buffer
632 stderr_buffer
.set_pos(i
+1);
635 pos
= stderr_buffer
.get_read_data();
638 // lineMode false or binaryMode true
640 message_PStderrBinary
.stderr_() =
641 OCTETSTRING(stderr_buffer
.get_read_len(), stderr_buffer
.get_read_data());
642 stderr_buffer
.clear();
643 incoming_message(message_PStderrBinary
);
646 message_PStderr
.stderr_() =
647 CHARSTRING(stderr_buffer
.get_read_len(), (const char*)stderr_buffer
.get_read_data());
648 stderr_buffer
.clear();
649 incoming_message(message_PStderr
);
651 // incoming_message(message);
656 /***************************
657 * Send exitcode msg to TTCN
658 ***************************/
659 void PIPEasp__PT::sendExitCode() {
660 if (disableSend
) return;
662 log("Sending ExitCode to TTCN");
663 PIPEasp__Types::ASP__PExit message_PExit
;
664 message_PExit
.code() = processExitCode
;
665 incoming_message(message_PExit
);
669 /***************************
670 * Send error msg to TTCN
671 ***************************/
672 void PIPEasp__PT::sendError(const char* error_msg
) {
673 PIPEasp__Types::ASP__PError message_PError
;
674 message_PError
.errorMessage() = error_msg
;
675 incoming_message(message_PError
);
679 /***************************
680 * Send Result msg to TTCN
681 ***************************/
682 void PIPEasp__PT::sendResult() {
683 if (!disableSend
) return; // do not send result if process was started by PExecuteBackground
685 log("Sending result to TTCN...");
686 PIPEasp__Types::ASP__PResult message_PResult
;
687 PIPEasp__Types::ASP__PResultBinary message_PResultBinary
;
689 message_PResultBinary
.stdout_() =
690 OCTETSTRING(stdout_buffer
.get_read_len(), stdout_buffer
.get_read_data());
691 message_PResultBinary
.stderr_() =
692 OCTETSTRING(stderr_buffer
.get_read_len(), stderr_buffer
.get_read_data());
693 message_PResultBinary
.code() = processExitCode
;
694 incoming_message(message_PResultBinary
);
696 int messageLen
= stdout_buffer
.get_read_len();
697 const char* messageData
= (const char*)stdout_buffer
.get_read_data();
699 if (lineMode
&& messageData
[messageLen
-1]=='\n') {
700 messageLen
--; // remove newline from the end
703 message_PResult
.stdout_() = CHARSTRING(messageLen
, messageData
);
705 messageLen
= stderr_buffer
.get_read_len();
706 messageData
= (const char*)stderr_buffer
.get_read_data();
708 if (lineMode
&& messageData
[messageLen
-1]=='\n') {
709 messageLen
--; // remove newline from the end
712 message_PResult
.stderr_() = CHARSTRING(messageLen
, messageData
);
713 message_PResult
.code() = processExitCode
;
714 incoming_message(message_PResult
);
717 // clearing the buffers
718 stdout_buffer
.clear();
719 stderr_buffer
.clear();
720 //incoming_message(message);
727 void PIPEasp__PT::log(const char *fmt
, ...)
729 TTCN_Logger::begin_event(TTCN_DEBUG
);
730 TTCN_Logger::log_event("PIPE test port (%s): ", get_name());
733 TTCN_Logger::log_event_va_list(fmt
, ap
);
735 TTCN_Logger::end_event();