Fixed issue #3815: TortoiseGitMerge crashes on Win7 on startup when winrt libraries...
[TortoiseGit.git] / src / TortoisePlink / RAW.C
blob59f64a8b53722ec66a983ccdcf98e05321bc981f
1 /*\r
2  * "Raw" backend.\r
3  */\r
4 \r
5 #include <stdio.h>\r
6 #include <stdlib.h>\r
7 #include <limits.h>\r
8 \r
9 #include "putty.h"\r
11 #define RAW_MAX_BACKLOG 4096\r
13 typedef struct Raw Raw;\r
14 struct Raw {\r
15     Socket *s;\r
16     bool closed_on_socket_error;\r
17     size_t bufsize;\r
18     Seat *seat;\r
19     LogContext *logctx;\r
20     bool sent_console_eof, sent_socket_eof, session_started;\r
22     Conf *conf;\r
24     Plug plug;\r
25     Backend backend;\r
26 };\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
31 {\r
32     size_t backlog = seat_stdout(raw->seat, buf, len);\r
33     sk_set_frozen(raw->s, backlog > RAW_MAX_BACKLOG);\r
34 }\r
36 static void raw_log(Plug *plug, PlugLogType type, SockAddr *addr, int port,\r
37                     const char *error_msg, int error_code)\r
38 {\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
42 }\r
44 static void raw_check_close(Raw *raw)\r
45 {\r
46     /*\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
49      */\r
50     if (raw->sent_console_eof && raw->sent_socket_eof) {\r
51         if (raw->s) {\r
52             sk_close(raw->s);\r
53             raw->s = NULL;\r
54             seat_notify_remote_exit(raw->seat);\r
55         }\r
56     }\r
57 }\r
59 static void raw_closing(Plug *plug, const char *error_msg, int error_code,\r
60                         bool calling_back)\r
61 {\r
62     Raw *raw = container_of(plug, Raw, plug);\r
64     if (error_msg) {\r
65         /* A socket error has occurred. */\r
66         if (raw->s) {\r
67             sk_close(raw->s);\r
68             raw->s = NULL;\r
69             raw->closed_on_socket_error = true;\r
70             seat_notify_remote_exit(raw->seat);\r
71         }\r
72         logevent(raw->logctx, error_msg);\r
73         seat_connection_fatal(raw->seat, "%s", error_msg);\r
74     } else {\r
75         /* Otherwise, the remote side closed the connection normally. */\r
76         if (!raw->sent_console_eof && seat_eof(raw->seat)) {\r
77             /*\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
80              */\r
81             if (!raw->sent_socket_eof) {\r
82                 if (raw->s)\r
83                     sk_write_eof(raw->s);\r
84                 raw->sent_socket_eof= true;\r
85             }\r
86         }\r
87         raw->sent_console_eof = true;\r
88         raw_check_close(raw);\r
89     }\r
90 }\r
92 static void raw_receive(Plug *plug, int urgent, const char *data, size_t len)\r
93 {\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
99 }\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
108     .log = raw_log,\r
109     .closing = raw_closing,\r
110     .receive = raw_receive,\r
111     .sent = raw_sent,\r
112 };\r
114 /*\r
115  * Called to set up the raw connection.\r
116  *\r
117  * Returns an error message, or NULL on success.\r
118  *\r
119  * Also places the canonical host name into `realhost'. It must be\r
120  * freed by the caller.\r
121  */\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
127     SockAddr *addr;\r
128     const char *err;\r
129     Raw *raw;\r
130     int addressfamily;\r
131     char *loghost;\r
133     /* No local authentication phase in this protocol */\r
134     seat_set_trust_status(seat, false);\r
136     raw = snew(Raw);\r
137     raw->plug.vt = &Raw_plugvt;\r
138     raw->backend.vt = vt;\r
139     raw->s = NULL;\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
143     raw->bufsize = 0;\r
144     raw->session_started = false;\r
145     raw->conf = conf_copy(conf);\r
147     raw->seat = seat;\r
148     raw->logctx = logctx;\r
150     addressfamily = conf_get_int(conf, CONF_addressfamily);\r
151     /*\r
152      * Try to find host.\r
153      */\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
159     }\r
161     if (port < 0)\r
162         port = 23;                     /* default telnet port */\r
164     /*\r
165      * Open socket.\r
166      */\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
173     if (*loghost) {\r
174         char *colon;\r
176         sfree(*realhost);\r
177         *realhost = dupstr(loghost);\r
179         colon = host_strrchr(*realhost, ':');\r
180         if (colon)\r
181             *colon++ = '\0';\r
182     }\r
184     return NULL;\r
187 static void raw_free(Backend *be)\r
189     Raw *raw = container_of(be, Raw, backend);\r
191     if (raw->s)\r
192         sk_close(raw->s);\r
193     conf_free(raw->conf);\r
194     sfree(raw);\r
197 /*\r
198  * Stub routine (we don't have any need to reconfigure this backend).\r
199  */\r
200 static void raw_reconfig(Backend *be, Conf *conf)\r
204 /*\r
205  * Called to send data down the raw connection.\r
206  */\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
212         return 0;\r
214     raw->bufsize = sk_write(raw->s, buf, len);\r
216     return raw->bufsize;\r
219 /*\r
220  * Called to query the current socket sendability status.\r
221  */\r
222 static size_t raw_sendbuffer(Backend *be)\r
224     Raw *raw = container_of(be, Raw, backend);\r
225     return raw->bufsize;\r
228 /*\r
229  * Called to set the size of the window\r
230  */\r
231 static void raw_size(Backend *be, int width, int height)\r
233     /* Do nothing! */\r
234     return;\r
237 /*\r
238  * Send raw special codes. We only handle outgoing EOF here.\r
239  */\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
247     }\r
249     return;\r
252 /*\r
253  * Return a list of the special codes that make sense in this\r
254  * protocol.\r
255  */\r
256 static const SessionSpecial *raw_get_specials(Backend *be)\r
258     return NULL;\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
269     return true;\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
281         return true;\r
282     return false;\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
297     else\r
298         /* Exit codes are a meaningless concept in the Raw protocol */\r
299         return 0;\r
302 /*\r
303  * cfg_info for Raw does nothing at all.\r
304  */\r
305 static int raw_cfg_info(Backend *be)\r
307     return 0;\r
310 const BackendVtable raw_backend = {\r
311     .init = raw_init,\r
312     .free = raw_free,\r
313     .reconfig = raw_reconfig,\r
314     .send = raw_send,\r
315     .sendbuffer = raw_sendbuffer,\r
316     .size = raw_size,\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
326     .id = "raw",\r
327     .displayname = "Raw",\r
328     .protocol = PROT_RAW,\r
329     .default_port = 0,\r
330 };\r