mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 17:38:00 +00:00
445030b3ea
The vtable method underneath sshfwd_write now takes an is_stderr parameter, and in SSH-2, this is implemented by having separate stdout and stderr bufchains in each outgoing channel, and counting the size of both for the purposes of measuring backlog and so forth. To avoid making _most_ call sites more verbose, the usual macro wrapper hasn't changed its API; it just sets is_stderr=FALSE. To use the new feature, there's an sshfwd_write_ext macro that exposes the extra parameter.
223 lines
7.4 KiB
C
223 lines
7.4 KiB
C
#ifndef PUTTY_SSH2CONNECTION_H
|
|
#define PUTTY_SSH2CONNECTION_H
|
|
|
|
struct outstanding_channel_request;
|
|
struct outstanding_global_request;
|
|
|
|
struct ssh2_connection_state {
|
|
int crState;
|
|
|
|
Ssh *ssh;
|
|
|
|
ssh_sharing_state *connshare;
|
|
char *peer_verstring;
|
|
|
|
mainchan *mainchan;
|
|
SshChannel *mainchan_sc;
|
|
int ldisc_opts[LD_N_OPTIONS];
|
|
int session_attempt, session_status;
|
|
int term_width, term_height;
|
|
int want_user_input;
|
|
|
|
int ssh_is_simple;
|
|
int persistent;
|
|
|
|
Conf *conf;
|
|
|
|
tree234 *channels; /* indexed by local id */
|
|
int all_channels_throttled;
|
|
|
|
int X11_fwd_enabled;
|
|
tree234 *x11authtree;
|
|
|
|
int got_pty;
|
|
int agent_fwd_enabled;
|
|
|
|
tree234 *rportfwds;
|
|
PortFwdManager *portfwdmgr;
|
|
int portfwdmgr_configured;
|
|
|
|
/*
|
|
* These store the list of global requests that we're waiting for
|
|
* replies to. (REQUEST_FAILURE doesn't come with any indication
|
|
* of what message caused it, so we have to keep track of the
|
|
* queue ourselves.)
|
|
*/
|
|
struct outstanding_global_request *globreq_head, *globreq_tail;
|
|
|
|
ConnectionLayer cl;
|
|
PacketProtocolLayer ppl;
|
|
};
|
|
|
|
typedef void (*gr_handler_fn_t)(struct ssh2_connection_state *s,
|
|
PktIn *pktin, void *ctx);
|
|
void ssh2_queue_global_request_handler(
|
|
struct ssh2_connection_state *s, gr_handler_fn_t handler, void *ctx);
|
|
|
|
struct ssh2_channel {
|
|
struct ssh2_connection_state *connlayer;
|
|
|
|
unsigned remoteid, localid;
|
|
int type;
|
|
/* True if we opened this channel but server hasn't confirmed. */
|
|
int halfopen;
|
|
|
|
/* Bitmap of whether we've sent/received CHANNEL_EOF and
|
|
* CHANNEL_CLOSE. */
|
|
#define CLOSES_SENT_EOF 1
|
|
#define CLOSES_SENT_CLOSE 2
|
|
#define CLOSES_RCVD_EOF 4
|
|
#define CLOSES_RCVD_CLOSE 8
|
|
int closes;
|
|
|
|
/*
|
|
* This flag indicates that an EOF is pending on the outgoing side
|
|
* of the channel: that is, wherever we're getting the data for
|
|
* this channel has sent us some data followed by EOF. We can't
|
|
* actually send the EOF until we've finished sending the data, so
|
|
* we set this flag instead to remind us to do so once our buffer
|
|
* is clear.
|
|
*/
|
|
int pending_eof;
|
|
|
|
/*
|
|
* True if this channel is causing the underlying connection to be
|
|
* throttled.
|
|
*/
|
|
int throttling_conn;
|
|
|
|
/*
|
|
* True if we currently have backed-up data on the direction of
|
|
* this channel pointing out of the SSH connection, and therefore
|
|
* would prefer the 'Channel' implementation not to read further
|
|
* local input if possible.
|
|
*/
|
|
int throttled_by_backlog;
|
|
|
|
bufchain outbuffer, errbuffer;
|
|
unsigned remwindow, remmaxpkt;
|
|
/* locwindow is signed so we can cope with excess data. */
|
|
int locwindow, locmaxwin;
|
|
/*
|
|
* remlocwin is the amount of local window that we think
|
|
* the remote end had available to it after it sent the
|
|
* last data packet or window adjust ack.
|
|
*/
|
|
int remlocwin;
|
|
|
|
/*
|
|
* These store the list of channel requests that we're waiting for
|
|
* replies to. (CHANNEL_FAILURE doesn't come with any indication
|
|
* of what message caused it, so we have to keep track of the
|
|
* queue ourselves.)
|
|
*/
|
|
struct outstanding_channel_request *chanreq_head, *chanreq_tail;
|
|
|
|
enum { THROTTLED, UNTHROTTLING, UNTHROTTLED } throttle_state;
|
|
|
|
ssh_sharing_connstate *sharectx; /* sharing context, if this is a
|
|
* downstream channel */
|
|
Channel *chan; /* handle the client side of this channel, if not */
|
|
SshChannel sc; /* entry point for chan to talk back to */
|
|
};
|
|
|
|
typedef void (*cr_handler_fn_t)(struct ssh2_channel *, PktIn *, void *);
|
|
|
|
void ssh2_channel_init(struct ssh2_channel *c);
|
|
PktOut *ssh2_chanreq_init(struct ssh2_channel *c, const char *type,
|
|
cr_handler_fn_t handler, void *ctx);
|
|
|
|
typedef enum ChanopenOutcome {
|
|
CHANOPEN_RESULT_FAILURE,
|
|
CHANOPEN_RESULT_SUCCESS,
|
|
CHANOPEN_RESULT_DOWNSTREAM,
|
|
} ChanopenOutcome;
|
|
|
|
typedef struct ChanopenResult {
|
|
ChanopenOutcome outcome;
|
|
union {
|
|
struct {
|
|
char *wire_message; /* must be freed by recipient */
|
|
unsigned reason_code;
|
|
} failure;
|
|
struct {
|
|
Channel *channel;
|
|
} success;
|
|
struct {
|
|
ssh_sharing_connstate *share_ctx;
|
|
} downstream;
|
|
} u;
|
|
} ChanopenResult;
|
|
|
|
PktOut *ssh2_chanopen_init(struct ssh2_channel *c, const char *type);
|
|
|
|
PktOut *ssh2_portfwd_chanopen(
|
|
struct ssh2_connection_state *s, struct ssh2_channel *c,
|
|
const char *hostname, int port,
|
|
const char *description, const SocketPeerInfo *peerinfo);
|
|
|
|
struct ssh_rportfwd *ssh2_rportfwd_alloc(
|
|
ConnectionLayer *cl,
|
|
const char *shost, int sport, const char *dhost, int dport,
|
|
int addressfamily, const char *log_description, PortFwdRecord *pfr,
|
|
ssh_sharing_connstate *share_ctx);
|
|
void ssh2_rportfwd_remove(
|
|
ConnectionLayer *cl, struct ssh_rportfwd *rpf);
|
|
|
|
SshChannel *ssh2_session_open(ConnectionLayer *cl, Channel *chan);
|
|
|
|
void ssh2channel_request_x11_forwarding(
|
|
SshChannel *c, int want_reply, const char *authproto,
|
|
const char *authdata, int screen_number, int oneshot);
|
|
void ssh2channel_request_agent_forwarding(SshChannel *c, int want_reply);
|
|
void ssh2channel_request_pty(
|
|
SshChannel *c, int want_reply, Conf *conf, int w, int h);
|
|
int ssh2channel_send_env_var(
|
|
SshChannel *c, int want_reply, const char *var, const char *value);
|
|
void ssh2channel_start_shell(SshChannel *c, int want_reply);
|
|
void ssh2channel_start_command(
|
|
SshChannel *c, int want_reply, const char *command);
|
|
int ssh2channel_start_subsystem(
|
|
SshChannel *c, int want_reply, const char *subsystem);
|
|
int ssh2channel_send_env_var(
|
|
SshChannel *c, int want_reply, const char *var, const char *value);
|
|
int ssh2channel_send_serial_break(
|
|
SshChannel *c, int want_reply, int length);
|
|
int ssh2channel_send_signal(
|
|
SshChannel *c, int want_reply, const char *signame);
|
|
void ssh2channel_send_terminal_size_change(SshChannel *c, int w, int h);
|
|
|
|
#define CHANOPEN_RETURN_FAILURE(code, msgparams) do \
|
|
{ \
|
|
ChanopenResult toret; \
|
|
toret.outcome = CHANOPEN_RESULT_FAILURE; \
|
|
toret.u.failure.reason_code = code; \
|
|
toret.u.failure.wire_message = dupprintf msgparams; \
|
|
return toret; \
|
|
} while (0)
|
|
|
|
#define CHANOPEN_RETURN_SUCCESS(chan) do \
|
|
{ \
|
|
ChanopenResult toret; \
|
|
toret.outcome = CHANOPEN_RESULT_SUCCESS; \
|
|
toret.u.success.channel = chan; \
|
|
return toret; \
|
|
} while (0)
|
|
|
|
#define CHANOPEN_RETURN_DOWNSTREAM(shctx) do \
|
|
{ \
|
|
ChanopenResult toret; \
|
|
toret.outcome = CHANOPEN_RESULT_DOWNSTREAM; \
|
|
toret.u.downstream.share_ctx = shctx; \
|
|
return toret; \
|
|
} while (0)
|
|
|
|
ChanopenResult ssh2_connection_parse_channel_open(
|
|
struct ssh2_connection_state *s, ptrlen type,
|
|
PktIn *pktin, SshChannel *sc);
|
|
|
|
int ssh2_connection_parse_global_request(
|
|
struct ssh2_connection_state *s, ptrlen type, PktIn *pktin);
|
|
|
|
#endif /* PUTTY_SSH2CONNECTION_H */
|