Fixed UDP transport handling.
authorPekka Riikonen <priikone@silcnet.org>
Wed, 6 Dec 2006 18:36:58 +0000 (18:36 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Wed, 6 Dec 2006 18:36:58 +0000 (18:36 +0000)
lib/silccore/silcpacket.c
lib/silccore/silcpacket.h

index 05ca279d86bd42b83a182422bf7af8812f7d78f2..e2bf31258f997f8cfe85df825dba98a6e1d59c0e 100644 (file)
@@ -151,10 +151,24 @@ do {                                                                      \
                                (s)->stream_context);                   \
 } while(0)
 
+static void silc_packet_dispatch(SilcPacket packet);
+static void silc_packet_read_process(SilcPacketStream stream);
 
 /************************ Static utility functions **************************/
 
-static void silc_packet_read_process(SilcPacketStream stream);
+/* Injects packet to new stream created with silc_packet_stream_add_remote. */
+
+SILC_TASK_CALLBACK(silc_packet_stream_inject_packet)
+{
+  SilcPacket packet = context;
+  SilcPacketStream stream = packet->stream;
+
+  SILC_LOG_DEBUG(("Injecting packet %p to stream %p", packet, packet->stream));
+
+  silc_mutex_lock(stream->lock);
+  silc_packet_dispatch(packet);
+  silc_mutex_unlock(stream->lock);
+}
 
 /* Write data to the stream.  Must be called with ps->lock locked.  Unlocks
    the lock inside this function. */
@@ -328,6 +342,7 @@ static inline SilcBool silc_packet_stream_read(SilcPacketStream ps,
       }
 
       /* Save sender IP and port */
+      silc_free(ps->remote_udp->remote_ip);
       ps->remote_udp->remote_ip = strdup(remote_ip);
       ps->remote_udp->remote_port = remote_port;
 
@@ -611,7 +626,8 @@ SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine,
 
 SilcPacketStream silc_packet_stream_add_remote(SilcPacketStream stream,
                                               const char *remote_ip,
-                                              SilcUInt16 remote_port)
+                                              SilcUInt16 remote_port,
+                                              SilcPacket packet)
 {
   SilcPacketEngine engine = stream->engine;
   SilcPacketStream ps;
@@ -688,6 +704,14 @@ SilcPacketStream silc_packet_stream_add_remote(SilcPacketStream stream,
     return NULL;
   }
 
+  if (packet) {
+    /* Inject packet to the new stream */
+    packet->stream = ps;
+    silc_schedule_task_add_timeout(silc_stream_get_schedule(stream->stream),
+                                  silc_packet_stream_inject_packet, packet,
+                                  0, 0);
+  }
+
   return ps;
 }
 
