5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2005 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; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
21 #include "silcincludes.h"
23 /* Writes data from encrypted buffer to the socket connection. If the
24 data cannot be written at once, it will be written later with a timeout.
25 The data is written from the data section of the buffer, not from head
26 or tail section. This automatically pulls the data section towards end
27 after writing the data. */
29 int silc_socket_write(SilcSocketConnection sock)
33 SilcBuffer src = sock->outbuf;
37 if (SILC_IS_DISABLED(sock))
40 SILC_LOG_DEBUG(("Writing data to socket %d", fd));
43 ret = write(fd, src->data, src->len);
45 if (errno == EAGAIN || errno == EINTR) {
46 SILC_LOG_DEBUG(("Could not write immediately, will do it later"));
49 SILC_LOG_DEBUG(("Cannot write to socket: %s", strerror(errno)));
50 sock->sock_error = errno;
55 SILC_LOG_DEBUG(("Wrote data %d of %d bytes, will write rest later",
57 silc_buffer_pull(src, ret);
61 silc_buffer_pull(src, ret);
64 SILC_LOG_DEBUG(("Wrote data %d bytes", ret));
69 /* QoS read handler, this will call the read and write events to indicate
70 that data is available again after a timeout. */
72 SILC_TASK_CALLBACK(silc_socket_read_qos)
74 SilcSocketConnectionQos qos = context;
75 SilcSocketConnection sock = qos->sock;
78 silc_schedule_set_listen_fd(qos->schedule, sock->sock,
79 (SILC_TASK_READ | SILC_TASK_WRITE), TRUE);
81 silc_schedule_unset_listen_fd(qos->schedule, sock->sock);
83 silc_socket_free(sock);
86 /* Reads data from the socket connection into the incoming data buffer.
87 It reads as much as possible from the socket connection. This returns
88 amount of bytes read or -1 on error or -2 on case where all of the
89 data could not be read at once. */
91 int silc_socket_read(SilcSocketConnection sock)
94 unsigned char buf[SILC_SOCKET_READ_SIZE];
97 if (SILC_IS_DISABLED(sock))
100 /* If QoS was applied to socket then return earlier read data but apply
101 QoS to it too, if necessary. */
103 if (sock->qos->applied) {
104 if (sock->qos->data_len) {
105 /* Pull hidden data since we have it from earlier QoS apply */
106 silc_buffer_pull_tail(sock->inbuf, sock->qos->data_len);
107 len = sock->qos->data_len;
108 sock->qos->data_len = 0;
111 if (sock->inbuf->len - len > sock->qos->read_limit_bytes) {
112 /* Seems we need to apply QoS for the remaining data as well */
113 silc_socket_dup(sock);
114 silc_schedule_task_add(sock->qos->schedule, sock->sock,
115 silc_socket_read_qos, sock->qos,
116 sock->qos->limit_sec, sock->qos->limit_usec,
117 SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
118 silc_schedule_unset_listen_fd(sock->qos->schedule, sock->sock);
120 /* Hide the rest of the data from the buffer. */
121 sock->qos->data_len = (sock->inbuf->len - len -
122 sock->qos->read_limit_bytes);
123 silc_buffer_push_tail(sock->inbuf, sock->qos->data_len);
126 if (sock->inbuf->len)
127 return sock->inbuf->len;
130 /* If we were called and we have active QoS data pending, return
132 if (sock->qos->data_len) {
133 silc_schedule_unset_listen_fd(sock->qos->schedule, sock->sock);
138 SILC_LOG_DEBUG(("Reading data from socket %d", fd));
140 /* Read the data from the socket. */
141 len = read(fd, buf, sizeof(buf));
143 if (errno == EAGAIN || errno == EINTR) {
144 SILC_LOG_DEBUG(("Could not read immediately, will do it later"));
147 SILC_LOG_DEBUG(("Cannot read from socket: %d:%s", fd, strerror(errno)));
148 sock->sock_error = errno;
155 /* Insert the data to the buffer. */
158 sock->inbuf = silc_buffer_alloc(SILC_SOCKET_BUF_SIZE);
160 /* If the data does not fit to the buffer reallocate it */
161 if ((sock->inbuf->end - sock->inbuf->tail) < len)
162 sock->inbuf = silc_buffer_realloc(sock->inbuf, sock->inbuf->truelen +
164 silc_buffer_put_tail(sock->inbuf, buf, len);
165 silc_buffer_pull_tail(sock->inbuf, len);
167 SILC_LOG_DEBUG(("Read %d bytes", len));
169 /* Apply QoS to the read data if necessary */
171 struct timeval curtime;
172 silc_gettimeofday(&curtime);
174 /* If we have passed the rate time limit, set our new time limit,
175 and zero the rate limit. */
176 if (!silc_compare_timeval(&curtime, &sock->qos->next_limit)) {
178 sock->qos->next_limit = curtime;
179 sock->qos->cur_rate = 0;
181 sock->qos->cur_rate++;
183 /* If we are not withing rate limit apply QoS for the read data */
184 if (sock->qos->cur_rate > sock->qos->read_rate) {
185 silc_socket_dup(sock);
186 silc_schedule_task_add(sock->qos->schedule, sock->sock,
187 silc_socket_read_qos, sock->qos,
188 sock->qos->limit_sec, sock->qos->limit_usec,
189 SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
190 silc_schedule_unset_listen_fd(sock->qos->schedule, sock->sock);
192 /* Check the byte limit as well, and do not return more than allowed */
193 if (sock->inbuf->len > sock->qos->read_limit_bytes) {
194 /* Hide the rest of the data from the buffer. */
195 sock->qos->data_len = sock->inbuf->len - sock->qos->read_limit_bytes;
196 silc_buffer_push_tail(sock->inbuf, sock->qos->data_len);
197 len = sock->inbuf->len;
199 /* Rate limit kicked in, do not return data yet */
203 /* Check the byte limit, and do not return more than allowed */
204 if (sock->inbuf->len > sock->qos->read_limit_bytes) {
205 silc_socket_dup(sock);
206 silc_schedule_task_add(sock->qos->schedule, sock->sock,
207 silc_socket_read_qos, sock->qos,
208 sock->qos->limit_sec, sock->qos->limit_usec,
209 SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
210 silc_schedule_unset_listen_fd(sock->qos->schedule, sock->sock);
212 /* Hide the rest of the data from the buffer. */
213 sock->qos->data_len = sock->inbuf->len - sock->qos->read_limit_bytes;
214 silc_buffer_push_tail(sock->inbuf, sock->qos->data_len);
215 len = sock->inbuf->len;
223 /* Returns human readable socket error message */
225 bool silc_socket_get_error(SilcSocketConnection sock, char *error,
226 SilcUInt32 error_len)
230 if (!sock->sock_error)
233 err = strerror(sock->sock_error);
234 if (strlen(err) > error_len)
237 memset(error, 0, error_len);
238 memcpy(error, err, strlen(err));