updates.
[silc.git] / lib / silccore / silcpacket.c
index 9895fa25915b47b38ae7624109eb7eded3097284..ec26ab1dd8cd60f64a0c7dfc529a2b6e61e9bb25 100644 (file)
 
 ******************************************************************************/
 
-/* Writes data from encrypted buffer to the socket connection. If the
-   data cannot be written at once, it will be written later with a timeout. 
-   The data is written from the data section of the buffer, not from head
-   or tail section. This automatically pulls the data section towards end
-   after writing the data. */
-
-int silc_packet_write(int sock, SilcBuffer src)
-{
-  int ret = 0;
-
-  SILC_LOG_DEBUG(("Writing data to socket %d", sock));
-
-  if (src->len > 0) {
-    ret = write(sock, src->data, src->len);
-    if (ret < 0) {
-      if (errno == EAGAIN) {
-       SILC_LOG_DEBUG(("Could not write immediately, will do it later"));
-       return -2;
-      }
-      SILC_LOG_ERROR(("Cannot write to socket: %s", strerror(errno)));
-      return -1;
-    }
-
-    silc_buffer_pull(src, ret);
-  }
-
-  SILC_LOG_DEBUG(("Wrote data %d bytes", ret));
-
-  return ret;
-}
-
 /* Actually sends the packet. This flushes the connections outgoing data
    buffer. If data is sent directly to the network this returns the bytes
    written, if error occured this returns -1 and if the data could not
@@ -85,7 +54,7 @@ int silc_packet_send(SilcSocketConnection sock, int force_send)
     SILC_LOG_DEBUG(("Forcing packet send, packet sent immediately"));
 
     /* Write to network */
