2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1999 University of Maryland at College Park
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of U.M. not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission. U.M. makes no representations about the
13 * suitability of this software for any purpose. It is provided "as is"
14 * without express or implied warranty.
16 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 * Author: James da Silva, Systems Design and Analysis Group
24 * Computer Science Department
25 * University of Maryland at College Park
28 * $Id: dgram.c,v 1.32.2.4 2006/10/16 18:23:53 martinea Exp $
30 * library routines to marshall/send, recv/unmarshall UDP packets
42 if(socket < 0 || socket >= FD_SETSIZE) {
43 error("dgram_socket: socket %d out of range (0 .. %d)\n",
44 socket, FD_SETSIZE-1);
47 dgram->socket = socket;
58 struct sockaddr_in name;
61 *portp = (in_port_t)0;
62 if((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
64 dbprintf(("%s: dgram_bind: socket() failed: %s\n",
66 strerror(save_errno)));
70 if(s < 0 || s >= (int)FD_SETSIZE) {
71 dbprintf(("%s: dgram_bind: socket out of range: %d\n",
75 errno = EMFILE; /* out of range */
79 memset(&name, 0, SIZEOF(name));
80 name.sin_family = (sa_family_t)AF_INET;
81 name.sin_addr.s_addr = INADDR_ANY;
84 * If a port range was specified, we try to get a port in that
85 * range first. Next, we try to get a reserved port. If that
86 * fails, we just go for any port.
88 * In all cases, not to use port that's assigned to other services.
90 * It is up to the caller to make sure we have the proper permissions
91 * to get the desired port, and to make sure we return a port that
92 * is within the range it requires.
94 for (retries = 0; ; retries++) {
96 if (bind_portrange(s, &name, UDPPORTRANGE, "udp") == 0)
98 dbprintf(("%s: dgram_bind: Could to bind to port in range: %d - %d.\n",
99 debug_prefix(NULL), UDPPORTRANGE));
102 if (bind_portrange(s, &name, (in_port_t)512,
103 (in_port_t)(IPPORT_RESERVED - 1), "udp") == 0)
105 dbprintf(("%s: dgram_bind: Could to bind to port in range: 512 - %d.\n",
106 debug_prefix(NULL), IPPORT_RESERVED - 1));
108 name.sin_port = INADDR_ANY;
109 if (bind(s, (struct sockaddr *)&name, (socklen_t)sizeof(name)) == 0)
111 dbprintf(("%s: dgram_bind: Could to bind to any port: %s\n",
112 debug_prefix(NULL), strerror(errno)));
114 if (retries >= BIND_CYCLE_RETRIES) {
115 dbprintf(("%s: dgram_bind: Giving up...\n", debug_prefix(NULL)));
119 dbprintf(("%s: dgram_bind: Retrying entire range after 10 second delay.\n",
120 debug_prefix(NULL)));
125 dbprintf(("%s: dgram_bind: bind(INADDR_ANY) failed: %s\n",
127 strerror(save_errno)));
133 /* find out what name was actually used */
135 len = (socklen_t)sizeof(name);
136 if(getsockname(s, (struct sockaddr *)&name, &len) == -1) {
138 dbprintf(("%s: dgram_bind: getsockname() failed: %s\n",
140 strerror(save_errno)));
145 *portp = (in_port_t)ntohs(name.sin_port);
148 dbprintf(("%s: dgram_bind: socket bound to %s.%d\n",
149 debug_prefix_time(NULL),
150 inet_ntoa(name.sin_addr),
158 struct sockaddr_in addr,
163 struct sockaddr_in addr_save;
167 #if defined(USE_REUSEADDR)
172 dbprintf(("%s: dgram_send_addr(addr=%p, dgram=%p)\n",
173 debug_prefix(NULL), &addr, dgram));
174 dump_sockaddr(&addr);
175 dbprintf(("%s: dgram_send_addr: %p->socket = %d\n",
176 debug_prefix(NULL), dgram, dgram->socket));
177 if(dgram->socket != -1) {
181 if((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
183 dbprintf(("%s: dgram_send_addr: socket() failed: %s\n",
185 strerror(save_errno)));
191 r = setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
192 (void *)&on, (socklen_t)sizeof(on));
194 dbprintf(("%s: dgram_send_addr: setsockopt(SO_REUSEADDR) failed: %s\n",
201 memcpy(&addr_save, &addr, SIZEOF(addr));
202 if(s < 0 || s >= FD_SETSIZE) {
203 dbprintf(("%s: dgram_send_addr: socket out of range: %d\n",
206 errno = EMFILE; /* out of range */
209 max_wait = 300 / 5; /* five minutes */
216 (struct sockaddr *)&addr,
217 (int)sizeof(struct sockaddr_in)) == -1) {
219 if(errno == ECONNREFUSED && wait_count++ < max_wait) {
221 dbprintf(("%s: dgram_send_addr: sendto(%s.%hu): retry %d after ECONNREFUSED\n",
222 debug_prefix_time(NULL),
223 inet_ntoa(addr_save.sin_addr),
224 (in_port_t)ntohs(addr.sin_port),
230 if(errno == EAGAIN && wait_count++ < max_wait) {
232 dbprintf(("%s: dgram_send_addr: sendto(%s.%hu): retry %d after EAGAIN\n",
233 debug_prefix_time(NULL),
234 inet_ntoa(addr_save.sin_addr),
235 (in_port_t)ntohs(addr.sin_port),
241 dbprintf(("%s: dgram_send_addr: sendto(%s.%d) failed: %s \n",
242 debug_prefix_time(NULL),
243 inet_ntoa(addr_save.sin_addr),
244 (int) ntohs(addr.sin_port),
245 strerror(save_errno)));
255 dbprintf(("%s: dgram_send_addr: close(%s.%d): failed: %s\n",
257 inet_ntoa(addr_save.sin_addr),
258 (int) ntohs(addr.sin_port),
261 * Calling function should not care that the close failed.
262 * It does care about the send results though.
278 struct sockaddr_in name;
282 if((hp = gethostbyname(hostname)) == 0) {
284 dbprintf(("%s: dgram_send: gethostbyname(%s) failed\n",
285 debug_prefix_time(NULL),
290 memcpy(&name.sin_addr, hp->h_addr, (size_t)hp->h_length);
291 name.sin_family = (sa_family_t)AF_INET;
292 name.sin_port = (in_port_t)htons(port);
294 return dgram_send_addr(name, dgram);
302 struct sockaddr_in *fromaddr)
304 SELECT_ARG_TYPE ready;
312 sock = dgram->socket;
315 FD_SET(sock, &ready);
319 dbprintf(("%s: dgram_recv(dgram=%p, timeout=%u, fromaddr=%p)\n",
320 debug_prefix_time(NULL), dgram, timeout, fromaddr));
322 nfound = (ssize_t)select(sock+1, &ready, NULL, NULL, &to);
323 if(nfound <= 0 || !FD_ISSET(sock, &ready)) {
326 dbprintf(("%s: dgram_recv: select() failed: %s\n",
327 debug_prefix_time(NULL),
328 strerror(save_errno)));
329 } else if(nfound == 0) {
330 dbprintf(("%s: dgram_recv: timeout after %d second%s\n",
331 debug_prefix_time(NULL),
333 (timeout == 1) ? "" : "s"));
335 } else if (!FD_ISSET(sock, &ready)) {
338 for(i = 0; i < sock + 1; i++) {
339 if(FD_ISSET(i, &ready)) {
340 dbprintf(("%s: dgram_recv: got fd %d instead of %d\n",
341 debug_prefix_time(NULL),
353 addrlen = (socklen_t)sizeof(struct sockaddr_in);
354 size = recvfrom(sock, dgram->data, (size_t)MAX_DGRAM, 0,
355 (struct sockaddr *)fromaddr, &addrlen);
358 dbprintf(("%s: dgram_recv: recvfrom() failed: %s\n",
360 strerror(save_errno)));
364 dump_sockaddr(fromaddr);
365 dgram->len = (size_t)size;
366 dgram->data[size] = '\0';
367 dgram->cur = dgram->data;
376 dgram->cur = dgram->data;
378 *(dgram->cur) = '\0';
381 printf_arglist_function1(int dgram_cat, dgram_t *, dgram, const char *, fmt)
387 assert(dgram != NULL);
390 assert(dgram->len == (size_t)(dgram->cur - dgram->data));
391 assert(dgram->len < SIZEOF(dgram->data));
393 bufsize = (ssize_t)(sizeof(dgram->data) - dgram->len);
397 arglist_start(argp, fmt);
398 len = vsnprintf(dgram->cur, (size_t)bufsize, fmt, argp);
402 } else if((ssize_t)len > bufsize) {
403 dgram->len = sizeof(dgram->data);
404 dgram->cur = dgram->data + dgram->len;
409 dgram->cur = dgram->data + dgram->len;
418 char *p = dgram->cur;
419 char *end = dgram->data + dgram->len;
421 while(p < end && *p && *p != '\n')