Merge pull request #71 from Memphiz/nolinger
[deb_libnfs.git] / lib / socket.c
CommitLineData
84004dbf
RS
1/*
2 Copyright (C) 2010 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation; either version 2.1 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program; if not, see <http://www.gnu.org/licenses/>.
16*/
00748f36
RS
17#ifdef HAVE_CONFIG_H
18#include "config.h"
19#endif
20
21#ifdef AROS
22#include "aros_compat.h"
23#endif
24
a8a1b858
M
25#ifdef WIN32
26#include "win32_compat.h"
c022471e
RS
27#endif
28
29#ifdef HAVE_ARPA_INET_H
a8a1b858 30#include <arpa/inet.h>
c022471e 31#endif
84004dbf 32
00748f36
RS
33#ifdef HAVE_POLL_H
34#include <poll.h>
fc01d2a9 35#endif
d7c6e9aa 36
00748f36
RS
37#ifdef HAVE_UNISTD_H
38#include <unistd.h>
d7c6e9aa
RS
39#endif
40
00748f36
RS
41#ifdef HAVE_SYS_IOCTL_H
42#include <sys/ioctl.h>
d7c6e9aa
RS
43#endif
44
7057e733
RS
45#ifdef HAVE_SYS_SOCKET_H
46#include <sys/socket.h>
47#endif
48
1c8b4547
PL
49#ifdef HAVE_NETINET_TCP_H
50#include <netinet/tcp.h>
51#endif
52
bff8fe46
RS
53#ifdef HAVE_NETDB_H
54#include <netdb.h>
55#endif
56
fc01d2a9
TN
57#ifdef HAVE_SYS_FILIO_H
58#include <sys/filio.h>
59#endif
bff8fe46 60
647d2ea1
RS
61#ifdef HAVE_SYS_SOCKIO_H
62#include <sys/sockio.h>
63#endif
bff8fe46
RS
64
65#include <stdio.h>
66#include <stdlib.h>
67#include <assert.h>
68#include <fcntl.h>
69#include <string.h>
70#include <errno.h>
485bc9b9 71#include <sys/types.h>
763cd6e3 72#include "libnfs-zdr.h"
84004dbf
RS
73#include "libnfs.h"
74#include "libnfs-raw.h"
75#include "libnfs-private.h"
76#include "slist.h"
77
fcc42bfe
M
78#ifdef WIN32
79//has to be included after stdlib!!
80#include "win32_errnowrapper.h"
81#endif
82
1744ef90
RS
83static int rpc_reconnect_requeue(struct rpc_context *rpc);
84static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_storage *s);
b077fdeb 85
84004dbf
RS
86static void set_nonblocking(int fd)
87{
99c14c9b 88 int v = 0;
6874f61e 89#if defined(WIN32)
99c14c9b 90 long nonblocking=1;
622489d3 91 v = ioctl(fd, FIONBIO, &nonblocking);
6874f61e 92#else
84004dbf
RS
93 v = fcntl(fd, F_GETFL, 0);
94 fcntl(fd, F_SETFL, v | O_NONBLOCK);
a8a1b858 95#endif //FIXME
84004dbf
RS
96}
97
74b037ec
M
98static void set_nolinger(int fd)
99{
100 struct linger lng;
101 lng.l_onoff = 1;
102 lng.l_linger = 0;
103 setsockopt(fd, SOL_SOCKET, SO_LINGER, &lng, sizeof(lng));
104}
105
1c8b4547
PL
106#ifdef HAVE_NETINET_TCP_H
107int set_tcp_sockopt(int sockfd, int optname, int value)
108{
109 int level;
110
111 #if defined(__FreeBSD__) || defined(__sun) || (defined(__APPLE__) && defined(__MACH__))
112 struct protoent *buf;
113
114 if ((buf = getprotobyname("tcp")) != NULL)
115 level = buf->p_proto;
116 else
117 return -1;
118 #else
119 level = SOL_TCP;
120 #endif
121
122 return setsockopt(sockfd, level, optname, (char *)&value, sizeof(value));
123}
124#endif
125
84004dbf
RS
126int rpc_get_fd(struct rpc_context *rpc)
127{
4a2b0876
RS
128 assert(rpc->magic == RPC_CONTEXT_MAGIC);
129
84004dbf
RS
130 return rpc->fd;
131}
132
133int rpc_which_events(struct rpc_context *rpc)
134{
4a2b0876
RS
135 int events;
136
137 assert(rpc->magic == RPC_CONTEXT_MAGIC);
138
139 events = rpc->is_connected ? POLLIN : POLLOUT;
84004dbf 140
5911f3e8
RS
141 if (rpc->is_udp != 0) {
142 /* for udp sockets we only wait for pollin */
143 return POLLIN;
144 }
145
84004dbf
RS
146 if (rpc->outqueue) {
147 events |= POLLOUT;
148 }
149 return events;
150}
151
152static int rpc_write_to_socket(struct rpc_context *rpc)
153{
d14e2838 154 int32_t count;
84004dbf 155
4a2b0876
RS
156 assert(rpc->magic == RPC_CONTEXT_MAGIC);
157
84004dbf 158 if (rpc->fd == -1) {
1896d37b
RS
159 rpc_set_error(rpc, "trying to write but not connected");
160 return -1;
84004dbf
RS
161 }
162
163 while (rpc->outqueue != NULL) {
183451cf 164 int64_t total;
84004dbf
RS
165
166 total = rpc->outqueue->outdata.size;
167
6874f61e 168 count = send(rpc->fd, rpc->outqueue->outdata.data + rpc->outqueue->written, total - rpc->outqueue->written, 0);
84004dbf
RS
169 if (count == -1) {
170 if (errno == EAGAIN || errno == EWOULDBLOCK) {
84004dbf
RS
171 return 0;
172 }
1896d37b
RS
173 rpc_set_error(rpc, "Error when writing to socket :%s(%d)", strerror(errno), errno);
174 return -1;
84004dbf
RS
175 }
176
177 rpc->outqueue->written += count;
178 if (rpc->outqueue->written == total) {
179 struct rpc_pdu *pdu = rpc->outqueue;
180
181 SLIST_REMOVE(&rpc->outqueue, pdu);
182 SLIST_ADD_END(&rpc->waitpdu, pdu);
183 }
184 }
185 return 0;
186}
187
188static int rpc_read_from_socket(struct rpc_context *rpc)
189{
190 int available;
191 int size;
cdb19ec1 192 int pdu_size;
d14e2838 193 int32_t count;
84004dbf 194
f3a75078 195 assert(rpc->magic == RPC_CONTEXT_MAGIC);
84004dbf
RS
196
197 if (ioctl(rpc->fd, FIONREAD, &available) != 0) {
198 rpc_set_error(rpc, "Ioctl FIONREAD returned error : %d. Closing socket.", errno);
199 return -1;
200 }
a8a1b858 201
84004dbf
RS
202 if (available == 0) {
203 rpc_set_error(rpc, "Socket has been closed");
1896d37b 204 return -1;
84004dbf 205 }
cdb19ec1 206
0268794f
RS
207 if (rpc->is_udp) {
208 char *buf;
209 socklen_t socklen = sizeof(rpc->udp_src);
210
211 buf = malloc(available);
212 if (buf == NULL) {
213 rpc_set_error(rpc, "Failed to malloc buffer for recvfrom");
214 return -1;
215 }
216 count = recvfrom(rpc->fd, buf, available, MSG_DONTWAIT, (struct sockaddr *)&rpc->udp_src, &socklen);
217 if (count < 0) {
218 rpc_set_error(rpc, "Failed recvfrom: %s", strerror(errno));
219 free(buf);
60af7e19 220 return -1;
0268794f
RS
221 }
222 if (rpc_process_pdu(rpc, buf, count) != 0) {
223 rpc_set_error(rpc, "Invalid/garbage pdu received from server. Ignoring PDU");
224 free(buf);
225 return -1;
226 }
227 free(buf);
228 return 0;
229 }
230
cdb19ec1
RS
231 /* read record marker, 4 bytes at the beginning of every pdu */
232 if (rpc->inbuf == NULL) {
233 rpc->insize = 4;
234 rpc->inbuf = malloc(rpc->insize);
235 if (rpc->inbuf == NULL) {
236 rpc_set_error(rpc, "Failed to allocate buffer for record marker, errno:%d. Closing socket.", errno);
237 return -1;
238 }
239 }
240 if (rpc->inpos < 4) {
241 size = 4 - rpc->inpos;
242
6874f61e 243 count = recv(rpc->fd, rpc->inbuf + rpc->inpos, size, 0);
cdb19ec1
RS
244 if (count == -1) {
245 if (errno == EINTR) {
246 return 0;
247 }
248 rpc_set_error(rpc, "Read from socket failed, errno:%d. Closing socket.", errno);
249 return -1;
250 }
251 available -= count;
252 rpc->inpos += count;
253 }
254
255 if (available == 0) {
256 return 0;
257 }
258
259 pdu_size = rpc_get_pdu_size(rpc->inbuf);
260 if (rpc->insize < pdu_size) {
261 unsigned char *buf;
8907aea9 262
cdb19ec1
RS
263 buf = malloc(pdu_size);
264 if (buf == NULL) {
265 rpc_set_error(rpc, "Failed to allocate buffer of %d bytes for pdu, errno:%d. Closing socket.", pdu_size, errno);
266 return -1;
267 }
268 memcpy(buf, rpc->inbuf, rpc->insize);
269 free(rpc->inbuf);
270 rpc->inbuf = buf;
271 rpc->insize = rpc_get_pdu_size(rpc->inbuf);
84004dbf 272 }
cdb19ec1
RS
273
274 size = available;
275 if (size > rpc->insize - rpc->inpos) {
276 size = rpc->insize - rpc->inpos;
84004dbf
RS
277 }
278
6874f61e 279 count = recv(rpc->fd, rpc->inbuf + rpc->inpos, size, 0);
84004dbf
RS
280 if (count == -1) {
281 if (errno == EINTR) {
84004dbf
RS
282 return 0;
283 }
284 rpc_set_error(rpc, "Read from socket failed, errno:%d. Closing socket.", errno);
1896d37b 285 return -1;
84004dbf 286 }
cdb19ec1
RS
287 available -= count;
288 rpc->inpos += count;
84004dbf 289
cdb19ec1 290 if (rpc->inpos == rpc->insize) {
dd97d43a
RS
291 char *buf = rpc->inbuf;
292
293 rpc->inbuf = NULL;
294 rpc->insize = 0;
295 rpc->inpos = 0;
296
297 if (rpc_process_pdu(rpc, buf, pdu_size) != 0) {
84004dbf 298 rpc_set_error(rpc, "Invalid/garbage pdu received from server. Closing socket");
1896d37b 299 return -1;
84004dbf 300 }
751770fd 301 free(buf);
84004dbf 302 }
cdb19ec1 303
84004dbf
RS
304 return 0;
305}
306
307
308
309int rpc_service(struct rpc_context *rpc, int revents)
310{
4a2b0876
RS
311 assert(rpc->magic == RPC_CONTEXT_MAGIC);
312
84004dbf 313 if (revents & POLLERR) {
fcc42bfe 314#ifdef WIN32
a8a1b858 315 char err = 0;
fcc42bfe
M
316#else
317 int err = 0;
318#endif
912f7ad5
RS
319 socklen_t err_size = sizeof(err);
320
321 if (getsockopt(rpc->fd, SOL_SOCKET, SO_ERROR,
bb4e9ed6 322 (char *)&err, &err_size) != 0 || err != 0) {
912f7ad5
RS
323 if (err == 0) {
324 err = errno;
325 }
326 rpc_set_error(rpc, "rpc_service: socket error "
327 "%s(%d).",
328 strerror(err), err);
84004dbf 329 } else {
912f7ad5
RS
330 rpc_set_error(rpc, "rpc_service: POLLERR, "
331 "Unknown socket error.");
84004dbf 332 }
b990de23
RS
333 if (rpc->connect_cb != NULL) {
334 rpc->connect_cb(rpc, RPC_STATUS_ERROR, rpc->error_string, rpc->connect_data);
335 }
84004dbf
RS
336 return -1;
337 }
338 if (revents & POLLHUP) {
84004dbf 339 rpc_set_error(rpc, "Socket failed with POLLHUP");
b990de23
RS
340 if (rpc->connect_cb != NULL) {
341 rpc->connect_cb(rpc, RPC_STATUS_ERROR, rpc->error_string, rpc->connect_data);
342 }
1896d37b 343 return -1;
84004dbf
RS
344 }
345
346 if (rpc->is_connected == 0 && rpc->fd != -1 && revents&POLLOUT) {
912f7ad5
RS
347 int err = 0;
348 socklen_t err_size = sizeof(err);
349
350 if (getsockopt(rpc->fd, SOL_SOCKET, SO_ERROR,
bb4e9ed6 351 (char *)&err, &err_size) != 0 || err != 0) {
912f7ad5
RS
352 if (err == 0) {
353 err = errno;
354 }
355 rpc_set_error(rpc, "rpc_service: socket error "
356 "%s(%d) while connecting.",
357 strerror(err), err);
b990de23
RS
358 if (rpc->connect_cb != NULL) {
359 rpc->connect_cb(rpc, RPC_STATUS_ERROR,
912f7ad5 360 NULL, rpc->connect_data);
b990de23 361 }
912f7ad5
RS
362 return -1;
363 }
364
84004dbf 365 rpc->is_connected = 1;
b990de23
RS
366 if (rpc->connect_cb != NULL) {
367 rpc->connect_cb(rpc, RPC_STATUS_SUCCESS, NULL, rpc->connect_data);
368 }
84004dbf
RS
369 return 0;
370 }
371
b077fdeb
RS
372 if (revents & POLLIN) {
373 if (rpc_read_from_socket(rpc) != 0) {
1744ef90 374 rpc_reconnect_requeue(rpc);
b077fdeb 375 return 0;
84004dbf
RS
376 }
377 }
378
b077fdeb
RS
379 if (revents & POLLOUT && rpc->outqueue != NULL) {
380 if (rpc_write_to_socket(rpc) != 0) {
381 rpc_set_error(rpc, "write to socket failed");
1896d37b 382 return -1;
84004dbf
RS
383 }
384 }
385
386 return 0;
387}
388
1744ef90 389void rpc_set_autoreconnect(struct rpc_context *rpc)
84004dbf 390{
4a2b0876
RS
391 assert(rpc->magic == RPC_CONTEXT_MAGIC);
392
1744ef90
RS
393 rpc->auto_reconnect = 1;
394}
84004dbf 395
1744ef90
RS
396void rpc_unset_autoreconnect(struct rpc_context *rpc)
397{
4a2b0876
RS
398 assert(rpc->magic == RPC_CONTEXT_MAGIC);
399
1744ef90
RS
400 rpc->auto_reconnect = 0;
401}
070287e5 402
1c8b4547
PL
403void rpc_set_tcp_syncnt(struct rpc_context *rpc, int v)
404{
405 assert(rpc->magic == RPC_CONTEXT_MAGIC);
406
407 rpc->tcp_syncnt = v;
408}
409
d43a8953
PL
410#ifndef TCP_SYNCNT
411#define TCP_SYNCNT 7
412#endif
413
1744ef90
RS
414static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_storage *s)
415{
416 int socksize;
84004dbf 417
4a2b0876
RS
418 assert(rpc->magic == RPC_CONTEXT_MAGIC);
419
1744ef90 420 switch (s->ss_family) {
84004dbf 421 case AF_INET:
84004dbf 422 socksize = sizeof(struct sockaddr_in);
6874f61e 423 rpc->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1c8b4547
PL
424#ifdef HAVE_NETINET_TCP_H
425 if (rpc->tcp_syncnt != RPC_PARAM_UNDEFINED) {
426 set_tcp_sockopt(rpc->fd, TCP_SYNCNT, rpc->tcp_syncnt);
427 }
1c1e09ad
RS
428#endif
429 break;
430 case AF_INET6:
431 socksize = sizeof(struct sockaddr_in6);
432 rpc->fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
433#ifdef HAVE_NETINET_TCP_H
434 if (rpc->tcp_syncnt != RPC_PARAM_UNDEFINED) {
435 set_tcp_sockopt(rpc->fd, TCP_SYNCNT, rpc->tcp_syncnt);
436 }
1c8b4547 437#endif
84004dbf 438 break;
1744ef90
RS
439 default:
440 rpc_set_error(rpc, "Can not handle AF_FAMILY:%d", s->ss_family);
441 return -1;
84004dbf
RS
442 }
443
444 if (rpc->fd == -1) {
445 rpc_set_error(rpc, "Failed to open socket");
1896d37b 446 return -1;
84004dbf
RS
447 }
448
07fd0cbc
RS
449 /* Some systems allow you to set capabilities on an executable
450 * to allow the file to be executed with privilege to bind to
451 * privileged system ports, even if the user is not root.
452 *
453 * Opportunistically try to bind the socket to a low numbered
454 * system port in the hope that the user is either root or the
455 * executable has the CAP_NET_BIND_SERVICE.
456 *
457 * As soon as we fail the bind() with EACCES we know we will never
458 * be able to bind to a system port so we terminate the loop.
459 *
460 * On linux, use
461 * sudo setcap 'cap_net_bind_service=+ep' /path/executable
462 * to make the executable able to bind to a system port.
ac559609
RI
463 *
464 * On Windows, there is no concept of privileged ports. Thus
465 * binding will usually succeed.
07fd0cbc 466 */
ac559609 467 {
1c1e09ad 468 struct sockaddr_storage ss;
ac559609
RI
469 static int portOfs = 0;
470 const int firstPort = 512; /* >= 512 according to Sun docs */
471 const int portCount = IPPORT_RESERVED - firstPort;
cb5b8be2 472 int startOfs, port, rc;
ac559609 473
cb5b8be2
RS
474 if (portOfs == 0) {
475 portOfs = time(NULL) % 400;
476 }
477 startOfs = portOfs;
ac559609
RI
478 do {
479 rc = -1;
480 port = htons(firstPort + portOfs);
481 portOfs = (portOfs + 1) % portCount;
482
483 /* skip well-known ports */
484 if (!getservbyport(port, "tcp")) {
1c1e09ad
RS
485 memset(&ss, 0, sizeof(ss));
486
487 switch (s->ss_family) {
488 case AF_INET:
489 ((struct sockaddr_in *)&ss)->sin_port = port;
490 ((struct sockaddr_in *)&ss)->sin_family = AF_INET;
491#ifdef HAVE_SOCKADDR_LEN
492 ((struct sockaddr_in *)&ss)->sin_len = sizeof(struct sockaddr_in);
493#endif
494 break;
495 case AF_INET6:
496 ((struct sockaddr_in6 *)&ss)->sin6_port = port;
497 ((struct sockaddr_in6 *)&ss)->sin6_family = AF_INET6;
498#ifdef HAVE_SOCKADDR_LEN
499 ((struct sockaddr_in6 *)&ss)->sin6_len = sizeof(struct sockaddr_in);
500#endif
501 break;
502 }
ac559609 503
1c1e09ad 504 rc = bind(rpc->fd, (struct sockaddr *)&ss, socksize);
ac559609
RI
505#if !defined(WIN32)
506 /* we got EACCES, so don't try again */
507 if (rc != 0 && errno == EACCES)
508 break;
509#endif
07fd0cbc 510 }
ac559609 511 } while (rc != 0 && portOfs != startOfs);
07fd0cbc 512 }
07fd0cbc 513
84004dbf 514 set_nonblocking(rpc->fd);
74b037ec 515 set_nolinger(rpc->fd);
07fd0cbc 516
f96b24fa
RI
517 if (connect(rpc->fd, (struct sockaddr *)s, socksize) != 0 && errno != EINPROGRESS) {
518 rpc_set_error(rpc, "connect() to server failed. %s(%d)", strerror(errno), errno);
1896d37b 519 return -1;
8907aea9 520 }
84004dbf
RS
521
522 return 0;
8907aea9 523}
84004dbf 524
1744ef90
RS
525int rpc_connect_async(struct rpc_context *rpc, const char *server, int port, rpc_cb cb, void *private_data)
526{
1c1e09ad 527 struct addrinfo *ai = NULL;
1744ef90 528
4a2b0876
RS
529 assert(rpc->magic == RPC_CONTEXT_MAGIC);
530
1744ef90
RS
531 if (rpc->fd != -1) {
532 rpc_set_error(rpc, "Trying to connect while already connected");
533 return -1;
534 }
535
536 if (rpc->is_udp != 0) {
537 rpc_set_error(rpc, "Trying to connect on UDP socket");
538 return -1;
539 }
540
541 rpc->auto_reconnect = 0;
542
1c1e09ad
RS
543 if (getaddrinfo(server, NULL, NULL, &ai) != 0) {
544 rpc_set_error(rpc, "Invalid address:%s. "
545 "Can not resolv into IPv4/v6 structure.", server);
1744ef90 546 return -1;
1c1e09ad 547 }
1744ef90 548
1c1e09ad 549 switch (ai->ai_family) {
1744ef90 550 case AF_INET:
1c1e09ad
RS
551 ((struct sockaddr_in *)&rpc->s)->sin_family = ai->ai_family;
552 ((struct sockaddr_in *)&rpc->s)->sin_port = htons(port);
1744ef90 553#ifdef HAVE_SOCKADDR_LEN
1c1e09ad
RS
554 ((struct sockaddr_in *)&rpc->s)->sin_len = sizeof(struct sockaddr_in);
555#endif
556 break;
557 case AF_INET6:
558 ((struct sockaddr_in6 *)&rpc->s)->sin6_family = ai->ai_family;
559 ((struct sockaddr_in6 *)&rpc->s)->sin6_port = htons(port);
560#ifdef HAVE_SOCKADDR_LEN
561 ((struct sockaddr_in6 *)&rpc->s)->sin6_len = sizeof(struct sockaddr_in6);
1744ef90
RS
562#endif
563 break;
564 }
565
566 rpc->connect_cb = cb;
567 rpc->connect_data = private_data;
568
1c1e09ad
RS
569 freeaddrinfo(ai);
570
1744ef90
RS
571 if (rpc_connect_sockaddr_async(rpc, &rpc->s) != 0) {
572 return -1;
573 }
574
575 return 0;
8907aea9 576}
1744ef90 577
84004dbf
RS
578int rpc_disconnect(struct rpc_context *rpc, char *error)
579{
4a2b0876
RS
580 assert(rpc->magic == RPC_CONTEXT_MAGIC);
581
1744ef90
RS
582 rpc_unset_autoreconnect(rpc);
583
84004dbf
RS
584 if (rpc->fd != -1) {
585 close(rpc->fd);
586 }
587 rpc->fd = -1;
588
589 rpc->is_connected = 0;
590
591 rpc_error_all_pdus(rpc, error);
592
593 return 0;
594}
485bc9b9 595
1744ef90
RS
596static void reconnect_cb(struct rpc_context *rpc, int status, void *data _U_, void *private_data)
597{
4a2b0876
RS
598 assert(rpc->magic == RPC_CONTEXT_MAGIC);
599
1744ef90
RS
600 if (status != RPC_STATUS_SUCCESS) {
601 rpc_error_all_pdus(rpc, "RPC ERROR: Failed to reconnect async");
602 return;
603 }
604
605 rpc->is_connected = 1;
b990de23 606 rpc->connect_cb = NULL;
1744ef90
RS
607}
608
609/* disconnect but do not error all PDUs, just move pdus in-flight back to the outqueue and reconnect */
610static int rpc_reconnect_requeue(struct rpc_context *rpc)
b077fdeb
RS
611{
612 struct rpc_pdu *pdu;
613
4a2b0876
RS
614 assert(rpc->magic == RPC_CONTEXT_MAGIC);
615
b077fdeb
RS
616 if (rpc->fd != -1) {
617 close(rpc->fd);
618 }
619 rpc->fd = -1;
620
621 rpc->is_connected = 0;
622
623 /* socket is closed so we will not get any replies to any commands
624 * in flight. Move them all over from the waitpdu queue back to the out queue
625 */
626 for (pdu=rpc->waitpdu; pdu; pdu=pdu->next) {
627 SLIST_REMOVE(&rpc->waitpdu, pdu);
628 SLIST_ADD(&rpc->outqueue, pdu);
1744ef90
RS
629 /* we have to re-send the whole pdu again */
630 pdu->written = 0;
631 }
632
633 if (rpc->auto_reconnect != 0) {
634 rpc->connect_cb = reconnect_cb;
635
636 if (rpc_connect_sockaddr_async(rpc, &rpc->s) != 0) {
637 rpc_error_all_pdus(rpc, "RPC ERROR: Failed to reconnect async");
638 return -1;
639 }
b077fdeb
RS
640 }
641
642 return 0;
643}
644
485bc9b9
RS
645
646int rpc_bind_udp(struct rpc_context *rpc, char *addr, int port)
647{
648 struct addrinfo *ai = NULL;
649 char service[6];
650
4a2b0876
RS
651 assert(rpc->magic == RPC_CONTEXT_MAGIC);
652
485bc9b9
RS
653 if (rpc->is_udp == 0) {
654 rpc_set_error(rpc, "Cant not bind UDP. Not UDP context");
655 return -1;
656 }
657
6874f61e 658 sprintf(service, "%d", port);
485bc9b9
RS
659 if (getaddrinfo(addr, service, NULL, &ai) != 0) {
660 rpc_set_error(rpc, "Invalid address:%s. "
8907aea9 661 "Can not resolv into IPv4/v6 structure.", addr);
485bc9b9
RS
662 return -1;
663 }
664
665 switch(ai->ai_family) {
666 case AF_INET:
667 rpc->fd = socket(ai->ai_family, SOCK_DGRAM, 0);
668 if (rpc->fd == -1) {
8907aea9 669 rpc_set_error(rpc, "Failed to create UDP socket: %s", strerror(errno));
485bc9b9
RS
670 freeaddrinfo(ai);
671 return -1;
672 }
673
674 if (bind(rpc->fd, (struct sockaddr *)ai->ai_addr, sizeof(struct sockaddr_in)) != 0) {
8907aea9 675 rpc_set_error(rpc, "Failed to bind to UDP socket: %s",strerror(errno));
485bc9b9
RS
676 freeaddrinfo(ai);
677 return -1;
678 }
679 break;
680 default:
681 rpc_set_error(rpc, "Can not handle UPD sockets of family %d yet", ai->ai_family);
682 freeaddrinfo(ai);
683 return -1;
684 }
685
686 freeaddrinfo(ai);
687
688 return 0;
689}
690
5bf60dc6
RS
691int rpc_set_udp_destination(struct rpc_context *rpc, char *addr, int port, int is_broadcast)
692{
693 struct addrinfo *ai = NULL;
694 char service[6];
695
4a2b0876
RS
696 assert(rpc->magic == RPC_CONTEXT_MAGIC);
697
5bf60dc6
RS
698 if (rpc->is_udp == 0) {
699 rpc_set_error(rpc, "Can not set destination sockaddr. Not UDP context");
700 return -1;
701 }
702
6874f61e 703 sprintf(service, "%d", port);
5bf60dc6
RS
704 if (getaddrinfo(addr, service, NULL, &ai) != 0) {
705 rpc_set_error(rpc, "Invalid address:%s. "
8907aea9 706 "Can not resolv into IPv4/v6 structure.", addr);
5bf60dc6
RS
707 return -1;
708 }
709
710 if (rpc->udp_dest) {
711 free(rpc->udp_dest);
712 rpc->udp_dest = NULL;
713 }
714 rpc->udp_dest = malloc(ai->ai_addrlen);
715 if (rpc->udp_dest == NULL) {
716 rpc_set_error(rpc, "Out of memory. Failed to allocate sockaddr structure");
be7f5933 717 freeaddrinfo(ai);
5bf60dc6
RS
718 return -1;
719 }
720 memcpy(rpc->udp_dest, ai->ai_addr, ai->ai_addrlen);
721 freeaddrinfo(ai);
722
723 rpc->is_broadcast = is_broadcast;
bb4e9ed6 724 setsockopt(rpc->fd, SOL_SOCKET, SO_BROADCAST, (char *)&is_broadcast, sizeof(is_broadcast));
5bf60dc6
RS
725
726 return 0;
727}
c481da67
RS
728
729struct sockaddr *rpc_get_recv_sockaddr(struct rpc_context *rpc)
730{
4a2b0876
RS
731 assert(rpc->magic == RPC_CONTEXT_MAGIC);
732
c481da67
RS
733 return (struct sockaddr *)&rpc->udp_src;
734}
83aa785d
RS
735
736int rpc_queue_length(struct rpc_context *rpc)
737{
738 int i=0;
739 struct rpc_pdu *pdu;
740
4a2b0876
RS
741 assert(rpc->magic == RPC_CONTEXT_MAGIC);
742
83aa785d
RS
743 for(pdu = rpc->outqueue; pdu; pdu = pdu->next) {
744 i++;
745 }
746 for(pdu = rpc->waitpdu; pdu; pdu = pdu->next) {
747 i++;
748 }
749 return i;
750}
6ec481d3
RS
751
752void rpc_set_fd(struct rpc_context *rpc, int fd)
753{
754 assert(rpc->magic == RPC_CONTEXT_MAGIC);
755
756 rpc->fd = fd;
757}