11 #define RAW_MAX_BACKLOG 4096
\r
13 typedef struct Raw Raw;
\r
16 bool closed_on_socket_error;
\r
20 bool sent_console_eof, sent_socket_eof, session_started;
\r
28 static void raw_size(Backend *be, int width, int height);
\r
30 static void c_write(Raw *raw, const void *buf, size_t len)
\r
32 size_t backlog = seat_stdout(raw->seat, buf, len);
\r
33 sk_set_frozen(raw->s, backlog > RAW_MAX_BACKLOG);
\r
36 static void raw_log(Plug *plug, PlugLogType type, SockAddr *addr, int port,
\r
37 const char *error_msg, int error_code)
\r
39 Raw *raw = container_of(plug, Raw, plug);
\r
40 backend_socket_log(raw->seat, raw->logctx, type, addr, port,
\r
41 error_msg, error_code, raw->conf, raw->session_started);
\r
44 static void raw_check_close(Raw *raw)
\r
47 * Called after we send EOF on either the socket or the console.
\r
48 * Its job is to wind up the session once we have sent EOF on both.
\r
50 if (raw->sent_console_eof && raw->sent_socket_eof) {
\r
54 seat_notify_remote_exit(raw->seat);
\r
59 static void raw_closing(Plug *plug, const char *error_msg, int error_code,
\r
62 Raw *raw = container_of(plug, Raw, plug);
\r
65 /* A socket error has occurred. */
\r
69 raw->closed_on_socket_error = true;
\r
70 seat_notify_remote_exit(raw->seat);
\r
72 logevent(raw->logctx, error_msg);
\r
73 seat_connection_fatal(raw->seat, "%s", error_msg);
\r
75 /* Otherwise, the remote side closed the connection normally. */
\r
76 if (!raw->sent_console_eof && seat_eof(raw->seat)) {
\r
78 * The front end wants us to close the outgoing side of the
\r
79 * connection as soon as we see EOF from the far end.
\r
81 if (!raw->sent_socket_eof) {
\r
83 sk_write_eof(raw->s);
\r
84 raw->sent_socket_eof= true;
\r
87 raw->sent_console_eof = true;
\r
88 raw_check_close(raw);
\r
92 static void raw_receive(Plug *plug, int urgent, const char *data, size_t len)
\r
94 Raw *raw = container_of(plug, Raw, plug);
\r
95 c_write(raw, data, len);
\r
96 /* We count 'session start', for proxy logging purposes, as being
\r
97 * when data is received from the network and printed. */
\r
98 raw->session_started = true;
\r
101 static void raw_sent(Plug *plug, size_t bufsize)
\r
103 Raw *raw = container_of(plug, Raw, plug);
\r
104 raw->bufsize = bufsize;
\r
107 static const PlugVtable Raw_plugvt = {
\r
109 .closing = raw_closing,
\r
110 .receive = raw_receive,
\r
115 * Called to set up the raw connection.
\r
117 * Returns an error message, or NULL on success.
\r
119 * Also places the canonical host name into `realhost'. It must be
\r
120 * freed by the caller.
\r
122 static char *raw_init(const BackendVtable *vt, Seat *seat,
\r
123 Backend **backend_handle, LogContext *logctx,
\r
124 Conf *conf, const char *host, int port,
\r
125 char **realhost, bool nodelay, bool keepalive)
\r
133 /* No local authentication phase in this protocol */
\r
134 seat_set_trust_status(seat, false);
\r
137 raw->plug.vt = &Raw_plugvt;
\r
138 raw->backend.vt = vt;
\r
140 raw->closed_on_socket_error = false;
\r
141 *backend_handle = &raw->backend;
\r
142 raw->sent_console_eof = raw->sent_socket_eof = false;
\r
144 raw->session_started = false;
\r
145 raw->conf = conf_copy(conf);
\r
148 raw->logctx = logctx;
\r
150 addressfamily = conf_get_int(conf, CONF_addressfamily);
\r
152 * Try to find host.
\r
154 addr = name_lookup(host, port, realhost, conf, addressfamily,
\r
155 raw->logctx, "main connection");
\r
156 if ((err = sk_addr_error(addr)) != NULL) {
\r
157 sk_addr_free(addr);
\r
158 return dupstr(err);
\r
162 port = 23; /* default telnet port */
\r
167 raw->s = new_connection(addr, *realhost, port, false, true, nodelay,
\r
168 keepalive, &raw->plug, conf);
\r
169 if ((err = sk_socket_error(raw->s)) != NULL)
\r
170 return dupstr(err);
\r
172 loghost = conf_get_str(conf, CONF_loghost);
\r
177 *realhost = dupstr(loghost);
\r
179 colon = host_strrchr(*realhost, ':');
\r
187 static void raw_free(Backend *be)
\r
189 Raw *raw = container_of(be, Raw, backend);
\r
193 conf_free(raw->conf);
\r
198 * Stub routine (we don't have any need to reconfigure this backend).
\r
200 static void raw_reconfig(Backend *be, Conf *conf)
\r
205 * Called to send data down the raw connection.
\r
207 static size_t raw_send(Backend *be, const char *buf, size_t len)
\r
209 Raw *raw = container_of(be, Raw, backend);
\r
211 if (raw->s == NULL)
\r
214 raw->bufsize = sk_write(raw->s, buf, len);
\r
216 return raw->bufsize;
\r
220 * Called to query the current socket sendability status.
\r
222 static size_t raw_sendbuffer(Backend *be)
\r
224 Raw *raw = container_of(be, Raw, backend);
\r
225 return raw->bufsize;
\r
229 * Called to set the size of the window
\r
231 static void raw_size(Backend *be, int width, int height)
\r
238 * Send raw special codes. We only handle outgoing EOF here.
\r
240 static void raw_special(Backend *be, SessionSpecialCode code, int arg)
\r
242 Raw *raw = container_of(be, Raw, backend);
\r
243 if (code == SS_EOF && raw->s) {
\r
244 sk_write_eof(raw->s);
\r
245 raw->sent_socket_eof= true;
\r
246 raw_check_close(raw);
\r
253 * Return a list of the special codes that make sense in this
\r
256 static const SessionSpecial *raw_get_specials(Backend *be)
\r
261 static bool raw_connected(Backend *be)
\r
263 Raw *raw = container_of(be, Raw, backend);
\r
264 return raw->s != NULL;
\r
267 static bool raw_sendok(Backend *be)
\r
272 static void raw_unthrottle(Backend *be, size_t backlog)
\r
274 Raw *raw = container_of(be, Raw, backend);
\r
275 sk_set_frozen(raw->s, backlog > RAW_MAX_BACKLOG);
\r
278 static bool raw_ldisc(Backend *be, int option)
\r
280 if (option == LD_EDIT || option == LD_ECHO)
\r
285 static void raw_provide_ldisc(Backend *be, Ldisc *ldisc)
\r
287 /* This is a stub. */
\r
290 static int raw_exitcode(Backend *be)
\r
292 Raw *raw = container_of(be, Raw, backend);
\r
293 if (raw->s != NULL)
\r
294 return -1; /* still connected */
\r
295 else if (raw->closed_on_socket_error)
\r
296 return INT_MAX; /* a socket error counts as an unclean exit */
\r
298 /* Exit codes are a meaningless concept in the Raw protocol */
\r
303 * cfg_info for Raw does nothing at all.
\r
305 static int raw_cfg_info(Backend *be)
\r
310 const BackendVtable raw_backend = {
\r
313 .reconfig = raw_reconfig,
\r
315 .sendbuffer = raw_sendbuffer,
\r
317 .special = raw_special,
\r
318 .get_specials = raw_get_specials,
\r
319 .connected = raw_connected,
\r
320 .exitcode = raw_exitcode,
\r
321 .sendok = raw_sendok,
\r
322 .ldisc_option_state = raw_ldisc,
\r
323 .provide_ldisc = raw_provide_ldisc,
\r
324 .unthrottle = raw_unthrottle,
\r
325 .cfg_info = raw_cfg_info,
\r
327 .displayname = "Raw",
\r
328 .protocol = PROT_RAW,
\r