Turn stream into function argument to use Telnet and Ncurses - c++

Hello fellow programmers.
I'm developing a C/C++ program with sockets that are supposed to connect to the server via Telnet.
To send text and ANSI codes to the Telnet remote terminal I'm using this funcion:
void writeline(int socketfd, string line)
{
string tosend = line + "\n";
write(socketfd, tosend.c_str(), tosend.length());
}
Is there a way to create a stream object like cout, cerr, clog or even a FILE (from C) that sends everything it gets to a function?
For example:
clientout << "Hello World";
would call something like this:
writeline(clientout.str()); //or alike
I did something like this last year when I programmed a microprocessor (with AVR) and redirected stdout into a function that sent everything to the USART connection. I was hoping I could do something like that now.
This is how I did it then:
static int usart_putchar(char c, FILE *stream)
{
while ( !(UCSR0A & (1<<UDRE0)) );
UDR0 = c;
return 0;
}
static FILE usart_stream = FDEV_SETUP_STREAM(usart_putchar, NULL, _FDEV_SETUP_WRITE);
int main()
{
//(...)
stdout = &usart_stream;
//(...)
}
I'm interested in this because, besides being an easier way to print into the remote terminal, I need a stream for even thinking about using ncurses with my program. To use it, I need this function which needs a stream for input and another for output.
I apologize for the long question.
Thank you in advance.

Yes, it's possible to do this, but it's quite a bit of work.
Basically, you have to implement a subclass of std::streambuf that implements std::streambuf's virtual methods to read and write from the socket directly, or call the wrapper functions you showed in your question. It's not really a lot of work, it's only a handful of virtual methods, but you have to understand their obscure semantics, and implement them correctly, 100%. No margin for error.
Once you have your std::streambuf subclass, you can then instantiate a std::istream, std::ostream, and/or std::iostream (which have a constructor that takes a pointer to a std::streambuf).
Now, you have your stream that reads and/or writes to the socket.

Could you use boost asio?
See example of using posix::stream_descriptor to implement a chat application http://www.boost.org/doc/libs/1_49_0/doc/html/boost_asio/example/chat/posix_chat_client.cpp

Related

How to send input to stdin from code not terminal?

I want to send input to a variable without having to type it in the terminal, as i am implementing a test case. for example consider the input to be sent is 2:
int a;
cin >> a;
The code should not wait for the user to give input, it should enter 2 there and populate a by itself.
i cant use the cin buffer, also taking input is compulsory.
you could create unnamed pipes pipe pd[2] and dup stdin & stdout to the pipe fds.
then write "2" into one pipe and read it from another.
You can get your input from a stringstream instead:
std::stringstream data = "2";
int a;
data >> a;
The basic question here (at least in my mind) is whether you're trying to write a single program, so that one part of the program provides the input to another part of the program, or you're writing two separate programs, one of which provides input to the other.
#Madhu Narayanan has already given a good summary of how you'd go about writing the code for the first case.
But, by far the preferable way to handle things inside a program is to have something like a function that takes (a reference to) an iostream as a parameter, so you can pass std::cin to read from the console, or some stringstream to have it read some predetermined data instead.
If what you care about is the second case, then you'd probably want to use popen (or Microsoft calls it _popen), which will spawn a child process, and connect a pipe to either its standard input or its standard output (but, regrettably, not both). So if this is what you want you'd do something like this:
// spawn the child, getting a handle to its standard input:
FILE *child = popen("child program", "w");
// write the input to the child:
if (child != nullptr) {
fprintf(child, "%d", 2);
}
For better or worse, there's no analog of this that gives you access to the child via an iostream (at least, not a pre-written one in the standard library, anyway).

Send Character TO CONIN$ (Windows Console)

