mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-09 00:00:04 +01:00
adopt: udp iface and AF_PACKET
This commit is contained in:
parent
70d2ca94b5
commit
3c95483518
9 changed files with 331 additions and 17 deletions
|
@ -166,7 +166,9 @@ lws_adopt_socket_vhost_readbuf(struct lws_vhost *vhost,
|
|||
lws_sockfd_type accept_fd, const char *readbuf,
|
||||
size_t len);
|
||||
|
||||
#define LWS_CAUDP_BIND 1
|
||||
#define LWS_CAUDP_BIND (1 << 0)
|
||||
#define LWS_CAUDP_BROADCAST (1 << 1)
|
||||
#define LWS_CAUDP_PF_PACKET (1 << 2)
|
||||
|
||||
#if defined(LWS_WITH_UDP)
|
||||
/**
|
||||
|
@ -177,6 +179,7 @@ lws_adopt_socket_vhost_readbuf(struct lws_vhost *vhost,
|
|||
* \param port: UDP port to bind to, -1 means unbound
|
||||
* \param flags: 0 or LWS_CAUDP_NO_BIND
|
||||
* \param protocol_name: Name of protocol on vhost to bind wsi to
|
||||
* \param ifname: NULL, for network interface name to bind socket to
|
||||
* \param parent_wsi: NULL or parent wsi new wsi will be a child of
|
||||
* \param retry_policy: NULL for vhost default policy else wsi specific policy
|
||||
*
|
||||
|
@ -185,7 +188,7 @@ lws_adopt_socket_vhost_readbuf(struct lws_vhost *vhost,
|
|||
* */
|
||||
LWS_VISIBLE LWS_EXTERN struct lws *
|
||||
lws_create_adopt_udp(struct lws_vhost *vhost, const char *ads, int port,
|
||||
int flags, const char *protocol_name,
|
||||
int flags, const char *protocol_name, const char *ifname,
|
||||
struct lws *parent_wsi, const lws_retry_bo_t *retry_policy);
|
||||
#endif
|
||||
///@}
|
||||
|
|
|
@ -430,18 +430,19 @@ lws_create_adopt_udp2(struct lws *wsi, const char *ads,
|
|||
const struct addrinfo *r, int n, void *opaque)
|
||||
{
|
||||
lws_sock_file_fd_type sock;
|
||||
int bc = 1;
|
||||
|
||||
assert(wsi);
|
||||
|
||||
if (!wsi->dns_results)
|
||||
wsi->dns_results_next = wsi->dns_results = r;
|
||||
|
||||
if (n < 0 || !r) {
|
||||
if (ads && (n < 0 || !r)) {
|
||||
/*
|
||||
* DNS lookup failed: there are no usable results. Fail the
|
||||
* overall connection request.
|
||||
*/
|
||||
lwsl_debug("%s: bad: n %d, r %p\n", __func__, n, r);
|
||||
lwsl_notice("%s: bad: n %d, r %p\n", __func__, n, r);
|
||||
|
||||
/*
|
||||
* We didn't get a callback on a cache item and bump the
|
||||
|
@ -464,27 +465,51 @@ lws_create_adopt_udp2(struct lws *wsi, const char *ads,
|
|||
* function is for.
|
||||
*/
|
||||
|
||||
#if !defined(__linux__)
|
||||
/* PF_PACKET is linux-only */
|
||||
sock.sockfd = socket(wsi->dns_results_next->ai_family,
|
||||
SOCK_DGRAM, IPPROTO_UDP);
|
||||
|
||||
#else
|
||||
sock.sockfd = socket(wsi->pf_packet ? PF_PACKET :
|
||||
wsi->dns_results_next->ai_family,
|
||||
SOCK_DGRAM, wsi->pf_packet ?
|
||||
htons(0x800) : IPPROTO_UDP);
|
||||
#endif
|
||||
if (sock.sockfd == LWS_SOCK_INVALID)
|
||||
goto resume;
|
||||
|
||||
((struct sockaddr_in *)wsi->dns_results_next->ai_addr)->sin_port =
|
||||
htons(wsi->c_port);
|
||||
|
||||
if (setsockopt(sock.sockfd, SOL_SOCKET, SO_REUSEADDR, (const char *)&bc,
|
||||
sizeof(bc)) < 0)
|
||||
lwsl_err("%s: failed to set reuse\n", __func__);
|
||||
|
||||
if (wsi->do_broadcast &&
|
||||
setsockopt(sock.sockfd, SOL_SOCKET, SO_BROADCAST, (const char *)&bc,
|
||||
sizeof(bc)) < 0)
|
||||
lwsl_err("%s: failed to set broadcast\n",
|
||||
__func__);
|
||||
|
||||
/* Bind the udp socket to a particular network interface */
|
||||
|
||||
if (opaque &&
|
||||
lws_plat_BINDTODEVICE(sock.sockfd, (const char *)opaque))
|
||||
goto resume;
|
||||
|
||||
if (wsi->do_bind &&
|
||||
bind(sock.sockfd, wsi->dns_results_next->ai_addr,
|
||||
#if defined(_WIN32)
|
||||
(int)wsi->dns_results_next->ai_addrlen
|
||||
#else
|
||||
wsi->dns_results_next->ai_addrlen
|
||||
sizeof(struct sockaddr)//wsi->dns_results_next->ai_addrlen
|
||||
#endif
|
||||
) == -1) {
|
||||
lwsl_notice("%s: bind failed\n", __func__);
|
||||
lwsl_err("%s: bind failed\n", __func__);
|
||||
goto resume;
|
||||
}
|
||||
|
||||
if (!wsi->do_bind) {
|
||||
((struct sockaddr_in *)wsi->dns_results_next->ai_addr)->
|
||||
sin_port = htons(wsi->c_port);
|
||||
if (!wsi->do_bind && !wsi->pf_packet) {
|
||||
|
||||
if (connect(sock.sockfd, wsi->dns_results_next->ai_addr,
|
||||
wsi->dns_results_next->ai_addrlen) == -1) {
|
||||
|
@ -514,7 +539,7 @@ resume:
|
|||
wsi->dns_results_next = wsi->dns_results_next->ai_next;
|
||||
}
|
||||
|
||||
lwsl_err("%s: unable to create INET socket\n", __func__);
|
||||
lwsl_err("%s: unable to create INET socket %d\n", __func__, LWS_ERRNO);
|
||||
lws_addrinfo_clean(wsi);
|
||||
|
||||
bail:
|
||||
|
@ -525,7 +550,7 @@ bail:
|
|||
|
||||
struct lws *
|
||||
lws_create_adopt_udp(struct lws_vhost *vhost, const char *ads, int port,
|
||||
int flags, const char *protocol_name,
|
||||
int flags, const char *protocol_name, const char *ifname,
|
||||
struct lws *parent_wsi, const lws_retry_bo_t *retry_policy)
|
||||
{
|
||||
#if !defined(LWS_PLAT_OPTEE)
|
||||
|
@ -543,6 +568,8 @@ lws_create_adopt_udp(struct lws_vhost *vhost, const char *ads, int port,
|
|||
goto bail;
|
||||
}
|
||||
wsi->do_bind = !!(flags & LWS_CAUDP_BIND);
|
||||
wsi->do_broadcast = !!(flags & LWS_CAUDP_BROADCAST);
|
||||
wsi->pf_packet = !!(flags & LWS_CAUDP_PF_PACKET);
|
||||
wsi->c_port = port;
|
||||
if (retry_policy)
|
||||
wsi->retry_policy = retry_policy;
|
||||
|
@ -599,7 +626,7 @@ lws_create_adopt_udp(struct lws_vhost *vhost, const char *ads, int port,
|
|||
*/
|
||||
n = lws_async_dns_query(vhost->context, 0, ads,
|
||||
LWS_ADNS_RECORD_A,
|
||||
lws_create_adopt_udp2, wsi, NULL);
|
||||
lws_create_adopt_udp2, wsi, (void *)ifname);
|
||||
lwsl_debug("%s: dns query returned %d\n", __func__, n);
|
||||
if (n == LADNS_RET_FAILED) {
|
||||
lwsl_err("%s: async dns failed\n", __func__);
|
||||
|
@ -611,8 +638,8 @@ lws_create_adopt_udp(struct lws_vhost *vhost, const char *ads, int port,
|
|||
goto bail;
|
||||
}
|
||||
} else {
|
||||
lwsl_debug("%s: fail on no ads\n", __func__);
|
||||
wsi = lws_create_adopt_udp2(wsi, ads, NULL, 0, NULL);
|
||||
lwsl_debug("%s: udp adopt has no ads\n", __func__);
|
||||
wsi = lws_create_adopt_udp2(wsi, ads, NULL, 0, (void *)ifname);
|
||||
}
|
||||
|
||||
/* dns lookup is happening asynchronously */
|
||||
|
|
|
@ -695,6 +695,8 @@ struct lws {
|
|||
unsigned int h2_acked_settings:1;
|
||||
unsigned int seen_nonpseudoheader:1;
|
||||
unsigned int listener:1;
|
||||
unsigned int pf_packet:1;
|
||||
unsigned int do_broadcast:1;
|
||||
unsigned int user_space_externally_allocated:1;
|
||||
unsigned int socket_is_permanently_unusable:1;
|
||||
unsigned int rxflow_change_to:2;
|
||||
|
|
|
@ -224,6 +224,44 @@ lws_plat_inet_pton(int af, const char *src, void *dst)
|
|||
return 1; // inet_pton(af, src, dst);
|
||||
}
|
||||
|
||||
int
|
||||
lws_plat_ifname_to_hwaddr(int fd, const char *ifname, uint8_t *hwaddr, int len)
|
||||
{
|
||||
lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
lws_plat_rawudp_broadcast(uint8_t *p, const uint8_t *canned, int canned_len,
|
||||
int n, int fd, const char *iface)
|
||||
{
|
||||
lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
lws_plat_if_up(const char *ifname, int fd, int up)
|
||||
{
|
||||
lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
lws_plat_BINDTODEVICE(int fd, const char *ifname)
|
||||
{
|
||||
lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
lws_plat_ifconfig_ip(const char *ifname, int fd, uint8_t *ip, uint8_t *mask_ip,
|
||||
uint8_t *gateway_ip)
|
||||
{
|
||||
lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -55,6 +55,8 @@
|
|||
#endif
|
||||
#if defined(__linux__)
|
||||
#include <endian.h>
|
||||
#include <linux/if_packet.h>
|
||||
#include <net/if.h>
|
||||
#endif
|
||||
#if defined(__QNX__)
|
||||
#include <gulliver.h>
|
||||
|
@ -147,6 +149,10 @@ wsi_from_fd(const struct lws_context *context, int fd);
|
|||
int
|
||||
insert_wsi(const struct lws_context *context, struct lws *wsi);
|
||||
|
||||
int
|
||||
lws_plat_ifconfig_ip(const char *ifname, int fd, uint8_t *ip, uint8_t *mask_ip,
|
||||
uint8_t *gateway_ip);
|
||||
|
||||
void
|
||||
delete_from_fd(const struct lws_context *context, int fd);
|
||||
|
||||
|
@ -174,3 +180,13 @@ delete_from_fd(const struct lws_context *context, int fd);
|
|||
#if defined(__sun) && !defined(MSG_NOSIGNAL)
|
||||
#define MSG_NOSIGNAL 0
|
||||
#endif
|
||||
|
||||
int
|
||||
lws_plat_BINDTODEVICE(int fd, const char *ifname);
|
||||
|
||||
int
|
||||
lws_plat_rawudp_broadcast(uint8_t *p, const uint8_t *canned, int canned_len,
|
||||
int n, int fd, const char *iface);
|
||||
|
||||
int
|
||||
lws_plat_if_up(const char *ifname, int fd, int up);
|
||||
|
|
|
@ -25,6 +25,10 @@
|
|||
#define _GNU_SOURCE
|
||||
#include "private-lib-core.h"
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/route.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
||||
|
@ -266,3 +270,184 @@ lws_plat_inet_pton(int af, const char *src, void *dst)
|
|||
{
|
||||
return inet_pton(af, src, dst);
|
||||
}
|
||||
|
||||
int
|
||||
lws_plat_ifname_to_hwaddr(int fd, const char *ifname, uint8_t *hwaddr, int len)
|
||||
{
|
||||
#if defined(__linux__)
|
||||
struct ifreq i;
|
||||
|
||||
memset(&i, 0, sizeof(i));
|
||||
lws_strncpy(i.ifr_name, ifname, sizeof(i.ifr_name));
|
||||
|
||||
if (ioctl(fd, SIOCGIFHWADDR, &i) < 0)
|
||||
return -1;
|
||||
|
||||
memcpy(hwaddr, &i.ifr_hwaddr.sa_data, 6);
|
||||
|
||||
return 6;
|
||||
#else
|
||||
lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
|
||||
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
lws_plat_rawudp_broadcast(uint8_t *p, const uint8_t *canned, int canned_len,
|
||||
int n, int fd, const char *iface)
|
||||
{
|
||||
#if defined(__linux__)
|
||||
struct sockaddr_ll sll;
|
||||
uint16_t *p16 = (uint16_t *)p;
|
||||
uint32_t ucs = 0;
|
||||
|
||||
memcpy(p, canned, canned_len);
|
||||
|
||||
p[2] = n >> 8;
|
||||
p[3] = n;
|
||||
|
||||
while (p16 < (uint16_t *)(p + 20))
|
||||
ucs += ntohs(*p16++);
|
||||
|
||||
ucs += ucs >> 16;
|
||||
ucs ^= 0xffff;
|
||||
|
||||
p[10] = ucs >> 8;
|
||||
p[11] = ucs;
|
||||
p[24] = (n - 20) >> 8;
|
||||
p[25] = (n - 20);
|
||||
|
||||
memset(&sll, 0, sizeof(sll));
|
||||
sll.sll_family = AF_PACKET;
|
||||
sll.sll_protocol = htons(0x800);
|
||||
sll.sll_halen = 6;
|
||||
sll.sll_ifindex = if_nametoindex(iface);
|
||||
memset(sll.sll_addr, 0xff, 6);
|
||||
|
||||
return sendto(fd, p, n, 0, (struct sockaddr *)&sll, sizeof(sll));
|
||||
#else
|
||||
lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
|
||||
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
lws_plat_if_up(const char *ifname, int fd, int up)
|
||||
{
|
||||
#if defined(__linux__)
|
||||
struct ifreq ifr;
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
lws_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
|
||||
|
||||
if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
|
||||
lwsl_err("%s: SIOCGIFFLAGS fail\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (up)
|
||||
ifr.ifr_flags |= IFF_UP;
|
||||
else
|
||||
ifr.ifr_flags &= ~IFF_UP;
|
||||
|
||||
if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
|
||||
lwsl_err("%s: SIOCSIFFLAGS fail\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
#else
|
||||
lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
|
||||
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
lws_plat_BINDTODEVICE(int fd, const char *ifname)
|
||||
{
|
||||
#if defined(__linux__)
|
||||
struct ifreq i;
|
||||
|
||||
memset(&i, 0, sizeof(i));
|
||||
i.ifr_addr.sa_family = AF_INET;
|
||||
lws_strncpy(i.ifr_ifrn.ifrn_name, ifname,
|
||||
sizeof(i.ifr_ifrn.ifrn_name));
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &i, sizeof(i)) < 0) {
|
||||
lwsl_notice("%s: failed %d\n", __func__, LWS_ERRNO);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
#else
|
||||
lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
|
||||
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
lws_plat_ifconfig_ip(const char *ifname, int fd, uint8_t *ip, uint8_t *mask_ip,
|
||||
uint8_t *gateway_ip)
|
||||
{
|
||||
#if defined(__linux__)
|
||||
struct sockaddr_in *addr;
|
||||
struct sockaddr_in sin;
|
||||
struct rtentry route;
|
||||
struct ifreq ifr;
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
memset(&route, 0, sizeof(route));
|
||||
memset(&sin, 0, sizeof(sin));
|
||||
|
||||
lws_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
|
||||
|
||||
lws_plat_if_up(ifname, fd, 0);
|
||||
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_addr.s_addr = htonl(*(uint32_t *)ip);
|
||||
|
||||
memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr));
|
||||
if (ioctl(fd, SIOCSIFADDR, &ifr) < 0) {
|
||||
lwsl_err("%s: SIOCSIFADDR fail\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
|
||||
sin.sin_addr.s_addr = htonl(*(uint32_t *)mask_ip);
|
||||
memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr));
|
||||
if (ioctl(fd, SIOCSIFNETMASK, &ifr) < 0) {
|
||||
lwsl_err("%s: SIOCSIFNETMASK fail\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
|
||||
lws_plat_if_up(ifname, fd, 1);
|
||||
|
||||
addr = (struct sockaddr_in *)&route.rt_gateway;
|
||||
addr->sin_family = AF_INET;
|
||||
addr->sin_addr.s_addr = htonl(*(uint32_t *)gateway_ip);
|
||||
|
||||
addr = (struct sockaddr_in *)&route.rt_dst;
|
||||
addr->sin_family = AF_INET;
|
||||
addr->sin_addr.s_addr = 0;
|
||||
|
||||
addr = (struct sockaddr_in *)&route.rt_genmask;
|
||||
addr->sin_family = AF_INET;
|
||||
addr->sin_addr.s_addr = 0;
|
||||
|
||||
route.rt_flags = RTF_UP | RTF_GATEWAY;
|
||||
route.rt_metric = 100;
|
||||
|
||||
if (ioctl(fd, SIOCADDRT, &route) < 0) {
|
||||
lwsl_err("%s: SIOCADDRT fail: %d\n", __func__, LWS_ERRNO);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
#else
|
||||
lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
|
||||
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -315,3 +315,46 @@ lws_plat_inet_pton(int af, const char *src, void *dst)
|
|||
lws_free(buffer);
|
||||
return ok ? 1 : -1;
|
||||
}
|
||||
|
||||
int
|
||||
lws_plat_ifname_to_hwaddr(int fd, const char *ifname, uint8_t *hwaddr, int len)
|
||||
{
|
||||
lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
lws_plat_rawudp_broadcast(uint8_t *p, const uint8_t *canned, int canned_len,
|
||||
int n, int fd, const char *iface)
|
||||
{
|
||||
lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
lws_plat_if_up(const char *ifname, int fd, int up)
|
||||
{
|
||||
lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
lws_plat_BINDTODEVICE(int fd, const char *ifname)
|
||||
{
|
||||
lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
lws_plat_ifconfig_ip(const char *ifname, int fd, uint8_t *ip, uint8_t *mask_ip,
|
||||
uint8_t *gateway_ip)
|
||||
{
|
||||
lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -312,7 +312,7 @@ lws_async_dns_init(struct lws_context *context)
|
|||
|
||||
context->async_dns.wsi = lws_create_adopt_udp(context->vhost_list, ads,
|
||||
53, 0, lws_async_dns_protocol.name, NULL,
|
||||
&retry_policy);
|
||||
NULL, &retry_policy);
|
||||
if (!dns->wsi) {
|
||||
lwsl_err("%s: foreign socket adoption failed\n", __func__);
|
||||
return 1;
|
||||
|
|
|
@ -170,7 +170,7 @@ int main(int argc, const char **argv)
|
|||
* Create our own "foreign" UDP socket bound to 7681/udp
|
||||
*/
|
||||
if (!lws_create_adopt_udp(vhost, NULL, 7681, LWS_CAUDP_BIND,
|
||||
protocols[0].name, NULL, NULL)) {
|
||||
protocols[0].name, NULL, NULL, NULL)) {
|
||||
lwsl_err("%s: foreign socket adoption failed\n", __func__);
|
||||
goto bail;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue