5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2001 Pekka Riikonen
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.
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.
22 #include "silcincludes.h"
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. */
30 int silc_socket_write(SilcSocketConnection sock)
34 SilcBuffer src = sock->outbuf;
38 if (SILC_IS_DISABLED(sock))
41 SILC_LOG_DEBUG(("Writing data to socket %d", fd));
44 ret = write(fd, src->data, src->len);
46 if (errno == EAGAIN || errno == EINTR) {
47 SILC_LOG_DEBUG(("Could not write immediately, will do it later"));
50 SILC_LOG_DEBUG(("Cannot write to socket: %s", strerror(errno)));
51 sock->sock_error = errno;
56 SILC_LOG_DEBUG(("Wrote data %d of %d bytes, will write rest later",
58 silc_buffer_pull(src, ret);
62 silc_buffer_pull(src, ret);
65 SILC_LOG_DEBUG(("Wrote data %d bytes", ret));
70 /* QoS read handler, this will call the read and write events to indicate
71 that data is available again after a timeout. */
73 SILC_TASK_CALLBACK(silc_socket_read_qos)
75 SilcSocketConnection sock = context;
76 sock->qos->applied = TRUE;
78 silc_schedule_set_listen_fd(sock->qos->schedule, sock->sock,
79 (SILC_TASK_READ | SILC_TASK_WRITE), TRUE);
80 sock->qos->applied = FALSE;
81 silc_socket_free(sock);
84 /* Reads data from the socket connection into the incoming data buffer.
85 It reads as much as possible from the socket connection. This returns
86 amount of bytes read or -1 on error or -2 on case where all of the
87 data could not be read at once. */
89 int silc_socket_read(SilcSocketConnection sock)
92 unsigned char buf[SILC_SOCKET_READ_SIZE];
95 if (SILC_IS_DISABLED(sock))
98 /* If QoS was applied to socket then return earlier read data but apply
99 QoS to it too, if necessary. */
101 if (sock->qos->applied) {
102 if (sock->qos->data_len) {
103 /* Pull hidden data since we have it from earlier QoS apply */
104 silc_buffer_pull_tail(sock->inbuf, sock->qos->data_len);
105 len = sock->qos->data_len;
106 sock->qos->data_len = 0;
109 if (sock->inbuf->len - len > sock->qos->read_limit_bytes) {
110 /* Seems we need to apply QoS for the remaining data as well */
111 silc_schedule_task_add(sock->qos->schedule, sock->sock,
112 silc_socket_read_qos, silc_socket_dup(sock),
113 sock->qos->limit_sec, sock->qos->limit_usec,
114 SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
115 silc_schedule_unset_listen_fd(sock->qos->schedule, sock->sock);
117 /* Hide the rest of the data from the buffer. */
118 sock->qos->data_len = (sock->inbuf->len - len -
119 sock->qos->read_limit_bytes);
120 silc_buffer_push_tail(sock->inbuf, sock->qos->data_len);
123 if (sock->inbuf->len)
124 return sock->inbuf->len;
127 /* If we were called and we have active QoS data pending, return
129 if (sock->qos->data_len) {
130 silc_schedule_unset_listen_fd(sock->qos->schedule, sock->sock);
135 SILC_LOG_DEBUG(("Reading data from socket %d", fd));
137 /* Read the data from the socket. */
138 len = read(fd, buf, sizeof(buf));
140 if (errno == EAGAIN || errno == EINTR) {
141 SILC_LOG_DEBUG(("Could not read immediately, will do it later"));
144 SILC_LOG_DEBUG(("Cannot read from socket: %d:%s", fd, strerror(errno)));
145 sock->sock_error = errno;
152 /* Insert the data to the buffer. */
155 sock->inbuf = silc_buffer_alloc(SILC_SOCKET_BUF_SIZE);
157 /* If the data does not fit to the buffer reallocate it */
158 if ((sock->inbuf->end - sock->inbuf->tail) < len)
159 sock->inbuf = silc_buffer_realloc(sock->inbuf, sock->inbuf->truelen +
161 silc_buffer_put_tail(sock->inbuf, buf, len);
162 silc_buffer_pull_tail(sock->inbuf, len);
164 SILC_LOG_DEBUG(("Read %d bytes", len));
166 /* Apply QoS to the read data if necessary */
168 struct timeval curtime;
169 silc_gettimeofday(&curtime);
171 /* If we have passed the rate time limit, set our new time limit,
172 and zero the rate limit. */
173 if (!silc_compare_timeval(&curtime, &sock->qos->next_limit)) {
175 sock->qos->next_limit = curtime;
176 sock->qos->cur_rate = 0;
178 sock->qos->cur_rate++;
180 /* If we are not withing rate limit apply QoS for the read data */
181 if (sock->qos->cur_rate > sock->qos->read_rate) {
182 silc_schedule_task_add(sock->qos->schedule, sock->sock,
183 silc_socket_read_qos, silc_socket_dup(sock),
184 sock->qos->limit_sec, sock->qos->limit_usec,
185 SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
186 silc_schedule_unset_listen_fd(sock->qos->schedule, sock->sock);
188 /* Check the byte limit as well, and do not return more than allowed */
189 if (sock->inbuf->len > sock->qos->read_limit_bytes) {
190 /* Hide the rest of the data from the buffer. */
191 sock->qos->data_len = sock->inbuf->len - sock->qos->read_limit_bytes;
192 silc_buffer_push_tail(sock->inbuf, sock->qos->data_len);
193 len = sock->inbuf->len;
195 /* Rate limit kicked in, do not return data yet */
199 /* Check the byte limit, and do not return more than allowed */
200 if (sock->inbuf->len > sock->qos->read_limit_bytes) {
201 silc_schedule_task_add(sock->qos->schedule, sock->sock,
202 silc_socket_read_qos, silc_socket_dup(sock),
203 sock->qos->limit_sec, sock->qos->limit_usec,
204 SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
205 silc_schedule_unset_listen_fd(sock->qos->schedule, sock->sock);
207 /* Hide the rest of the data from the buffer. */
208 sock->qos->data_len = sock->inbuf->len - sock->qos->read_limit_bytes;
209 silc_buffer_push_tail(sock->inbuf, sock->qos->data_len);
210 len = sock->inbuf->len;
218 /* Returns human readable socket error message */
220 bool silc_socket_get_error(SilcSocketConnection sock, char *error,
221 SilcUInt32 error_len)
225 if (!sock->sock_error)
228 err = strerror(sock->sock_error);
229 if (strlen(err) > error_len)
232 memset(error, 0, error_len);
233 memcpy(error, err, strlen(err));