_libssh2_transport_write: remade to send without malloc
Этот коммит содержится в:
родитель
3a391f6cf2
Коммит
5ede32a826
184
src/comp.c
184
src/comp.c
@ -53,7 +53,30 @@
|
||||
* Minimalist compression: Absolutely none
|
||||
*/
|
||||
static int
|
||||
comp_method_none_comp(LIBSSH2_SESSION * session,
|
||||
comp_method_none_comp(LIBSSH2_SESSION *session,
|
||||
unsigned char *dest,
|
||||
size_t *dest_len,
|
||||
const unsigned char *src,
|
||||
size_t src_len,
|
||||
void **abstract)
|
||||
{
|
||||
(void) session;
|
||||
(void) abstract;
|
||||
(void) dest;
|
||||
(void) dest_len;
|
||||
(void) src;
|
||||
(void) src_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* comp_method_none_decomp
|
||||
*
|
||||
* Minimalist decompression: Absolutely none
|
||||
*/
|
||||
static int
|
||||
comp_method_none_decomp(LIBSSH2_SESSION * session,
|
||||
int compress,
|
||||
unsigned char **dest,
|
||||
size_t *dest_len,
|
||||
@ -81,7 +104,7 @@ static const LIBSSH2_COMP_METHOD comp_method_none = {
|
||||
0, /* not really compressing */
|
||||
NULL,
|
||||
comp_method_none_comp,
|
||||
comp_method_none_comp,
|
||||
comp_method_none_decomp,
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -154,141 +177,35 @@ comp_method_zlib_init(LIBSSH2_SESSION * session, int compress,
|
||||
/*
|
||||
* libssh2_comp_method_zlib_comp
|
||||
*
|
||||
* Compresses source to destination. Without any allocation.
|
||||
* Compresses source to destination. Without allocation.
|
||||
*/
|
||||
static int
|
||||
comp_method_zlib_comp(LIBSSH2_SESSION * session,
|
||||
int compress,
|
||||
unsigned char **dest,
|
||||
comp_method_zlib_comp(LIBSSH2_SESSION *session,
|
||||
unsigned char *dest,
|
||||
|
||||
/* dest_len is a pointer to allow this function to
|
||||
update it with the final actual size used */
|
||||
size_t *dest_len,
|
||||
size_t payload_limit,
|
||||
int *free_dest,
|
||||
const unsigned char *src,
|
||||
size_t src_len, void **abstract)
|
||||
size_t src_len,
|
||||
void **abstract)
|
||||
{
|
||||
z_stream *strm = *abstract;
|
||||
/* A short-term alloc of a full data chunk is better than a series of
|
||||
reallocs */
|
||||
char *out;
|
||||
int out_maxlen = compress ? (src_len + 4) : (2 * src_len);
|
||||
int limiter = 0;
|
||||
|
||||
/* If strm is null, then we have not yet been initialized. */
|
||||
if (strm == NULL) {
|
||||
*dest = (unsigned char *) src;
|
||||
*dest_len = src_len;
|
||||
|
||||
*free_dest = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* In practice they never come smaller than this */
|
||||
if (out_maxlen < 25) {
|
||||
out_maxlen = 25;
|
||||
}
|
||||
|
||||
if (out_maxlen > (int) payload_limit) {
|
||||
out_maxlen = payload_limit;
|
||||
}
|
||||
int out_maxlen = *dest_len;
|
||||
int status;
|
||||
|
||||
strm->next_in = (unsigned char *) src;
|
||||
strm->avail_in = src_len;
|
||||
strm->next_out = (unsigned char *) LIBSSH2_ALLOC(session, out_maxlen);
|
||||
out = (char *) strm->next_out;
|
||||
strm->next_out = dest;
|
||||
strm->avail_out = out_maxlen;
|
||||
if (!strm->next_out) {
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to allocate compression/decompression "
|
||||
"buffer");
|
||||
}
|
||||
while (strm->avail_in) {
|
||||
int status;
|
||||
|
||||
if (compress) {
|
||||
status = deflate(strm, Z_PARTIAL_FLUSH);
|
||||
} else {
|
||||
status = inflate(strm, Z_PARTIAL_FLUSH);
|
||||
}
|
||||
if (status != Z_OK) {
|
||||
LIBSSH2_FREE(session, out);
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_ZLIB,
|
||||
"compress/decompression failure");
|
||||
}
|
||||
if (strm->avail_in) {
|
||||
size_t out_ofs = out_maxlen - strm->avail_out;
|
||||
char *newout;
|
||||
status = deflate(strm, Z_PARTIAL_FLUSH);
|
||||
|
||||
out_maxlen +=
|
||||
compress ? (strm->avail_in + 4) : (2 * strm->avail_in);
|
||||
if (status != Z_OK)
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_ZLIB,
|
||||
"compression failure");
|
||||
|
||||
if ((out_maxlen > (int) payload_limit) && !compress && limiter++) {
|
||||
LIBSSH2_FREE(session, out);
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_ZLIB,
|
||||
"Excessive growth in decompression phase");
|
||||
}
|
||||
|
||||
newout = LIBSSH2_REALLOC(session, out, out_maxlen);
|
||||
if (!newout) {
|
||||
LIBSSH2_FREE(session, out);
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to expand compress/"
|
||||
"decompression buffer");
|
||||
}
|
||||
out = newout;
|
||||
strm->next_out = (unsigned char *) out + out_ofs;
|
||||
strm->avail_out +=
|
||||
compress ? (strm->avail_in + 4) : (2 * strm->avail_in);
|
||||
} else
|
||||
while (!strm->avail_out) {
|
||||
/* Done with input, might be a byte or two in internal buffer
|
||||
* during compress. Or potentially many bytes if it's a
|
||||
* decompress
|
||||
*/
|
||||
int grow_size = compress ? 8 : 1024;
|
||||
char *newout;
|
||||
|
||||
if (out_maxlen >= (int) payload_limit) {
|
||||
LIBSSH2_FREE(session, out);
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_ZLIB,
|
||||
"Excessive growth in decompression "
|
||||
"phase");
|
||||
}
|
||||
|
||||
if (grow_size > (int) (payload_limit - out_maxlen)) {
|
||||
grow_size = payload_limit - out_maxlen;
|
||||
}
|
||||
|
||||
out_maxlen += grow_size;
|
||||
strm->avail_out = grow_size;
|
||||
|
||||
newout = LIBSSH2_REALLOC(session, out, out_maxlen);
|
||||
if (!newout) {
|
||||
LIBSSH2_FREE(session, out);
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to expand final compress/"
|
||||
"decompress buffer");
|
||||
}
|
||||
out = newout;
|
||||
strm->next_out = (unsigned char *) out + out_maxlen -
|
||||
grow_size;
|
||||
|
||||
if (compress) {
|
||||
status = deflate(strm, Z_PARTIAL_FLUSH);
|
||||
} else {
|
||||
status = inflate(strm, Z_PARTIAL_FLUSH);
|
||||
}
|
||||
if (status != Z_OK) {
|
||||
LIBSSH2_FREE(session, out);
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_ZLIB,
|
||||
"compress/decompression failure");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*dest = (unsigned char *) out;
|
||||
*dest_len = out_maxlen - strm->avail_out;
|
||||
*free_dest = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -438,7 +355,7 @@ comp_method_zlib_decomp(LIBSSH2_SESSION * session,
|
||||
* All done, no more compression for you
|
||||
*/
|
||||
static int
|
||||
comp_method_zlib_dtor(LIBSSH2_SESSION * session, int compress,
|
||||
comp_method_zlib_dtor(LIBSSH2_SESSION *session, int compress,
|
||||
void **abstract)
|
||||
{
|
||||
z_stream *strm = *abstract;
|
||||
@ -470,10 +387,8 @@ static const LIBSSH2_COMP_METHOD comp_method_zlib = {
|
||||
};
|
||||
#endif /* LIBSSH2_HAVE_ZLIB */
|
||||
|
||||
/* ***********************
|
||||
* Compression Methods *
|
||||
*********************** */
|
||||
|
||||
/* If compression is enabled by the API, then this array is used which then
|
||||
may allow compression if zlib is available at build time */
|
||||
static const LIBSSH2_COMP_METHOD *comp_methods[] = {
|
||||
#ifdef LIBSSH2_HAVE_ZLIB
|
||||
&comp_method_zlib,
|
||||
@ -482,8 +397,17 @@ static const LIBSSH2_COMP_METHOD *comp_methods[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
/* If compression is disabled by the API, then this array is used */
|
||||
static const LIBSSH2_COMP_METHOD *no_comp_methods[] = {
|
||||
&comp_method_none,
|
||||
NULL
|
||||
};
|
||||
|
||||
const LIBSSH2_COMP_METHOD **
|
||||
_libssh2_comp_methods(void)
|
||||
_libssh2_comp_methods(LIBSSH2_SESSION *session)
|
||||
{
|
||||
return comp_methods;
|
||||
if(session->flag.compress)
|
||||
return comp_methods;
|
||||
else
|
||||
return no_comp_methods;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifndef __LIBSSH2_COMP_H
|
||||
#define __LIBSSH2_COMP_H
|
||||
|
||||
/* Copyright (C) 2009 by Daniel Stenberg
|
||||
/* Copyright (C) 2009-2010 by Daniel Stenberg
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
@ -40,6 +40,6 @@
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
|
||||
const LIBSSH2_COMP_METHOD **_libssh2_comp_methods(void);
|
||||
const LIBSSH2_COMP_METHOD **_libssh2_comp_methods(LIBSSH2_SESSION *session);
|
||||
|
||||
#endif /* __LIBSSH2_COMP_H */
|
||||
|
21
src/kex.c
21
src/kex.c
@ -1,4 +1,5 @@
|
||||
/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
|
||||
* Copyright (c) 2010, Daniel Stenberg <daniel@haxx.se>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@ -1043,10 +1044,10 @@ static int kexinit(LIBSSH2_SESSION * session)
|
||||
_libssh2_mac_methods());
|
||||
comp_cs_len =
|
||||
LIBSSH2_METHOD_PREFS_LEN(session->local.comp_prefs,
|
||||
_libssh2_comp_methods());
|
||||
_libssh2_comp_methods(session));
|
||||
comp_sc_len =
|
||||
LIBSSH2_METHOD_PREFS_LEN(session->remote.comp_prefs,
|
||||
_libssh2_comp_methods());
|
||||
_libssh2_comp_methods(session));
|
||||
lang_cs_len =
|
||||
LIBSSH2_METHOD_PREFS_LEN(session->local.lang_prefs, NULL);
|
||||
lang_sc_len =
|
||||
@ -1083,9 +1084,9 @@ static int kexinit(LIBSSH2_SESSION * session)
|
||||
LIBSSH2_METHOD_PREFS_STR(s, mac_sc_len, session->remote.mac_prefs,
|
||||
_libssh2_mac_methods());
|
||||
LIBSSH2_METHOD_PREFS_STR(s, comp_cs_len, session->local.comp_prefs,
|
||||
_libssh2_comp_methods());
|
||||
_libssh2_comp_methods(session));
|
||||
LIBSSH2_METHOD_PREFS_STR(s, comp_sc_len, session->remote.comp_prefs,
|
||||
_libssh2_comp_methods());
|
||||
_libssh2_comp_methods(session));
|
||||
LIBSSH2_METHOD_PREFS_STR(s, lang_cs_len, session->local.lang_prefs,
|
||||
NULL);
|
||||
LIBSSH2_METHOD_PREFS_STR(s, lang_sc_len, session->remote.lang_prefs,
|
||||
@ -1487,11 +1488,11 @@ static int kex_agree_mac(LIBSSH2_SESSION * session,
|
||||
/* kex_agree_comp
|
||||
* Agree on a compression scheme
|
||||
*/
|
||||
static int kex_agree_comp(LIBSSH2_SESSION * session,
|
||||
libssh2_endpoint_data * endpoint, unsigned char *comp,
|
||||
static int kex_agree_comp(LIBSSH2_SESSION *session,
|
||||
libssh2_endpoint_data *endpoint, unsigned char *comp,
|
||||
unsigned long comp_len)
|
||||
{
|
||||
const LIBSSH2_COMP_METHOD **compp = _libssh2_comp_methods();
|
||||
const LIBSSH2_COMP_METHOD **compp = _libssh2_comp_methods(session);
|
||||
unsigned char *s;
|
||||
(void) session;
|
||||
|
||||
@ -1827,12 +1828,14 @@ libssh2_session_method_pref(LIBSSH2_SESSION * session, int method_type,
|
||||
|
||||
case LIBSSH2_METHOD_COMP_CS:
|
||||
prefvar = &session->local.comp_prefs;
|
||||
mlist = (const LIBSSH2_COMMON_METHOD **) _libssh2_comp_methods();
|
||||
mlist = (const LIBSSH2_COMMON_METHOD **)
|
||||
_libssh2_comp_methods(session);
|
||||
break;
|
||||
|
||||
case LIBSSH2_METHOD_COMP_SC:
|
||||
prefvar = &session->remote.comp_prefs;
|
||||
mlist = (const LIBSSH2_COMMON_METHOD **) _libssh2_comp_methods();
|
||||
mlist = (const LIBSSH2_COMMON_METHOD **)
|
||||
_libssh2_comp_methods(session);
|
||||
break;
|
||||
|
||||
case LIBSSH2_METHOD_LANG_CS:
|
||||
|
@ -492,8 +492,8 @@ struct transportpacket
|
||||
are currently writing decrypted data */
|
||||
|
||||
/* ------------- for outgoing data --------------- */
|
||||
unsigned char *outbuf; /* pointer to a LIBSSH2_ALLOC() area for the
|
||||
outgoing data */
|
||||
unsigned char outbuf[MAX_SSH_PACKET_LEN]; /* area for the outgoing data */
|
||||
|
||||
int ototal_num; /* size of outbuf in number of bytes */
|
||||
unsigned char *odata; /* original pointer to the data we stored in
|
||||
outbuf */
|
||||
@ -1009,12 +1009,14 @@ struct _LIBSSH2_COMP_METHOD
|
||||
{
|
||||
const char *name;
|
||||
int compress; /* 1 if it does compress, 0 if it doesn't */
|
||||
int (*init) (LIBSSH2_SESSION * session, int compress, void **abstract);
|
||||
int (*comp) (LIBSSH2_SESSION * session, int compress, unsigned char **dest,
|
||||
size_t *dest_len, size_t payload_limit,
|
||||
int *free_dest, const unsigned char *src,
|
||||
size_t src_len, void **abstract);
|
||||
int (*decomp) (LIBSSH2_SESSION * session, int compress,
|
||||
int (*init) (LIBSSH2_SESSION *session, int compress, void **abstract);
|
||||
int (*comp) (LIBSSH2_SESSION *session,
|
||||
unsigned char *dest,
|
||||
size_t *dest_len,
|
||||
const unsigned char *src,
|
||||
size_t src_len,
|
||||
void **abstract);
|
||||
int (*decomp) (LIBSSH2_SESSION *session, int compress,
|
||||
unsigned char **dest,
|
||||
size_t *dest_len, size_t payload_limit,
|
||||
int *free_dest, const unsigned char *src,
|
||||
|
@ -980,11 +980,6 @@ session_free(LIBSSH2_SESSION *session)
|
||||
LIBSSH2_FREE(session, pkg);
|
||||
}
|
||||
|
||||
/* Cleanup remaining outgoing packet buffer */
|
||||
if (p->outbuf) {
|
||||
LIBSSH2_FREE(session, p->outbuf);
|
||||
}
|
||||
|
||||
if(session->socket_prev_blockstate)
|
||||
/* if the socket was previously blocking, put it back so */
|
||||
session_nonblock(session->socket_fd, 0);
|
||||
|
@ -200,13 +200,13 @@ fullpacket(LIBSSH2_SESSION * session, int encrypted /* 1 or 0 */ )
|
||||
size_t data_len;
|
||||
int free_payload = 1;
|
||||
|
||||
rc = session->remote.comp->comp(session, 0,
|
||||
&data, &data_len,
|
||||
LIBSSH2_PACKET_MAXDECOMP,
|
||||
&free_payload,
|
||||
p->payload,
|
||||
session->fullpacket_payload_len,
|
||||
&session->remote.comp_abstract);
|
||||
rc = session->remote.comp->decomp(session, 0,
|
||||
&data, &data_len,
|
||||
LIBSSH2_PACKET_MAXDECOMP,
|
||||
&free_payload,
|
||||
p->payload,
|
||||
session->fullpacket_payload_len,
|
||||
&session->remote.comp_abstract);
|
||||
if(rc) {
|
||||
LIBSSH2_FREE(session, p->payload);
|
||||
return rc;
|
||||
@ -605,7 +605,7 @@ send_existing(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
ssize_t length;
|
||||
struct transportpacket *p = &session->packet;
|
||||
|
||||
if (!p->outbuf) {
|
||||
if (!p->olen) {
|
||||
*ret = 0;
|
||||
return LIBSSH2_ERROR_NONE;
|
||||
}
|
||||
@ -642,8 +642,6 @@ send_existing(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
|
||||
if (rc == length) {
|
||||
/* the remainder of the package was sent */
|
||||
LIBSSH2_FREE(session, p->outbuf);
|
||||
p->outbuf = NULL;
|
||||
p->ototal_num = 0;
|
||||
}
|
||||
else if (rc < 0) {
|
||||
@ -673,10 +671,6 @@ send_existing(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
* then be called with the same argument set (same data pointer and same
|
||||
* data_len) until ERROR_NONE or failure is returned.
|
||||
*
|
||||
* NOTE: this function does not verify that 'data_len' is less than ~35000
|
||||
* which is what all implementations should support at least as packet size.
|
||||
* (RFC4253 section 6.1)
|
||||
*
|
||||
* This function DOES not call _libssh2_error() on any errors.
|
||||
*/
|
||||
int
|
||||
@ -689,7 +683,6 @@ _libssh2_transport_write(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
int padding_length;
|
||||
int packet_length;
|
||||
int total_length;
|
||||
int free_data = 0;
|
||||
#ifdef RANDOM_PADDING
|
||||
int rand_max;
|
||||
int seed = data[0]; /* FIXME: make this random */
|
||||
@ -702,6 +695,11 @@ _libssh2_transport_write(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
unsigned char *orgdata = data;
|
||||
size_t orgdata_len = data_len;
|
||||
|
||||
if(data_len >= MAX_SSH_PACKET_LEN)
|
||||
/* too large packet, return error for this until we make this function
|
||||
split it up and send multiple SSH packets */
|
||||
return LIBSSH2_ERROR_INVAL;
|
||||
|
||||
debugdump(session, "libssh2_transport_write plain", data, data_len);
|
||||
|
||||
/* FIRST, check if we have a pending write to complete */
|
||||
@ -717,15 +715,21 @@ _libssh2_transport_write(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
|
||||
encrypted = (session->state & LIBSSH2_STATE_NEWKEYS) ? 1 : 0;
|
||||
|
||||
/* check if we should compress */
|
||||
if (encrypted && session->local.comp->compress) {
|
||||
rc = session->local.comp->comp(session, 1, &data, &data_len,
|
||||
LIBSSH2_PACKET_MAXCOMP,
|
||||
&free_data, data, data_len,
|
||||
/* compress directly to the target buffer */
|
||||
rc = session->local.comp->comp(session,
|
||||
data, &data_len,
|
||||
&p->outbuf[5], MAX_SSH_PACKET_LEN-5,
|
||||
&session->local.comp_abstract);
|
||||
if(rc)
|
||||
return rc; /* compression failure */
|
||||
|
||||
data = p->outbuf;
|
||||
/* data_len is already updated by the compression function */
|
||||
}
|
||||
else
|
||||
/* copy the payload data */
|
||||
memcpy(&p->outbuf[5], data, data_len);
|
||||
|
||||
/* RFC4253 says: Note that the length of the concatenation of
|
||||
'packet_length', 'padding_length', 'payload', and 'random padding'
|
||||
@ -766,26 +770,14 @@ _libssh2_transport_write(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
total_length =
|
||||
packet_length + (encrypted ? session->local.mac->mac_len : 0);
|
||||
|
||||
/* allocate memory to store the outgoing packet in, in case we can't
|
||||
send the whole one and thus need to keep it after this function
|
||||
returns. */
|
||||
p->outbuf = LIBSSH2_ALLOC(session, total_length);
|
||||
if (!p->outbuf) {
|
||||
return LIBSSH2_ERROR_ALLOC;
|
||||
}
|
||||
|
||||
/* store packet_length, which is the size of the whole packet except
|
||||
the MAC and the packet_length field itself */
|
||||
_libssh2_htonu32(p->outbuf, packet_length - 4);
|
||||
/* store padding_length */
|
||||
p->outbuf[4] = padding_length;
|
||||
/* copy the payload data */
|
||||
memcpy(p->outbuf + 5, data, data_len);
|
||||
|
||||
/* fill the padding area with random junk */
|
||||
_libssh2_random(p->outbuf + 5 + data_len, padding_length);
|
||||
if (free_data) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
}
|
||||
|
||||
if (encrypted) {
|
||||
/* Calculate MAC hash. Put the output at index packet_length,
|
||||
@ -837,8 +829,6 @@ _libssh2_transport_write(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
/* the whole thing got sent away */
|
||||
p->odata = NULL;
|
||||
p->olen = 0;
|
||||
LIBSSH2_FREE(session, p->outbuf);
|
||||
p->outbuf = NULL;
|
||||
|
||||
return LIBSSH2_ERROR_NONE; /* all is good */
|
||||
}
|
||||
|
Загрузка…
Ссылка в новой задаче
Block a user