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;
77 silc_schedule_set_listen_fd(sock->qos->schedule, sock->sock,
78 (SILC_TASK_READ | SILC_TASK_WRITE), TRUE);
79 sock->qos->applied = FALSE;
80 silc_socket_free(sock);
83 /* Reads data from the socket connection into the incoming data buffer.
84 It reads as much as possible from the socket connection. This returns
85 amount of bytes read or -1 on error or -2 on case where all of the
86 data could not be read at once. */
88 int silc_socket_read(SilcSocketConnection sock)
91 unsigned char buf[SILC_SOCKET_READ_SIZE];
94 if (SILC_IS_DISABLED(sock))
97 /* If QoS was applied to socket then return earlier read data but apply
98 QoS to it too, if necessary. */
100 if (sock->qos->applied) {
101 if (sock->qos->data_len) {
102 /* Pull hidden data since we have it from earlier QoS apply */
103 silc_buffer_pull_tail(sock->inbuf, sock->qos->data_len);
104 len = sock->qos->data_len;
105 sock->qos->data_len = 0;
108 if (sock->inbuf->len - len > sock->qos->read_limit_bytes) {
109 /* Seems we need to apply QoS for the remaining data as well */
110 silc_schedule_task_add(sock->qos->schedule, sock->sock,
111 silc_socket_read_qos, silc_socket_dup(sock),
112 sock->qos->limit_sec, sock->qos->limit_usec,
113 SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
114 silc_schedule_unset_listen_fd(sock->qos->schedule, sock->sock);
116 /* Hide the rest of the data from the buffer. */
117 sock->qos->data_len = (sock->inbuf->len - len -
118 sock->qos->read_limit_bytes);
119 silc_buffer_push_tail(sock->inbuf, sock->qos->data_len);
122 if (sock->inbuf->len)
123 return sock->inbuf->len;
126 /* If we were called and we have active QoS data pending, return
128 if (sock->qos->data_len) {
129 silc_schedule_unset_listen_fd(sock->qos->schedule, sock->sock);
134 SILC_LOG_DEBUG(("Reading data from socket %d", fd));
136 /* Read the data from the socket. */
137 len = read(fd, buf, sizeof(buf));
139 if (errno == EAGAIN || errno == EINTR) {
140 SILC_LOG_DEBUG(("Could not read immediately, will do it later"));
143 SILC_LOG_DEBUG(("Cannot read from socket: %d:%s", fd, strerror(errno)));
144 sock->sock_error = errno;
151 /* Insert the data to the buffer. */
154 sock->inbuf = silc_buffer_alloc(SILC_SOCKET_BUF_SIZE);
156 /* If the data does not fit to the buffer reallocate it */
157 if ((sock->inbuf->end - sock->inbuf->tail) < len)
158 sock->inbuf = silc_buffer_realloc(sock->inbuf, sock->inbuf->truelen +
160 silc_buffer_put_tail(sock->inbuf, buf, len);
161 silc_buffer_pull_tail(sock->inbuf, len);
163 SILC_LOG_DEBUG(("Read %d bytes", len));
165 /* Apply QoS to the read data if necessary */
167 struct timeval curtime;
168 silc_gettimeofday(&curtime);
170 /* If we have passed the rate time limit, set our new time limit,
171 and zero the rate limit. */
172 if (!silc_compare_timeval(&curtime, &sock->qos->next_limit)) {
174 sock->qos->next_limit = curtime;
175 sock->qos->cur_rate = 0;
177 sock->qos->cur_rate++;
179 /* If we are not withing rate limit apply QoS for the read data */
180 if (sock->qos->cur_rate > sock->qos->read_rate) {
181 silc_schedule_task_add(sock->qos->schedule, sock->sock,
182 silc_socket_read_qos, silc_socket_dup(sock),
183 sock->qos->limit_sec, sock->qos->limit_usec,
184 SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
185 silc_schedule_unset_listen_fd(sock->qos->schedule, sock->sock);
187 /* Check the byte limit as well, and do not return more than allowed */
188 if (sock->inbuf->len > sock->qos->read_limit_bytes) {
189 /* Hide the rest of the data from the buffer. */
190 sock->qos->data_len = sock->inbuf->len - sock->qos->read_limit_bytes;
191 silc_buffer_push_tail(sock->inbuf, sock->qos->data_len);
192 len = sock->inbuf->len;
194 /* Rate limit kicked in, do not return data yet */
198 /* Check the byte limit, and do not return more than allowed */
199 if (sock->inbuf->len > sock->qos->read_limit_bytes) {
200 silc_schedule_task_add(sock->qos->schedule, sock->sock,
201 silc_socket_read_qos, silc_socket_dup(sock),
202 sock->qos->limit_sec, sock->qos->limit_usec,
203 SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
204 silc_schedule_unset_listen_fd(sock->qos->schedule, sock->sock);
206 /* Hide the rest of the data from the buffer. */
207 sock->qos->data_len = sock->inbuf->len - sock->qos->read_limit_bytes;
208 silc_buffer_push_tail(sock->inbuf, sock->qos->data_len);
209 len = sock->inbuf->len;
217 /* Returns human readable socket error message */
219 bool silc_socket_get_error(SilcSocketConnection sock, char *error,
220 SilcUInt32 error_len)
224 if (!sock->sock_error)
227 err = strerror(sock->sock_error);
228 if (strlen(err) > error_len)
231 memset(error, 0, error_len);
232 memcpy(error, err, strlen(err));