@@ -888,15 +912,15 @@ void silc_packet_stream_unlink(SilcPacketStream stream,
 
 /* Return packet sender IP and port for UDP packet stream */
 
-SilcBool silc_packet_stream_get_sender(SilcPacketStream stream,
-                                      const char **sender_ip,
-                                      SilcUInt16 *sender_port)
+SilcBool silc_packet_get_sender(SilcPacket packet,
+                               const char **sender_ip,
+                               SilcUInt16 *sender_port)
 {
-  if (!stream->remote_udp)
+  if (!packet->stream->remote_udp)
     return FALSE;
 
-  *sender_ip = stream->remote_udp->remote_ip;
-  *sender_port = stream->remote_udp->remote_port;
+  *sender_ip = packet->stream->remote_udp->remote_ip;
+  *sender_port = packet->stream->remote_udp->remote_port;
 
   return TRUE;
 }
@@ -1439,12 +1463,12 @@ SilcBool silc_packet_send_va_ext(SilcPacketStream stream,
 
 /* Checks MAC in the packet. Returns TRUE if MAC is Ok. */
 
-static SilcBool silc_packet_check_mac(SilcHmac hmac,
-                                     const unsigned char *data,
-                                     SilcUInt32 data_len,
-                                     const unsigned char *packet_mac,
-                                     const unsigned char *packet_seq,
-                                     SilcUInt32 sequence)
+static inline SilcBool silc_packet_check_mac(SilcHmac hmac,
+                                            const unsigned char *data,
+                                            SilcUInt32 data_len,
+                                            const unsigned char *packet_mac,
+                                            const unsigned char *packet_seq,
+                                            SilcUInt32 sequence)
 {
   /* Check MAC */
   if (hmac) {
@@ -1480,9 +1504,9 @@ static SilcBool silc_packet_check_mac(SilcHmac hmac,
 /* Decrypts SILC packet.  Handles both normal and special packet decryption.
    Return 0 when packet is normal and 1 when it it special, -1 on error. */
 
-static int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
-                              SilcUInt32 sequence, SilcBuffer buffer,
-                              SilcBool normal)
+static inline int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
+                                     SilcUInt32 sequence, SilcBuffer buffer,
+                                     SilcBool normal)
 {
   if (normal == TRUE) {
     if (cipher) {
@@ -1528,7 +1552,7 @@ static int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
    parsed. The buffer sent must be already decrypted before calling this
    function. */
 
-static SilcBool silc_packet_parse(SilcPacket packet)
+static inline SilcBool silc_packet_parse(SilcPacket packet)
 {
   SilcBuffer buffer = &packet->buffer;
   SilcUInt8 padlen = (SilcUInt8)buffer->data[4];
@@ -1546,14 +1570,18 @@ static SilcBool silc_packet_parse(SilcPacket packet)
                             SILC_STR_UI_CHAR(&src_id_type),
                             SILC_STR_END);
   if (ret == -1) {
-    SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
+    if (!packet->stream->udp &&
+       !silc_socket_stream_is_udp(packet->stream->stream, NULL))
+      SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
     return FALSE;
   }
 
   if (src_id_len > SILC_PACKET_MAX_ID_LEN ||
       dst_id_len > SILC_PACKET_MAX_ID_LEN) {
-    SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
-                   packet->src_id_len, packet->dst_id_len));
+    if (!packet->stream->udp &&
+       !silc_socket_stream_is_udp(packet->stream->stream, NULL))
+      SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
+                     packet->src_id_len, packet->dst_id_len));
     return FALSE;
   }
 
@@ -1565,14 +1593,18 @@ static SilcBool silc_packet_parse(SilcPacket packet)
                             SILC_STR_OFFSET(padlen),
                             SILC_STR_END);
   if (ret == -1) {
-    SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
+    if (!packet->stream->udp &&
+       !silc_socket_stream_is_udp(packet->stream->stream, NULL))
+      SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
     return FALSE;
   }
 
   if (src_id_type > SILC_ID_CHANNEL ||
       dst_id_type > SILC_ID_CHANNEL) {
-    SILC_LOG_ERROR(("Bad ID types in packet (%d and %d)",
-                   src_id_type, dst_id_type));
+    if (!packet->stream->udp &&
+       !silc_socket_stream_is_udp(packet->stream->stream, NULL))
+      SILC_LOG_ERROR(("Bad ID types in packet (%d and %d)",
+                     src_id_type, dst_id_type));
     return FALSE;
   }
 
@@ -1600,15 +1632,6 @@ static void silc_packet_dispatch(SilcPacket packet)
   SilcBool default_sent = FALSE;
   SilcPacketType *pt;
 
-  /* Parse the packet */
-  if (!silc_packet_parse(packet)) {
-    silc_mutex_unlock(stream->lock);
-    SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
-    silc_mutex_lock(stream->lock);
-    silc_packet_free(packet);
-    return;
-  }
-
   /* Dispatch packet to all packet processors that want it */
 
   if (!stream->process) {
@@ -1779,7 +1802,8 @@ static void silc_packet_read_process(SilcPacketStream stream)
 
     /* Sanity checks */
     if (packetlen < SILC_PACKET_MIN_LEN) {
-      SILC_LOG_ERROR(("Received too short packet"));
+      if (!stream->udp && !silc_socket_stream_is_udp(stream->stream, NULL))
+       SILC_LOG_ERROR(("Received too short packet"));
       silc_mutex_unlock(stream->lock);
       SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
       silc_mutex_lock(stream->lock);
@@ -1888,6 +1912,16 @@ static void silc_packet_read_process(SilcPacketStream stream)
     /* Pull the packet from inbuf thus we'll get the next one in the inbuf. */
     silc_buffer_pull(&stream->inbuf, paddedlen + mac_len);
 
+    /* Parse the packet */
+    if (!silc_packet_parse(packet)) {
+      silc_mutex_unlock(stream->lock);
+      SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
+      silc_mutex_lock(stream->lock);
+      silc_packet_free(packet);
+      memset(tmp, 0, sizeof(tmp));
+      return;
+    }
+
     /* Dispatch the packet to application */
     silc_packet_dispatch(packet);
   }
index 86f7a7642f83f23b01f0ba60797458d696bca595..dfc659004a9237b5b218173c9eb79a3bbccebf9a 100644 (file)
@@ -406,13 +406,14 @@ SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine,
                                           SilcSchedule schedule,
                                           SilcStream stream);
 
-/****f* silccore/SilcPacketAPI/silc_packet_stream_shared_create
+/****f* silccore/SilcPacketAPI/silc_packet_stream_add_remote
  *
  * SYNOPSIS
  *
  *    SilcPacketStream silc_packet_stream_add_remote(SilcPacketStream stream,
  *                                                   const char *remote_ip,
- *                                                   SilcUInt16 remote_port);
+ *                                                   SilcUInt16 remote_port,
+ *                                                   SilcPacket packet);
  *
  * DESCRIPTION
  *
@@ -427,9 +428,13 @@ SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine,
  *    and port that does not have its own remote packet stream, it returns
  *    the packet to the packet callback set for `stream'.  The sender's
  *    IP address and port can then be retrieved by using the
- *    silc_packet_stream_get_sender function and to create new packet
- *    stream by calling this function.  After that, all packets from that
- *    IP address and port will be received by the new packet stream.
+ *    silc_packet_get_sender function and to create new packet stream by
+ *    calling this function.  After that, all packets from that IP address
+ *    and port will be received by the new packet stream.
+ *
+ *    If the `packet' is non-NULL it will be injected into the new packet
+ *    stream as soon as the scheduler associated with `stream' schedules
+ *    new tasks.  It can be used to inject an incoming packet to the stream.
  *
  *    This interface is for connectionless UDP streams.  If it is possible
  *    to create connected stream it should be done for performance reasons.
@@ -442,15 +447,16 @@ SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine,
  *
  *    ...
  *    // Received a packet to the parent stream, get the sender information.
- *    silc_packet_stream_get_sender(parent, &ip, &port);
+ *    silc_packet_get_sender(packet, &ip, &port);
  *
  *    // Create new packet stream for this remote location.
- *    remote = silc_packet_stream_set_remote(parent, ip, port);
+ *    remote = silc_packet_stream_add_remote(parent, ip, port, packet);
  *
  ***/
 SilcPacketStream silc_packet_stream_add_remote(SilcPacketStream stream,
                                               const char *remote_ip,
-                                              SilcUInt16 remote_port);
+                                              SilcUInt16 remote_port,
+                                              SilcPacket packet);
 
 /****f* silccore/SilcPacketAPI/silc_packet_stream_destroy
  *
@@ -606,25 +612,25 @@ void silc_packet_stream_unlink(SilcPacketStream stream,
                               SilcPacketCallbacks *callbacks,
                               void *callback_context);
 
-/****f* silccore/SilcPacketAPI/silc_packet_stream_get_sender
+/****f* silccore/SilcPacketAPI/silc_packet_get_sender
  *
  * SYNOPSIS
  *
- *    SilcBool silc_packet_stream_get_sender(SilcPacketStream stream,
- *                                           const char **sender_ip,
- *                                           SilcUInt16 *sender_port);
+ *    SilcBool silc_packet_get_sender(SilcPacket packet,
+ *                                    const char **sender_ip,
+ *                                    SilcUInt16 *sender_port);
  *
  * DESCRIPTION
  *
- *    Returns the packet sender's IP address and port from UDP packet stream
- *    indicated by `stream'.  This can be called only from the packet
+ *    Returns the packet sender's IP address and port from UDP packet
+ *    indicated by `packet'.  This can be called only from the packet
  *    callback to retrieve the information of the packet's sender.  Returns
  *    FALSE if the information is not available.
  *
  ***/
-SilcBool silc_packet_stream_get_sender(SilcPacketStream stream,
-                                      const char **sender_ip,
-                                      SilcUInt16 *sender_port);
+SilcBool silc_packet_get_sender(SilcPacket packet,
+                               const char **sender_ip,
+                               SilcUInt16 *sender_port);
 
 /****f* silccore/SilcPacketAPI/silc_packet_stream_ref
  *