950
|
1 /*****************************************************************************/
|
|
2 /* sockutils.c - various utilities for dealing with sockets */
|
|
3 /* Copyright (C) 1998-2008 Brian Masney <masneyb@gftp.org> */
|
|
4 /* */
|
|
5 /* This program is free software; you can redistribute it and/or modify */
|
|
6 /* it under the terms of the GNU General Public License as published by */
|
|
7 /* the Free Software Foundation; either version 2 of the License, or */
|
|
8 /* (at your option) any later version. */
|
|
9 /* */
|
|
10 /* This program is distributed in the hope that it will be useful, */
|
|
11 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
|
|
12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
|
|
13 /* GNU General Public License for more details. */
|
|
14 /* */
|
|
15 /* You should have received a copy of the GNU General Public License */
|
|
16 /* along with this program; if not, write to the Free Software */
|
|
17 /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA */
|
|
18 /*****************************************************************************/
|
|
19
|
|
20 #include "gftp.h"
|
|
21 static const char cvsid[] = "$Id: protocols.c 952 2008-01-24 23:31:26Z masneyb $";
|
|
22
|
|
23 ssize_t
|
|
24 gftp_get_line (gftp_request * request, gftp_getline_buffer ** rbuf,
|
|
25 char * str, size_t len, int fd)
|
|
26 {
|
|
27 ssize_t (*read_function) (gftp_request * request, void *ptr, size_t size,
|
|
28 int fd);
|
|
29 char *pos, *nextpos;
|
|
30 size_t rlen, nslen;
|
|
31 int end_of_buffer;
|
|
32 ssize_t ret;
|
|
33
|
|
34 if (request == NULL || request->read_function == NULL)
|
|
35 read_function = gftp_fd_read;
|
|
36 else
|
|
37 read_function = request->read_function;
|
|
38
|
|
39 if (*rbuf == NULL)
|
|
40 {
|
|
41 *rbuf = g_malloc0 (sizeof (**rbuf));
|
|
42 (*rbuf)->max_bufsize = len;
|
|
43 (*rbuf)->buffer = g_malloc0 ((gulong) ((*rbuf)->max_bufsize + 1));
|
|
44
|
|
45 if ((ret = read_function (request, (*rbuf)->buffer,
|
|
46 (*rbuf)->max_bufsize, fd)) <= 0)
|
|
47 {
|
|
48 gftp_free_getline_buffer (rbuf);
|
|
49 return (ret);
|
|
50 }
|
|
51 (*rbuf)->buffer[ret] = '\0';
|
|
52 (*rbuf)->cur_bufsize = ret;
|
|
53 (*rbuf)->curpos = (*rbuf)->buffer;
|
|
54 }
|
|
55
|
|
56 ret = 0;
|
|
57 while (1)
|
|
58 {
|
|
59 pos = strchr ((*rbuf)->curpos, '\n');
|
|
60 end_of_buffer = (*rbuf)->curpos == (*rbuf)->buffer &&
|
|
61 ((*rbuf)->max_bufsize == (*rbuf)->cur_bufsize || (*rbuf)->eof);
|
|
62
|
|
63 if ((*rbuf)->cur_bufsize > 0 && (pos != NULL || end_of_buffer))
|
|
64 {
|
|
65 if (pos != NULL)
|
|
66 {
|
|
67 nslen = pos - (*rbuf)->curpos + 1;
|
|
68 nextpos = pos + 1;
|
|
69 if (pos > (*rbuf)->curpos && *(pos - 1) == '\r')
|
|
70 pos--;
|
|
71 *pos = '\0';
|
|
72 }
|
|
73 else
|
|
74 {
|
|
75 nslen = (*rbuf)->cur_bufsize;
|
|
76 nextpos = NULL;
|
|
77
|
|
78 /* This is not an overflow since we allocated one extra byte to
|
|
79 buffer above */
|
|
80 ((*rbuf)->buffer)[nslen] = '\0';
|
|
81 }
|
|
82
|
|
83 strncpy (str, (*rbuf)->curpos, len);
|
|
84 str[len - 1] = '\0';
|
|
85 (*rbuf)->cur_bufsize -= nslen;
|
|
86
|
|
87 if (nextpos != NULL)
|
|
88 (*rbuf)->curpos = nextpos;
|
|
89 else
|
|
90 (*rbuf)->cur_bufsize = 0;
|
|
91
|
|
92 ret = nslen;
|
|
93 break;
|
|
94 }
|
|
95 else
|
|
96 {
|
|
97 if ((*rbuf)->cur_bufsize == 0 || *(*rbuf)->curpos == '\0')
|
|
98 {
|
|
99 rlen = (*rbuf)->max_bufsize;
|
|
100 pos = (*rbuf)->buffer;
|
|
101 }
|
|
102 else
|
|
103 {
|
|
104 memmove ((*rbuf)->buffer, (*rbuf)->curpos, (*rbuf)->cur_bufsize);
|
|
105 pos = (*rbuf)->buffer + (*rbuf)->cur_bufsize;
|
|
106 rlen = (*rbuf)->max_bufsize - (*rbuf)->cur_bufsize;
|
|
107 }
|
|
108
|
|
109 (*rbuf)->curpos = (*rbuf)->buffer;
|
|
110
|
|
111 if ((*rbuf)->eof)
|
|
112 ret = 0;
|
|
113 else
|
|
114 {
|
|
115 ret = read_function (request, pos, rlen, fd);
|
|
116 if (ret < 0)
|
|
117 {
|
|
118 gftp_free_getline_buffer (rbuf);
|
|
119 return (ret);
|
|
120 }
|
|
121 }
|
|
122
|
|
123 if (ret == 0)
|
|
124 {
|
|
125 if ((*rbuf)->cur_bufsize == 0)
|
|
126 {
|
|
127 gftp_free_getline_buffer (rbuf);
|
|
128 return (ret);
|
|
129 }
|
|
130
|
|
131 (*rbuf)->eof = 1;
|
|
132 }
|
|
133
|
|
134 (*rbuf)->cur_bufsize += ret;
|
|
135 (*rbuf)->buffer[(*rbuf)->cur_bufsize] = '\0';
|
|
136 }
|
|
137 }
|
|
138
|
|
139 return (ret);
|
|
140 }
|
|
141
|
|
142
|
|
143 void
|
|
144 gftp_free_getline_buffer (gftp_getline_buffer ** rbuf)
|
|
145 {
|
|
146 g_free ((*rbuf)->buffer);
|
|
147 g_free (*rbuf);
|
|
148 *rbuf = NULL;
|
|
149 }
|
|
150
|
|
151
|
|
152 ssize_t
|
|
153 gftp_fd_read (gftp_request * request, void *ptr, size_t size, int fd)
|
|
154 {
|
|
155 intptr_t network_timeout;
|
|
156 struct timeval tv;
|
|
157 fd_set fset;
|
|
158 ssize_t ret;
|
|
159 int s_ret;
|
|
160
|
|
161 g_return_val_if_fail (fd >= 0, GFTP_EFATAL);
|
|
162
|
|
163 gftp_lookup_request_option (request, "network_timeout", &network_timeout);
|
|
164
|
|
165 errno = 0;
|
|
166 ret = 0;
|
|
167 FD_ZERO (&fset);
|
|
168
|
|
169 do
|
|
170 {
|
|
171 FD_SET (fd, &fset);
|
|
172 tv.tv_sec = network_timeout;
|
|
173 tv.tv_usec = 0;
|
|
174 s_ret = select (fd + 1, &fset, NULL, NULL, &tv);
|
|
175 if (s_ret == -1 && (errno == EINTR || errno == EAGAIN))
|
|
176 {
|
|
177 if (request != NULL && request->cancel)
|
|
178 {
|
|
179 gftp_disconnect (request);
|
|
180 return (GFTP_ERETRYABLE);
|
|
181 }
|
|
182
|
|
183 continue;
|
|
184 }
|
|
185 else if (s_ret <= 0)
|
|
186 {
|
|
187 if (request != NULL)
|
|
188 {
|
|
189 request->logging_function (gftp_logging_error, request,
|
|
190 _("Connection to %s timed out\n"),
|
|
191 request->hostname);
|
|
192 gftp_disconnect (request);
|
|
193 }
|
|
194
|
|
195 return (GFTP_ERETRYABLE);
|
|
196 }
|
|
197
|
|
198 if ((ret = read (fd, ptr, size)) < 0)
|
|
199 {
|
|
200 if (errno == EINTR || errno == EAGAIN)
|
|
201 {
|
|
202 if (request != NULL && request->cancel)
|
|
203 {
|
|
204 gftp_disconnect (request);
|
|
205 return (GFTP_ERETRYABLE);
|
|
206 }
|
|
207
|
|
208 continue;
|
|
209 }
|
|
210
|
|
211 if (request != NULL)
|
|
212 {
|
|
213 request->logging_function (gftp_logging_error, request,
|
|
214 _("Error: Could not read from socket: %s\n"),
|
|
215 g_strerror (errno));
|
|
216 gftp_disconnect (request);
|
|
217 }
|
|
218
|
|
219 return (GFTP_ERETRYABLE);
|
|
220 }
|
|
221
|
|
222 break;
|
|
223 }
|
|
224 while (1);
|
|
225
|
|
226 return (ret);
|
|
227 }
|
|
228
|
|
229
|
|
230 ssize_t
|
|
231 gftp_fd_write (gftp_request * request, const char *ptr, size_t size, int fd)
|
|
232 {
|
|
233 intptr_t network_timeout;
|
|
234 struct timeval tv;
|
|
235 int ret, s_ret;
|
|
236 ssize_t w_ret;
|
|
237 fd_set fset;
|
|
238
|
|
239 g_return_val_if_fail (fd >= 0, GFTP_EFATAL);
|
|
240
|
|
241 gftp_lookup_request_option (request, "network_timeout", &network_timeout);
|
|
242
|
|
243 errno = 0;
|
|
244 ret = 0;
|
|
245 FD_ZERO (&fset);
|
|
246
|
|
247 do
|
|
248 {
|
|
249 FD_SET (fd, &fset);
|
|
250 tv.tv_sec = network_timeout;
|
|
251 tv.tv_usec = 0;
|
|
252 s_ret = select (fd + 1, NULL, &fset, NULL, &tv);
|
|
253 if (s_ret == -1 && (errno == EINTR || errno == EAGAIN))
|
|
254 {
|
|
255 if (request != NULL && request->cancel)
|
|
256 {
|
|
257 gftp_disconnect (request);
|
|
258 return (GFTP_ERETRYABLE);
|
|
259 }
|
|
260
|
|
261 continue;
|
|
262 }
|
|
263 else if (s_ret <= 0)
|
|
264 {
|
|
265 if (request != NULL)
|
|
266 {
|
|
267 request->logging_function (gftp_logging_error, request,
|
|
268 _("Connection to %s timed out\n"),
|
|
269 request->hostname);
|
|
270 gftp_disconnect (request);
|
|
271 }
|
|
272
|
|
273 return (GFTP_ERETRYABLE);
|
|
274 }
|
|
275
|
|
276 w_ret = write (fd, ptr, size);
|
|
277 if (w_ret < 0)
|
|
278 {
|
|
279 if (errno == EINTR || errno == EAGAIN)
|
|
280 {
|
|
281 if (request != NULL && request->cancel)
|
|
282 {
|
|
283 gftp_disconnect (request);
|
|
284 return (GFTP_ERETRYABLE);
|
|
285 }
|
|
286
|
|
287 continue;
|
|
288 }
|
|
289
|
|
290 if (request != NULL)
|
|
291 {
|
|
292 request->logging_function (gftp_logging_error, request,
|
|
293 _("Error: Could not write to socket: %s\n"),
|
|
294 g_strerror (errno));
|
|
295 gftp_disconnect (request);
|
|
296 }
|
|
297
|
|
298 return (GFTP_ERETRYABLE);
|
|
299 }
|
|
300
|
|
301 ptr += w_ret;
|
|
302 size -= w_ret;
|
|
303 ret += w_ret;
|
|
304 }
|
|
305 while (size > 0);
|
|
306
|
|
307 return (ret);
|
|
308 }
|
|
309
|
|
310
|
|
311 ssize_t
|
|
312 gftp_writefmt (gftp_request * request, int fd, const char *fmt, ...)
|
|
313 {
|
|
314 char *tempstr;
|
|
315 va_list argp;
|
|
316 ssize_t ret;
|
|
317
|
|
318 va_start (argp, fmt);
|
|
319 tempstr = g_strdup_vprintf (fmt, argp);
|
|
320 va_end (argp);
|
|
321
|
|
322 ret = request->write_function (request, tempstr, strlen (tempstr), fd);
|
|
323 g_free (tempstr);
|
|
324 return (ret);
|
|
325 }
|
|
326
|
|
327
|
|
328 int
|
|
329 gftp_fd_set_sockblocking (gftp_request * request, int fd, int non_blocking)
|
|
330 {
|
|
331 int flags;
|
|
332
|
|
333 g_return_val_if_fail (fd >= 0, GFTP_EFATAL);
|
|
334
|
|
335 if ((flags = fcntl (fd, F_GETFL, 0)) < 0)
|
|
336 {
|
|
337 request->logging_function (gftp_logging_error, request,
|
|
338 _("Cannot get socket flags: %s\n"),
|
|
339 g_strerror (errno));
|
|
340 gftp_disconnect (request);
|
|
341 return (GFTP_ERETRYABLE);
|
|
342 }
|
|
343
|
|
344 if (non_blocking)
|
|
345 flags |= O_NONBLOCK;
|
|
346 else
|
|
347 flags &= ~O_NONBLOCK;
|
|
348
|
|
349 if (fcntl (fd, F_SETFL, flags) < 0)
|
|
350 {
|
|
351 request->logging_function (gftp_logging_error, request,
|
|
352 _("Cannot set socket to non-blocking: %s\n"),
|
|
353 g_strerror (errno));
|
|
354 gftp_disconnect (request);
|
|
355 return (GFTP_ERETRYABLE);
|
|
356 }
|
|
357
|
|
358 return (0);
|
|
359 }
|
|
360
|