Siksha Sarovar

Siksha Sarovar (sikshasarovar.com) is a free educational web application that helps students in India learn programming and prepare for academic and competitive exams. The platform offers structured coding courses (C, C++, Python, Java, HTML, CSS, PHP, Power BI, AI, Machine Learning, Data Science), complete university curriculum notes for BCA/MCA students with previous year question papers, Class 10 and Class 12 CBSE/HBSE school notes, and dedicated preparation material for SSC, UPSC, Banking, Railway and other government exams. Browsing the site is completely free and requires no account. Users may optionally sign in with Google solely to save their learning progress, quiz scores and personal preferences across devices.

Privacy Policy | Terms of Service | Contact Siksha Sarovar | About Siksha Sarovar

v4.0.9 · PWA
Siksha Sarovar logo
Siksha Sarovar
Your Learning Universe

Siksha Sarovar is a free e-learning platform for coding courses, BCA university notes and competitive exam preparation. Optional Google sign-in saves your learning progress across devices.

Initializing knowledge base…
Compiling modules 0%

Unit 4: Remote Login — Terminals, Pseudo-Terminals & RPC Transparency

Lesson 15 of 15 in the free Network Programming notes on Siksha Sarovar, written by Rohit Jangra.

7.1 Terminal line disciplines and modes

Between a terminal device and the processes reading it sits the kernel's terminal line discipline — the layer that turns raw keystrokes into a usable input stream:

  • echoes characters back to the screen;
  • buffers a line and handles editing (erase ^H, kill ^U);
  • translates signals: ^C → SIGINT, ^Z → SIGTSTP, ^\ → SIGQUIT;
  • maps newlines (NL ↔ CR-NL), controls flow (^S/^Q).

Terminal modes (set via tcgetattr/tcsetattr on struct termios):

ModeBehaviourUsed by
Canonical (cooked)line-at-a-time, editing & signals in kernelshells, line tools
Rawbyte-at-a-time, no echo, no special charseditors (vi), ssh/telnet clients
Cbreakbyte-at-a-time but signals still workmore, games

A remote-login client must go raw: every keystroke (even ^C!) belongs to the remote side, so nothing may be interpreted locally.

Control terminals & job control: every session has at most one controlling terminal; the foreground process group receives its signals; background groups that touch the terminal get SIGTTIN/SIGTTOU. (The daemon lesson's double-fork was exactly about escaping this machinery.)

7.2 Pseudo-terminals — the trick that makes remote login possible

The remote shell expects a terminal; the network delivers a socket. The adapter is the pseudo-terminal (pty): a kernel device pair

  • slave side: looks exactly like a terminal (line discipline and all) — the shell sits here, fooled completely;
  • master side: whatever is written/read here appears as keyboard-input/screen-output on the slave — the server daemon sits here, splicing to the socket.

Server setup: open master (posix_openpt/grantpt/unlockpt/ptsname) → fork → child: setsid, open slave as controlling terminal, dup2 onto 0/1/2, exec login shell → parent: select-loop copying socket ↔ master. Ptys power far more than remote login: ssh, xterm and every GUI terminal, script, expect, tmux/screen — any program that must drive another program "as if from a keyboard".

7.3 rlogin overview

The BSD r-command for remote login (port 513, server rlogind) — simpler than telnet because both ends are Unix:

  • Startup negotiation: client sends null-terminated strings — local username, remote username, terminal type/speed ("xterm/38400"); server (historically) trusted .rhosts for password-less entry.
  • Data flow: keystrokes → server → pty master → shell; output back the same path. Client raw; the slave's line discipline does the real terminal work — the architecture above, verbatim.
  • In-band control from server: byte 0x02 + command in the TCP urgent data: flush output, toggle raw, request window size. Urgent mode lets these bypass a full pipe (output flooding) — the textbook's showcase for OOB data.
  • Out-of-band-ish control from client: window-size changes (the client catches SIGWINCH) sent as a magic in-band sequence; the server pushes it to the pty with ioctl(TIOCSWINSZ) so vi re-draws at the new size.
  • Flow control (^S/^Q) handled client-side for responsiveness (when the server permits).

Security postscript: rlogin/telnet send everything in cleartext, and .rhosts trust is address-based — both are museum pieces replaced by ssh, which keeps exactly this pty architecture and adds crypto. Exams ask rlogin because the architecture, not the protocol, is the lesson.

7.4 RPC transparency issues

RPC (remote procedure call) dresses a network exchange as a local function call. The classic question: can the disguise be perfect? No — the famous transparency issues:

IssueLocal callRemote call
Parameter passingby-reference possible (shared memory)only by-value/copy — pointers, graphs, shared structures don't travel
Data representationone machine's formatsbyte order, sizes, alignment, float formats differ → need XDR-style neutral encoding
Failure modescall either completes or process diescall may fail partway: request lost? server crashed before or after executing? reply lost?
Execution semanticsexactly once, alwaysat-least-once (retry — only safe if idempotent), at-most-once (dedup cache), exactly-once is unattainable over failures
Performancenanoseconds10³–10⁶× slower, variable, can hang
Authentication/identitysame UIDcaller may be anyone, anywhere

The crash-timing taxonomy (request lost / server dies before executing / server dies after executing / reply lost) and the resulting at-least-once vs at-most-once choice is the expected exam answer. These issues — first catalogued for Sun RPC — apply unchanged to gRPC, REST retries and every microservice you will ever build: the network can be hidden from the syntax, never from the semantics. A fitting last sentence for the course.

7.5 Going raw, in code — the termios fragment

"Set a terminal to raw mode" is a standard short program; the shape matters more than every flag:

struct termios raw, saved;
tcgetattr(STDIN_FILENO, &saved);          /* 1: fetch & KEEP the old state  */
raw = saved;
raw.c_lflag &= ~(ECHO | ICANON | ISIG);   /* 2: no echo, no line-editing,
                                                no ^C→SIGINT translation    */
raw.c_iflag &= ~(IXON | ICRNL);           /* 3: no ^S/^Q, no CR→NL mapping  */
raw.c_oflag &= ~OPOST;                    /* 4: no output processing        */
raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0;  /* 5: read returns per byte       */
tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw);
/* ... the client's copy loop runs here ... */
tcsetattr(STDIN_FILENO, TCSAFLUSH, &saved); /* 6: ALWAYS restore on exit    */

