Merge commit 'origin/silc.1.1.branch'
[silc.git] / lib / silccore / silcpacket.c
index d03f0d8526afe25af61c55af203c050631f2c060..26f721f56f0d34448725a4c7a1e43673702e1429 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
@@ -40,7 +40,7 @@ struct SilcPacketEngineStruct {
   SilcMutex lock;                       /* Engine lock */
   SilcRng rng;                          /* RNG for engine */
   SilcHashTable contexts;               /* Per scheduler contexts */
-  SilcPacketCallbacks *callbacks;       /* Packet callbacks */
+  const SilcPacketCallbacks *callbacks;         /* Packet callbacks */
   void *callback_context;               /* Context for callbacks */
   SilcList streams;                     /* All streams in engine */
   SilcList packet_pool;                 /* Free list for received packets */
@@ -51,7 +51,7 @@ struct SilcPacketEngineStruct {
 /* Packet processor context */
 typedef struct SilcPacketProcessStruct {
   SilcPacketType *types;                /* Packets to process */
-  SilcPacketCallbacks *callbacks;       /* Callbacks or NULL */
+  const SilcPacketCallbacks *callbacks;         /* Callbacks or NULL */
   void *callback_context;
   SilcInt32 priority;                   /* Priority */
 } *SilcPacketProcess;
@@ -81,7 +81,7 @@ struct SilcPacketStreamStruct {
   unsigned char *dst_id;                /* Destination ID */
   SilcUInt32 send_psn;                  /* Sending sequence */
   SilcUInt32 receive_psn;               /* Receiving sequence */
-  SilcAtomic8 refcnt;                   /* Reference counter */
+  SilcAtomic32 refcnt;                  /* Reference counter */
   SilcUInt8 sid;                        /* Security ID, set if IV included */
   unsigned int src_id_len  : 6;
   unsigned int src_id_type : 2;
@@ -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;
     }
 
@@ -542,7 +540,7 @@ static void silc_packet_engine_context_destr(void *key, void *context,
 
 SilcPacketEngine
 silc_packet_engine_start(SilcRng rng, SilcBool router,
-                        SilcPacketCallbacks *callbacks,
+                        const SilcPacketCallbacks *callbacks,
                         void *callback_context)
 {
   SilcPacketEngine engine;
@@ -561,7 +559,8 @@ silc_packet_engine_start(SilcRng rng, SilcBool router,
   if (!engine)
     return NULL;
 
-  engine->contexts = silc_hash_table_alloc(0, silc_hash_ptr, NULL, NULL, NULL,
+  engine->contexts = silc_hash_table_alloc(NULL, 0, silc_hash_ptr,
+                                          NULL, NULL, NULL,
                                           silc_packet_engine_context_destr,
                                           engine, TRUE);
   if (!engine->contexts) {
@@ -623,7 +622,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",
@@ -697,7 +696,7 @@ SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine,
     return NULL;
 
   ps->stream = stream;
-  silc_atomic_init8(&ps->refcnt, 1);
+  silc_atomic_init32(&ps->refcnt, 1);
   silc_mutex_alloc(&ps->lock);
 
   /* Allocate out buffer */
@@ -723,8 +722,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 +734,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 +745,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 +757,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;
     }
   }
@@ -770,10 +769,10 @@ SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine,
 
   /* If this is UDP stream, allocate UDP remote stream hash table */
   if (!engine->udp_remote && silc_socket_stream_is_udp(stream, NULL))
-    engine->udp_remote = silc_hash_table_alloc(0, silc_hash_string, NULL,
-                                              silc_hash_string_compare, NULL,
-                                              silc_packet_engine_hash_destr,
-                                              NULL, TRUE);
+    engine->udp_remote =
+      silc_hash_table_alloc(NULL, 0, silc_hash_string_case, NULL,
+                           silc_hash_string_case_compare, NULL,
+                           silc_packet_engine_hash_destr, NULL, TRUE);
 
   silc_mutex_unlock(engine->lock);
 
@@ -818,7 +817,7 @@ SilcPacketStream silc_packet_stream_add_remote(SilcPacketStream stream,
     return NULL;
   ps->sc = stream->sc;
 
-  silc_atomic_init8(&ps->refcnt, 1);
+  silc_atomic_init32(&ps->refcnt, 1);
   silc_mutex_alloc(&ps->lock);
 
   /* Set the UDP packet stream as underlaying stream */
@@ -886,7 +885,9 @@ void silc_packet_stream_destroy(SilcPacketStream stream)
   if (!stream)
     return;
 
-  if (silc_atomic_sub_int8(&stream->refcnt, 1) > 0) {
+  if (silc_atomic_sub_int32(&stream->refcnt, 1) > 0) {
+    if (stream->destroyed)
+      return;
     stream->destroyed = TRUE;
 
     SILC_LOG_DEBUG(("Marking packet stream %p destroyed", stream));
@@ -901,17 +902,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)
@@ -971,7 +973,7 @@ void silc_packet_stream_destroy(SilcPacketStream stream)
   silc_free(stream->src_id);
   silc_free(stream->dst_id);
 
-  silc_atomic_uninit8(&stream->refcnt);
+  silc_atomic_uninit32(&stream->refcnt);
   silc_mutex_free(stream->lock);
   silc_free(stream);
 }
@@ -1000,7 +1002,7 @@ void silc_packet_stream_set_iv_included(SilcPacketStream stream)
 /* Links `callbacks' to `stream' for specified packet types */
 
 static SilcBool silc_packet_stream_link_va(SilcPacketStream stream,
-                                          SilcPacketCallbacks *callbacks,
+                                          const SilcPacketCallbacks *callbacks,
                                           void *callback_context,
                                           int priority, va_list ap)
 {
@@ -1029,6 +1031,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;
     }
   }
@@ -1078,7 +1081,7 @@ static SilcBool silc_packet_stream_link_va(SilcPacketStream stream,
 /* Links `callbacks' to `stream' for specified packet types */
 
 SilcBool silc_packet_stream_link(SilcPacketStream stream,
-                                SilcPacketCallbacks *callbacks,
+                                const SilcPacketCallbacks *callbacks,
                                 void *callback_context,
                                 int priority, ...)
 {
@@ -1096,7 +1099,7 @@ SilcBool silc_packet_stream_link(SilcPacketStream stream,
 /* Unlinks `callbacks' from `stream'. */
 
 void silc_packet_stream_unlink(SilcPacketStream stream,
-                              SilcPacketCallbacks *callbacks,
+                              const SilcPacketCallbacks *callbacks,
                               void *callback_context)
 {
   SilcPacketProcess p;
@@ -1152,10 +1155,10 @@ SilcBool silc_packet_get_sender(SilcPacket packet,
 
 void silc_packet_stream_ref(SilcPacketStream stream)
 {
-  silc_atomic_add_int8(&stream->refcnt, 1);
+  silc_atomic_add_int32(&stream->refcnt, 1);
   SILC_LOG_DEBUG(("Stream %p, refcnt %d->%d", stream,
-                 silc_atomic_get_int8(&stream->refcnt) - 1,
-                 silc_atomic_get_int8(&stream->refcnt)));
+                 silc_atomic_get_int32(&stream->refcnt) - 1,
+                 silc_atomic_get_int32(&stream->refcnt)));
 }
 
 /* Unreference packet stream */
@@ -1163,11 +1166,11 @@ void silc_packet_stream_ref(SilcPacketStream stream)
 void silc_packet_stream_unref(SilcPacketStream stream)
 {
   SILC_LOG_DEBUG(("Stream %p, refcnt %d->%d", stream,
-                 silc_atomic_get_int8(&stream->refcnt),
-                 silc_atomic_get_int8(&stream->refcnt) - 1));
-  if (silc_atomic_sub_int8(&stream->refcnt, 1) > 0)
+                 silc_atomic_get_int32(&stream->refcnt),
+                 silc_atomic_get_int32(&stream->refcnt) - 1));
+  if (silc_atomic_sub_int32(&stream->refcnt, 1) > 0)
     return;
-  silc_atomic_add_int8(&stream->refcnt, 1);
+  silc_atomic_add_int32(&stream->refcnt, 1);
   silc_packet_stream_destroy(stream);
 }
 
@@ -1322,6 +1325,7 @@ SilcBool silc_packet_set_ids(SilcPacketStream stream,
 {
   SilcUInt32 len;
   unsigned char tmp[32];
+  void *tmp_id;
 
   if (!src_id && !dst_id)
     return FALSE;
@@ -1331,16 +1335,17 @@ SilcBool silc_packet_set_ids(SilcPacketStream stream,
   if (src_id) {
     SILC_LOG_DEBUG(("Setting source ID to packet stream %p", stream));
 
-    silc_free(stream->src_id);
     if (!silc_id_id2str(src_id, src_id_type, tmp, sizeof(tmp), &len)) {
       silc_mutex_unlock(stream->lock);
       return FALSE;
     }
-    stream->src_id = silc_memdup(tmp, len);
-    if (!stream->src_id) {
+    tmp_id = silc_memdup(tmp, len);
+    if (!tmp_id) {
       silc_mutex_unlock(stream->lock);
       return FALSE;
     }
+    silc_free(stream->src_id);
+    stream->src_id = tmp_id;
     stream->src_id_type = src_id_type;
     stream->src_id_len = len;
   }
@@ -1348,16 +1353,17 @@ SilcBool silc_packet_set_ids(SilcPacketStream stream,
   if (dst_id) {
     SILC_LOG_DEBUG(("Setting destination ID to packet stream %p", stream));
 
-    silc_free(stream->dst_id);
     if (!silc_id_id2str(dst_id, dst_id_type, tmp, sizeof(tmp), &len)) {
       silc_mutex_unlock(stream->lock);
       return FALSE;
     }
-    stream->dst_id = silc_memdup(tmp, len);
-    if (!stream->dst_id) {
+    tmp_id = silc_memdup(tmp, len);
+    if (!tmp_id) {
       silc_mutex_unlock(stream->lock);
       return FALSE;
     }
+    silc_free(stream->dst_id);
+    stream->dst_id = tmp_id;
     stream->dst_id_type = dst_id_type;
     stream->dst_id_len = len;
   }
@@ -1471,14 +1477,6 @@ static inline void silc_packet_send_ctr_increment(SilcPacketStream stream,
   unsigned char *iv = silc_cipher_get_iv(cipher);
   SilcUInt32 pc1, pc2;
 
-  /* Increment 64-bit packet counter */
-  SILC_GET32_MSB(pc1, iv + 4);
-  SILC_GET32_MSB(pc2, iv + 8);
-  if (++pc2 == 0)
-    ++pc1;
-  SILC_PUT32_MSB(pc1, iv + 4);
-  SILC_PUT32_MSB(pc2, iv + 8);
-
   /* Reset block counter */
   memset(iv + 12, 0, 4);
 
@@ -1489,17 +1487,30 @@ static inline void silc_packet_send_ctr_increment(SilcPacketStream stream,
     ret_iv[1] = ret_iv[0] + iv[4];
     ret_iv[2] = ret_iv[0] ^ ret_iv[1];
     ret_iv[3] = ret_iv[0] + ret_iv[2];
-    SILC_PUT32_MSB(pc2, ret_iv + 4);
+
+    /* Increment 32-bit packet counter */
+    SILC_GET32_MSB(pc1, iv + 8);
+    pc1++;
+    SILC_PUT32_MSB(pc1, ret_iv + 4);
+
     SILC_LOG_HEXDUMP(("IV"), ret_iv, 8);
 
-    /* Set new nonce to counter block */
-    memcpy(iv + 4, ret_iv, 4);
+    /* Set new IV to counter block */
+    memcpy(iv + 4, ret_iv, 8);
+  } else {
+    /* Increment 64-bit packet counter */
+    SILC_GET32_MSB(pc1, iv + 4);
+    SILC_GET32_MSB(pc2, iv + 8);
+    if (++pc2 == 0)
+      ++pc1;
+    SILC_PUT32_MSB(pc1, iv + 4);
+    SILC_PUT32_MSB(pc2, iv + 8);
   }
 
   SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
 }
 
-/* Internal routine to assemble outgoing packet.  Assembles and encryptes
+/* Internal routine to assemble outgoing packet.  Assembles and encrypts
    the packet.  The silc_packet_stream_write needs to be called to send it
    after this returns TRUE. */
 
@@ -1608,6 +1619,12 @@ static inline SilcBool silc_packet_send_raw(SilcPacketStream stream,
 
   silc_mutex_lock(stream->lock);
 
+  if (silc_unlikely(stream->destroyed)) {
+    SILC_LOG_DEBUG(("Stream %p is destroyed, cannot send packet", stream));
+    silc_mutex_unlock(stream->lock);
+    return FALSE;
+  }
+
   /* Get packet pointer from the outgoing buffer */
   if (silc_unlikely(!silc_packet_send_prepare(stream, truelen + padlen + ivlen
                                              + psnlen, hmac, &packet))) {
@@ -2334,7 +2351,7 @@ silc_packet_wait_packet_receive(SilcPacketEngine engine,
                                void *stream_context);
 
 /* Packet waiting callbacks */
-static SilcPacketCallbacks silc_packet_wait_cbs =
+static const SilcPacketCallbacks silc_packet_wait_cbs =
 {
   silc_packet_wait_packet_receive, NULL, NULL
 };
@@ -2523,7 +2540,7 @@ typedef struct {
 } *SilcPacketWrapperStream;
 
 /* Packet wrapper callbacks */
-static SilcPacketCallbacks silc_packet_wrap_cbs =
+static const SilcPacketCallbacks silc_packet_wrap_cbs =
 {
   silc_packet_wrap_packet_receive, NULL, NULL
 };