If you want to spawn a Windows console in an otherwise SUBSYSTEM:WINDOWS application you can use this code:
if (AllocConsole())
{
FILE* file = nullptr;
_wfreopen_s(&file, L"CONIN$", L"r", stdin);
_wfreopen_s(&file, L"CONOUT$", L"w", stdout);
_wfreopen_s(&file, L"CONOUT$", L"w", stderr);
}
The _wfreopen_s function maps stdin to CONIN$ and provides a pointer to pointer in the file variable (which we are effectively discarding).
What I'd like to do is instead map an input from something other than stdin, for example, another file stream and then write that stream to CONIN$.
For a larger picture of what I'm trying to do here, I've got a secondary thread running std::getline(std::cin... which blocks. I'd like the thread context object to just send a \n to the console to break the blocking call.
If there are other ideas, I'm open. The alternative currently is that I print a message to the console that says "Shutting down, press ENTER to quit..." Which, I guess, also works ;)
What I tried was using the FILE* conin = new FILE(); and then did a memcpy to fill it with a \n and then I used WriteFile to that pointer, thinking that it might write the file stream out to CONIN$, and while the code compiles, and the contents of the FILE* appears to be correct (0x0a), it does not appear to send that stream to the console.
I tested this by having std::cout above and below the code testing the stream write. If it works, I'd expect the two lines to be on separate lines, but they always show up on the same, suggesting that I'm not sending the file stream.
Thanks for reading!
You should not discard the FILE* handle, otherwise you won't be able to manipulate it, in particular you won't be able to properly flush/close it if required.
If you're working with threads, simply give the FILE* to the thread that requires it. Threads share the same memory space.
If you're working with processes, then you should create a pipe between the two processes involved (see Win32 API for CreatePipe for details), and connect one's stdout to the other's stdin.

Capturing child stdout to a buffer

I'm developing a cross platform project currently. On windows i had a class that ran a process/script (using a commandline), waited for it to end, and read everything from it's stdout/stderr to a buffer. I then printed the output to a custom 'console'. Note: This was not a redirection of child stdout to parent stdout, just a pipe from child stdout to parent.
I'm new to OSX/unix-like api's but i can understand the canonical way of doing something like this is forking and piping stdouts together. However, i dont want to redirect it to stdout and i would like to capture the output.. It should work pretty much like this (pseudocode, resemblance with unix functions purely coincidental):
class program
{
string name, cmdline;
string output;
program(char * name, char * cmdline)
: name(name), cmdline(cmdline) {};
int run()
{
// run program - spawn it as a new process
int pid = exec(name, cmdline);
// wait for it to finish
wait(pid);
char buf[size];
int n;
// read output of program's stdout
// keep appending data until there's nothing left to read
while (read(pid, buf, size, &n))
output.append(buf, n);
// return exit code of process
return getexitcode(pid);
}
const string & getOutput() { return output; }
};
How would i go about doing this on OSX?
E:
Okay so i studied the relevant api's and it seems that some kind of fork/exec combo is unavoidable. Problem at hand is that my process is very large and forking it really seems like a bad idea (i see that some unix implementations can't do it if the parent process takes up 50%+ of the system ram).
Can't i avoid this scheme in any way? I see that vfork() might be a possible contender, so maybe i could try to mimic the popen() function using vfork. But then again, most man pages state that vfork might very well just be fork()
You have a library call to do just that: popen. It will provide you with a return value of a file descriptor, and you can read that descriptor till eof. It's part of stdio, so you can do that on OSX, but other systems as well. Just remember to pclose() the descriptor.
#include <stdio.h>
FILE * popen(const char *command, const char *mode);
int pclose(FILE *stream);
if you want to keep output with absolutely no redirection, the only thing we can think of is using something like "tee" - a command which splits the output to a file but maintains its own stdout. It's fairly easy to implement that in code as well, but it might not be necessary in this case.

Do a popen(), put the FILE* pointer in an fstream, what about the pclose()?

So... I start another process that accepts some input from my program (it could go the other way around too). Something of the sort:
FILE *f(popen("sendmail", "w"));
Now, I can put f in an fstream so that way I can just use the stream (since my program is in C++, it seems to be a sensible thing to do.)
std::ofstream output(fileno(f));
...
output << "To: santa.claus#example.com" << std::endl;
...
Up to here, I'm good. Now comes the point where I'm done sending data to the child process. All I want is to close the pipe. From what I know, we are expected to use pclose() because that function ensures that the other process receives all the data. In otherwise words, the pclose() function knows how to cleanly severe a pipe.
Unfortunately, since I put f in an ofstream, I cannot just close it, can I?
pclose(f); // proper way to close a pipe
...
ofstream::~ofstream() { ... close(fd); ... } // not the right way to close a pipe
Is there a way to capture the close from the ofstream and ensure it closes the way I want it to eb closed.
I would inherit a custom class from ofstream:
class PipeStream : public std::ofstream
and overwrite destructor
PipeStream::~PipeStream { pclose(f) };
so that pclose(f) is run before fclose(f)?

fflush on stderrr causes program to crash

I am redirecting stderr to a log file on Windows Phone Runtime:
int stdError = 0;
FILE* pLogFile = NULL;
// Redirect stderror to a logfile
if ( ! m_logFilePath.empty( ) )
{
// Get a duplicate file descriptor for stderror
// This returns -1 on failure
stdError = ::_dup( ::_fileno( stderr ) );
if ( stdError != -1 )
{
// Redirect stderror to a log file so we can capture
// ffmpeg error information
// Ignore the return value (nothing we can do if this fails)
::freopen_s( &pLogFile, m_logFilePath.c_str( ), "w", stderr );
}
}
The program intermittently crashes while calling fflush(stderr);. When I don't redirect stderr everything seems to be working fine.
It's windows so who knows?
Try std::cerr.flush(); because I can totally see windows doing their own thing again (like sockets not being like files, they like doing their own IO stuff).
Using what I just said above puts the task to their standard library, rather than assuming it's a file and such. Remember "abstraction", it makes sense flush is a method, it is a verb, and we don't care how (or in this case don't (want) to know) so let's just assume flush does what flush ought to do!
Leave a comment if this doesn't work and I shall have a think.
I don't use windows or windows phones (I am not one of the lucky 24 out there in the world :P) but I do know that there are I/O problems ("differences") on Windows, fortunately MinGW and co hide them from me :)
OR
Change your tactics, if I really wanted to side-step the problem (because it isn't your code) create a new class called my_error_stream or something, that extends std::ostream (that way you can use it like std::cerr which "is a" std::ostream).
Put a static method in that called get_error_stream() or something that returns one of two classes derived from my_error_stream, one forwards right to std::err, the other to a file.
It depends on how you like your code to look and feel, I said this way because it keeps the implementations separate, and under their own "branch" of the class hierarchy.
It doesn't really answer your question, but your code seems fine, and Windows sucks at pipes and sockets.