Hi,

I am trying to write some code in order to communicate with a telnet clent from a c++ application. My idea was to open a telnet session with popen and to use the input/output pipes to communicate but it does not seem to work. When I test, the program says that the pipes are not usable:

"
ioctl: is a good pipe ? =-1
isastream: is a good pipe ? =0
"

I know that the network communication can be done using sockets but before doing this, I would like to be sure that it is not possible to use telnet with popen. I did not find something clear on the web yet.

Here is an example of the code I would like to use:

#include <stropts.h>
#include <stdio.h>
#include <unistd.h>

int main ( int argc, char** argv)
{
	printf("Open a network client\n");

	FILE* pipe = popen("telnet\n", "r");

	sleep(1);

	printf("File number %d\n", fileno(pipe));
	
	printf("ioctl: is a good pipe ? =%d\n", ioctl(fileno(pipe), I_CANPUT,0));
	printf("isastream: is a good pipe ? =%d\n", isastream(fileno(pipe)));
  
  return 0;
}

And the associated makefile:

all:
	g++ main.cpp -o test

clean:
	rm test

popen is a SIMPLE wrapper for uni-directional communication only (either reading or writing). Some enhanced versions of popen() allow bi-directional flow (which is what you would want for an interactive program like telnet).

If you want real control over what is going on, then you'll need to read up on these API calls
pipe()
dup() or dup2()
fork()
exec()
close()

Thanks a lot for your reply Salem,

I took a look on those commands and, if I well understood, it seems that nothing is really convenient for my project.

- exec functions will block till the executed program returns which is a problem for an application such as telnet.
- fork will do a copy of my program which is a problem because it will be quite big at the end. I also do not know what will happen if I fork the GUI. Actually, I do not understand the benefit of this command concerning my problem.
- the other commands are used to define (or to end) the communication flow but do not permit to run an external process.

Am I completely wrong?

Yes, you are completely wrong.

fork() creates a copy of your program, but it's another process in a "parent-child" relationship. Use the return result to figure out which is which.

pid = fork();
if ( /*RTFM*/ ) {
  // in child, call exec() to run telnet
} else {
  // in parent, read/write to the ends of pipes to communicate
  // with telnet (the child process you just exec'ed above).
}

The rest of the calls are for creating the pipes and mapping stdin,stdout to the ends of those pipes.

Hi Salem,

Thanks again to take time on this problem. I change my code to use "fork" and "pipe" instead of "popen":

#include <stropts.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main ( int argc, char** argv)
{
	int fd[2];

	int pid, nbytes;
  char    string[] = "open localhost\n";
  char    readbuffer[80];
 
  pipe(fd);

	if ((pid = fork()) < 0) {
		printf("Error doing fork\n");
	}
	else if (pid == 0){
		// Child process closes up output side of pipe 
    close(fd[1]);

		printf("telnet execution\n");
		char* cmd[] = { "", (char *)0 };
		execvp("telnet",cmd);

		

    // Read in a string from the pipe 
    nbytes = read(fd[0], readbuffer, sizeof(readbuffer));
    printf("Received string: %s\n", readbuffer);

		printf("close Child\n");

		return 0;
	}
	else {
		printf("Mother\n");

		// Parent process closes up input side of pipe 
    close(fd[0]);

    // Send "string" through the output side of pipe 
    write(fd[1], string, (strlen(string)+1));

		sleep(4);

	}
  printf("close Mother\n");
  return 0;
}

As I was expecting, the forked process is blocked into the "execvp" call. It does not seem to read what is coming from Mother process via the pipe.

If I write "execvp("telnet &",cmd);", the forked process is not blocked, it can read what is coming from the pipe but this string is not going into telnet.

Nothing change if I put the line " close(fd[1]);" before the "execvp" call.

Am I deeper completely wrong?

Everything after the exec() does NOT get executed (unless there is an error). Your process gets replaced by the telnet process.

Any (and all) the communication with the child (telnet) process needs to be placed after
printf("Mother\n");

I would suggest you try a much simpler process to play with rather than telnet. A simple "echo" program perhaps, which reads stdin, and writes it back out to stdout.

Thanks Salem for your help. I finally achieved a piece of code that seems to work (maybe a bit dirty):

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <fcntl.h>

using namespace std;


int main ( int argc, char** argv)
{
	int comMother2Child[2];
	int comChild2Mother[2];

	int pid = -1;

	char command[32];
  char readbuffer[8];
 
  pipe(comMother2Child);
	pipe(comChild2Mother);


	if ((pid = fork()) < 0) {
		printf("Error doing fork\n");
	}
	else if (pid == 0){

		printf("Child\n");

		dup2(comMother2Child[0], 0);
		dup2(comChild2Mother[1], 1);

		char* cmd[] = { "telnet", (char *)0 };
		execvp("telnet",cmd);

		printf("close child\n");
		return 0;
	}
	else {
		printf("Mother\n");
		close(comChild2Mother[1]);
		close(comMother2Child[0]);
		
		fcntl (comChild2Mother[0], F_SETFL, O_NONBLOCK);

		while(1) {
			//writting command
			cin.getline(command, 20);		  

		  write(comMother2Child[1], command, (strlen(command)));
			write(comMother2Child[1], "\n", 2);

			//give time to the child process to achieve the commanded task
			sleep(1);

			//reading the respons
			while (read(comChild2Mother[0], readbuffer, strlen(readbuffer))!=-1) {
				printf("%s",readbuffer);				
			}
		}

	}
  printf("close Mother\n");
  return 0;
}
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.