1
1

_libssh2_transport_write: remade to send without malloc

Этот коммит содержится в:
Daniel Stenberg 2010-10-21 21:00:28 +02:00
родитель 3a391f6cf2
Коммит 5ede32a826
6 изменённых файлов: 102 добавлений и 188 удалений

Просмотреть файл

@ -53,7 +53,30 @@
* Minimalist compression: Absolutely none * Minimalist compression: Absolutely none
*/ */
static int 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, int compress,
unsigned char **dest, unsigned char **dest,
size_t *dest_len, size_t *dest_len,
@ -81,7 +104,7 @@ static const LIBSSH2_COMP_METHOD comp_method_none = {
0, /* not really compressing */ 0, /* not really compressing */
NULL, NULL,
comp_method_none_comp, comp_method_none_comp,
comp_method_none_comp, comp_method_none_decomp,
NULL NULL
}; };
@ -154,141 +177,35 @@ comp_method_zlib_init(LIBSSH2_SESSION * session, int compress,
/* /*
* libssh2_comp_method_zlib_comp * libssh2_comp_method_zlib_comp
* *
* Compresses source to destination. Without any allocation. * Compresses source to destination. Without allocation.
*/ */
static int static int
comp_method_zlib_comp(LIBSSH2_SESSION * session, comp_method_zlib_comp(LIBSSH2_SESSION *session,
int compress, unsigned char *dest,
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 *dest_len,
size_t payload_limit,
int *free_dest,
const unsigned char *src, const unsigned char *src,
size_t src_len, void **abstract) size_t src_len,
void **abstract)
{ {
z_stream *strm = *abstract; z_stream *strm = *abstract;
/* A short-term alloc of a full data chunk is better than a series of int out_maxlen = *dest_len;
reallocs */ int status;
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;
}
strm->next_in = (unsigned char *) src; strm->next_in = (unsigned char *) src;
strm->avail_in = src_len; strm->avail_in = src_len;
strm->next_out = (unsigned char *) LIBSSH2_ALLOC(session, out_maxlen); strm->next_out = dest;
out = (char *) strm->next_out;
strm->avail_out = out_maxlen; 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);
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;
out_maxlen += if (status != Z_OK)
compress ? (strm->avail_in + 4) : (2 * strm->avail_in); 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; *dest_len = out_maxlen - strm->avail_out;
*free_dest = 1;
return 0; return 0;
} }
@ -438,7 +355,7 @@ comp_method_zlib_decomp(LIBSSH2_SESSION * session,
* All done, no more compression for you * All done, no more compression for you
*/ */
static int static int
comp_method_zlib_dtor(LIBSSH2_SESSION * session, int compress, comp_method_zlib_dtor(LIBSSH2_SESSION *session, int compress,
void **abstract) void **abstract)
{ {
z_stream *strm = *abstract; z_stream *strm = *abstract;
@ -470,10 +387,8 @@ static const LIBSSH2_COMP_METHOD comp_method_zlib = {
}; };
#endif /* LIBSSH2_HAVE_ZLIB */ #endif /* LIBSSH2_HAVE_ZLIB */
/* *********************** /* If compression is enabled by the API, then this array is used which then
* Compression Methods * may allow compression if zlib is available at build time */
*********************** */
static const LIBSSH2_COMP_METHOD *comp_methods[] = { static const LIBSSH2_COMP_METHOD *comp_methods[] = {
#ifdef LIBSSH2_HAVE_ZLIB #ifdef LIBSSH2_HAVE_ZLIB
&comp_method_zlib, &comp_method_zlib,
@ -482,8 +397,17 @@ static const LIBSSH2_COMP_METHOD *comp_methods[] = {
NULL 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 ** 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 #ifndef __LIBSSH2_COMP_H
#define __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, * Redistribution and use in source and binary forms,
* with or without modification, are permitted provided * with or without modification, are permitted provided
@ -40,6 +40,6 @@
#include "libssh2_priv.h" #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 */ #endif /* __LIBSSH2_COMP_H */

Просмотреть файл

@ -1,4 +1,5 @@
/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org> /* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
* Copyright (c) 2010, Daniel Stenberg <daniel@haxx.se>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, * Redistribution and use in source and binary forms,
@ -1043,10 +1044,10 @@ static int kexinit(LIBSSH2_SESSION * session)
_libssh2_mac_methods()); _libssh2_mac_methods());
comp_cs_len = comp_cs_len =
LIBSSH2_METHOD_PREFS_LEN(session->local.comp_prefs, LIBSSH2_METHOD_PREFS_LEN(session->local.comp_prefs,
_libssh2_comp_methods()); _libssh2_comp_methods(session));
comp_sc_len = comp_sc_len =
LIBSSH2_METHOD_PREFS_LEN(session->remote.comp_prefs, LIBSSH2_METHOD_PREFS_LEN(session->remote.comp_prefs,
_libssh2_comp_methods()); _libssh2_comp_methods(session));
lang_cs_len = lang_cs_len =
LIBSSH2_METHOD_PREFS_LEN(session->local.lang_prefs, NULL); LIBSSH2_METHOD_PREFS_LEN(session->local.lang_prefs, NULL);
lang_sc_len = 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_METHOD_PREFS_STR(s, mac_sc_len, session->remote.mac_prefs,
_libssh2_mac_methods()); _libssh2_mac_methods());
LIBSSH2_METHOD_PREFS_STR(s, comp_cs_len, session->local.comp_prefs, 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_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, LIBSSH2_METHOD_PREFS_STR(s, lang_cs_len, session->local.lang_prefs,
NULL); NULL);
LIBSSH2_METHOD_PREFS_STR(s, lang_sc_len, session->remote.lang_prefs, 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 /* kex_agree_comp
* Agree on a compression scheme * Agree on a compression scheme
*/ */
static int kex_agree_comp(LIBSSH2_SESSION * session, static int kex_agree_comp(LIBSSH2_SESSION *session,
libssh2_endpoint_data * endpoint, unsigned char *comp, libssh2_endpoint_data *endpoint, unsigned char *comp,
unsigned long comp_len) unsigned long comp_len)
{ {
const LIBSSH2_COMP_METHOD **compp = _libssh2_comp_methods(); const LIBSSH2_COMP_METHOD **compp = _libssh2_comp_methods(session);
unsigned char *s; unsigned char *s;
(void) session; (void) session;
@ -1827,12 +1828,14 @@ libssh2_session_method_pref(LIBSSH2_SESSION * session, int method_type,
case LIBSSH2_METHOD_COMP_CS: case LIBSSH2_METHOD_COMP_CS:
prefvar = &session->local.comp_prefs; prefvar = &session->local.comp_prefs;
mlist = (const LIBSSH2_COMMON_METHOD **) _libssh2_comp_methods(); mlist = (const LIBSSH2_COMMON_METHOD **)
_libssh2_comp_methods(session);
break; break;
case LIBSSH2_METHOD_COMP_SC: case LIBSSH2_METHOD_COMP_SC:
prefvar = &session->remote.comp_prefs; prefvar = &session->remote.comp_prefs;
mlist = (const LIBSSH2_COMMON_METHOD **) _libssh2_comp_methods(); mlist = (const LIBSSH2_COMMON_METHOD **)
_libssh2_comp_methods(session);
break; break;
case LIBSSH2_METHOD_LANG_CS: case LIBSSH2_METHOD_LANG_CS:

Просмотреть файл

@ -492,8 +492,8 @@ struct transportpacket
are currently writing decrypted data */ are currently writing decrypted data */
/* ------------- for outgoing data --------------- */ /* ------------- for outgoing data --------------- */
unsigned char *outbuf; /* pointer to a LIBSSH2_ALLOC() area for the unsigned char outbuf[MAX_SSH_PACKET_LEN]; /* area for the outgoing data */
outgoing data */
int ototal_num; /* size of outbuf in number of bytes */ int ototal_num; /* size of outbuf in number of bytes */
unsigned char *odata; /* original pointer to the data we stored in unsigned char *odata; /* original pointer to the data we stored in
outbuf */ outbuf */
@ -1009,12 +1009,14 @@ struct _LIBSSH2_COMP_METHOD
{ {
const char *name; const char *name;
int compress; /* 1 if it does compress, 0 if it doesn't */ int compress; /* 1 if it does compress, 0 if it doesn't */
int (*init) (LIBSSH2_SESSION * session, int compress, void **abstract); int (*init) (LIBSSH2_SESSION *session, int compress, void **abstract);
int (*comp) (LIBSSH2_SESSION * session, int compress, unsigned char **dest, int (*comp) (LIBSSH2_SESSION *session,
size_t *dest_len, size_t payload_limit, unsigned char *dest,
int *free_dest, const unsigned char *src, size_t *dest_len,
size_t src_len, void **abstract); const unsigned char *src,
int (*decomp) (LIBSSH2_SESSION * session, int compress, size_t src_len,
void **abstract);
int (*decomp) (LIBSSH2_SESSION *session, int compress,
unsigned char **dest, unsigned char **dest,
size_t *dest_len, size_t payload_limit, size_t *dest_len, size_t payload_limit,
int *free_dest, const unsigned char *src, int *free_dest, const unsigned char *src,

Просмотреть файл

@ -980,11 +980,6 @@ session_free(LIBSSH2_SESSION *session)
LIBSSH2_FREE(session, pkg); LIBSSH2_FREE(session, pkg);
} }
/* Cleanup remaining outgoing packet buffer */
if (p->outbuf) {
LIBSSH2_FREE(session, p->outbuf);
}
if(session->socket_prev_blockstate) if(session->socket_prev_blockstate)
/* if the socket was previously blocking, put it back so */ /* if the socket was previously blocking, put it back so */
session_nonblock(session->socket_fd, 0); session_nonblock(session->socket_fd, 0);

Просмотреть файл

@ -200,13 +200,13 @@ fullpacket(LIBSSH2_SESSION * session, int encrypted /* 1 or 0 */ )
size_t data_len; size_t data_len;
int free_payload = 1; int free_payload = 1;
rc = session->remote.comp->comp(session, 0, rc = session->remote.comp->decomp(session, 0,
&data, &data_len, &data, &data_len,
LIBSSH2_PACKET_MAXDECOMP, LIBSSH2_PACKET_MAXDECOMP,
&free_payload, &free_payload,
p->payload, p->payload,
session->fullpacket_payload_len, session->fullpacket_payload_len,
&session->remote.comp_abstract); &session->remote.comp_abstract);
if(rc) { if(rc) {
LIBSSH2_FREE(session, p->payload); LIBSSH2_FREE(session, p->payload);
return rc; return rc;
@ -605,7 +605,7 @@ send_existing(LIBSSH2_SESSION * session, unsigned char *data,
ssize_t length; ssize_t length;
struct transportpacket *p = &session->packet; struct transportpacket *p = &session->packet;
if (!p->outbuf) { if (!p->olen) {
*ret = 0; *ret = 0;
return LIBSSH2_ERROR_NONE; return LIBSSH2_ERROR_NONE;
} }
@ -642,8 +642,6 @@ send_existing(LIBSSH2_SESSION * session, unsigned char *data,
if (rc == length) { if (rc == length) {
/* the remainder of the package was sent */ /* the remainder of the package was sent */
LIBSSH2_FREE(session, p->outbuf);
p->outbuf = NULL;
p->ototal_num = 0; p->ototal_num = 0;
} }
else if (rc < 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 * then be called with the same argument set (same data pointer and same
* data_len) until ERROR_NONE or failure is returned. * 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. * This function DOES not call _libssh2_error() on any errors.
*/ */
int int
@ -689,7 +683,6 @@ _libssh2_transport_write(LIBSSH2_SESSION * session, unsigned char *data,
int padding_length; int padding_length;
int packet_length; int packet_length;
int total_length; int total_length;
int free_data = 0;
#ifdef RANDOM_PADDING #ifdef RANDOM_PADDING
int rand_max; int rand_max;
int seed = data[0]; /* FIXME: make this random */ 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; unsigned char *orgdata = data;
size_t orgdata_len = data_len; 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); debugdump(session, "libssh2_transport_write plain", data, data_len);
/* FIRST, check if we have a pending write to complete */ /* 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; encrypted = (session->state & LIBSSH2_STATE_NEWKEYS) ? 1 : 0;
/* check if we should compress */
if (encrypted && session->local.comp->compress) { if (encrypted && session->local.comp->compress) {
rc = session->local.comp->comp(session, 1, &data, &data_len, /* compress directly to the target buffer */
LIBSSH2_PACKET_MAXCOMP, rc = session->local.comp->comp(session,
&free_data, data, data_len, data, &data_len,
&p->outbuf[5], MAX_SSH_PACKET_LEN-5,
&session->local.comp_abstract); &session->local.comp_abstract);
if(rc) if(rc)
return rc; /* compression failure */ 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 /* RFC4253 says: Note that the length of the concatenation of
'packet_length', 'padding_length', 'payload', and 'random padding' 'packet_length', 'padding_length', 'payload', and 'random padding'
@ -766,26 +770,14 @@ _libssh2_transport_write(LIBSSH2_SESSION * session, unsigned char *data,
total_length = total_length =
packet_length + (encrypted ? session->local.mac->mac_len : 0); 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 /* store packet_length, which is the size of the whole packet except
the MAC and the packet_length field itself */ the MAC and the packet_length field itself */
_libssh2_htonu32(p->outbuf, packet_length - 4); _libssh2_htonu32(p->outbuf, packet_length - 4);
/* store padding_length */ /* store padding_length */
p->outbuf[4] = 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 */ /* fill the padding area with random junk */
_libssh2_random(p->outbuf + 5 + data_len, padding_length); _libssh2_random(p->outbuf + 5 + data_len, padding_length);
if (free_data) {
LIBSSH2_FREE(session, data);
}
if (encrypted) { if (encrypted) {
/* Calculate MAC hash. Put the output at index packet_length, /* 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 */ /* the whole thing got sent away */
p->odata = NULL; p->odata = NULL;
p->olen = 0; p->olen = 0;
LIBSSH2_FREE(session, p->outbuf);
p->outbuf = NULL;
return LIBSSH2_ERROR_NONE; /* all is good */ return LIBSSH2_ERROR_NONE; /* all is good */
} }