2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1999 University of Maryland at College Park
4 * Copyright (c) 2007-2012 Zmanda, Inc. All Rights Reserved.
7 * Permission to use, copy, modify, distribute, and sell this software and its
8 * documentation for any purpose is hereby granted without fee, provided that
9 * the above copyright notice appear in all copies and that both that
10 * copyright notice and this permission notice appear in supporting
11 * documentation, and that the name of U.M. not be used in advertising or
12 * publicity pertaining to distribution of the software without specific,
13 * written prior permission. U.M. makes no representations about the
14 * suitability of this software for any purpose. It is provided "as is"
15 * without express or implied warranty.
17 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
19 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
21 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
22 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 * Author: James da Silva, Systems Design and Analysis Group
25 * Computer Science Department
26 * University of Maryland at College Park
29 * $Id: dgram.c,v 1.32 2006/07/05 19:54:20 martinea Exp $
31 * library routines to marshall/send, recv/unmarshall UDP packets
38 #include "sockaddr-util.h"
45 if(socket < 0 || socket >= (int)FD_SETSIZE) {
46 error(_("dgram_socket: socket %d out of range (0 .. %d)\n"),
47 socket, (int)FD_SETSIZE-1);
50 dgram->socket = socket;
65 int sndbufsize = MAX_DGRAM;
67 portrange = getconf_intrange(CNF_RESERVED_UDP_PORT);
68 *portp = (in_port_t)0;
69 g_debug("dgram_bind: setting up a socket with family %d", family);
70 if((s = socket(family, SOCK_DGRAM, 0)) == -1) {
72 dbprintf(_("dgram_bind: socket() failed: %s\n"),
73 strerror(save_errno));
77 if(s < 0 || s >= (int)FD_SETSIZE) {
78 dbprintf(_("dgram_bind: socket out of range: %d\n"),
81 errno = EMFILE; /* out of range */
85 /* try setting the buffer size (= maximum allowable UDP packet size) */
86 if (setsockopt(s, SOL_SOCKET, SO_SNDBUF,
87 (void *) &sndbufsize, sizeof(sndbufsize)) < 0) {
88 dbprintf("dgram_bind: could not set udp send buffer to %d: %s (ignored)\n",
89 sndbufsize, strerror(errno));
92 SU_INIT(&name, family);
93 SU_SET_INADDR_ANY(&name);
96 * If a port range was specified, we try to get a port in that
97 * range first. Next, we try to get a reserved port. If that
98 * fails, we just go for any port.
100 * In all cases, not to use port that's assigned to other services.
102 * It is up to the caller to make sure we have the proper permissions
103 * to get the desired port, and to make sure we return a port that
104 * is within the range it requires.
106 for (retries = 0; ; retries++) {
107 if (bind_portrange(s, &name, portrange[0], portrange[1], "udp") == 0)
109 dbprintf(_("dgram_bind: Could not bind to port in range: %d - %d.\n"),
110 portrange[0], portrange[1]);
111 if (retries >= BIND_CYCLE_RETRIES) {
112 dbprintf(_("dgram_bind: Giving up...\n"));
116 dbprintf(_("dgram_bind: Retrying entire range after 10 second delay.\n"));
121 dbprintf(_("dgram_bind: bind(in6addr_any) failed: %s\n"),
122 strerror(save_errno));
128 /* find out what name was actually used */
130 len = (socklen_t_equiv)sizeof(name);
131 if(getsockname(s, (struct sockaddr *)&name, &len) == -1) {
133 dbprintf(_("dgram_bind: getsockname() failed: %s\n"), strerror(save_errno));
138 *portp = SU_GET_PORT(&name);
141 dbprintf(_("dgram_bind: socket %d bound to %s\n"),
142 dgram->socket, str_sockaddr(&name));
149 sockaddr_union *addr,
157 #if defined(USE_REUSEADDR)
162 dbprintf(_("dgram_send_addr(addr=%p, dgram=%p)\n"),
165 dbprintf(_("dgram_send_addr: %p->socket = %d\n"),
166 dgram, dgram->socket);
167 if(dgram->socket != -1) {
171 int sndbufsize = MAX_DGRAM;
173 g_debug("dgram_send_addr: setting up a socket with family %d", SU_GET_FAMILY(addr));
174 if((s = socket(SU_GET_FAMILY(addr), SOCK_DGRAM, 0)) == -1) {
176 dbprintf(_("dgram_send_addr: socket() failed: %s\n"),
177 strerror(save_errno));
183 r = setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
184 (void *)&on, (socklen_t_equiv)sizeof(on));
186 dbprintf(_("dgram_send_addr: setsockopt(SO_REUSEADDR) failed: %s\n"),
191 /* try setting the buffer size (= maximum allowable UDP packet size) */
192 if (setsockopt(s, SOL_SOCKET, SO_SNDBUF,
193 (void *) &sndbufsize, sizeof(sndbufsize)) < 0) {
194 dbprintf("dgram_send_addr: could not set udp send buffer to %d: %s (ignored)\n",
195 sndbufsize, strerror(errno));
199 if(s < 0 || s >= (int)FD_SETSIZE) {
200 dbprintf(_("dgram_send_addr: socket out of range: %d\n"), s);
201 errno = EMFILE; /* out of range */
204 max_wait = 300 / 5; /* five minutes */
211 (struct sockaddr *)addr,
212 SS_LEN(addr)) == -1) {
214 if(errno == ECONNREFUSED && wait_count++ < max_wait) {
216 dbprintf(_("dgram_send_addr: sendto(%s): retry %d after ECONNREFUSED\n"),
223 if(errno == EAGAIN && wait_count++ < max_wait) {
225 dbprintf(_("dgram_send_addr: sendto(%s): retry %d after EAGAIN\n"),
232 dbprintf(_("dgram_send_addr: sendto(%s) failed: %s \n"),
234 strerror(save_errno));
244 dbprintf(_("dgram_send_addr: close(%s): failed: %s\n"),
248 * Calling function should not care that the close failed.
249 * It does care about the send results though.
264 sockaddr_union *fromaddr)
266 SELECT_ARG_TYPE ready;
270 socklen_t_equiv addrlen;
274 sock = dgram->socket;
277 FD_SET(sock, &ready);
281 dbprintf(_("dgram_recv(dgram=%p, timeout=%u, fromaddr=%p)\n"),
282 dgram, timeout, fromaddr);
284 nfound = (ssize_t)select(sock+1, &ready, NULL, NULL, &to);
285 if(nfound <= 0 || !FD_ISSET(sock, &ready)) {
288 dbprintf(_("dgram_recv: select() failed: %s\n"), strerror(save_errno));
289 } else if(nfound == 0) {
290 dbprintf(plural(_("dgram_recv: timeout after %d second\n"),
291 _("dgram_recv: timeout after %d seconds\n"),
295 } else if (!FD_ISSET(sock, &ready)) {
298 for(i = 0; i < sock + 1; i++) {
299 if(FD_ISSET(i, &ready)) {
300 dbprintf(_("dgram_recv: got fd %d instead of %d\n"), i, sock);
310 addrlen = (socklen_t_equiv)sizeof(sockaddr_union);
311 size = recvfrom(sock, dgram->data, (size_t)MAX_DGRAM, 0,
312 (struct sockaddr *)fromaddr, &addrlen);
315 dbprintf(_("dgram_recv: recvfrom() failed: %s\n"), strerror(save_errno));
319 dump_sockaddr(fromaddr);
320 dgram->len = (size_t)size;
321 dgram->data[size] = '\0';
322 dgram->cur = dgram->data;
331 dgram->cur = dgram->data;
333 *(dgram->cur) = '\0';
336 printf_arglist_function1(int dgram_cat, dgram_t *, dgram, const char *, fmt)
342 assert(dgram != NULL);
345 assert(dgram->len == (size_t)(dgram->cur - dgram->data));
346 assert(dgram->len < SIZEOF(dgram->data));
348 bufsize = (ssize_t)(sizeof(dgram->data) - dgram->len);
352 arglist_start(argp, fmt);
353 len = g_vsnprintf(dgram->cur, (size_t)bufsize, fmt, argp);
357 } else if((ssize_t)len > bufsize) {
358 dgram->len = sizeof(dgram->data);
359 dgram->cur = dgram->data + dgram->len;
364 dgram->cur = dgram->data + dgram->len;
373 char *p = dgram->cur;
374 char *end = dgram->data + dgram->len;
376 while(p < end && *p && *p != '\n')