The two viva-bait lines: clearing ISIG is what lets ^C travel to the remote host as an ordinary byte (the whole point of §7.1's "raw client" rule); and step 6 — restore on every exit path, including signals — is why a crashed ssh leaves your terminal garbled until you type reset: someone skipped it.

7.6 The rlogin data path, end to end — one keystroke's journey

Worked trace for "explain rlogin's operation": the user types v (running vi remotely):

  1. client terminal is raw → the byte reaches the client unprocessed, no local echo;
  2. client write()s it to the TCP connection (TCP_NODELAY territory — single-byte segments are the canonical Nagle case study);
  3. rlogind read()s it from the socket and write()s it to the pty master;
  4. the byte "appears typed" on the pty slave; the slave's line discipline is in whatever mode vi requested (raw too, as it happens) and hands it to vi;
  5. vi redraws; its output written to the slave appears as readable data on the master; rlogind copies master → socket;
  6. the client read()s the screen update and write()s it to the real terminal.

Count the echo's round trip: the character you see was echoed by the remote application, a full RTT later — why typing over a slow link feels the way it does. Every hop in this trace names a piece of machinery from §7.1–§7.3; reproducing it is the synthesis answer for this lesson.

7.7 rlogin vs telnet vs ssh — the protocol family table

Criterionrlogintelnetssh
scopeUnix↔Unix onlyany↔any (NVT abstraction)any↔any
option negotiationnone — fixed assumptionselaborate (WILL/WONT/DO/DONT)key/cipher negotiation
encryptionnone — cleartextnone — cleartexteverything encrypted
authentication.rhosts address trust / passwordpassword (cleartext!)keys, passwords (encrypted), agent
server-side pty architectureyesyesidentical — the lesson's diagram unchanged
port5132322
statusmuseummuseum (still a debugging tool)the living descendant

The table's moral, worth stating: the security layer was replaced wholesale; the terminal architecture — raw client, server splicing socket↔pty-master, line discipline at the slave — survived intact from rlogin to ssh. Architecture outlives protocols.

7.8 Structuring the RPC answer — semantics under each failure

The §7.4 taxonomy becomes a full-marks answer when arranged as a matrix — failure × retry policy:

Failure momentClient retries (at-least-once)Client gives up (at-most-once flavour)
request lost in networkexecutes once — correctexecutes zero times
server crashed before executingexecutes once — correctzero times
server crashed after executingexecutes twiceonce
reply lostexecutes twiceonce (but client doesn't know!)

The two ⚠ cells are the whole argument: the client cannot distinguish "request never arrived" from "reply never returned", so blind retry risks re-execution — harmless for idempotent operations (read block N of a file), catastrophic for non-idempotent ones (append; debit ₹500). At-most-once implementations therefore carry request IDs + a server-side duplicate-reply cache; exactly-once under crashes would additionally require the server to make "execute + record" atomic across reboots — which is why it's described as unattainable in general. Define idempotent, give one example of each kind, and place them in this matrix: that is the complete expected answer.

Exam pointers

  • "What does the terminal line discipline do? Distinguish canonical, raw and cbreak modes" — the §7.1 list + table; add which flag bits (ICANON, ECHO, ISIG) §7.5 clears for each property.
  • "What is a pseudo-terminal? How does it enable remote login?" — the master/slave pair, who sits where (diagram), then the server-setup call sequence; name three non-login users of ptys (xterm, script, tmux/expect).
  • "Explain RPC transparency issues" — the §7.4 table for breadth, the §7.8 matrix for the semantics question; always define idempotence — it's the hinge of the marking scheme.
  • "How does the rlogin server flush output urgently?" — the 0x02-command-in-urgent-data mechanism, and why OOB: the command must overtake a pipe full of normal output.

Check yourself

  1. In the keystroke trace of §7.6, which component performs echo when running a canonical-mode shell remotely — and what would double-echo indicate?
  2. Why must the client be raw while the slave may be in any mode? Who decides the slave's mode?
  3. A program wants to drive an interactive password prompt of another program. Why does a pipe fail where a pty succeeds? (What does the driven program check on its stdin?)
  4. Classify: NFS read-block, DNS query, bank transfer, "append line to log". Which retry policy suits each, and why?
  5. ssh keeps rlogin's architecture but added one byte-stream complication: everything is encrypted, including window-size messages. Where in the §7.6 path must encryption/decryption sit?