Commit | Line | Data |
---|---|---|
970ed795 | 1 | /////////////////////////////////////////////////////////////////////////////// |
3abe9331 | 2 | // Copyright (c) 2000-2015 Ericsson Telecom AB |
970ed795 EL |
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 | /******************************************************************************* | |
9 | * Contributors: | |
10 | * Zoltan Janos Szabo (Ericsson) - initial architecture design and implementation | |
11 | * Roland Gecse (Ericsson) - initial architecture design | |
12 | * Akos Cserveni (Ericsson) - Basic AST in compiler, semantic checking | |
13 | * Gabor Szalai (Ericsson) - RAW and TEXT codecs | |
14 | * Matyas Forstner (Ericsson) - ASN.1 extension of the compiler and BER/CER/DER codecs | |
15 | * Kristof Szabados (Ericsson) - Eclipse Designer, Executor, Titanium UIs | |
16 | * Szabolcs Beres (Ericsson) - Eclipse LogViewer | |
17 | * Ferenc Kovacs (Ericsson) - log interfaces, big number support, subtype checking | |
18 | * Csaba Raduly (Ericsson) - ASN.1 additions, XML encoder/decoder | |
19 | * Adam Delic (Ericsson) - template restrictions, try&catch, support of pre-processor directives in Eclipse | |
20 | * Krisztian Pandi (Ericsson) - import of imports | |
21 | * Peter Dimitrov (Ericsson)- maintenance | |
22 | * Balazs Andor Zalanyi (Ericsson) - code splitting | |
23 | * Gabor Szalai (Ericsson) - RAW encoding/decoding | |
24 | * Jeno Attila Balasko (Ericsson) - tests, maintenance | |
25 | * Csaba Feher (Ericsson) - epoll support | |
26 | * Tamas Buti (Ericsson)- maintenance | |
27 | * Matyas Ormandi (Ericsson) - maintenance | |
28 | * Botond Baranyi (Ericsson) - JSON encoder | |
29 | * Arpad Lovassy (Ericsson) - Java Executor API | |
30 | * Laszlo Baji (Ericsson) - maintenance | |
31 | * Marton Godar (Ericsson) - xsd2ttcn converter | |
32 | *******************************************************************************/ | |
33 | // | |
34 | // File: PIPEasp_PT.cc | |
35 | // Description: Source code of PIPE testport implementation | |
36 | // Rev: <RnXnn> | |
37 | // Prodnr: CNL 113 334 | |
38 | // Updated: 2008-06-03 | |
39 | // Contact: http://ttcn.ericsson.se | |
40 | // | |
41 | ||
42 | ||
43 | #include "PIPEasp_PT.hh" | |
44 | #include <signal.h> //kill | |
45 | #include <unistd.h> //pipe | |
46 | #include <errno.h> //errno | |
47 | #include <ctype.h> //isspace | |
48 | #include <sys/select.h> //FD_ZERO | |
49 | #include <stdio.h> // sys_errlist | |
50 | #include <sys/types.h> //wait | |
51 | #include <sys/wait.h> //wait | |
52 | ||
53 | #ifndef PIPE_BUF_SIZE | |
54 | #define PIPE_BUF_SIZE 655536 | |
55 | #endif | |
56 | ||
57 | namespace PIPEasp__PortType { | |
58 | ||
59 | PIPEasp__PT::PIPEasp__PT(const char *par_port_name) | |
60 | : PIPEasp__PT_BASE(par_port_name) | |
61 | , lineMode(true) | |
62 | , processExecuting(false) | |
63 | , binaryMode(false) | |
64 | , disableSend(false) | |
65 | , processPid(-1) // pid of the process currently executing | |
66 | , processStdin(-1) // fd of stdin of the process | |
67 | , processStdout(-1) // fd of stdout of the process | |
68 | , processStderr(-1) // fd of stderr of the process | |
69 | , processExitCode(0) // exit code of the process | |
70 | { | |
71 | FD_ZERO(&readfds); | |
72 | stdout_buffer.clear(); | |
73 | stderr_buffer.clear(); | |
74 | } | |
75 | ||
76 | PIPEasp__PT::~PIPEasp__PT() | |
77 | { | |
78 | // nothing to do | |
79 | } | |
80 | ||
81 | void PIPEasp__PT::set_parameter(const char *parameter_name, | |
82 | const char *parameter_value) | |
83 | { | |
84 | // no config parameters | |
85 | } | |
86 | ||
87 | void PIPEasp__PT::Event_Handler(const fd_set *read_fds, | |
88 | const fd_set *write_fds, const fd_set *error_fds, | |
89 | double time_since_last_call) | |
90 | { | |
91 | log("PIPEasp__PT::Event_Handler called"); | |
92 | if (processStdout != -1 && FD_ISSET(processStdout, read_fds)) { | |
93 | if (!processExecuting) { | |
94 | TTCN_warning("Unexpected message from stdout, no command is executing"); | |
95 | } else { | |
96 | log("Incoming stdout message received from process"); | |
97 | } | |
98 | ||
99 | long nBytes; | |
100 | int r; | |
101 | ||
102 | nBytes = PIPE_BUF_SIZE; | |
103 | unsigned char* buffer; | |
104 | size_t end_len = nBytes; | |
105 | stdout_buffer.get_end(buffer, end_len); | |
106 | r = read(processStdout,buffer,(int)nBytes); | |
107 | if (r <= 0) { | |
108 | log("ttcn_pipe_port: read problem on stdout.\n"); | |
109 | // close the pipe and remove it from event handler | |
110 | close(processStdout); | |
111 | FD_CLR(processStdout, &readfds); | |
112 | Install_Handler(&readfds, NULL, NULL, 0.0); | |
113 | processStdout = -1; | |
114 | ||
115 | // check if stderr is closed: | |
116 | if (processStderr == -1) { | |
117 | // child died | |
118 | log("Child might have died."); | |
119 | handle_childDeath(); | |
120 | } | |
121 | } | |
122 | else { | |
123 | log("incoming stdout %ld bytes\n", r); | |
124 | stdout_buffer.increase_length(r); | |
125 | sendStdout(); | |
126 | } | |
127 | return; | |
128 | } | |
129 | if (processStderr != -1 && FD_ISSET(processStderr, read_fds)) { | |
130 | if (!processExecuting) { | |
131 | TTCN_warning("Unexpected message from stderr, no command is executing"); | |
132 | } else { | |
133 | log("Incoming stderr message received from process"); | |
134 | } | |
135 | ||
136 | long nBytes; | |
137 | int r; | |
138 | ||
139 | nBytes = PIPE_BUF_SIZE; | |
140 | unsigned char* buffer; | |
141 | size_t end_len = nBytes; | |
142 | stderr_buffer.get_end(buffer, end_len); | |
143 | r = read(processStderr,buffer,(int)nBytes); | |
144 | if (r <= 0) { | |
145 | log("ttcn_pipe_port: read problem on stderr.\n"); | |
146 | // close the pipe and remove it from event handler | |
147 | close(processStderr); | |
148 | FD_CLR(processStderr, &readfds); | |
149 | Install_Handler(&readfds, NULL, NULL, 0.0); | |
150 | processStderr = -1; | |
151 | ||
152 | // check if stdout is closed: | |
153 | if (processStdout == -1) { | |
154 | // child died | |
155 | log("Child might have died."); | |
156 | handle_childDeath(); | |
157 | } | |
158 | } | |
159 | else { | |
160 | log("incoming stderr %ld bytes\n", r); | |
161 | stderr_buffer.increase_length(r); | |
162 | sendStderr(); | |
163 | } | |
164 | return; | |
165 | } | |
166 | } | |
167 | ||
168 | void PIPEasp__PT::user_map(const char *system_port) | |
169 | { | |
170 | // nothing to do | |
171 | } | |
172 | ||
173 | void PIPEasp__PT::user_unmap(const char *system_port) | |
174 | { | |
175 | // nothing to do | |
176 | } | |
177 | ||
178 | void PIPEasp__PT::user_start() | |
179 | { | |
180 | // nothing to do | |
181 | } | |
182 | ||
183 | void PIPEasp__PT::user_stop() | |
184 | { | |
185 | // nothing to do | |
186 | } | |
187 | ||
188 | /************************************* | |
189 | * Specific outgoing_send functions | |
190 | *************************************/ | |
191 | void PIPEasp__PT::outgoing_send(const PIPEasp__Types::ASP__PExecute& send_par) { | |
192 | log("PIPEasp__PT::outgoing_send_PExecute called"); | |
193 | // disable sendStdout, sendStderr until process exits | |
194 | if (processExecuting) { | |
195 | sendError("Pipe Test Port: Command already executing"); | |
196 | TTCN_Logger::begin_event(TTCN_DEBUG); | |
197 | TTCN_Logger::log_event("PIPE test port (%s): Command already executing. Following ASP is ignored: ", get_name()); | |
198 | send_par.log(); | |
199 | TTCN_Logger::end_event(); | |
200 | return; | |
201 | } | |
202 | PIPEasp__Types::ASP__PExecuteBackground message_PExecuteBackground; | |
203 | // starting command | |
204 | message_PExecuteBackground.command() = send_par.command(); | |
205 | outgoing_send(message_PExecuteBackground); | |
206 | // sending input | |
207 | PIPEasp__Types::ASP__PStdin message_PStdin; | |
208 | message_PStdin.stdin_() = send_par.stdin_(); | |
209 | outgoing_send(message_PStdin); | |
210 | disableSend = true; | |
211 | ||
212 | // closing stdin pipe: | |
213 | outgoing_send(PIPEasp__Types::ASP__PEndOfInput()); | |
214 | ||
215 | log("PIPEasp__PT::outgoing_send_PExecute exited"); | |
216 | } | |
217 | ||
218 | void PIPEasp__PT::outgoing_send(const PIPEasp__Types::ASP__PExecuteBinary& send_par) { | |
219 | log("PIPEasp__PT::outgoing_send_PExecuteBinary called"); | |
220 | // disable sendStdout, sendStderr until process exits | |
221 | if (processExecuting) { | |
222 | sendError("Pipe Test Port: Command already executing"); | |
223 | TTCN_Logger::begin_event(TTCN_DEBUG); | |
224 | TTCN_Logger::log_event("PIPE test port (%s): Command already executing. Following ASP is ignored: ", get_name()); | |
225 | send_par.log(); | |
226 | TTCN_Logger::end_event(); | |
227 | return; | |
228 | } | |
229 | PIPEasp__Types::ASP__PExecuteBackground message_PExecuteBackground; | |
230 | // starting command | |
231 | message_PExecuteBackground.command() = send_par.command(); | |
232 | outgoing_send(message_PExecuteBackground); | |
233 | // sending input | |
234 | PIPEasp__Types::ASP__PStdinBinary message_PStdinBinary; | |
235 | message_PStdinBinary.stdin_() = send_par.stdin_(); | |
236 | outgoing_send(message_PStdinBinary); | |
237 | disableSend = true; | |
238 | ||
239 | // closing stdin pipe: | |
240 | outgoing_send(PIPEasp__Types::ASP__PEndOfInput()); | |
241 | ||
242 | log("PIPEasp__PT::outgoing_send_PExecuteBinary exited"); | |
243 | } | |
244 | ||
245 | void PIPEasp__PT::outgoing_send(const PIPEasp__Types::ASP__PExecuteBackground& send_par) { | |
246 | log("PIPEasp__PT::outgoing_send_PExecuteBackground called"); | |
247 | ||
248 | if (processExecuting) { | |
249 | log("Process already executing. Cannot start new process."); | |
250 | sendError("Pipe Test Port: Command already executing"); | |
251 | TTCN_Logger::begin_event(TTCN_DEBUG); | |
252 | TTCN_Logger::log_event("PIPE test port (%s): Command already executing. Following ASP is ignored: ", get_name()); | |
253 | send_par.log(); | |
254 | TTCN_Logger::end_event(); | |
255 | log("PIPEasp__PT::outgoing_send_PExecuteBackground exited"); | |
256 | return; | |
257 | } | |
258 | ||
259 | // creating pipes for process | |
260 | int pipesStdin[2]; | |
261 | int pipesStdout[2]; | |
262 | int pipesStderr[2]; | |
263 | ||
264 | if (pipe(pipesStdin) != 0) { | |
265 | sendError("Pipe Test Port: Cannot create stdin pipe"); | |
266 | log("PIPEasp__PT::outgoing_send_PExecuteBackground exited"); | |
267 | return; | |
268 | } | |
269 | if (pipe(pipesStdout) != 0) { | |
270 | sendError("Pipe Test Port: Cannot create stdout pipe"); | |
271 | log("PIPEasp__PT::outgoing_send_PExecuteBackground exited"); | |
272 | return; | |
273 | } | |
274 | if (pipe(pipesStderr) != 0) { | |
275 | sendError("Pipe Test Port: Cannot create stderr pipe"); | |
276 | log("PIPEasp__PT::outgoing_send_PExecuteBackground exited"); | |
277 | return; | |
278 | } | |
279 | ||
280 | processStdin = pipesStdin[1]; | |
281 | processStdout = pipesStdout[0]; | |
282 | processStderr = pipesStderr[0]; | |
283 | ||
284 | processPid = fork(); | |
285 | if (processPid < 0) { | |
286 | // | |
287 | // Error | |
288 | // | |
289 | ||
290 | // close the pipes | |
291 | close(pipesStdin[0]); | |
292 | close(pipesStdout[1]); | |
293 | close(pipesStderr[1]); | |
294 | ||
295 | close(processStdin); | |
296 | close(processStdout); | |
297 | close(processStderr); | |
298 | ||
299 | sendError("Pipe Test Port: Cannot fork"); | |
300 | } | |
301 | else if (processPid == 0) { | |
302 | ||
303 | // | |
304 | // Child process | |
305 | // | |
306 | ||
307 | // close the parent end of the pipes | |
308 | close(processStdin); | |
309 | close(processStdout); | |
310 | close(processStderr); | |
311 | ||
312 | /*// set these to the other end of the pipe | |
313 | processStdin = pipesStdin[0]; | |
314 | processStdout = pipesStdout[1]; | |
315 | processStderr = pipesStderr[1];*/ | |
316 | ||
317 | int r; | |
318 | // redirect pipeStdin to stdin | |
319 | r = dup2(pipesStdin[0], 0); | |
320 | if (r<0) { | |
321 | TTCN_error("Cannot redirect stdin"); | |
322 | exit(errno); | |
323 | } | |
324 | ||
325 | // redirect pipeStdout to stdout | |
326 | r = dup2(pipesStdout[1], 1); | |
327 | if (r<0) { | |
328 | TTCN_error("Cannot redirect stdout"); | |
329 | exit(errno); | |
330 | } | |
331 | ||
332 | // redirect pipeStderr to stderr | |
333 | r = dup2(pipesStderr[1], 2); | |
334 | if (r<0) { | |
335 | TTCN_error("Cannot redirect stderr"); | |
336 | exit(errno); | |
337 | } | |
338 | ||
339 | processExitCode = execCommand((const char*)send_par.command()); | |
340 | ||
341 | // There is a problem executing the command | |
342 | // Exiting... | |
343 | ||
344 | fflush(stdout); | |
345 | fflush(stderr); | |
346 | ||
347 | //closing pipes: | |
348 | close(pipesStdin[0]); | |
349 | close(pipesStdout[1]); | |
350 | close(pipesStderr[1]); | |
351 | ||
352 | exit(processExitCode); // end of child process | |
353 | } | |
354 | else { | |
355 | ||
356 | // | |
357 | // Parent process | |
358 | // | |
359 | ||
360 | log("Process started with pid: %d", processPid); | |
361 | // close child end of the pipes | |
362 | close(pipesStdin[0]); | |
363 | close(pipesStdout[1]); | |
364 | close(pipesStderr[1]); | |
365 | ||
366 | ||
367 | processExecuting = true; | |
368 | ||
369 | // install handler for the process pipes: | |
370 | //FD_SET(processStdin, &readfds); | |
371 | FD_SET(processStdout, &readfds); | |
372 | FD_SET(processStderr, &readfds); | |
373 | ||
374 | Install_Handler(&readfds, NULL, NULL, 0.0); | |
375 | } | |
376 | ||
377 | log("PIPEasp__PT::outgoing_send_PExecuteBackground exited"); | |
378 | } | |
379 | ||
380 | void PIPEasp__PT::outgoing_send(const PIPEasp__Types::ASP__PStdin& send_par) { | |
381 | ||
382 | log("PIPEasp__PT::outgoing_send_PStdin called"); | |
383 | binaryMode = false; | |
384 | if (!processExecuting) { | |
385 | sendError("Pipe Test Port: No command executing"); | |
386 | return; | |
387 | } | |
388 | if (disableSend) { // process was started with PExecute(Binary) | |
389 | sendError("Pipe Test Port: PStdin is not sent: current process is not started with PExecuteBackground!"); | |
390 | return; | |
391 | } | |
392 | ||
393 | log("will now write to stdin: '%s'", | |
394 | (const char*)(send_par.stdin_()+((lineMode)?"\n":""))); | |
395 | write(processStdin, | |
396 | (const char*)(send_par.stdin_()+((lineMode)?"\n":"")), | |
397 | send_par.stdin_().lengthof()+((lineMode)?1:0)); | |
398 | ||
399 | log("PIPEasp__PT::outgoing_send_PStdin exited"); | |
400 | } | |
401 | ||
402 | void PIPEasp__PT::outgoing_send(const PIPEasp__Types::ASP__PStdinBinary& send_par) { | |
403 | log("PIPEasp__PT::outgoing_send_PStdinBinary called"); | |
404 | binaryMode = true; | |
405 | if (!processExecuting) { | |
406 | sendError("Pipe Test Port: No command executing"); | |
407 | return; | |
408 | } | |
409 | if (disableSend) { // process was started with PExecute(Binary) | |
410 | sendError("Pipe Test Port: PStdinBinary is not sent: current process is not started with PExecuteBackground!"); | |
411 | return; | |
412 | } | |
413 | ||
414 | TTCN_Logger::begin_event(TTCN_DEBUG); | |
415 | TTCN_Logger::log_event("PIPE test port (%s): will now write binary data to stdin: ", get_name()); | |
416 | send_par.stdin_().log(); | |
417 | TTCN_Logger::end_event(); | |
418 | ||
419 | write(processStdin, | |
420 | (const char*)(const unsigned char*)(send_par.stdin_()), | |
421 | send_par.stdin_().lengthof()); | |
422 | log("PIPEasp__PT::outgoing_send_PStdinBinary exited"); | |
423 | } | |
424 | ||
425 | void PIPEasp__PT::outgoing_send(const PIPEasp__Types::ASP__PKill& send_par) { | |
426 | log("PIPEasp__PT::outgoing_send_PKill called"); | |
427 | if (!processExecuting) { | |
428 | // no process is running | |
429 | log("No process executing."); | |
430 | sendError("Pipe Test Port: No command executing"); | |
431 | log("PIPEasp__PT::outgoing_send_PKill exited"); | |
432 | return; | |
433 | } | |
434 | ||
435 | int signo = (int)send_par.signal(); | |
436 | if (signo<1 || signo>31) { | |
437 | // signo out of range; | |
438 | log("Signo out of range."); | |
439 | sendError( | |
440 | "Pipe Test port: Signal number should be " | |
441 | "between 1 and 31"); | |
442 | log("PIPEasp__PT::outgoing_send_PKill exited"); | |
443 | return; | |
444 | } | |
445 | // killing process | |
446 | log("Killing process %d, signo: %d", processPid, signo); | |
447 | int r = kill(processPid, signo); | |
448 | log("Kill process returned %d", r); | |
449 | log("PIPEasp__PT::outgoing_send_PKill exited"); | |
450 | } | |
451 | ||
452 | void PIPEasp__PT::outgoing_send(const PIPEasp__Types::ASP__PLineMode& send_par) { | |
453 | log("PIPEasp__PT::outgoing_send_PLineMode called"); | |
454 | lineMode = (bool)send_par.lineMode(); | |
455 | log("LineMode is set to %s", (lineMode)?"TRUE":"FALSE"); | |
456 | log("PIPEasp__PT::outgoing_send_PLineMode exited"); | |
457 | } | |
458 | ||
459 | void PIPEasp__PT::outgoing_send(const PIPEasp__Types::ASP__PEndOfInput& send_par) { | |
460 | log("PIPEasp__PT::outgoing_send_PEndOfInput called"); | |
461 | // close stdin pipe | |
462 | close(processStdin); | |
463 | processStdin = -1; | |
464 | log("stdin closed"); | |
465 | log("PIPEasp__PT::outgoing_send_PEndOfInput exited"); | |
466 | } | |
467 | ||
468 | /******************************** | |
469 | * Execute the given command | |
470 | * returns the exitcode of the process | |
471 | *********************************/ | |
472 | int PIPEasp__PT::execCommand(const char* command) { | |
473 | log("PIPEasp__PT::execCommand called"); | |
474 | log("Executing command: %s", command); | |
475 | ||
476 | // with this it is not possible to access the pid of the process | |
477 | //return system(command); | |
478 | ||
479 | int argc = 0; | |
480 | char* argv[1024]; | |
481 | ||
482 | CHARSTRING temp = ""; | |
483 | for (int i = 0; command[i] != 0; i++) { | |
484 | if (isspace(command[i])) { | |
485 | argv[argc++] = strdup(temp); | |
486 | log("command argument added: %s", (const char*)temp); | |
487 | while (command[i] != '0' && isspace(command[i])) i++; | |
488 | i--; | |
489 | temp = ""; | |
490 | } else { | |
491 | temp = temp + CHARSTRING(1, command+i); | |
492 | } | |
493 | } | |
494 | ||
495 | if (temp != "") { | |
496 | argv[argc++] = strdup(temp); | |
497 | log("command argument added: %s", (const char*)temp); | |
498 | } | |
499 | ||
500 | argv[argc++] = (char*)NULL; | |
501 | ||
502 | log("execCommand(%s,%d)\n", argv[0], argc); | |
503 | execvp(argv[0],argv); | |
504 | ||
505 | fprintf(stderr,"Error executing command %s (%d): %s\n", | |
506 | argv[0], errno, strerror(errno)); | |
507 | fflush(stderr); | |
508 | // exit(errno); | |
509 | return errno; | |
510 | } | |
511 | ||
512 | /*********************************** | |
513 | * if the the child process died, gets | |
514 | * the exit code and sends it to TTCN | |
515 | * should be called when stdout/err are closed | |
516 | ************************************/ | |
517 | void PIPEasp__PT::handle_childDeath() { | |
518 | log("Getting process status for pid %d...", processPid); | |
519 | processExitCode = 0; // reset the exitcode | |
520 | int pid = wait(&processExitCode); | |
521 | //waitpid(processPid,&processExitCode, 0); | |
522 | if (pid!=processPid) { | |
523 | log("other child died with pid: %d, exit code: %d", pid, processExitCode); | |
524 | return; | |
525 | } | |
526 | ||
527 | log("Child process exit status is: %d", processExitCode); | |
528 | // send code to TTCN: | |
529 | sendExitCode(); | |
530 | // send result to TTCN | |
531 | sendResult(); | |
532 | ||
533 | // removing fd-s installed for the process: | |
534 | Uninstall_Handler(); // no handler is needed | |
535 | FD_ZERO(&readfds); | |
536 | /* | |
537 | // equivalent with: | |
538 | //FD_CLR(processStdin, &readfds); | |
539 | FD_CLR(processStdout, &readfds); | |
540 | FD_CLR(processStderr, &readfds); | |
541 | Install_Handler(&readfds, NULL, NULL, 0.0); | |
542 | */ | |
543 | ||
544 | // closing pipes: | |
545 | close(processStdin); | |
546 | //close(processStdout); // already closed | |
547 | //close(processStderr); // already closed | |
548 | ||
549 | processStdin = -1; | |
550 | //processStdout = -1; | |
551 | //processStderr = -1; | |
552 | ||
553 | processExecuting = false; | |
554 | disableSend = false; | |
555 | } | |
556 | ||
557 | /*************************** | |
558 | * Send stdout msg to TTCN | |
559 | ***************************/ | |
560 | void PIPEasp__PT::sendStdout() { | |
561 | if (disableSend) return; | |
562 | ||
563 | PIPEasp__Types::ASP__PStdout message_PStdout; | |
564 | PIPEasp__Types::ASP__PStdoutBinary message_PStdoutBinary; | |
565 | if (lineMode && !binaryMode) { | |
566 | // send complete lines from buffer | |
567 | const unsigned char* pos = stdout_buffer.get_read_data(); | |
568 | for(unsigned int i=0; i<stdout_buffer.get_read_len(); i++) { | |
569 | // not end of line: | |
570 | if (pos[i] != '\n') { | |
571 | continue; | |
572 | } | |
573 | ||
574 | // at end of line | |
575 | // length of data is i (+1 is for \n and is not sent) | |
576 | message_PStdout.stdout_() = CHARSTRING(i, (const char*)pos); | |
577 | ||
578 | // send message | |
579 | incoming_message(message_PStdout); | |
580 | ||
581 | // remove the complete line from buffer, | |
582 | // also set i and pos to the beginning of buffer | |
583 | stdout_buffer.set_pos(i+1); | |
584 | stdout_buffer.cut(); | |
585 | i = 0; | |
586 | pos = stdout_buffer.get_read_data(); | |
587 | } | |
588 | } else { | |
589 | // lineMode false or binaryMode true | |
590 | if (binaryMode) { | |
591 | message_PStdoutBinary.stdout_() = | |
592 | OCTETSTRING(stdout_buffer.get_read_len(), stdout_buffer.get_read_data()); | |
593 | stdout_buffer.clear(); | |
594 | incoming_message(message_PStdoutBinary); | |
595 | } | |
596 | else { | |
597 | message_PStdout.stdout_() = | |
598 | CHARSTRING(stdout_buffer.get_read_len(), (const char*)stdout_buffer.get_read_data()); | |
599 | stdout_buffer.clear(); | |
600 | incoming_message(message_PStdout); | |
601 | } | |
602 | // incoming_message(message); | |
603 | } | |
604 | } | |
605 | ||
606 | ||
607 | /*************************** | |
608 | * Send stderr msg to TTCN | |
609 | ***************************/ | |
610 | void PIPEasp__PT::sendStderr() { | |
611 | if (disableSend) return; | |
612 | ||
613 | PIPEasp__Types::ASP__PStderr message_PStderr; | |
614 | PIPEasp__Types::ASP__PStderrBinary message_PStderrBinary; | |
615 | if (lineMode && !binaryMode) { | |
616 | // send complete lines from buffer | |
617 | const unsigned char* pos = stderr_buffer.get_read_data(); | |
618 | for(unsigned int i=0; i<stderr_buffer.get_read_len(); i++) { | |
619 | // not end of line: | |
620 | if (pos[i] != '\n') { | |
621 | continue; | |
622 | } | |
623 | ||
624 | // at end of line | |
625 | // length of data is i (+1 is for \n and is not sent) | |
626 | message_PStderr.stderr_() = CHARSTRING(i, (const char*)pos); | |
627 | ||
628 | // send message | |
629 | incoming_message(message_PStderr); | |
630 | ||
631 | // remove the complete line from buffer, | |
632 | // also set i and pos to the beginning of buffer | |
633 | stderr_buffer.set_pos(i+1); | |
634 | stderr_buffer.cut(); | |
635 | i = 0; | |
636 | pos = stderr_buffer.get_read_data(); | |
637 | } | |
638 | } else { | |
639 | // lineMode false or binaryMode true | |
640 | if (binaryMode) { | |
641 | message_PStderrBinary.stderr_() = | |
642 | OCTETSTRING(stderr_buffer.get_read_len(), stderr_buffer.get_read_data()); | |
643 | stderr_buffer.clear(); | |
644 | incoming_message(message_PStderrBinary); | |
645 | } | |
646 | else { | |
647 | message_PStderr.stderr_() = | |
648 | CHARSTRING(stderr_buffer.get_read_len(), (const char*)stderr_buffer.get_read_data()); | |
649 | stderr_buffer.clear(); | |
650 | incoming_message(message_PStderr); | |
651 | } | |
652 | // incoming_message(message); | |
653 | } | |
654 | } | |
655 | ||
656 | ||
657 | /*************************** | |
658 | * Send exitcode msg to TTCN | |
659 | ***************************/ | |
660 | void PIPEasp__PT::sendExitCode() { | |
661 | if (disableSend) return; | |
662 | ||
663 | log("Sending ExitCode to TTCN"); | |
664 | PIPEasp__Types::ASP__PExit message_PExit; | |
665 | message_PExit.code() = processExitCode; | |
666 | incoming_message(message_PExit); | |
667 | } | |
668 | ||
669 | ||
670 | /*************************** | |
671 | * Send error msg to TTCN | |
672 | ***************************/ | |
673 | void PIPEasp__PT::sendError(const char* error_msg) { | |
674 | PIPEasp__Types::ASP__PError message_PError; | |
675 | message_PError.errorMessage() = error_msg; | |
676 | incoming_message(message_PError); | |
677 | } | |
678 | ||
679 | ||
680 | /*************************** | |
681 | * Send Result msg to TTCN | |
682 | ***************************/ | |
683 | void PIPEasp__PT::sendResult() { | |
684 | if (!disableSend) return; // do not send result if process was started by PExecuteBackground | |
685 | ||
686 | log("Sending result to TTCN..."); | |
687 | PIPEasp__Types::ASP__PResult message_PResult; | |
688 | PIPEasp__Types::ASP__PResultBinary message_PResultBinary; | |
689 | if (binaryMode) { | |
690 | message_PResultBinary.stdout_() = | |
691 | OCTETSTRING(stdout_buffer.get_read_len(), stdout_buffer.get_read_data()); | |
692 | message_PResultBinary.stderr_() = | |
693 | OCTETSTRING(stderr_buffer.get_read_len(), stderr_buffer.get_read_data()); | |
694 | message_PResultBinary.code() = processExitCode; | |
695 | incoming_message(message_PResultBinary); | |
696 | } else { | |
697 | int messageLen = stdout_buffer.get_read_len(); | |
698 | const char* messageData = (const char*)stdout_buffer.get_read_data(); | |
699 | ||
700 | if (lineMode && messageData[messageLen-1]=='\n') { | |
701 | messageLen--; // remove newline from the end | |
702 | } | |
703 | ||
704 | message_PResult.stdout_() = CHARSTRING(messageLen, messageData); | |
705 | ||
706 | messageLen = stderr_buffer.get_read_len(); | |
707 | messageData = (const char*)stderr_buffer.get_read_data(); | |
708 | ||
709 | if (lineMode && messageData[messageLen-1]=='\n') { | |
710 | messageLen--; // remove newline from the end | |
711 | } | |
712 | ||
713 | message_PResult.stderr_() = CHARSTRING(messageLen, messageData); | |
714 | message_PResult.code() = processExitCode; | |
715 | incoming_message(message_PResult); | |
716 | } | |
717 | ||
718 | // clearing the buffers | |
719 | stdout_buffer.clear(); | |
720 | stderr_buffer.clear(); | |
721 | //incoming_message(message); | |
722 | } | |
723 | ||
724 | ||
725 | //////////////// | |
726 | // Log function | |
727 | //////////////// | |
728 | void PIPEasp__PT::log(const char *fmt, ...) | |
729 | { | |
730 | TTCN_Logger::begin_event(TTCN_DEBUG); | |
731 | TTCN_Logger::log_event("PIPE test port (%s): ", get_name()); | |
732 | va_list ap; | |
733 | va_start(ap, fmt); | |
734 | TTCN_Logger::log_event_va_list(fmt, ap); | |
735 | va_end(ap); | |
736 | TTCN_Logger::end_event(); | |
737 | } | |
738 | ||
739 | }//namespace |