In the case of a telnet session, here is where the kernel (Hijack) sets this up in ktelnetd:
Code:

        // set up stdin,stdout,stderr to all point at the socket
        sockfd = get_fd(parms->clientsock->inode);  /* 0: stdin */
        dup(sockfd);   /* 1: stdout */
        dup(sockfd);   /* 2: stderr */


So in this case, stdout/stderr (and stdin for reading) point at the "socket", which is a handle for the remote connection (the telnet client running on a PC).

The important bit is that the program itself doesn't need to know this. It just reads stuff from stdin, and writes stuff to stdout (and/or stderr). And it all works. Whether running locally on a serial port, in a window on a desktop GUI, or at the end of some remote network connection (ssh, telnet.. ).

EDIT: So, while we're on this topic: Anything that has been "opened" on a Linux system has a file descriptor associated with it. A file descriptor is what you get back from calling open(). Or socket().

These begin with 0 for the first thing opened, and each new thing gets the lowest number that is not currently in use. So stdin=0, stdout=1, stderr=2 .. is the most commonly seen order, though it is not guaranteed to look like that.

The numbers are simply indexes into a kernel table describing each open "object" and the state of reading/writing on that object. Aka. the File Descriptor table. There is a unique file descriptor table for each process.

In the /proc/ directory on Linux (including the empeg), there is a subdirectory for each process, as well as one called "self" for the current running program. If you telnet to the empeg, and do cd /proc/self, you will see a lower level subdirectory called fd. This is a view of the process's file descriptor table. Look into it like this: ls -lF /proc/self/fd/
Code:
ls -lF /proc/self/fd/

total 0
lrwx------    1 0        0              64 Aug  3 12:07 0 -> socket:[8]
lrwx------    1 0        0              64 Aug  3 12:07 1 -> socket:[8]
lrwx------    1 0        0              64 Aug  3 12:07 2 -> socket:[8]
lrwx------    1 0        0              64 Aug  3 12:07 255 -> socket:[8]

Doing the same thing when logged in via the serial port gives this instead:
Code:
ls -lF /proc/self/fd/

total 0
lrwx------    1 0        0              64 Aug  3 12:12 0 -> /dev/ttyS1
lrwx------    1 0        0              64 Aug  3 12:12 1 -> /dev/ttyS1
lrwx------    1 0        0              64 Aug  3 12:12 2 -> /dev/ttyS1
lr-x------    1 0        0              64 Aug  3 12:12 3 -> /proc/35/fd/


Note that the fourth entry in the second case is the file descriptor for reading from /proc/self/fd/ at that point in time, when "self" was process id (PID) number 35.

Some fun, huh!


Edited by mlord (04/11/2017 18:06)