diff --git a/network.h b/network.h index 851e1738..9b63d39f 100644 --- a/network.h +++ b/network.h @@ -51,6 +51,12 @@ typedef enum PlugLogType { PLUGLOG_PROXY_MSG, } PlugLogType; +typedef enum PlugCloseType { + PLUGCLOSE_NORMAL, + PLUGCLOSE_ERROR, + PLUGCLOSE_BROKEN_PIPE, +} PlugCloseType; + struct PlugVtable { /* * Passes the client progress reports on the process of setting @@ -88,18 +94,26 @@ struct PlugVtable { const char *error_msg, int error_code); /* - * Notifies the Plug that the socket is closing. + * Notifies the Plug that the socket is closing, and something + * about why. * - * For a normal non-error close, error_msg is NULL. If the socket - * has encountered an error, error_msg will contain a string - * (ownership not transferred), and error_code will contain the OS - * error code, if available. + * - PLUGCLOSE_NORMAL means an ordinary non-error closure. In + * this case, error_msg should be ignored (and hopefully + * callers will have passed NULL). * - * OS error codes will vary between platforms, of course, but - * platform.h should define any that we need to distinguish here, - * in particular BROKEN_PIPE_ERROR_CODE. + * - PLUGCLOSE_ERROR indicates that an OS error occurred, and + * 'error_msg' contains a string describing it, for use in + * diagnostics. (Ownership of the string is not transferred.) + * This error class covers anything other than the special + * case below: + * + * - PLUGCLOSE_BROKEN_PIPE behaves like PLUGCLOSE_ERROR (in + * particular, there's still an error message provided), but + * distinguishes the particular error condition signalled by + * EPIPE / ERROR_BROKEN_PIPE, which ssh/sharing.c needs to + * recognise and handle specially in one situation. */ - void (*closing)(Plug *p, const char *error_msg, int error_code); + void (*closing)(Plug *p, PlugCloseType type, const char *error_msg); /* * Provides incoming socket data to the Plug. Three cases: @@ -222,12 +236,12 @@ static inline void sk_write_eof(Socket *s) static inline void plug_log( Plug *p, int type, SockAddr *addr, int port, const char *msg, int code) { p->vt->log(p, type, addr, port, msg, code); } -static inline void plug_closing(Plug *p, const char *msg, int code) -{ p->vt->closing(p, msg, code); } +static inline void plug_closing(Plug *p, PlugCloseType type, const char *msg) +{ p->vt->closing(p, type, msg); } static inline void plug_closing_normal(Plug *p) -{ p->vt->closing(p, NULL, 0); } +{ p->vt->closing(p, PLUGCLOSE_NORMAL, NULL); } static inline void plug_closing_error(Plug *p, const char *msg) -{ p->vt->closing(p, msg, 0); } +{ p->vt->closing(p, PLUGCLOSE_ERROR, msg); } static inline void plug_receive(Plug *p, int urg, const char *data, size_t len) { p->vt->receive(p, urg, data, len); } static inline void plug_sent (Plug *p, size_t bufsize) @@ -352,7 +366,7 @@ extern Plug *const nullplug; */ void nullplug_log(Plug *plug, PlugLogType type, SockAddr *addr, int port, const char *err_msg, int err_code); -void nullplug_closing(Plug *plug, const char *error_msg, int error_code); +void nullplug_closing(Plug *plug, PlugCloseType type, const char *error_msg); void nullplug_receive(Plug *plug, int urgent, const char *data, size_t len); void nullplug_sent(Plug *plug, size_t bufsize); diff --git a/nullplug.c b/nullplug.c index ad65f5ea..d583d156 100644 --- a/nullplug.c +++ b/nullplug.c @@ -12,7 +12,7 @@ void nullplug_log(Plug *plug, PlugLogType type, SockAddr *addr, { } -void nullplug_closing(Plug *plug, const char *error_msg, int error_code) +void nullplug_closing(Plug *plug, PlugCloseType type, const char *error_msg) { } diff --git a/otherbackends/raw.c b/otherbackends/raw.c index 80ce8fe1..59a6611d 100644 --- a/otherbackends/raw.c +++ b/otherbackends/raw.c @@ -65,11 +65,11 @@ static void raw_check_close(Raw *raw) } } -static void raw_closing(Plug *plug, const char *error_msg, int error_code) +static void raw_closing(Plug *plug, PlugCloseType type, const char *error_msg) { Raw *raw = container_of(plug, Raw, plug); - if (error_msg) { + if (type != PLUGCLOSE_NORMAL) { /* A socket error has occurred. */ if (raw->s) { sk_close(raw->s); diff --git a/otherbackends/rlogin.c b/otherbackends/rlogin.c index e626eff4..341ecae7 100644 --- a/otherbackends/rlogin.c +++ b/otherbackends/rlogin.c @@ -85,7 +85,8 @@ static void rlogin_log(Plug *plug, PlugLogType type, SockAddr *addr, int port, } } -static void rlogin_closing(Plug *plug, const char *error_msg, int error_code) +static void rlogin_closing(Plug *plug, PlugCloseType type, + const char *error_msg) { Rlogin *rlogin = container_of(plug, Rlogin, plug); @@ -103,11 +104,12 @@ static void rlogin_closing(Plug *plug, const char *error_msg, int error_code) seat_notify_remote_exit(rlogin->seat); seat_notify_remote_disconnect(rlogin->seat); } - if (error_msg) { + if (type != PLUGCLOSE_NORMAL) { /* A socket error has occurred. */ logevent(rlogin->logctx, error_msg); seat_connection_fatal(rlogin->seat, "%s", error_msg); - } /* Otherwise, the remote side closed the connection normally. */ + } + /* Otherwise, the remote side closed the connection normally. */ } static void rlogin_receive( diff --git a/otherbackends/supdup.c b/otherbackends/supdup.c index c1867086..697c3e84 100644 --- a/otherbackends/supdup.c +++ b/otherbackends/supdup.c @@ -573,7 +573,8 @@ static void supdup_log(Plug *plug, PlugLogType type, SockAddr *addr, int port, } } -static void supdup_closing(Plug *plug, const char *error_msg, int error_code) +static void supdup_closing(Plug *plug, PlugCloseType type, + const char *error_msg) { Supdup *supdup = container_of(plug, Supdup, plug); @@ -591,7 +592,7 @@ static void supdup_closing(Plug *plug, const char *error_msg, int error_code) seat_notify_remote_exit(supdup->seat); seat_notify_remote_disconnect(supdup->seat); } - if (error_msg) { + if (type != PLUGCLOSE_NORMAL) { logevent(supdup->logctx, error_msg); seat_connection_fatal(supdup->seat, "%s", error_msg); } diff --git a/otherbackends/telnet.c b/otherbackends/telnet.c index 66f7308e..80a7cc24 100644 --- a/otherbackends/telnet.c +++ b/otherbackends/telnet.c @@ -635,7 +635,8 @@ static void telnet_log(Plug *plug, PlugLogType type, SockAddr *addr, int port, } } -static void telnet_closing(Plug *plug, const char *error_msg, int error_code) +static void telnet_closing(Plug *plug, PlugCloseType type, + const char *error_msg) { Telnet *telnet = container_of(plug, Telnet, plug); @@ -653,7 +654,7 @@ static void telnet_closing(Plug *plug, const char *error_msg, int error_code) seat_notify_remote_exit(telnet->seat); seat_notify_remote_disconnect(telnet->seat); } - if (error_msg) { + if (type != PLUGCLOSE_NORMAL) { logevent(telnet->logctx, error_msg); seat_connection_fatal(telnet->seat, "%s", error_msg); } diff --git a/pageant.c b/pageant.c index bb658cfe..f64026d8 100644 --- a/pageant.c +++ b/pageant.c @@ -1463,12 +1463,12 @@ struct pageant_conn_state { Plug plug; }; -static void pageant_conn_closing(Plug *plug, const char *error_msg, - int error_code) +static void pageant_conn_closing(Plug *plug, PlugCloseType type, + const char *error_msg) { struct pageant_conn_state *pc = container_of( plug, struct pageant_conn_state, plug); - if (error_msg) + if (type != PLUGCLOSE_NORMAL) pageant_listener_client_log(pc->plc, "c#%"SIZEu": error: %s", pc->conn_index, error_msg); else @@ -1610,12 +1610,12 @@ struct pageant_listen_state { Plug plug; }; -static void pageant_listen_closing(Plug *plug, const char *error_msg, - int error_code) +static void pageant_listen_closing(Plug *plug, PlugCloseType type, + const char *error_msg) { struct pageant_listen_state *pl = container_of( plug, struct pageant_listen_state, plug); - if (error_msg) + if (type != PLUGCLOSE_NORMAL) pageant_listener_client_log(pl->plc, "listening socket: error: %s", error_msg); sk_close(pl->listensock); diff --git a/proxy/proxy.c b/proxy/proxy.c index d4963db4..d6041754 100644 --- a/proxy/proxy.c +++ b/proxy/proxy.c @@ -181,16 +181,17 @@ static void plug_proxy_log(Plug *plug, PlugLogType type, SockAddr *addr, plug_log(ps->plug, type, addr, port, error_msg, error_code); } -static void plug_proxy_closing(Plug *p, const char *error_msg, int error_code) +static void plug_proxy_closing(Plug *p, PlugCloseType type, + const char *error_msg) { ProxySocket *ps = container_of(p, ProxySocket, plugimpl); if (ps->state != PROXY_STATE_ACTIVE) { + ps->closing_type = type; ps->closing_error_msg = error_msg; - ps->closing_error_code = error_code; ps->negotiate(ps, PROXY_CHANGE_CLOSING); } else { - plug_closing(ps->plug, error_msg, error_code); + plug_closing(ps->plug, type, error_msg); } } @@ -615,7 +616,7 @@ int proxy_http_negotiate (ProxySocket *p, int change) * a socket close, then some error must have occurred. we'll * just pass those errors up to the backend. */ - plug_closing(p->plug, p->closing_error_msg, p->closing_error_code); + plug_closing(p->plug, p->closing_type, p->closing_error_msg); return 0; /* ignored */ } @@ -803,7 +804,7 @@ int proxy_socks4_negotiate (ProxySocket *p, int change) * a socket close, then some error must have occurred. we'll * just pass those errors up to the backend. */ - plug_closing(p->plug, p->closing_error_msg, p->closing_error_code); + plug_closing(p->plug, p->closing_type, p->closing_error_msg); return 0; /* ignored */ } @@ -945,7 +946,7 @@ int proxy_socks5_negotiate (ProxySocket *p, int change) * a socket close, then some error must have occurred. we'll * just pass those errors up to the backend. */ - plug_closing(p->plug, p->closing_error_msg, p->closing_error_code); + plug_closing(p->plug, p->closing_type, p->closing_error_msg); return 0; /* ignored */ } @@ -1467,7 +1468,7 @@ int proxy_telnet_negotiate (ProxySocket *p, int change) * a socket close, then some error must have occurred. we'll * just pass those errors up to the backend. */ - plug_closing(p->plug, p->closing_error_msg, p->closing_error_code); + plug_closing(p->plug, p->closing_type, p->closing_error_msg); return 0; /* ignored */ } diff --git a/proxy/proxy.h b/proxy/proxy.h index 3ec3261c..06692b70 100644 --- a/proxy/proxy.h +++ b/proxy/proxy.h @@ -58,8 +58,8 @@ struct ProxySocket { */ /* closing */ + PlugCloseType closing_type; const char *closing_error_msg; - int closing_error_code; /* receive */ bool receive_urgent; diff --git a/psocks.c b/psocks.c index f3c8efa0..64c46953 100644 --- a/psocks.c +++ b/psocks.c @@ -94,8 +94,7 @@ static const SshChannelVtable psocks_scvt = { static void psocks_plug_log(Plug *p, PlugLogType type, SockAddr *addr, int port, const char *error_msg, int error_code); -static void psocks_plug_closing(Plug *p, const char *error_msg, - int error_code); +static void psocks_plug_closing(Plug *p, PlugCloseType, const char *error_msg); static void psocks_plug_receive(Plug *p, int urgent, const char *data, size_t len); static void psocks_plug_sent(Plug *p, size_t bufsize); @@ -354,8 +353,8 @@ static void psocks_plug_log(Plug *plug, PlugLogType type, SockAddr *addr, }; } -static void psocks_plug_closing(Plug *plug, const char *error_msg, - int error_code) +static void psocks_plug_closing(Plug *plug, PlugCloseType type, + const char *error_msg) { psocks_connection *conn = container_of(plug, psocks_connection, plug); if (conn->connecting) { diff --git a/ssh/portfwd.c b/ssh/portfwd.c index 204f0632..2afa9507 100644 --- a/ssh/portfwd.c +++ b/ssh/portfwd.c @@ -109,12 +109,12 @@ static void pfl_log(Plug *plug, PlugLogType type, SockAddr *addr, int port, static void pfd_close(struct PortForwarding *pf); -static void pfd_closing(Plug *plug, const char *error_msg, int error_code) +static void pfd_closing(Plug *plug, PlugCloseType type, const char *error_msg) { struct PortForwarding *pf = container_of(plug, struct PortForwarding, plug); - if (error_msg) { + if (type != PLUGCLOSE_NORMAL) { /* * Socket error. Slam the connection instantly shut. */ @@ -141,7 +141,7 @@ static void pfd_closing(Plug *plug, const char *error_msg, int error_code) static void pfl_terminate(struct PortListener *pl); -static void pfl_closing(Plug *plug, const char *error_msg, int error_code) +static void pfl_closing(Plug *plug, PlugCloseType type, const char *error_msg) { struct PortListener *pl = (struct PortListener *) plug; pfl_terminate(pl); diff --git a/ssh/server.c b/ssh/server.c index 888ff87d..99237616 100644 --- a/ssh/server.c +++ b/ssh/server.c @@ -140,10 +140,11 @@ static void server_socket_log(Plug *plug, PlugLogType type, SockAddr *addr, /* FIXME */ } -static void server_closing(Plug *plug, const char *error_msg, int error_code) +static void server_closing(Plug *plug, PlugCloseType type, + const char *error_msg) { server *srv = container_of(plug, server, plug); - if (error_msg) { + if (type != PLUGCLOSE_NORMAL) { ssh_remote_error(&srv->ssh, "%s", error_msg); } else if (srv->bpp) { srv->bpp->input_eof = true; diff --git a/ssh/sesschan.c b/ssh/sesschan.c index 56ee37e1..5379b308 100644 --- a/ssh/sesschan.c +++ b/ssh/sesschan.c @@ -367,7 +367,7 @@ bool sesschan_run_subsystem(Channel *chan, ptrlen subsys) static void fwd_log(Plug *plug, PlugLogType type, SockAddr *addr, int port, const char *error_msg, int error_code) { /* don't expect any weirdnesses from a listening socket */ } -static void fwd_closing(Plug *plug, const char *error_msg, int error_code) +static void fwd_closing(Plug *plug, PlugCloseType type, const char *error_msg) { /* not here, either */ } static int xfwd_accepting(Plug *p, accept_fn_t constructor, accept_ctx_t ctx) diff --git a/ssh/sharing.c b/ssh/sharing.c index 92e2a786..dfa0ca22 100644 --- a/ssh/sharing.c +++ b/ssh/sharing.c @@ -937,27 +937,25 @@ static void share_disconnect(struct ssh_sharing_connstate *cs, share_begin_cleanup(cs); } -static void share_closing(Plug *plug, const char *error_msg, int error_code) +static void share_closing(Plug *plug, PlugCloseType type, + const char *error_msg) { struct ssh_sharing_connstate *cs = container_of( plug, struct ssh_sharing_connstate, plug); - if (error_msg) { -#ifdef BROKEN_PIPE_ERROR_CODE - /* - * Most of the time, we log what went wrong when a downstream - * disappears with a socket error. One exception, though, is - * receiving EPIPE when we haven't received a protocol version - * string from the downstream, because that can happen as a result - * of plink -shareexists (opening the connection and instantly - * closing it again without bothering to read our version string). - * So that one case is not treated as a log-worthy error. - */ - if (error_code == BROKEN_PIPE_ERROR_CODE && !cs->got_verstring) - /* do nothing */; - else -#endif - log_downstream(cs, "Socket error: %s", error_msg); + /* + * Most of the time, we log what went wrong when a downstream + * disappears with a socket error. One exception, though, is + * receiving EPIPE when we haven't received a protocol version + * string from the downstream, because that can happen as a result + * of plink -shareexists (opening the connection and instantly + * closing it again without bothering to read our version string). + * So that one case is not treated as a log-worthy error. + */ + if (type == PLUGCLOSE_BROKEN_PIPE && !cs->got_verstring) { + /* do nothing */; + } else if (type != PLUGCLOSE_NORMAL) { + log_downstream(cs, "Socket error: %s", error_msg); } share_begin_cleanup(cs); } @@ -1844,12 +1842,12 @@ static void share_sent(Plug *plug, size_t bufsize) */ } -static void share_listen_closing(Plug *plug, const char *error_msg, - int error_code) +static void share_listen_closing(Plug *plug, PlugCloseType type, + const char *error_msg) { ssh_sharing_state *sharestate = container_of(plug, ssh_sharing_state, plug); - if (error_msg) + if (type != PLUGCLOSE_NORMAL) log_general(sharestate, "listening socket: %s", error_msg); sk_close(sharestate->listensock); sharestate->listensock = NULL; diff --git a/ssh/ssh.c b/ssh/ssh.c index ae7c1f6f..831afd72 100644 --- a/ssh/ssh.c +++ b/ssh/ssh.c @@ -603,10 +603,10 @@ static void ssh_socket_log(Plug *plug, PlugLogType type, SockAddr *addr, ssh->session_started); } -static void ssh_closing(Plug *plug, const char *error_msg, int error_code) +static void ssh_closing(Plug *plug, PlugCloseType type, const char *error_msg) { Ssh *ssh = container_of(plug, Ssh, plug); - if (error_msg) { + if (type != PLUGCLOSE_NORMAL) { ssh_remote_error(ssh, "%s", error_msg); } else if (ssh->bpp) { ssh->bpp->input_eof = true; diff --git a/ssh/x11fwd.c b/ssh/x11fwd.c index 1d2fe512..4a2073e6 100644 --- a/ssh/x11fwd.c +++ b/ssh/x11fwd.c @@ -267,12 +267,12 @@ static void x11_log(Plug *p, PlugLogType type, SockAddr *addr, int port, static void x11_send_init_error(struct X11Connection *conn, const char *err_message); -static void x11_closing(Plug *plug, const char *error_msg, int error_code) +static void x11_closing(Plug *plug, PlugCloseType type, const char *error_msg) { struct X11Connection *xconn = container_of( plug, struct X11Connection, plug); - if (error_msg) { + if (type != PLUGCLOSE_NORMAL) { /* * Socket error. If we're still at the connection setup stage, * construct an X11 error packet passing on the problem. diff --git a/unix/network.c b/unix/network.c index 32cc3c9e..b8f923e9 100644 --- a/unix/network.c +++ b/unix/network.c @@ -1086,7 +1086,10 @@ void *sk_getxdmdata(Socket *sock, int *lenp) void plug_closing_errno(Plug *plug, int error) { - plug_closing(plug, strerror(error), error); + PlugCloseType type = PLUGCLOSE_ERROR; + if (error == EPIPE) + type = PLUGCLOSE_BROKEN_PIPE; + plug_closing(plug, type, strerror(error)); } /* diff --git a/unix/pageant.c b/unix/pageant.c index 2fa3eeaa..f2f75eac 100644 --- a/unix/pageant.c +++ b/unix/pageant.c @@ -249,7 +249,7 @@ static void x11_log(Plug *p, PlugLogType type, SockAddr *addr, int port, const char *error_msg, int error_code) {} static void x11_receive(Plug *plug, int urgent, const char *data, size_t len) {} static void x11_sent(Plug *plug, size_t bufsize) {} -static void x11_closing(Plug *plug, const char *error_msg, int error_code) +static void x11_closing(Plug *plug, PlugCloseType type, const char *error_msg) { time_to_die = true; } diff --git a/unix/psusan.c b/unix/psusan.c index 8fcef33a..6560adf2 100644 --- a/unix/psusan.c +++ b/unix/psusan.c @@ -273,9 +273,11 @@ static void server_log(Plug *plug, PlugLogType type, SockAddr *addr, int port, log_to_stderr(-1, error_msg); } -static void server_closing(Plug *plug, const char *error_msg, int error_code) +static void server_closing(Plug *plug, PlugCloseType type, + const char *error_msg) { - log_to_stderr(-1, error_msg); + if (type != PLUGCLOSE_NORMAL) + log_to_stderr(-1, error_msg); } static int server_accepting(Plug *p, accept_fn_t constructor, accept_ctx_t ctx) diff --git a/unix/uppity.c b/unix/uppity.c index 0701ddab..7f74fed6 100644 --- a/unix/uppity.c +++ b/unix/uppity.c @@ -482,9 +482,11 @@ static void server_log(Plug *plug, PlugLogType type, SockAddr *addr, int port, log_to_stderr((unsigned)-1, error_msg); } -static void server_closing(Plug *plug, const char *error_msg, int error_code) +static void server_closing(Plug *plug, PlugCloseType type, + const char *error_msg) { - log_to_stderr((unsigned)-1, error_msg); + if (type != PLUGCLOSE_NORMAL) + log_to_stderr((unsigned)-1, error_msg); } static int server_accepting(Plug *p, accept_fn_t constructor, accept_ctx_t ctx) diff --git a/windows/network.c b/windows/network.c index b5b5ab0e..a1a74b4c 100644 --- a/windows/network.c +++ b/windows/network.c @@ -1337,12 +1337,15 @@ static void sk_net_close(Socket *sock) void plug_closing_system_error(Plug *plug, DWORD error) { - plug_closing(plug, win_strerror(error), error); + PlugCloseType type = PLUGCLOSE_ERROR; + if (error == ERROR_BROKEN_PIPE) + type = PLUGCLOSE_BROKEN_PIPE; + plug_closing(plug, type, win_strerror(error)); } void plug_closing_winsock_error(Plug *plug, DWORD error) { - plug_closing(plug, winsock_error_string(error), error); + plug_closing(plug, PLUGCLOSE_ERROR, winsock_error_string(error)); } /* diff --git a/windows/platform.h b/windows/platform.h index 0a1a6ef7..cfd47281 100644 --- a/windows/platform.h +++ b/windows/platform.h @@ -121,8 +121,6 @@ static inline uintmax_t strtoumax(const char *nptr, char **endptr, int base) #define strnicmp strncasecmp #endif -#define BROKEN_PIPE_ERROR_CODE ERROR_BROKEN_PIPE /* used in ssh/sharing.c */ - /* * Dynamically linked functions. These come in two flavours: *