diff --git a/daemon/control_ng.c b/daemon/control_ng.c index c3ac7dbfb..d91343267 100644 --- a/daemon/control_ng.c +++ b/daemon/control_ng.c @@ -4,7 +4,7 @@ #include "bencode.h" -static void control_ng_incoming(int fd, void *p, uintptr_t x) { +static void control_ng_incoming(struct obj *obj, char *buf, int len, struct sockaddr_in6 *sin, char *addr) { } struct control_ng *control_ng_new(struct poller *p, struct in6_addr ip, u_int16_t port, struct callmaster *m) { diff --git a/daemon/control_udp.c b/daemon/control_udp.c index eaecdc9a5..6a20112f4 100644 --- a/daemon/control_udp.c +++ b/daemon/control_udp.c @@ -17,48 +17,30 @@ #include "udp_listener.h" -static void control_udp_incoming(int fd, void *p, uintptr_t x) { - struct control_udp *u = p; - int ret, len; - char buf[8192]; - struct sockaddr_in6 sin; - socklen_t sin_len; +static void control_udp_incoming(struct obj *obj, char *buf, int len, struct sockaddr_in6 *sin, char *addr) { + struct control_udp *u = (void *) obj; + int ret; int ovec[100]; const char **out; char *reply; struct msghdr mh; struct iovec iov[10]; - char addr[64]; - -next: - sin_len = sizeof(sin); - len = recvfrom(fd, buf, sizeof(buf) - 1, 0, (struct sockaddr *) &sin, &sin_len); - if (len < 0) { - if (errno == EINTR) - goto next; - if (errno != EWOULDBLOCK && errno != EAGAIN) - mylog(LOG_WARNING, "Error reading from UDP socket"); - return; - } - - buf[len] = '\0'; - smart_ntop_p(addr, &sin.sin6_addr, sizeof(addr)); ret = pcre_exec(u->parse_re, u->parse_ree, buf, len, 0, 0, ovec, G_N_ELEMENTS(ovec)); if (ret <= 0) { ret = pcre_exec(u->fallback_re, NULL, buf, len, 0, 0, ovec, G_N_ELEMENTS(ovec)); if (ret <= 0) { - mylog(LOG_WARNING, "Unable to parse command line from udp:%s:%u: %s", addr, ntohs(sin.sin6_port), buf); - goto next; + mylog(LOG_WARNING, "Unable to parse command line from udp:%s:%u: %s", addr, ntohs(sin->sin6_port), buf); + return; } - mylog(LOG_WARNING, "Failed to properly parse UDP command line '%s' from %s:%u, using fallback RE", buf, addr, ntohs(sin.sin6_port)); + mylog(LOG_WARNING, "Failed to properly parse UDP command line '%s' from %s:%u, using fallback RE", buf, addr, ntohs(sin->sin6_port)); pcre_get_substring_list(buf, ovec, ret, &out); ZERO(mh); - mh.msg_name = &sin; - mh.msg_namelen = sizeof(sin); + mh.msg_name = sin; + mh.msg_namelen = sizeof(*sin); mh.msg_iov = iov; iov[0].iov_base = (void *) out[RE_UDP_COOKIE]; @@ -78,21 +60,21 @@ next: mh.msg_iovlen = 2; } - sendmsg(fd, &mh, 0); + sendmsg(u->udp_listener.fd, &mh, 0); pcre_free(out); - goto next; + return; } - mylog(LOG_INFO, "Got valid command from udp:%s:%u: %s", addr, ntohs(sin.sin6_port), buf); + mylog(LOG_INFO, "Got valid command from udp:%s:%u: %s", addr, ntohs(sin->sin6_port), buf); pcre_get_substring_list(buf, ovec, ret, &out); reply = cookie_cache_lookup(&u->cookie_cache, out[RE_UDP_COOKIE]); if (reply) { - mylog(LOG_INFO, "Detected command from udp:%s:%u as a duplicate", addr, ntohs(sin.sin6_port)); - sendto(fd, reply, strlen(reply), 0, (struct sockaddr *) &sin, sin_len); + mylog(LOG_INFO, "Detected command from udp:%s:%u as a duplicate", addr, ntohs(sin->sin6_port)); + sendto(u->udp_listener.fd, reply, strlen(reply), 0, (struct sockaddr *) sin, sizeof(*sin)); goto out; } @@ -106,8 +88,8 @@ next: reply = call_query_udp(out, u->callmaster); else if (chrtoupper(out[RE_UDP_V_CMD][0]) == 'V') { ZERO(mh); - mh.msg_name = &sin; - mh.msg_namelen = sizeof(sin); + mh.msg_name = sin; + mh.msg_namelen = sizeof(*sin); mh.msg_iov = iov; mh.msg_iovlen = 2; @@ -133,12 +115,12 @@ next: iov[2].iov_len = 9; mh.msg_iovlen++; } - sendmsg(fd, &mh, 0); + sendmsg(u->udp_listener.fd, &mh, 0); } if (reply) { len = strlen(reply); - sendto(fd, reply, len, 0, (struct sockaddr *) &sin, sin_len); + sendto(u->udp_listener.fd, reply, len, 0, (struct sockaddr *) sin, sizeof(*sin)); cookie_cache_insert(&u->cookie_cache, out[RE_UDP_COOKIE], reply, len); free(reply); } @@ -147,7 +129,6 @@ next: out: pcre_free(out); - goto next; } struct control_udp *control_udp_new(struct poller *p, struct in6_addr ip, u_int16_t port, struct callmaster *m) { diff --git a/daemon/udp_listener.c b/daemon/udp_listener.c index 7b6c327d9..bfaf5102b 100644 --- a/daemon/udp_listener.c +++ b/daemon/udp_listener.c @@ -3,22 +3,60 @@ #include #include #include +#include #include "udp_listener.h" #include "poller.h" #include "aux.h" +struct udp_listener_callback { + struct obj obj; + udp_listener_callback_t func; + struct obj *p; +}; + static void udp_listener_closed(int fd, void *p, uintptr_t x) { abort(); } -int udp_listener_init(struct udp_listener *u, struct poller *p, struct in6_addr ip, u_int16_t port, poller_func_t func, struct obj *obj) { +static void udp_listener_incoming(int fd, void *p, uintptr_t x) { + struct udp_listener_callback *cb = p; + struct sockaddr_in6 sin; + socklen_t sin_len; + int len; + char buf[8192]; + char addr[64]; + + for (;;) { + sin_len = sizeof(sin); + len = recvfrom(fd, buf, sizeof(buf) - 1, 0, (struct sockaddr *) &sin, &sin_len); + if (len < 0) { + if (errno == EINTR) + continue; + if (errno != EWOULDBLOCK && errno != EAGAIN) + mylog(LOG_WARNING, "Error reading from UDP socket"); + return; + } + + buf[len] = '\0'; + smart_ntop_p(addr, &sin.sin6_addr, sizeof(addr)); + + cb->func(cb->p, buf, len, &sin, addr); + } +} + +int udp_listener_init(struct udp_listener *u, struct poller *p, struct in6_addr ip, u_int16_t port, udp_listener_callback_t func, struct obj *obj) { struct sockaddr_in6 sin; struct poller_item i; + struct udp_listener_callback *cb; + + cb = obj_alloc("udp_listener_callback", sizeof(*cb), NULL); + cb->func = func; + cb->p = obj_get(obj); u->fd = socket(AF_INET6, SOCK_DGRAM, 0); if (u->fd == -1) - return -1; + goto fail; nonblock(u->fd); reuseaddr(u->fd); @@ -34,14 +72,17 @@ int udp_listener_init(struct udp_listener *u, struct poller *p, struct in6_addr ZERO(i); i.fd = u->fd; i.closed = udp_listener_closed; - i.readable = func; - i.obj = obj; + i.readable = udp_listener_incoming; + i.obj = &cb->obj; if (poller_add_item(p, &i)) goto fail; return 0; fail: - close(u->fd); + if (u->fd != -1) + close(u->fd); + obj_put(obj); + obj_put(&cb->obj); return -1; } diff --git a/daemon/udp_listener.h b/daemon/udp_listener.h index 1a989cdb5..e601869ad 100644 --- a/daemon/udp_listener.h +++ b/daemon/udp_listener.h @@ -7,11 +7,13 @@ struct poller; struct obj; +typedef void (*udp_listener_callback_t)(struct obj *p, char *buf, int len, struct sockaddr_in6 *sin, char *addr); + struct udp_listener { int fd; struct poller *poller; }; -int udp_listener_init(struct udp_listener *, struct poller *p, struct in6_addr ip, u_int16_t port, poller_func_t, struct obj *); +int udp_listener_init(struct udp_listener *, struct poller *p, struct in6_addr ip, u_int16_t port, udp_listener_callback_t, struct obj *); #endif