-    ret = silc_packet_write(sock->sock, sock->outbuf);
+    ret = silc_socket_write(sock);
 
     if (ret == -1) {
       SILC_LOG_ERROR(("Error sending packet, dropped"));
@@ -162,23 +131,23 @@ void silc_packet_encrypt(SilcCipher cipher, SilcHmac hmac,
 
    Packet construct is as follows (* = won't be encrypted):
 
-   x bytes       SILC Header
+   n bytes       SILC Header
       2 bytes     Payload length  (*)
       1 byte      Flags
       1 byte      Packet type
-      1 byte      Source ID Type
       2 bytes     Source ID Length
-      x bytes     Source ID
-      1 byte      Destination ID Type
       2 bytes     Destination ID Length
-      x bytes     Destination ID
+      1 byte      Source ID Type
+      n bytes     Source ID
+      1 byte      Destination ID Type
+      n bytes     Destination ID
 
    1 - 16 bytes    Padding
 
-   x bytes        Data payload
+   n bytes        Data payload
 
    All fields in the packet will be authenticated by MAC. The MAC is
-   not computed here, it must be computed differently before encrypting
+   not computed here, it must be computed separately before encrypting
    the packet.
 
 */
@@ -264,10 +233,12 @@ void silc_packet_send_prepare(SilcSocketConnection sock,
       /* There is some pending data in the buffer. */
 
       /* Allocate more space if needed */
-      if ((sock->outbuf->end - sock->outbuf->tail) < data_len) {
+      if ((sock->outbuf->end - sock->outbuf->tail) < 
+         (totlen + 20)) {
        SILC_LOG_DEBUG(("Reallocating outgoing data buffer"));
        sock->outbuf = silc_buffer_realloc(sock->outbuf, 
-                                          sock->outbuf->truelen + totlen);
+                                          sock->outbuf->truelen +
+                                          (totlen * 2));
       }
 
       oldlen = sock->outbuf->len;
@@ -276,6 +247,15 @@ void silc_packet_send_prepare(SilcSocketConnection sock,
     } else {
       /* Buffer is free for use */
       silc_buffer_clear(sock->outbuf);
+
+      /* Allocate more space if needed */
+      if ((sock->outbuf->end - sock->outbuf->tail) < (totlen + 20)) {
+       SILC_LOG_DEBUG(("Reallocating outgoing data buffer"));
+       sock->outbuf = silc_buffer_realloc(sock->outbuf, 
+                                          sock->outbuf->truelen + 
+                                          (totlen * 2));
+      }
+
       silc_buffer_pull_tail(sock->outbuf, totlen);
       silc_buffer_pull(sock->outbuf, header_len + padlen);
     }
@@ -288,76 +268,6 @@ void silc_packet_send_prepare(SilcSocketConnection sock,
 
 ******************************************************************************/
 
-/* Reads data from the socket connection into the incoming data buffer.
-   However, this does not parse the packet, it only reads some amount from
-   the network. If there are more data available that can be read at a time
-   the rest of the data will be read later with a timeout and only after
-   that the packet is ready to be parsed. 
-
-   The destination buffer sent as argument must be initialized before 
-   calling this function, and, the data section and the start of the tail
-   section must be same. Ie. we add the read data to the tail section of
-   the buffer hence the data section is the start of the buffer.
-
-   This returns amount of bytes read or -1 on error or -2 on case where
-   all of the data could not be read at once. */
-
-int silc_packet_read(int sock, SilcBuffer dest)
-{
-  int len = 0;
-  unsigned char buf[SILC_PACKET_READ_SIZE];
-
-  SILC_LOG_DEBUG(("Reading data from socket %d", sock));
-
-  /* Read the data from the socket. */
-  len = read(sock, buf, sizeof(buf));
-  if (len < 0) {
-    if (errno == EAGAIN || errno == EINTR) {
-      SILC_LOG_DEBUG(("Could not read immediately, will do it later"));
-      return -2;
-    }
-    SILC_LOG_ERROR(("Cannot read from socket: %d:%s", sock, strerror(errno)));
-    return -1;
-  }
-
-  if (!len)
-    return 0;
-
-  /* Insert the data to the buffer. If the data doesn't fit to the 
-     buffer space is allocated for the buffer. */
-  /* XXX: This may actually be bad thing as if there is pending data in
-     the buffer they will be lost! */
-  if (dest) {
-
-    /* If the data doesn't fit we just have to allocate a whole new 
-       data area */
-    if (dest->truelen <= len) {
-
-      /* Free the old buffer */
-      memset(dest->head, 'F', dest->truelen);
-      silc_free(dest->head);
-
-      /* Allocate new data area */
-      len += SILC_PACKET_DEFAULT_SIZE;
-      dest->data = silc_calloc(len, sizeof(char));
-      dest->truelen = len;
-      dest->len = 0;
-      dest->head = dest->data;
-      dest->data = dest->data;
-      dest->tail = dest->data;
-      dest->end = dest->data + dest->truelen;
-      len -= SILC_PACKET_DEFAULT_SIZE;
-    }
-
-    silc_buffer_put_tail(dest, buf, len);
-    silc_buffer_pull_tail(dest, len);
-  }
-
-  SILC_LOG_DEBUG(("Read %d bytes", len));
-
-  return len;
-}
-
 /* Processes the received data. This checks the received data and 
    calls parser callback that handles the actual packet decryption
    and parsing. If more than one packet was received this calls the
@@ -403,8 +313,6 @@ void silc_packet_receive_process(SilcSocketConnection sock,
     parse_ctx->packet = silc_packet_context_alloc();
     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, 
@@ -450,12 +358,8 @@ int silc_packet_receive(SilcSocketConnection sock)
                   sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
                   "Router")));
 
-  /* Allocate the incoming data buffer if not done already. */
-  if (!sock->inbuf)
-    sock->inbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE);
-
   /* Read some data from connection */
-  ret = silc_packet_read(sock->sock, sock->inbuf);
+  ret = silc_socket_read(sock);
 
   return ret;
 }
@@ -478,7 +382,7 @@ static int silc_packet_check_mac(SilcHmac hmac, SilcBuffer buffer)
 
     /* Compare the HMAC's (buffer->tail has the packet's HMAC) */
     if (memcmp(mac, buffer->tail, mac_len)) {
-      SILC_LOG_DEBUG(("MAC failed"));
+      SILC_LOG_ERROR(("MAC failed"));
       return FALSE;
     }
     
@@ -559,6 +463,12 @@ static int silc_packet_decrypt_rest_special(SilcCipher cipher,
     len1 = (truelen + padlen) - (SILC_PACKET_MIN_HEADER_LEN - 2);
 
     silc_buffer_pull(buffer, SILC_PACKET_MIN_HEADER_LEN - 2);
+    if (len1 - 2 > buffer->len) {
+      SILC_LOG_DEBUG(("Garbage in header of packet, bad packet length, "
+                     "packet dropped"));
+      return FALSE;
+    }
+
     cipher->cipher->decrypt(cipher->context, buffer->data + 2,
                            buffer->data + 2, len1 - 2,
                            cipher->iv);
@@ -607,7 +517,7 @@ int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
 
     /* Check MAC */
     if (!silc_packet_check_mac(hmac, buffer))
-      return FALSE;
+      return -1;
 
     return 0;
   } else {
@@ -618,7 +528,7 @@ int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
 
     /* Check MAC */
     if (!silc_packet_check_mac(hmac, buffer))
-      return FALSE;
+      return -1;
 
     return 1;
   }
@@ -761,7 +671,7 @@ SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx)
 
 /* Allocate packet context */
 
-SilcPacketContext *silc_packet_context_alloc()
+SilcPacketContext *silc_packet_context_alloc(void)
 {
   SilcPacketContext *ctx = silc_calloc(1, sizeof(*ctx));
   ctx->users++;