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.29 2006/01/12 01:57:05 paddy_s Exp $
30 * library routines to marshall/send, recv/unmarshall UDP packets
37 void dgram_socket(dgram, socket)
41 if(socket < 0 || socket >= FD_SETSIZE) {
42 error("dgram_socket: socket %d out of range (0 .. %d)\n",
43 socket, FD_SETSIZE-1);
45 dgram->socket = socket;
49 int dgram_bind(dgram, portp)
55 struct sockaddr_in name;
58 if((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
60 dbprintf(("%s: dgram_bind: socket() failed: %s\n",
62 strerror(save_errno)));
66 if(s < 0 || s >= FD_SETSIZE) {
67 dbprintf(("%s: dgram_bind: socket out of range: %d\n",
71 errno = EMFILE; /* out of range */
75 memset(&name, 0, sizeof(name));
76 name.sin_family = AF_INET;
77 name.sin_addr.s_addr = INADDR_ANY;
80 * If a port range was specified, we try to get a port in that
81 * range first. Next, we try to get a reserved port. If that
82 * fails, we just go for any port.
84 * In all cases, not to use port that's assigned to other services.
86 * It is up to the caller to make sure we have the proper permissions
87 * to get the desired port, and to make sure we return a port that
88 * is within the range it requires.
91 if (bind_portrange(s, &name, UDPPORTRANGE, "udp") == 0)
95 if (bind_portrange(s, &name, 512, IPPORT_RESERVED - 1, "udp") == 0)
98 name.sin_port = INADDR_ANY;
99 if (bind(s, (struct sockaddr *)&name, (socklen_t)sizeof name) == -1) {
101 dbprintf(("%s: dgram_bind: bind(INADDR_ANY) failed: %s\n",
103 strerror(save_errno)));
110 /* find out what name was actually used */
112 len = (socklen_t) sizeof name;
113 if(getsockname(s, (struct sockaddr *)&name, &len) == -1) {
115 dbprintf(("%s: dgram_bind: getsockname() failed: %s\n",
117 strerror(save_errno)));
122 *portp = ntohs(name.sin_port);
125 dbprintf(("%s: dgram_bind: socket bound to %s.%d\n",
126 debug_prefix_time(NULL),
127 inet_ntoa(name.sin_addr),
133 int dgram_send_addr(addr, dgram)
134 struct sockaddr_in addr;
139 struct sockaddr_in addr_save;
144 if(dgram->socket != -1) {
148 if((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
150 dbprintf(("%s: dgram_send_addr: socket() failed: %s\n",
152 strerror(save_errno)));
159 if(s < 0 || s >= FD_SETSIZE) {
160 dbprintf(("%s: dgram_send_addr: socket out of range: %d\n",
166 errno = EMFILE; /* out of range */
170 memcpy(&addr_save, &addr, sizeof(addr));
171 max_wait = 300 / 5; /* five minutes */
177 (struct sockaddr *)&addr,
178 (socklen_t) sizeof(struct sockaddr_in)) == -1) {
180 if(errno == ECONNREFUSED && wait_count++ < max_wait) {
182 dbprintf(("%s: dgram_send_addr: sendto(%s.%d): retry %d after ECONNREFUSED\n",
183 debug_prefix_time(NULL),
184 inet_ntoa(addr_save.sin_addr),
185 (int) ntohs(addr.sin_port),
191 if(errno == EAGAIN && wait_count++ < max_wait) {
193 dbprintf(("%s: dgram_send_addr: sendto(%s.%d): retry %d after EAGAIN\n",
194 debug_prefix_time(NULL),
195 inet_ntoa(addr_save.sin_addr),
196 (int) ntohs(addr.sin_port),
202 dbprintf(("%s: dgram_send_addr: sendto(%s.%d) failed: %s \n",
203 debug_prefix_time(NULL),
204 inet_ntoa(addr_save.sin_addr),
205 (int) ntohs(addr.sin_port),
206 strerror(save_errno)));
214 dbprintf(("%s: dgram_send_addr: close(%s.%d): failed: %s\n",
216 inet_ntoa(addr_save.sin_addr),
217 (int) ntohs(addr.sin_port),
218 strerror(save_errno)));
229 int dgram_send(hostname, port, dgram)
234 struct sockaddr_in name;
238 if((hp = gethostbyname(hostname)) == 0) {
240 dbprintf(("%s: dgram_send: gethostbyname(%s) failed\n",
241 debug_prefix_time(NULL),
246 memcpy(&name.sin_addr, hp->h_addr, hp->h_length);
247 name.sin_family = AF_INET;
248 name.sin_port = htons(port);
250 return dgram_send_addr(name, dgram);
254 int dgram_recv(dgram, timeout, fromaddr)
257 struct sockaddr_in *fromaddr;
267 sock = dgram->socket;
270 FD_SET(sock, &ready);
274 nfound = select(sock+1, (SELECT_ARG_TYPE *)&ready, NULL, NULL, &to);
275 if(nfound <= 0 || !FD_ISSET(sock, &ready)) {
278 dbprintf(("%s: dgram_recv: select() failed: %s\n",
279 debug_prefix_time(NULL),
280 strerror(save_errno)));
281 } else if(nfound == 0) {
282 dbprintf(("%s: dgram_recv: timeout after %d second%s\n",
283 debug_prefix_time(NULL),
285 (timeout == 1) ? "" : "s"));
287 } else if (!FD_ISSET(sock, &ready)) {
290 for(i = 0; i < sock + 1; i++) {
291 if(FD_ISSET(i, &ready)) {
292 dbprintf(("%s: dgram_recv: got fd %d instead of %d\n",
293 debug_prefix_time(NULL),
305 addrlen = (socklen_t) sizeof(struct sockaddr_in);
306 size = recvfrom(sock, dgram->data, MAX_DGRAM, 0,
307 (struct sockaddr *)fromaddr, &addrlen);
310 dbprintf(("%s: dgram_recv: recvfrom() failed: %s\n",
312 strerror(save_errno)));
317 dgram->data[size] = '\0';
318 dgram->cur = dgram->data;
323 void dgram_zero(dgram)
326 dgram->cur = dgram->data;
328 *(dgram->cur) = '\0';
331 printf_arglist_function1(void dgram_cat, dgram_t *, dgram, const char *, fmt)
336 assert(dgram != NULL);
339 assert(dgram->len == dgram->cur - dgram->data);
340 assert(dgram->len >= 0 && dgram->len < sizeof(dgram->data));
342 bufsize = sizeof(dgram->data) - dgram->len;
346 arglist_start(argp, fmt);
347 dgram->len += vsnprintf(dgram->cur, bufsize, fmt, argp);
348 dgram->cur = dgram->data + dgram->len;
352 void dgram_eatline(dgram)
355 char *p = dgram->cur;
356 char *end = dgram->data + dgram->len;
358 while(p < end && *p && *p != '\n') p++;