1 /* UDP send/receive module for secnet */
3 /* This module enables sites to communicate by sending UDP
4 * packets. When an instance of the module is created we can
5 * optionally bind to a particular local IP address (not implemented
8 * Sites register an interest in local port numbers for receiving
9 * packets, and can also send packets. We don't care about the source
10 * port number for sending packets.
12 * Packets are offered to registered receivers in turn. Once one
13 * accepts it, it isn't offered to any more. */
21 #include <sys/socket.h>
24 #include "unaligned.h"
26 static beforepoll_fn udp_beforepoll
;
27 static afterpoll_fn udp_afterpoll
;
28 static comm_request_notify_fn request_notify
;
29 static comm_release_notify_fn release_notify
;
30 static comm_sendmsg_fn udp_sendmsg
;
32 /* The UDP module exports a pure closure which can be used to construct a
33 * UDP send/receive module. Arguments:
39 struct notify_list
*next
;
49 struct buffer_if
*rbuf
;
50 struct notify_list
*notify
;
53 static int udp_beforepoll(void *state
, struct pollfd
*fds
, int *nfds_io
,
54 int *timeout_io
, const struct timeval
*tv
,
68 static void udp_afterpoll(void *state
, struct pollfd
*fds
, int nfds
,
69 const struct timeval
*tv
, uint64_t *now
)
72 struct sockaddr_in from
;
74 struct notify_list
*n
;
78 if (nfds
&& (fds
->revents
& POLLIN
)) {
81 BUF_ASSERT_FREE(st
->rbuf
);
82 BUF_ALLOC(st
->rbuf
,"udp_afterpoll");
83 rv
=recvfrom(st
->fd
, st
->rbuf
->start
, st
->rbuf
->len
, 0,
84 (struct sockaddr
*)&from
, &fromlen
);
88 for (n
=st
->notify
; n
; n
=n
->next
) {
89 if (n
->fn(n
->state
, st
->rbuf
, &from
)) {
96 /* XXX manufacture and send NAK packet */
97 source
=get_uint32(st
->rbuf
->start
); /* Us */
98 dest
=get_uint32(st
->rbuf
->start
+4); /* Them */
99 Message(M_INFO
,"udp (port %d): sending NAK\n",st
->port
);
100 buffer_init(st
->rbuf
,0);
101 buf_append_uint32(st
->rbuf
,dest
);
102 buf_append_uint32(st
->rbuf
,source
);
103 buf_append_uint32(st
->rbuf
,0); /* NAK is msg type 0 */
104 sendto(st
->fd
, st
->rbuf
->start
, st
->rbuf
->size
, 0,
105 (struct sockaddr
*)&from
, sizeof(from
));
108 BUF_ASSERT_FREE(st
->rbuf
);
116 static void request_notify(void *commst
, void *nst
, comm_notify_fn
*fn
)
118 struct udp
*st
=commst
;
119 struct notify_list
*n
;
121 n
=safe_malloc(sizeof(*n
),"request_notify");
128 static void release_notify(void *commst
, void *nst
, comm_notify_fn
*fn
)
130 struct udp
*st
=commst
;
131 struct notify_list
*n
, **p
, *t
;
135 for (n
=st
->notify
; n
; )
137 if (n
->state
==nst
&& n
->fn
==fn
) {
149 static bool_t
udp_sendmsg(void *commst
, struct buffer_if
*buf
,
150 struct sockaddr_in
*dest
)
152 struct udp
*st
=commst
;
154 /* XXX fix error reporting */
155 sendto(st
->fd
, buf
->start
, buf
->size
, 0,
156 (struct sockaddr
*)dest
, sizeof(*dest
));
161 static void udp_phase_hook(void *sst
, uint32_t new_phase
)
164 struct sockaddr_in addr
;
166 st
->fd
=socket(AF_INET
, SOCK_DGRAM
, 0);
168 fatal_perror("udp (%s:%d): socket",st
->loc
.file
,st
->loc
.line
);
170 if (fcntl(st
->fd
, F_SETFL
, fcntl(st
->fd
, F_GETFL
)|O_NONBLOCK
)==-1) {
171 fatal_perror("udp (%s:%d): fcntl(set O_NONBLOCK)",
172 st
->loc
.file
,st
->loc
.line
);
174 if (fcntl(st
->fd
, F_SETFD
, FD_CLOEXEC
)==-1) {
175 fatal_perror("udp (%s:%d): fcntl(set FD_CLOEXEC)",
176 st
->loc
.file
,st
->loc
.line
);
179 memset(&addr
, 0, sizeof(addr
));
180 addr
.sin_family
=AF_INET
;
181 addr
.sin_port
=htons(st
->port
);
186 /* XXX this fork() and waitpid() business needs to be hidden
187 in some system-specific library functions. */
190 fatal_perror("udp_phase_hook: fork() for authbind");
194 argv
[0]=st
->authbind
;
197 if (!argv
[2]) exit(ENOMEM
);
198 sprintf(argv
[2],"%04X",htons(st
->port
));
201 execvp(st
->authbind
,argv
);
204 waitpid(c
,&status
,0);
205 if (WEXITSTATUS(status
)!=0) {
206 errno
=WEXITSTATUS(status
);
207 fatal_perror("udp (%s:%d): authbind",st
->loc
.file
,st
->loc
.line
);
210 if (bind(st
->fd
, (struct sockaddr
*)&addr
, sizeof(addr
))!=0) {
211 fatal_perror("udp (%s:%d): bind",st
->loc
.file
,st
->loc
.line
);
215 register_for_poll(st
,udp_beforepoll
,udp_afterpoll
,1,"udp");
218 static list_t
*udp_apply(closure_t
*self
, struct cloc loc
, dict_t
*context
,
225 st
=safe_malloc(sizeof(*st
),"udp_apply(st)");
227 st
->cl
.description
="udp";
230 st
->cl
.interface
=&st
->ops
;
232 st
->ops
.request_notify
=request_notify
;
233 st
->ops
.release_notify
=release_notify
;
234 st
->ops
.sendmsg
=udp_sendmsg
;
238 if (!i
|| i
->type
!=t_dict
) {
239 cfgfatal(st
->loc
,"udp","first argument must be a dictionary\n");
243 st
->port
=dict_read_number(d
,"port",True
,"udp",st
->loc
,0);
244 st
->rbuf
=find_cl_if(d
,"buffer",CL_BUFFER
,True
,"udp",st
->loc
);
245 st
->authbind
=dict_read_string(d
,"authbind",False
,"udp",st
->loc
);
247 add_hook(PHASE_GETRESOURCES
,udp_phase_hook
,st
);
249 return new_closure(&st
->cl
);
252 init_module udp_module
;
253 void udp_module(dict_t
*dict
)
255 add_closure(dict
,"udp",udp_apply
);