Fixed outoing packet queue handling bug on very high load.
[silc.git] / lib / silcutil / unix / silcunixsockconn.c
1 /*
2
3   silcunixsockconn.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2001 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 2 of the License, or
12   (at your option) any later version.
13   
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19 */
20 /* $Id$ */
21
22 #include "silcincludes.h"
23
24 /* Writes data from encrypted buffer to the socket connection. If the
25    data cannot be written at once, it will be written later with a timeout. 
26    The data is written from the data section of the buffer, not from head
27    or tail section. This automatically pulls the data section towards end
28    after writing the data. */
29
30 int silc_socket_write(SilcSocketConnection sock)
31 {
32   int ret = 0;
33   int fd = sock->sock;
34   SilcBuffer src = sock->outbuf;
35
36   if (SILC_IS_DISABLED(sock))
37     return -1;
38
39   SILC_LOG_DEBUG(("Writing data to socket %d", fd));
40
41   if (src->len > 0) {
42     ret = write(fd, src->data, src->len);
43     if (ret < 0) {
44       if (errno == EAGAIN) {
45         SILC_LOG_DEBUG(("Could not write immediately, will do it later"));
46         return -2;
47       }
48       SILC_LOG_DEBUG(("Cannot write to socket: %s", strerror(errno)));
49       sock->sock_error = errno;
50       return -1;
51     }
52
53     if (ret < src->len) {
54       SILC_LOG_DEBUG(("Wrote data %d of %d bytes, will write rest later",
55                       ret, src->len));
56       silc_buffer_pull(src, ret);
57       return -2;
58     }
59
60     silc_buffer_pull(src, ret);
61   }
62
63   SILC_LOG_DEBUG(("Wrote data %d bytes", ret));
64
65   return ret;
66 }
67
68 /* Reads data from the socket connection into the incoming data buffer.
69    It reads as much as possible from the socket connection. This returns
70    amount of bytes read or -1 on error or -2 on case where all of the
71    data could not be read at once. */
72
73 int silc_socket_read(SilcSocketConnection sock)
74 {
75   int len = 0;
76   unsigned char buf[SILC_SOCKET_READ_SIZE];
77   int fd = sock->sock;
78
79   if (SILC_IS_DISABLED(sock))
80     return -1;
81
82   SILC_LOG_DEBUG(("Reading data from socket %d", fd));
83
84   /* Read the data from the socket. */
85   len = read(fd, buf, sizeof(buf));
86   if (len < 0) {
87     if (errno == EAGAIN || errno == EINTR) {
88       SILC_LOG_DEBUG(("Could not read immediately, will do it later"));
89       return -2;
90     }
91     SILC_LOG_DEBUG(("Cannot read from socket: %d:%s", fd, strerror(errno)));
92     sock->sock_error = errno;
93     return -1;
94   }
95
96   if (!len)
97     return 0;
98
99   /* Insert the data to the buffer. */
100
101   if (!sock->inbuf)
102     sock->inbuf = silc_buffer_alloc(SILC_SOCKET_BUF_SIZE);
103   
104   /* If the data does not fit to the buffer reallocate it */
105   if ((sock->inbuf->end - sock->inbuf->tail) < len)
106     sock->inbuf = silc_buffer_realloc(sock->inbuf, sock->inbuf->truelen + 
107                                       (len * 2));
108   silc_buffer_put_tail(sock->inbuf, buf, len);
109   silc_buffer_pull_tail(sock->inbuf, len);
110
111   SILC_LOG_DEBUG(("Read %d bytes", len));
112
113   return len;
114 }
115
116 /* Returns human readable socket error message */
117
118 bool silc_socket_get_error(SilcSocketConnection sock, char *error,
119                            SilcUInt32 error_len)
120 {
121   char *err;
122
123   if (!sock->sock_error)
124     return FALSE;
125
126   err = strerror(sock->sock_error);
127   if (strlen(err) > error_len)
128     return FALSE;
129
130   memset(error, 0, error_len);
131   memcpy(error, err, strlen(err));
132   return TRUE;
133 }