A LOT updates. Cannot separate. :)
[silc.git] / lib / silccore / silcpacket.c
index 25e1d694f10d7daa7701a94be8b0c8c445ac70c9..63f179aea402b2d441648286fad2151b35121cf2 100644 (file)
 /*
  * Created: Fri Jul 25 18:52:14 1997
  */
-/*
- * $Id$
- * $Log$
- * Revision 1.3  2000/07/14 06:10:15  priikone
- *     Moved all the generic packet sending, enryption, reception,
- *     decryption and processing function from client and server to
- *     here as they were duplicated code in the applications. Now they
- *     are generic code over generic API. Some functions were rewritter;
- *     packet reception and HMAC computation and checking is now more
- *     optimized.
- *
- * Revision 1.2  2000/07/05 06:06:35  priikone
- *     Global cosmetic change.
- *
- * Revision 1.1.1.1  2000/06/27 11:36:55  priikone
- *     Imported from internal CVS/Added Log headers.
- *
- *
- */
+/* $Id$ */
 
 #include "silcincludes.h"
 
@@ -98,8 +80,9 @@ int silc_packet_send(SilcSocketConnection sock, int force_send)
     /* Write to network */
     ret = silc_packet_write(sock->sock, sock->outbuf);
 
-    if (ret == -1)
+    if (ret == -1) {
       SILC_LOG_ERROR(("Error sending packet, dropped"));
+    }
     if (ret != -2)
       return ret;
 
