Packet streams: avoid double free if silc_id_id2str fails.
[silc.git] / lib / silccore / silcpacket.c
index bea6357939731b0db4ba92ed16cda2cab5e83e9d..614dc894650ce0e334051a508d1c052cef6e0d44 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2007 Pekka Riikonen
+  Copyright (C) 1997 - 2008 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -336,7 +336,6 @@ static inline SilcBool silc_packet_stream_read(SilcPacketStream ps,
        silc_mutex_unlock(ps->lock);
        if (ret == -1) {
          /* Cannot read now, do it later. */
-         silc_buffer_pull(inbuf, silc_buffer_len(inbuf));
          return FALSE;
        }
 
@@ -394,7 +393,6 @@ static inline SilcBool silc_packet_stream_read(SilcPacketStream ps,
 
     if (ret == -1) {
       /* Cannot read now, do it later. */
-      silc_buffer_pull(inbuf, silc_buffer_len(inbuf));
       return FALSE;
     }
 
@@ -623,7 +621,7 @@ void silc_packet_engine_stop(SilcPacketEngine engine)
   silc_free(engine);
 }
 
-static const char *packet_error[] = {
+static const char * const packet_error[] = {
   "Cannot read from stream",
   "Cannot write to stream",
   "Packet MAC failed",
@@ -723,8 +721,8 @@ SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine,
                            (void *)&ps->sc)) {
     ps->sc = silc_calloc(1, sizeof(*ps->sc));
     if (!ps->sc) {
-      silc_packet_stream_destroy(ps);
       silc_mutex_unlock(engine->lock);
+      silc_packet_stream_destroy(ps);
       return NULL;
     }
     ps->sc->engine = engine;
@@ -735,8 +733,8 @@ SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine,
     if (!inbuf) {
       silc_free(ps->sc);
       ps->sc = NULL;
-      silc_packet_stream_destroy(ps);
       silc_mutex_unlock(engine->lock);
+      silc_packet_stream_destroy(ps);
       return NULL;
     }
     silc_buffer_reset(inbuf);
@@ -746,8 +744,8 @@ SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine,
       silc_buffer_free(inbuf);
       silc_free(ps->sc);
       ps->sc = NULL;
-      silc_packet_stream_destroy(ps);
       silc_mutex_unlock(engine->lock);
+      silc_packet_stream_destroy(ps);
       return NULL;
     }
     silc_dlist_add(ps->sc->inbufs, inbuf);
@@ -758,8 +756,8 @@ SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine,
       silc_dlist_del(ps->sc->inbufs, inbuf);
       silc_free(ps->sc);
       ps->sc = NULL;
-      silc_packet_stream_destroy(ps);
       silc_mutex_unlock(engine->lock);
+      silc_packet_stream_destroy(ps);
       return NULL;
     }
   }
@@ -887,6 +885,8 @@ void silc_packet_stream_destroy(SilcPacketStream stream)
     return;
 
   if (silc_atomic_sub_int8(&stream->refcnt, 1) > 0) {
+    if (stream->destroyed)
+      return;
     stream->destroyed = TRUE;
 
     SILC_LOG_DEBUG(("Marking packet stream %p destroyed", stream));
@@ -901,17 +901,18 @@ void silc_packet_stream_destroy(SilcPacketStream stream)
 
   if (!stream->udp) {
     /* Delete from engine */
-    engine = stream->sc->engine;
-    silc_mutex_lock(engine->lock);
-    silc_list_del(engine->streams, stream);
-
-    /* Remove per scheduler context, if it is not used anymore */
     if (stream->sc) {
+      engine = stream->sc->engine;
+      silc_mutex_lock(engine->lock);
+      silc_list_del(engine->streams, stream);
+
+      /* Remove per scheduler context, if it is not used anymore */
       stream->sc->stream_count--;
       if (!stream->sc->stream_count)
        silc_hash_table_del(engine->contexts, stream->sc->schedule);
+
+      silc_mutex_unlock(engine->lock);
     }
-    silc_mutex_unlock(engine->lock);
 
     /* Destroy the underlaying stream */
     if (stream->stream)
@@ -1029,6 +1030,7 @@ static SilcBool silc_packet_stream_link_va(SilcPacketStream stream,
     stream->process = silc_dlist_init();
     if (!stream->process) {
       silc_mutex_unlock(stream->lock);
+      silc_free(p);
       return FALSE;
     }
   }
@@ -1332,6 +1334,7 @@ SilcBool silc_packet_set_ids(SilcPacketStream stream,
     SILC_LOG_DEBUG(("Setting source ID to packet stream %p", stream));
 
     silc_free(stream->src_id);
+    stream->src_id = NULL;
     if (!silc_id_id2str(src_id, src_id_type, tmp, sizeof(tmp), &len)) {
       silc_mutex_unlock(stream->lock);
       return FALSE;
@@ -1349,6 +1352,7 @@ SilcBool silc_packet_set_ids(SilcPacketStream stream,
     SILC_LOG_DEBUG(("Setting destination ID to packet stream %p", stream));
 
     silc_free(stream->dst_id);
+    stream->dst_id = NULL;
     if (!silc_id_id2str(dst_id, dst_id_type, tmp, sizeof(tmp), &len)) {
       silc_mutex_unlock(stream->lock);
       return FALSE;