a38c6d4c |
1 | /******************************************************************************* |
3abe9331 |
2 | * Copyright (c) 2000-2015 Ericsson Telecom AB |
a38c6d4c |
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 |
7 | * |
8 | * Contributors: |
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 | *******************************************************************************/ |
32 | // |
33 | // File: PIPEasp_PT.cc |
34 | // Description: Source code of PIPE testport implementation |
35 | // Rev: <RnXnn> |
36 | // Prodnr: CNL 113 334 |
37 | // Updated: 2008-06-03 |
38 | // Contact: http://ttcn.ericsson.se |
39 | // |
40 | |
41 | |
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 |
51 | |
52 | #ifndef PIPE_BUF_SIZE |
53 | #define PIPE_BUF_SIZE 655536 |
54 | #endif |
55 | |
56 | namespace PIPEasp__PortType { |
57 | |
58 | PIPEasp__PT::PIPEasp__PT(const char *par_port_name) |
59 | : PIPEasp__PT_BASE(par_port_name) |
60 | , lineMode(true) |
61 | , processExecuting(false) |
62 | , binaryMode(false) |
63 | , disableSend(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 |
69 | { |
70 | FD_ZERO(&readfds); |
71 | stdout_buffer.clear(); |
72 | stderr_buffer.clear(); |
73 | } |
74 | |
75 | PIPEasp__PT::~PIPEasp__PT() |
76 | { |
77 | // nothing to do |
78 | } |
79 | |
80 | void PIPEasp__PT::set_parameter(const char * /*parameter_name*/, |
81 | const char * /*parameter_value*/) |
82 | { |
83 | // no config parameters |
84 | } |
85 | |
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*/) |
89 | { |
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"); |
94 | } else { |
95 | log("Incoming stdout message received from process"); |
96 | } |
97 | |
98 | long nBytes; |
99 | int r; |
100 | |
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); |
106 | if (r <= 0) { |
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); |
112 | processStdout = -1; |
113 | |
114 | // check if stderr is closed: |
115 | if (processStderr == -1) { |
116 | // child died |
117 | log("Child might have died."); |
118 | handle_childDeath(); |
119 | } |
120 | } |
121 | else { |
122 | log("incoming stdout %ld bytes\n", r); |
123 | stdout_buffer.increase_length(r); |
124 | sendStdout(); |
125 | } |
126 | return; |
127 | } |
128 | if (processStderr != -1 && FD_ISSET(processStderr, read_fds)) { |
129 | if (!processExecuting) { |
130 | TTCN_warning("Unexpected message from stderr, no command is executing"); |
131 | } else { |
132 | log("Incoming stderr message received from process"); |
133 | } |
134 | |
135 | long nBytes; |
136 | int r; |
137 | |
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); |
143 | if (r <= 0) { |
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); |
149 | processStderr = -1; |
150 | |
151 | // check if stdout is closed: |
152 | if (processStdout == -1) { |
153 | // child died |
154 | log("Child might have died."); |
155 | handle_childDeath(); |
156 | } |
157 | } |
158 | else { |
159 | log("incoming stderr %ld bytes\n", r); |
160 | stderr_buffer.increase_length(r); |
161 | sendStderr(); |
162 | } |
163 | return; |
164 | } |
165 | } |
166 | |
167 | void PIPEasp__PT::user_map(const char * /*system_port*/) |
168 | { |
169 | // nothing to do |
170 | } |
171 | |
172 | void PIPEasp__PT::user_unmap(const char * /*system_port*/) |
173 | { |
174 | // nothing to do |
175 | } |
176 | |
177 | void PIPEasp__PT::user_start() |
178 | { |
179 | // nothing to do |
180 | } |
181 | |
182 | void PIPEasp__PT::user_stop() |
183 | { |
184 | // nothing to do |
185 | } |
186 | |
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()); |
197 | send_par.log(); |
198 | TTCN_Logger::end_event(); |
199 | return; |
200 | } |
201 | PIPEasp__Types::ASP__PExecuteBackground message_PExecuteBackground; |
202 | // starting command |
203 | message_PExecuteBackground.command() = send_par.command(); |
204 | outgoing_send(message_PExecuteBackground); |
205 | // sending input |
206 | PIPEasp__Types::ASP__PStdin message_PStdin; |
207 | message_PStdin.stdin_() = send_par.stdin_(); |
208 | outgoing_send(message_PStdin); |
209 | disableSend = true; |
210 | |
211 | // closing stdin pipe: |
212 | outgoing_send(PIPEasp__Types::ASP__PEndOfInput()); |
213 | |
214 | log("PIPEasp__PT::outgoing_send_PExecute exited"); |
215 | } |
216 | |
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()); |
224 | send_par.log(); |
225 | TTCN_Logger::end_event(); |
226 | return; |
227 | } |
228 | PIPEasp__Types::ASP__PExecuteBackground message_PExecuteBackground; |
229 | // starting command |
230 | message_PExecuteBackground.command() = send_par.command(); |
231 | outgoing_send(message_PExecuteBackground); |
232 | // sending input |
233 | PIPEasp__Types::ASP__PStdinBinary message_PStdinBinary; |
234 | message_PStdinBinary.stdin_() = send_par.stdin_(); |
235 | outgoing_send(message_PStdinBinary); |
236 | disableSend = true; |
237 | |
238 | // closing stdin pipe: |
239 | outgoing_send(PIPEasp__Types::ASP__PEndOfInput()); |
240 | |
241 | log("PIPEasp__PT::outgoing_send_PExecuteBinary exited"); |
242 | } |
243 | |
244 | void PIPEasp__PT::outgoing_send(const PIPEasp__Types::ASP__PExecuteBackground& send_par) { |
245 | log("PIPEasp__PT::outgoing_send_PExecuteBackground called"); |
246 | |
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()); |
252 | send_par.log(); |
253 | TTCN_Logger::end_event(); |
254 | log("PIPEasp__PT::outgoing_send_PExecuteBackground exited"); |
255 | return; |
256 | } |
257 | |
258 | // creating pipes for process |
259 | int pipesStdin[2]; |
260 | int pipesStdout[2]; |
261 | int pipesStderr[2]; |
262 | |
263 | if (pipe(pipesStdin) != 0) { |
264 | sendError("Pipe Test Port: Cannot create stdin pipe"); |
265 | log("PIPEasp__PT::outgoing_send_PExecuteBackground exited"); |
266 | return; |
267 | } |
268 | if (pipe(pipesStdout) != 0) { |
269 | sendError("Pipe Test Port: Cannot create stdout pipe"); |
270 | log("PIPEasp__PT::outgoing_send_PExecuteBackground exited"); |
271 | return; |
272 | } |
273 | if (pipe(pipesStderr) != 0) { |
274 | sendError("Pipe Test Port: Cannot create stderr pipe"); |
275 | log("PIPEasp__PT::outgoing_send_PExecuteBackground exited"); |
276 | return; |
277 | } |
278 | |
279 | processStdin = pipesStdin[1]; |
280 | processStdout = pipesStdout[0]; |
281 | processStderr = pipesStderr[0]; |
282 | |
283 | processPid = fork(); |
284 | if (processPid < 0) { |
285 | // |
286 | // Error |
287 | // |
288 | |
289 | // close the pipes |
290 | close(pipesStdin[0]); |
291 | close(pipesStdout[1]); |
292 | close(pipesStderr[1]); |
293 | |
294 | close(processStdin); |
295 | close(processStdout); |
296 | close(processStderr); |
297 | |
298 | sendError("Pipe Test Port: Cannot fork"); |
299 | } |
300 | else if (processPid == 0) { |
301 | |
302 | // |
303 | // Child process |
304 | // |
305 | |
306 | // close the parent end of the pipes |
307 | close(processStdin); |
308 | close(processStdout); |
309 | close(processStderr); |
310 | |
311 | /*// set these to the other end of the pipe |
312 | processStdin = pipesStdin[0]; |
313 | processStdout = pipesStdout[1]; |
314 | processStderr = pipesStderr[1];*/ |
315 | |
316 | int r; |
317 | // redirect pipeStdin to stdin |
318 | r = dup2(pipesStdin[0], 0); |
319 | if (r<0) { |
320 | TTCN_error("Cannot redirect stdin"); |
321 | exit(errno); |
322 | } |
323 | |
324 | // redirect pipeStdout to stdout |
325 | r = dup2(pipesStdout[1], 1); |
326 | if (r<0) { |
327 | TTCN_error("Cannot redirect stdout"); |
328 | exit(errno); |
329 | } |
330 | |
331 | // redirect pipeStderr to stderr |
332 | r = dup2(pipesStderr[1], 2); |
333 | if (r<0) { |
334 | TTCN_error("Cannot redirect stderr"); |
335 | exit(errno); |
336 | } |
337 | |
338 | processExitCode = execCommand((const char*)send_par.command()); |
339 | |
340 | // There is a problem executing the command |
341 | // Exiting... |
342 | |
343 | fflush(stdout); |
344 | fflush(stderr); |
345 | |
346 | //closing pipes: |
347 | close(pipesStdin[0]); |
348 | close(pipesStdout[1]); |
349 | close(pipesStderr[1]); |
350 | |
351 | exit(processExitCode); // end of child process |
352 | } |
353 | else { |
354 | |
355 | // |
356 | // Parent process |
357 | // |
358 | |
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]); |
364 | |
365 | |
366 | processExecuting = true; |
367 | |
368 | // install handler for the process pipes: |
369 | //FD_SET(processStdin, &readfds); |
370 | FD_SET(processStdout, &readfds); |
371 | FD_SET(processStderr, &readfds); |
372 | |
373 | Install_Handler(&readfds, NULL, NULL, 0.0); |
374 | } |
375 | |
376 | log("PIPEasp__PT::outgoing_send_PExecuteBackground exited"); |
377 | } |
378 | |
379 | void PIPEasp__PT::outgoing_send(const PIPEasp__Types::ASP__PStdin& send_par) { |
380 | |
381 | log("PIPEasp__PT::outgoing_send_PStdin called"); |
382 | binaryMode = false; |
383 | if (!processExecuting) { |
384 | sendError("Pipe Test Port: No command executing"); |
385 | return; |
386 | } |
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!"); |
389 | return; |
390 | } |
391 | |
392 | log("will now write to stdin: '%s'", |
393 | (const char*)(send_par.stdin_()+((lineMode)?"\n":""))); |
394 | write(processStdin, |
395 | (const char*)(send_par.stdin_()+((lineMode)?"\n":"")), |
396 | send_par.stdin_().lengthof()+((lineMode)?1:0)); |
397 | |
398 | log("PIPEasp__PT::outgoing_send_PStdin exited"); |
399 | } |
400 | |
401 | void PIPEasp__PT::outgoing_send(const PIPEasp__Types::ASP__PStdinBinary& send_par) { |
402 | log("PIPEasp__PT::outgoing_send_PStdinBinary called"); |
403 | binaryMode = true; |
404 | if (!processExecuting) { |
405 | sendError("Pipe Test Port: No command executing"); |
406 | return; |
407 | } |
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!"); |
410 | return; |
411 | } |
412 | |
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(); |
417 | |
418 | write(processStdin, |
419 | (const char*)(const unsigned char*)(send_par.stdin_()), |
420 | send_par.stdin_().lengthof()); |
421 | log("PIPEasp__PT::outgoing_send_PStdinBinary exited"); |
422 | } |
423 | |
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"); |
431 | return; |
432 | } |
433 | |
434 | int signo = (int)send_par.signal(); |
435 | if (signo<1 || signo>31) { |
436 | // signo out of range; |
437 | log("Signo out of range."); |
438 | sendError( |
439 | "Pipe Test port: Signal number should be " |
440 | "between 1 and 31"); |
441 | log("PIPEasp__PT::outgoing_send_PKill exited"); |
442 | return; |
443 | } |
444 | // killing process |
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"); |
449 | } |
450 | |
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"); |
456 | } |
457 | |
458 | void PIPEasp__PT::outgoing_send(const PIPEasp__Types::ASP__PEndOfInput& /*send_par*/) { |
459 | log("PIPEasp__PT::outgoing_send_PEndOfInput called"); |
460 | // close stdin pipe |
461 | close(processStdin); |
462 | processStdin = -1; |
463 | log("stdin closed"); |
464 | log("PIPEasp__PT::outgoing_send_PEndOfInput exited"); |
465 | } |
466 | |
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); |
474 | |
475 | // with this it is not possible to access the pid of the process |
476 | //return system(command); |
477 | |
478 | int argc = 0; |
479 | char* argv[1024]; |
480 | |
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++; |
487 | i--; |
488 | temp = ""; |
489 | } else { |
490 | temp = temp + CHARSTRING(1, command+i); |
491 | } |
492 | } |
493 | |
494 | if (temp != "") { |
495 | argv[argc++] = strdup(temp); |
496 | log("command argument added: %s", (const char*)temp); |
497 | } |
498 | |
499 | argv[argc++] = (char*)NULL; |
500 | |
501 | log("execCommand(%s,%d)\n", argv[0], argc); |
502 | execvp(argv[0],argv); |
503 | |
504 | fprintf(stderr,"Error executing command %s (%d): %s\n", |
505 | argv[0], errno, strerror(errno)); |
506 | fflush(stderr); |
507 | // exit(errno); |
508 | return errno; |
509 | } |
510 | |
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); |
523 | return; |
524 | } |
525 | |
526 | log("Child process exit status is: %d", processExitCode); |
527 | // send code to TTCN: |
528 | sendExitCode(); |
529 | // send result to TTCN |
530 | sendResult(); |
531 | |
532 | // removing fd-s installed for the process: |
533 | Uninstall_Handler(); // no handler is needed |
534 | FD_ZERO(&readfds); |
535 | /* |
536 | // equivalent with: |
537 | //FD_CLR(processStdin, &readfds); |
538 | FD_CLR(processStdout, &readfds); |
539 | FD_CLR(processStderr, &readfds); |
540 | Install_Handler(&readfds, NULL, NULL, 0.0); |
541 | */ |
542 | |
543 | // closing pipes: |
544 | close(processStdin); |
545 | //close(processStdout); // already closed |
546 | //close(processStderr); // already closed |
547 | |
548 | processStdin = -1; |
549 | //processStdout = -1; |
550 | //processStderr = -1; |
551 | |
552 | processExecuting = false; |
553 | disableSend = false; |
554 | } |
555 | |
556 | /*************************** |
557 | * Send stdout msg to TTCN |
558 | ***************************/ |
559 | void PIPEasp__PT::sendStdout() { |
560 | if (disableSend) return; |
561 | |
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++) { |
568 | // not end of line: |
569 | if (pos[i] != '\n') { |
570 | continue; |
571 | } |
572 | |
573 | // at end of line |
574 | // length of data is i (+1 is for \n and is not sent) |
575 | message_PStdout.stdout_() = CHARSTRING(i, (const char*)pos); |
576 | |
577 | // send message |
578 | incoming_message(message_PStdout); |
579 | |
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); |
583 | stdout_buffer.cut(); |
584 | i = 0; |
585 | pos = stdout_buffer.get_read_data(); |
586 | } |
587 | } else { |
588 | // lineMode false or binaryMode true |
589 | if (binaryMode) { |
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); |
594 | } |
595 | else { |
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); |
600 | } |
601 | // incoming_message(message); |
602 | } |
603 | } |
604 | |
605 | |
606 | /*************************** |
607 | * Send stderr msg to TTCN |
608 | ***************************/ |
609 | void PIPEasp__PT::sendStderr() { |
610 | if (disableSend) return; |
611 | |
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++) { |
618 | // not end of line: |
619 | if (pos[i] != '\n') { |
620 | continue; |
621 | } |
622 | |
623 | // at end of line |
624 | // length of data is i (+1 is for \n and is not sent) |
625 | message_PStderr.stderr_() = CHARSTRING(i, (const char*)pos); |
626 | |
627 | // send message |
628 | incoming_message(message_PStderr); |
629 | |
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); |
633 | stderr_buffer.cut(); |
634 | i = 0; |
635 | pos = stderr_buffer.get_read_data(); |
636 | } |
637 | } else { |
638 | // lineMode false or binaryMode true |
639 | if (binaryMode) { |
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); |
644 | } |
645 | else { |
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); |
650 | } |
651 | // incoming_message(message); |
652 | } |
653 | } |
654 | |
655 | |
656 | /*************************** |
657 | * Send exitcode msg to TTCN |
658 | ***************************/ |
659 | void PIPEasp__PT::sendExitCode() { |
660 | if (disableSend) return; |
661 | |
662 | log("Sending ExitCode to TTCN"); |
663 | PIPEasp__Types::ASP__PExit message_PExit; |
664 | message_PExit.code() = processExitCode; |
665 | incoming_message(message_PExit); |
666 | } |
667 | |
668 | |
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); |
676 | } |
677 | |
678 | |
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 |
684 | |
685 | log("Sending result to TTCN..."); |
686 | PIPEasp__Types::ASP__PResult message_PResult; |
687 | PIPEasp__Types::ASP__PResultBinary message_PResultBinary; |
688 | if (binaryMode) { |
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); |
695 | } else { |
696 | int messageLen = stdout_buffer.get_read_len(); |
697 | const char* messageData = (const char*)stdout_buffer.get_read_data(); |
698 | |
699 | if (lineMode && messageData[messageLen-1]=='\n') { |
700 | messageLen--; // remove newline from the end |
701 | } |
702 | |
703 | message_PResult.stdout_() = CHARSTRING(messageLen, messageData); |
704 | |
705 | messageLen = stderr_buffer.get_read_len(); |
706 | messageData = (const char*)stderr_buffer.get_read_data(); |
707 | |
708 | if (lineMode && messageData[messageLen-1]=='\n') { |
709 | messageLen--; // remove newline from the end |
710 | } |
711 | |
712 | message_PResult.stderr_() = CHARSTRING(messageLen, messageData); |
713 | message_PResult.code() = processExitCode; |
714 | incoming_message(message_PResult); |
715 | } |
716 | |
717 | // clearing the buffers |
718 | stdout_buffer.clear(); |
719 | stderr_buffer.clear(); |
720 | //incoming_message(message); |
721 | } |
722 | |
723 | |
724 | //////////////// |
725 | // Log function |
726 | //////////////// |
727 | void PIPEasp__PT::log(const char *fmt, ...) |
728 | { |
729 | TTCN_Logger::begin_event(TTCN_DEBUG); |
730 | TTCN_Logger::log_event("PIPE test port (%s): ", get_name()); |
731 | va_list ap; |
732 | va_start(ap, fmt); |
733 | TTCN_Logger::log_event_va_list(fmt, ap); |
734 | va_end(ap); |
735 | TTCN_Logger::end_event(); |
736 | } |
737 | |
738 | }//namespace |