@@ -324,7 +307,7 @@ int silc_packet_read(int sock, SilcBuffer dest)
   /* Read the data from the socket. */
   len = read(sock, buf, sizeof(buf));
   if (len < 0) {
-    if (errno == EAGAIN) {
+    if (errno == EAGAIN || errno == EINTR) {
       SILC_LOG_DEBUG(("Could not read immediately, will do it later"));
       return -2;
     }
@@ -375,97 +358,71 @@ int silc_packet_read(int sock, SilcBuffer dest)
    and parsing. If more than one packet was received this calls the
    parser multiple times. The parser callback will get context
    SilcPacketParserContext that includes the packet and the `context'
-   sent to this function. Returns TRUE on success and FALSE on error. */
+   sent to this function. */
 
-int silc_packet_receive_process(SilcSocketConnection sock, 
-                               SilcCipher cipher, SilcHmac hmac,
-                               SilcPacketParserCallback parser, 
-                               void *context)
+void silc_packet_receive_process(SilcSocketConnection sock,
+                                SilcCipher cipher, SilcHmac hmac,
+                                SilcPacketParserCallback parser,
+                                void *context)
 {
   SilcPacketParserContext *parse_ctx;
-  int packetlen, paddedlen, mac_len = 0;
-
-  /* Check whether we received a whole packet. If reading went without
-     errors we either read a whole packet or the read packet is 
-     incorrect and will be dropped. */
-  SILC_PACKET_LENGTH(sock->inbuf, packetlen, paddedlen);
-  if (sock->inbuf->len < paddedlen || (packetlen < SILC_PACKET_MIN_LEN)) {
-    SILC_LOG_DEBUG(("Received incorrect packet, dropped"));
-    silc_buffer_clear(sock->inbuf);
-    return FALSE;
-  }
+  int packetlen, paddedlen, count, mac_len = 0;
 
-  /* Parse the packets from the data */
-  if (sock->inbuf->len - 2 > (paddedlen + mac_len)) {
-    /* Received possibly many packets at once */
+  /* We need at least 2 bytes of data to be able to start processing
+     the packet. */
+  if (sock->inbuf->len < 2)
+    return;
 
-    if (hmac)
-      mac_len = hmac->hash->hash->hash_len;
-
-    while(sock->inbuf->len > 0) {
-      SILC_PACKET_LENGTH(sock->inbuf, packetlen, paddedlen);
-
-      if (sock->inbuf->len < paddedlen) {
-       SILC_LOG_DEBUG(("Received incorrect packet, dropped"));
-       return FALSE;
-      }
+  if (hmac)
+    mac_len = hmac->hash->hash->hash_len;
 
-      paddedlen += 2;
-      parse_ctx = silc_calloc(1, sizeof(*parse_ctx));
-      parse_ctx->packet = silc_calloc(1, sizeof(*parse_ctx->packet));
-      parse_ctx->packet->buffer = silc_buffer_alloc(paddedlen + mac_len);
-      parse_ctx->sock = sock;
-      parse_ctx->cipher = cipher;
-      parse_ctx->hmac = hmac;
-      parse_ctx->context = context;
-
-      silc_buffer_pull_tail(parse_ctx->packet->buffer, 
-                           SILC_BUFFER_END(parse_ctx->packet->buffer));
-      silc_buffer_put(parse_ctx->packet->buffer, sock->inbuf->data, 
-                     paddedlen + mac_len);
-
-      SILC_LOG_HEXDUMP(("Incoming packet, len %d", 
-                       parse_ctx->packet->buffer->len),
-                      parse_ctx->packet->buffer->data, 
-                      parse_ctx->packet->buffer->len);
-
-      /* Call the parser */
-      if (parser)
-       (*parser)(parse_ctx);
-
-      /* Pull the packet from inbuf thus we'll get the next one
-        in the inbuf. */
-      silc_buffer_pull(sock->inbuf, paddedlen);
-      if (hmac)
-       silc_buffer_pull(sock->inbuf, mac_len);
+  /* Parse the packets from the data */
+  count = 0;
+  while (sock->inbuf->len > 0) {
+    SILC_PACKET_LENGTH(sock->inbuf, packetlen, paddedlen);
+    paddedlen += 2;
+    count++;
+
+    if (packetlen < SILC_PACKET_MIN_LEN) {
+      SILC_LOG_DEBUG(("Received invalid packet, dropped"));
+      return;
     }
 
-    /* All packets are processed, return successfully. */
-    silc_buffer_clear(sock->inbuf);
-    return TRUE;
-
-  } else {
-    /* Received one packet */
-    
-    SILC_LOG_HEXDUMP(("An incoming packet, len %d", sock->inbuf->len),
-                    sock->inbuf->data, sock->inbuf->len);
+    if (sock->inbuf->len < paddedlen + mac_len) {
+      SILC_LOG_DEBUG(("Received partial packet, waiting for the rest"));
+      return;
+    }
 
     parse_ctx = silc_calloc(1, sizeof(*parse_ctx));
     parse_ctx->packet = silc_calloc(1, sizeof(*parse_ctx->packet));
-    parse_ctx->packet->buffer = silc_buffer_copy(sock->inbuf);
+    parse_ctx->packet->buffer = silc_buffer_alloc(paddedlen + mac_len);
     parse_ctx->sock = sock;
     parse_ctx->cipher = cipher;
     parse_ctx->hmac = hmac;
     parse_ctx->context = context;
-    silc_buffer_clear(sock->inbuf);
+
+    silc_buffer_pull_tail(parse_ctx->packet->buffer, 
+                         SILC_BUFFER_END(parse_ctx->packet->buffer));
+    silc_buffer_put(parse_ctx->packet->buffer, sock->inbuf->data, 
+                   paddedlen + mac_len);
+
+    SILC_LOG_HEXDUMP(("Incoming packet, len %d", 
+                     parse_ctx->packet->buffer->len),
+                    parse_ctx->packet->buffer->data, 
+                    parse_ctx->packet->buffer->len);
 
     /* Call the parser */
     if (parser)
       (*parser)(parse_ctx);
 
-    /* Return successfully */
-    return TRUE;
+    /* Pull the packet from inbuf thus we'll get the next one
+       in the inbuf. */
+    silc_buffer_pull(sock->inbuf, paddedlen);
+    if (hmac)
+      silc_buffer_pull(sock->inbuf, mac_len);
   }
+
+  silc_buffer_clear(sock->inbuf);
 }
 
 /* Receives packet from network and reads the data into connection's
@@ -487,8 +444,9 @@ int silc_packet_receive(SilcSocketConnection sock)
   ret = silc_packet_read(sock->sock, sock->inbuf);
 
   /* Error */
-  if (ret == -1)
+  if (ret == -1) {
     SILC_LOG_ERROR(("Error reading packet, dropped"));
+  }
 
   return ret;
 }
@@ -774,3 +732,37 @@ SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx)
 
   return ctx->type;
 }
+
+/* Duplicates packet context. Duplicates the entire context and its
+   contents. */
+
+SilcPacketContext *silc_packet_context_dup(SilcPacketContext *ctx)
+{
+  SilcPacketContext *new;
+
+  new = silc_calloc(1, sizeof(*new));
+  new->buffer = silc_buffer_copy(ctx->buffer);
+  new->type = ctx->type;
+  new->flags = ctx->flags;
+
+  new->src_id = silc_calloc(ctx->src_id_len, sizeof(*new->src_id));
+  memcpy(new->src_id, ctx->src_id, ctx->src_id_len);
+  new->src_id_len = ctx->src_id_len;
+  new->src_id_type = ctx->src_id_type;
+
+  new->dst_id = silc_calloc(ctx->dst_id_len, sizeof(*new->dst_id));
+  memcpy(new->dst_id, ctx->dst_id, ctx->dst_id_len);
+  new->dst_id_len = ctx->dst_id_len;
+  new->dst_id_type = ctx->dst_id_type;
+
+  new->truelen = ctx->truelen;
+  new->padlen = ctx->padlen;
+
+  new->rng = ctx->rng;
+  new->context = ctx->context;
+  new->sock = ctx->sock;
+
+  return new;
+}
+
+