]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - raw.c
Ronald Landheer-Cieslak points out that the various back ends which
[PuTTY.git] / raw.c
1 /*
2  * "Raw" backend.
3  */
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <limits.h>
8
9 #include "putty.h"
10
11 #ifndef FALSE
12 #define FALSE 0
13 #endif
14 #ifndef TRUE
15 #define TRUE 1
16 #endif
17
18 #define RAW_MAX_BACKLOG 4096
19
20 typedef struct raw_backend_data {
21     const struct plug_function_table *fn;
22     /* the above field _must_ be first in the structure */
23
24     Socket s;
25     int closed_on_socket_error;
26     int bufsize;
27     void *frontend;
28     int sent_console_eof, sent_socket_eof;
29 } *Raw;
30
31 static void raw_size(void *handle, int width, int height);
32
33 static void c_write(Raw raw, char *buf, int len)
34 {
35     int backlog = from_backend(raw->frontend, 0, buf, len);
36     sk_set_frozen(raw->s, backlog > RAW_MAX_BACKLOG);
37 }
38
39 static void raw_log(Plug plug, int type, SockAddr addr, int port,
40                     const char *error_msg, int error_code)
41 {
42     Raw raw = (Raw) plug;
43     char addrbuf[256], *msg;
44
45     sk_getaddr(addr, addrbuf, lenof(addrbuf));
46
47     if (type == 0)
48         msg = dupprintf("Connecting to %s port %d", addrbuf, port);
49     else
50         msg = dupprintf("Failed to connect to %s: %s", addrbuf, error_msg);
51
52     logevent(raw->frontend, msg);
53 }
54
55 static void raw_check_close(Raw raw)
56 {
57     /*
58      * Called after we send EOF on either the socket or the console.
59      * Its job is to wind up the session once we have sent EOF on both.
60      */
61     if (raw->sent_console_eof && raw->sent_socket_eof) {
62         if (raw->s) {
63             sk_close(raw->s);
64             raw->s = NULL;
65             notify_remote_exit(raw->frontend);
66         }
67     }
68 }
69
70 static int raw_closing(Plug plug, const char *error_msg, int error_code,
71                        int calling_back)
72 {
73     Raw raw = (Raw) plug;
74
75     if (error_msg) {
76         /* A socket error has occurred. */
77         if (raw->s) {
78             sk_close(raw->s);
79             raw->s = NULL;
80             raw->closed_on_socket_error = TRUE;
81             notify_remote_exit(raw->frontend);
82         }
83         logevent(raw->frontend, error_msg);
84         connection_fatal(raw->frontend, "%s", error_msg);
85     } else {
86         /* Otherwise, the remote side closed the connection normally. */
87         if (!raw->sent_console_eof && from_backend_eof(raw->frontend)) {
88             /*
89              * The front end wants us to close the outgoing side of the
90              * connection as soon as we see EOF from the far end.
91              */
92             if (!raw->sent_socket_eof) {
93                 if (raw->s)
94                     sk_write_eof(raw->s);
95                 raw->sent_socket_eof= TRUE;
96             }
97         }
98         raw->sent_console_eof = TRUE;
99         raw_check_close(raw);
100     }
101     return 0;
102 }
103
104 static int raw_receive(Plug plug, int urgent, char *data, int len)
105 {
106     Raw raw = (Raw) plug;
107     c_write(raw, data, len);
108     return 1;
109 }
110
111 static void raw_sent(Plug plug, int bufsize)
112 {
113     Raw raw = (Raw) plug;
114     raw->bufsize = bufsize;
115 }
116
117 /*
118  * Called to set up the raw connection.
119  * 
120  * Returns an error message, or NULL on success.
121  *
122  * Also places the canonical host name into `realhost'. It must be
123  * freed by the caller.
124  */
125 static const char *raw_init(void *frontend_handle, void **backend_handle,
126                             Conf *conf,
127                             char *host, int port, char **realhost, int nodelay,
128                             int keepalive)
129 {
130     static const struct plug_function_table fn_table = {
131         raw_log,
132         raw_closing,
133         raw_receive,
134         raw_sent
135     };
136     SockAddr addr;
137     const char *err;
138     Raw raw;
139     int addressfamily;
140     char *loghost;
141
142     raw = snew(struct raw_backend_data);
143     raw->fn = &fn_table;
144     raw->s = NULL;
145     raw->closed_on_socket_error = FALSE;
146     *backend_handle = raw;
147     raw->sent_console_eof = raw->sent_socket_eof = FALSE;
148
149     raw->frontend = frontend_handle;
150
151     addressfamily = conf_get_int(conf, CONF_addressfamily);
152     /*
153      * Try to find host.
154      */
155     {
156         char *buf;
157         buf = dupprintf("Looking up host \"%s\"%s", host,
158                         (addressfamily == ADDRTYPE_IPV4 ? " (IPv4)" :
159                          (addressfamily == ADDRTYPE_IPV6 ? " (IPv6)" :
160                           "")));
161         logevent(raw->frontend, buf);
162         sfree(buf);
163     }
164     addr = name_lookup(host, port, realhost, conf, addressfamily);
165     if ((err = sk_addr_error(addr)) != NULL) {
166         sk_addr_free(addr);
167         return err;
168     }
169
170     if (port < 0)
171         port = 23;                     /* default telnet port */
172
173     /*
174      * Open socket.
175      */
176     raw->s = new_connection(addr, *realhost, port, 0, 1, nodelay, keepalive,
177                             (Plug) raw, conf);
178     if ((err = sk_socket_error(raw->s)) != NULL)
179         return err;
180
181     loghost = conf_get_str(conf, CONF_loghost);
182     if (*loghost) {
183         char *colon;
184
185         sfree(*realhost);
186         *realhost = dupstr(loghost);
187         colon = strrchr(*realhost, ':');
188         if (colon) {
189             /*
190              * FIXME: if we ever update this aspect of ssh.c for
191              * IPv6 literal management, this should change in line
192              * with it.
193              */
194             *colon++ = '\0';
195         }
196     }
197
198     return NULL;
199 }
200
201 static void raw_free(void *handle)
202 {
203     Raw raw = (Raw) handle;
204
205     if (raw->s)
206         sk_close(raw->s);
207     sfree(raw);
208 }
209
210 /*
211  * Stub routine (we don't have any need to reconfigure this backend).
212  */
213 static void raw_reconfig(void *handle, Conf *conf)
214 {
215 }
216
217 /*
218  * Called to send data down the raw connection.
219  */
220 static int raw_send(void *handle, char *buf, int len)
221 {
222     Raw raw = (Raw) handle;
223
224     if (raw->s == NULL)
225         return 0;
226
227     raw->bufsize = sk_write(raw->s, buf, len);
228
229     return raw->bufsize;
230 }
231
232 /*
233  * Called to query the current socket sendability status.
234  */
235 static int raw_sendbuffer(void *handle)
236 {
237     Raw raw = (Raw) handle;
238     return raw->bufsize;
239 }
240
241 /*
242  * Called to set the size of the window
243  */
244 static void raw_size(void *handle, int width, int height)
245 {
246     /* Do nothing! */
247     return;
248 }
249
250 /*
251  * Send raw special codes. We only handle outgoing EOF here.
252  */
253 static void raw_special(void *handle, Telnet_Special code)
254 {
255     Raw raw = (Raw) handle;
256     if (code == TS_EOF && raw->s) {
257         sk_write_eof(raw->s);
258         raw->sent_socket_eof= TRUE;
259         raw_check_close(raw);
260     }
261
262     return;
263 }
264
265 /*
266  * Return a list of the special codes that make sense in this
267  * protocol.
268  */
269 static const struct telnet_special *raw_get_specials(void *handle)
270 {
271     return NULL;
272 }
273
274 static int raw_connected(void *handle)
275 {
276     Raw raw = (Raw) handle;
277     return raw->s != NULL;
278 }
279
280 static int raw_sendok(void *handle)
281 {
282     return 1;
283 }
284
285 static void raw_unthrottle(void *handle, int backlog)
286 {
287     Raw raw = (Raw) handle;
288     sk_set_frozen(raw->s, backlog > RAW_MAX_BACKLOG);
289 }
290
291 static int raw_ldisc(void *handle, int option)
292 {
293     if (option == LD_EDIT || option == LD_ECHO)
294         return 1;
295     return 0;
296 }
297
298 static void raw_provide_ldisc(void *handle, void *ldisc)
299 {
300     /* This is a stub. */
301 }
302
303 static void raw_provide_logctx(void *handle, void *logctx)
304 {
305     /* This is a stub. */
306 }
307
308 static int raw_exitcode(void *handle)
309 {
310     Raw raw = (Raw) handle;
311     if (raw->s != NULL)
312         return -1;                     /* still connected */
313     else if (raw->closed_on_socket_error)
314         return INT_MAX;     /* a socket error counts as an unclean exit */
315     else
316         /* Exit codes are a meaningless concept in the Raw protocol */
317         return 0;
318 }
319
320 /*
321  * cfg_info for Raw does nothing at all.
322  */
323 static int raw_cfg_info(void *handle)
324 {
325     return 0;
326 }
327
328 Backend raw_backend = {
329     raw_init,
330     raw_free,
331     raw_reconfig,
332     raw_send,
333     raw_sendbuffer,
334     raw_size,
335     raw_special,
336     raw_get_specials,
337     raw_connected,
338     raw_exitcode,
339     raw_sendok,
340     raw_ldisc,
341     raw_provide_ldisc,
342     raw_provide_logctx,
343     raw_unthrottle,
344     raw_cfg_info,
345     "raw",
346     PROT_RAW,
347     0
348 };