typedef struct {
SilcSchedule schedule; /* The scheduler */
SilcPacketEngine engine; /* Packet engine */
- SilcBufferStruct inbuf; /* Data input buffer */
+ SilcDList inbufs; /* Data inbut buffer list */
SilcUInt32 stream_count; /* Number of streams using this */
} *SilcPacketEngineContext;
SilcPacketRemoteUDP remote_udp; /* UDP remote stream tuple, or NULL */
void *stream_context; /* Stream context */
SilcBufferStruct outbuf; /* Out buffer */
+ SilcBuffer inbuf; /* Inbuf from inbuf list or NULL */
SilcCipher send_key[2]; /* Sending key */
SilcHmac send_hmac[2]; /* Sending HMAC */
SilcCipher receive_key[2]; /* Receiving key */
static inline SilcBool silc_packet_stream_read(SilcPacketStream ps,
SilcPacketStream *ret_ps)
{
- SilcStream stream;
+ SilcStream stream = ps->stream;
SilcBuffer inbuf;
SilcBool connected;
int ret;
- stream = ps->stream;
- inbuf = &ps->sc->inbuf;
+ /* Get inbuf. If there is already some data for this stream in the buffer
+ we already have it. Otherwise get the current one from list, it will
+ include the data. */
+ inbuf = ps->inbuf;
+ if (!inbuf) {
+ silc_dlist_start(ps->sc->inbufs);
+ inbuf = silc_dlist_get(ps->sc->inbufs);
+ if (!inbuf) {
+ /* Allocate new data input buffer */
+ inbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE * 31);
+ if (!inbuf) {
+ silc_mutex_unlock(ps->lock);
+ return FALSE;
+ }
+ silc_buffer_reset(inbuf);
+ silc_dlist_add(ps->sc->inbufs, inbuf);
+ }
+ }
/* Make sure there is enough room to read */
if (SILC_PACKET_DEFAULT_SIZE * 2 > silc_buffer_taillen(inbuf))
void *user_context)
{
SilcPacketEngineContext sc = context;
- silc_buffer_clear(&sc->inbuf);
- silc_buffer_purge(&sc->inbuf);
+ SilcBuffer buffer;
+
+ silc_dlist_start(sc->inbufs);
+ while ((buffer = silc_dlist_get(sc->inbufs))) {
+ silc_buffer_clear(buffer);
+ silc_buffer_free(buffer);
+ silc_dlist_del(sc->inbufs, buffer);
+ }
+
+ silc_dlist_uninit(sc->inbufs);
silc_free(sc);
}
SilcStream stream)
{
SilcPacketStream ps;
+ SilcBuffer inbuf;
void *tmp;
SILC_LOG_DEBUG(("Creating new packet stream"));
ps->sc->schedule = schedule;
/* Allocate data input buffer */
- tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE * 31);
- if (!tmp) {
+ inbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE * 31);
+ if (!inbuf) {
silc_free(ps->sc);
ps->sc = NULL;
silc_packet_stream_destroy(ps);
silc_mutex_unlock(engine->lock);
return NULL;
}
- silc_buffer_set(&ps->sc->inbuf, tmp, SILC_PACKET_DEFAULT_SIZE * 31);
- silc_buffer_reset(&ps->sc->inbuf);
+ silc_buffer_reset(inbuf);
+
+ ps->sc->inbufs = silc_dlist_init();
+ if (!ps->sc->inbufs) {
+ silc_buffer_free(inbuf);
+ silc_free(ps->sc);
+ ps->sc = NULL;
+ silc_packet_stream_destroy(ps);
+ silc_mutex_unlock(engine->lock);
+ return NULL;
+ }
+ silc_dlist_add(ps->sc->inbufs, inbuf);
/* Add to per scheduler context hash table */
if (!silc_hash_table_add(engine->contexts, schedule, ps->sc)) {
- silc_buffer_purge(&ps->sc->inbuf);
+ silc_buffer_free(inbuf);
+ silc_dlist_del(ps->sc->inbufs, inbuf);
silc_free(ps->sc);
ps->sc = NULL;
silc_packet_stream_destroy(ps);
static void silc_packet_read_process(SilcPacketStream stream)
{
- SilcBuffer inbuf = &stream->sc->inbuf;
+ SilcBuffer inbuf;
SilcCipher cipher;
SilcHmac hmac;
SilcPacket packet;
SilcBool normal;
int ret;
+ /* Get inbuf. If there is already some data for this stream in the buffer
+ we already have it. Otherwise get the current one from list, it will
+ include the data. */
+ inbuf = stream->inbuf;
+ if (!inbuf) {
+ silc_dlist_start(stream->sc->inbufs);
+ inbuf = silc_dlist_get(stream->sc->inbufs);
+ }
+
/* Parse the packets from the data */
while (silc_buffer_len(inbuf) > 0) {
ivlen = psnlen = 0;
(stream->iv_included ? SILC_PACKET_MIN_HEADER_LEN_IV :
SILC_PACKET_MIN_HEADER_LEN))) {
SILC_LOG_DEBUG(("Partial packet in queue, waiting for the rest"));
+ silc_dlist_del(stream->sc->inbufs, inbuf);
+ stream->inbuf = inbuf;
return;
}
silc_mutex_unlock(stream->lock);
SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_UNKNOWN_SID);
silc_mutex_lock(stream->lock);
- silc_buffer_reset(inbuf);
- return;
+ goto out;
}
}
} else {
SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
silc_mutex_lock(stream->lock);
memset(tmp, 0, sizeof(tmp));
- silc_buffer_reset(inbuf);
- return;
+ goto out;
}
if (silc_buffer_len(inbuf) < paddedlen + ivlen + mac_len) {
"(%d bytes)",
paddedlen + mac_len - silc_buffer_len(inbuf)));
memset(tmp, 0, sizeof(tmp));
+ silc_dlist_del(stream->sc->inbufs, inbuf);
+ stream->inbuf = inbuf;
return;
}
SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MAC_FAILED);
silc_mutex_lock(stream->lock);
memset(tmp, 0, sizeof(tmp));
- silc_buffer_reset(inbuf);
- return;
+ goto out;
}
/* Get packet */
SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
silc_mutex_lock(stream->lock);
memset(tmp, 0, sizeof(tmp));
- silc_buffer_reset(inbuf);
- return;
+ goto out;
}
packet->stream = stream;
silc_mutex_lock(stream->lock);
silc_packet_free(packet);
memset(tmp, 0, sizeof(tmp));
- silc_buffer_reset(inbuf);
- return;
+ goto out;
}
}
silc_mutex_lock(stream->lock);
silc_packet_free(packet);
memset(tmp, 0, sizeof(tmp));
- return;
+ goto out;
}
stream->receive_psn++;
silc_mutex_lock(stream->lock);
silc_packet_free(packet);
memset(tmp, 0, sizeof(tmp));
- return;
+ goto out;
}
/* Dispatch the packet to application */
break;
}
+ out:
+ /* Add inbuf back to free list, if we owned it. */
+ if (stream->inbuf) {
+ silc_dlist_add(stream->sc->inbufs, inbuf);
+ stream->inbuf = NULL;
+ }
+
silc_buffer_reset(inbuf);
}