Browse Source

now works across all interfaces

master
boB Rudis 4 years ago
parent
commit
b8c9a5380c
No known key found for this signature in database GPG Key ID: 1D7529BE14E2BBA9
  1. 8
      DESCRIPTION
  2. 8
      R/RcppExports.R
  3. 7
      R/discover.R
  4. 7
      R/query.R
  5. 3
      README.Rmd
  6. 21
      README.md
  7. 8
      man/bnjr_discover.Rd
  8. 8
      man/bnjr_query.Rd
  9. 18
      src/RcppExports.cpp
  10. 430
      src/bonjour-main.cpp
  11. 2257
      src/mdns.h

8
DESCRIPTION

@ -1,8 +1,8 @@
Package: bonjour
Type: Package
Title: Discover and Query Multicast DNS (mDNS)/zeroconf Services
Version: 0.2.0
Date: 2020-05-04
Version: 0.3.0
Date: 2020-09-20
Authors@R: c(
person("Bob", "Rudis", email = "bob@rud.is", role = c("aut", "cre"),
comment = c(ORCID = "0000-0001-5670-2640")),
@ -27,11 +27,11 @@ License: MIT + file LICENSE
Suggests:
covr, tinytest
Depends:
R (>= 3.2.0)
R (>= 3.6.0)
Imports:
Rcpp,
ndjson
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.1.0
RoxygenNote: 7.1.1
LinkingTo:
Rcpp

8
R/RcppExports.R

@ -1,11 +1,11 @@
# Generated by using Rcpp::compileAttributes() -> do not edit by hand
# Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393
int_bnjr_discover <- function(scan_time = 10L, proto = "ipv4") {
.Call(`_bonjour_int_bnjr_discover`, scan_time, proto)
int_bnjr_discover <- function(scan_time = 10L) {
.Call(`_bonjour_int_bnjr_discover`, scan_time)
}
int_bnjr_query <- function(q, scan_time = 5L, proto = "ipv4") {
.Call(`_bonjour_int_bnjr_query`, q, scan_time, proto)
int_bnjr_query <- function(q, scan_time = 5L) {
.Call(`_bonjour_int_bnjr_query`, q, scan_time)
}

7
R/discover.R

@ -2,14 +2,11 @@
#'
#' @param scan_time how long to scan for services; default is 10 and
#' should not really be that much lower in most networks.
#' @param proto "`ipv4`" or "`ipv6`"
#' @return data frame
#' @export
bnjr_discover <- function(scan_time = 10L, proto = c("ipv4", "ipv6")) {
bnjr_discover <- function(scan_time = 10L) {
proto <- match.arg(tolower(trimws(proto[1])), c("ipv4", "ipv6"))
res <- int_bnjr_discover(scan_time, proto = proto)
res <- int_bnjr_discover(scan_time)
res <- unlist(strsplit(res, "\n"))
ndjson::flatten(res, "tbl")

7
R/query.R

@ -3,14 +3,11 @@
#' @param query service to look for
#' @param scan_time how long to scan for services; default is 10 and
#' should not really be that much lower in most networks.
#' @param proto "`ipv4`" or "`ipv6`"
#' @return data frame
#' @export
bnjr_query <- function(query, scan_time = 10L, proto = c("ipv4", "ipv6")) {
bnjr_query <- function(query, scan_time = 10L) {
proto <- match.arg(tolower(trimws(proto[1])), c("ipv4", "ipv6"))
res <- int_bnjr_query(query, scan_time, proto = proto)
res <- int_bnjr_query(query, scan_time)
res <- unlist(strsplit(res, "\n"))
ndjson::flatten(res, "tbl")

3
README.Rmd

@ -58,5 +58,4 @@ cloc::cloc_pkg_md()
## Code of Conduct
Please note that this project is released with a Contributor Code of Conduct.
By participating in this project you agree to abide by its terms.
Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.

21
README.md

@ -7,9 +7,11 @@ by](https://img.shields.io/badge/Keybase-Verified-brightgreen.svg)](https://keyb
![Signed commit
%](https://img.shields.io/badge/Signed_Commits-100%25-lightgrey.svg)
[![Linux build
Status](https://travis-ci.org/hrbrmstr/bonjour.svg?branch=master)](https://travis-ci.org/hrbrmstr/bonjour)
Status](https://travis-ci.org/hrbrmstr/bonjour.svg?branch=master)](https://travis-ci.org/hrbrmstr/bonjour)
[![Coverage
Status](https://codecov.io/gh/hrbrmstr/bonjour/branch/master/graph/badge.svg)](https://codecov.io/gh/hrbrmstr/bonjour)
![Minimal R
Version](https://img.shields.io/badge/R%3E%3D-3.2.0-blue.svg)
Version](https://img.shields.io/badge/R%3E%3D-3.6.0-blue.svg)
![License](https://img.shields.io/badge/License-MIT-blue.svg)
# bonjour
@ -102,12 +104,15 @@ bnjr_query("_ssh._tcp.local.") %>%
## bonjour Metrics
| Lang | \# Files | (%) | LoC | (%) | Blank lines | (%) | \# Lines | (%) |
| :----------- | -------: | ---: | --: | ---: | ----------: | ---: | -------: | ---: |
| C/C++ Header | 1 | 0.11 | 932 | 0.76 | 154 | 0.54 | 91 | 0.46 |
| C++ | 2 | 0.22 | 261 | 0.21 | 101 | 0.35 | 31 | 0.16 |
| R | 5 | 0.56 | 26 | 0.02 | 15 | 0.05 | 46 | 0.23 |
| Rmd | 1 | 0.11 | 13 | 0.01 | 17 | 0.06 | 32 | 0.16 |
| Lang | \# Files | (%) | LoC | (%) | Blank lines | (%) | \# Lines | (%) |
| :----------- | -------: | ---: | ---: | ---: | ----------: | ---: | -------: | ---: |
| C/C++ Header | 1 | 0.06 | 980 | 0.33 | 159 | 0.26 | 129 | 0.26 |
| C++ | 2 | 0.11 | 462 | 0.16 | 113 | 0.19 | 40 | 0.08 |
| R | 5 | 0.28 | 24 | 0.01 | 13 | 0.02 | 44 | 0.09 |
| Rmd | 1 | 0.06 | 13 | 0.00 | 17 | 0.03 | 31 | 0.06 |
| SUM | 9 | 0.50 | 1479 | 0.50 | 302 | 0.50 | 244 | 0.50 |
clock Package Metrics for bonjour
## Code of Conduct

8
man/bnjr_discover.Rd

@ -6,17 +6,15 @@
\alias{mdns_discover}
\title{Browse available services}
\usage{
bnjr_discover(scan_time = 10L, proto = c("ipv4", "ipv6"))
bnjr_discover(scan_time = 10L)
bjr_discover(scan_time = 10L, proto = c("ipv4", "ipv6"))
bjr_discover(scan_time = 10L)
mdns_discover(scan_time = 10L, proto = c("ipv4", "ipv6"))
mdns_discover(scan_time = 10L)
}
\arguments{
\item{scan_time}{how long to scan for services; default is 10 and
should not really be that much lower in most networks.}
\item{proto}{"\code{ipv4}" or "\code{ipv6}"}
}
\value{
data frame

8
man/bnjr_query.Rd

@ -6,19 +6,17 @@
\alias{mdns_query}
\title{Look for a particular service}
\usage{
bnjr_query(query, scan_time = 10L, proto = c("ipv4", "ipv6"))
bnjr_query(query, scan_time = 10L)
bjr_query(query, scan_time = 10L, proto = c("ipv4", "ipv6"))
bjr_query(query, scan_time = 10L)
mdns_query(query, scan_time = 10L, proto = c("ipv4", "ipv6"))
mdns_query(query, scan_time = 10L)
}
\arguments{
\item{query}{service to look for}
\item{scan_time}{how long to scan for services; default is 10 and
should not really be that much lower in most networks.}
\item{proto}{"\code{ipv4}" or "\code{ipv6}"}
}
\value{
data frame

18
src/RcppExports.cpp

@ -6,34 +6,32 @@
using namespace Rcpp;
// int_bnjr_discover
std::string int_bnjr_discover(int scan_time, std::string proto);
RcppExport SEXP _bonjour_int_bnjr_discover(SEXP scan_timeSEXP, SEXP protoSEXP) {
std::string int_bnjr_discover(int scan_time);
RcppExport SEXP _bonjour_int_bnjr_discover(SEXP scan_timeSEXP) {
BEGIN_RCPP
Rcpp::RObject rcpp_result_gen;
Rcpp::RNGScope rcpp_rngScope_gen;
Rcpp::traits::input_parameter< int >::type scan_time(scan_timeSEXP);
Rcpp::traits::input_parameter< std::string >::type proto(protoSEXP);
rcpp_result_gen = Rcpp::wrap(int_bnjr_discover(scan_time, proto));
rcpp_result_gen = Rcpp::wrap(int_bnjr_discover(scan_time));
return rcpp_result_gen;
END_RCPP
}
// int_bnjr_query
std::string int_bnjr_query(std::string q, int scan_time, std::string proto);
RcppExport SEXP _bonjour_int_bnjr_query(SEXP qSEXP, SEXP scan_timeSEXP, SEXP protoSEXP) {
std::string int_bnjr_query(std::string q, int scan_time);
RcppExport SEXP _bonjour_int_bnjr_query(SEXP qSEXP, SEXP scan_timeSEXP) {
BEGIN_RCPP
Rcpp::RObject rcpp_result_gen;
Rcpp::RNGScope rcpp_rngScope_gen;
Rcpp::traits::input_parameter< std::string >::type q(qSEXP);
Rcpp::traits::input_parameter< int >::type scan_time(scan_timeSEXP);
Rcpp::traits::input_parameter< std::string >::type proto(protoSEXP);
rcpp_result_gen = Rcpp::wrap(int_bnjr_query(q, scan_time, proto));
rcpp_result_gen = Rcpp::wrap(int_bnjr_query(q, scan_time));
return rcpp_result_gen;
END_RCPP
}
static const R_CallMethodDef CallEntries[] = {
{"_bonjour_int_bnjr_discover", (DL_FUNC) &_bonjour_int_bnjr_discover, 2},
{"_bonjour_int_bnjr_query", (DL_FUNC) &_bonjour_int_bnjr_query, 3},
{"_bonjour_int_bnjr_discover", (DL_FUNC) &_bonjour_int_bnjr_discover, 1},
{"_bonjour_int_bnjr_query", (DL_FUNC) &_bonjour_int_bnjr_query, 2},
{NULL, NULL, 0}
};

430
src/bonjour-main.cpp

@ -15,9 +15,17 @@ using namespace Rcpp;
# define sleep(x) Sleep(x * 1000)
#else
# include <netdb.h>
# include <ifaddrs.h>
#endif
static uint32_t service_address_ipv4;
static uint8_t service_address_ipv6[16];
static int has_ipv4;
static int has_ipv6;
static char addrbuffer[64];
static char entrybuffer[256];
static char namebuffer[256];
//static char sendbuffer[256];
static mdns_record_txt_t txtbuffer[128];
@ -30,13 +38,15 @@ typedef struct {
int port;
} service_record_t;
static mdns_string_t
ipv4_address_to_string(char* buffer, size_t capacity, const struct sockaddr_in* addr, size_t addrlen) {
ipv4_address_to_string(char* buffer, size_t capacity, const struct sockaddr_in* addr,
size_t addrlen) {
char host[NI_MAXHOST] = {0};
char service[NI_MAXSERV] = {0};
int ret = getnameinfo((const struct sockaddr*)addr, addrlen,
host, NI_MAXHOST, service, NI_MAXSERV,
NI_NUMERICSERV | NI_NUMERICHOST);
int ret = getnameinfo((const struct sockaddr*)addr, (socklen_t)addrlen, host, NI_MAXHOST,
service, NI_MAXSERV, NI_NUMERICSERV | NI_NUMERICHOST);
int len = 0;
if (ret == 0) {
if (addr->sin_port != 0)
@ -44,18 +54,21 @@ static mdns_string_t
else
len = snprintf(buffer, capacity, "%s", host);
}
if (len >= (int)capacity) len = (int)capacity - 1;
mdns_string_t str = {buffer, (size_t)len};
if (len >= (int)capacity)
len = (int)capacity - 1;
mdns_string_t str;
str.str = buffer;
str.length = len;
return str;
}
static mdns_string_t
ipv6_address_to_string(char* buffer, size_t capacity, const struct sockaddr_in6* addr, size_t addrlen) {
ipv6_address_to_string(char* buffer, size_t capacity, const struct sockaddr_in6* addr,
size_t addrlen) {
char host[NI_MAXHOST] = {0};
char service[NI_MAXSERV] = {0};
int ret = getnameinfo((const struct sockaddr*)addr, addrlen,
host, NI_MAXHOST, service, NI_MAXSERV,
NI_NUMERICSERV | NI_NUMERICHOST);
int ret = getnameinfo((const struct sockaddr*)addr, (socklen_t)addrlen, host, NI_MAXHOST,
service, NI_MAXSERV, NI_NUMERICSERV | NI_NUMERICHOST);
int len = 0;
if (ret == 0) {
if (addr->sin6_port != 0)
@ -65,7 +78,9 @@ static mdns_string_t
}
if (len >= (int)capacity)
len = (int)capacity - 1;
mdns_string_t str = {buffer, (size_t)len};
mdns_string_t str;
str.str = buffer;
str.length = len;
return str;
}
@ -76,15 +91,228 @@ static mdns_string_t
return ipv4_address_to_string(buffer, capacity, (const struct sockaddr_in*)addr, addrlen);
}
static int query_callback(int sock, const struct sockaddr* from, size_t addrlen,
mdns_entry_type_t entry, uint16_t transaction_id,
uint16_t rtype, uint16_t rclass, uint32_t ttl,
const void* data, size_t size, size_t offset, size_t length,
static int
open_client_sockets(int* sockets, int max_sockets, int port) {
// When sending, each socket can only send to one network interface
// Thus we need to open one socket for each interface and address family
int num_sockets = 0;
#ifdef _WIN32
IP_ADAPTER_ADDRESSES* adapter_address = 0;
ULONG address_size = 8000;
unsigned int ret;
unsigned int num_retries = 4;
do {
adapter_address = malloc(address_size);
ret = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_ANYCAST, 0,
adapter_address, &address_size);
if (ret == ERROR_BUFFER_OVERFLOW) {
free(adapter_address);
adapter_address = 0;
} else {
break;
}
} while (num_retries-- > 0);
if (!adapter_address || (ret != NO_ERROR)) {
free(adapter_address);
printf("Failed to get network adapter addresses\n");
return num_sockets;
}
int first_ipv4 = 1;
int first_ipv6 = 1;
for (PIP_ADAPTER_ADDRESSES adapter = adapter_address; adapter; adapter = adapter->Next) {
if (adapter->TunnelType == TUNNEL_TYPE_TEREDO)
continue;
if (adapter->OperStatus != IfOperStatusUp)
continue;
for (IP_ADAPTER_UNICAST_ADDRESS* unicast = adapter->FirstUnicastAddress; unicast;
unicast = unicast->Next) {
if (unicast->Address.lpSockaddr->sa_family == AF_INET) {
struct sockaddr_in* saddr = (struct sockaddr_in*)unicast->Address.lpSockaddr;
if ((saddr->sin_addr.S_un.S_un_b.s_b1 != 127) ||
(saddr->sin_addr.S_un.S_un_b.s_b2 != 0) ||
(saddr->sin_addr.S_un.S_un_b.s_b3 != 0) ||
(saddr->sin_addr.S_un.S_un_b.s_b4 != 1)) {
int log_addr = 0;
if (first_ipv4) {
service_address_ipv4 = saddr->sin_addr.S_un.S_addr;
first_ipv4 = 0;
log_addr = 1;
}
has_ipv4 = 1;
if (num_sockets < max_sockets) {
saddr->sin_port = htons((unsigned short)port);
int sock = mdns_socket_open_ipv4(saddr);
if (sock >= 0) {
sockets[num_sockets++] = sock;
log_addr = 1;
} else {
log_addr = 0;
}
}
if (log_addr) {
char buffer[128];
mdns_string_t addr = ipv4_address_to_string(buffer, sizeof(buffer), saddr,
sizeof(struct sockaddr_in));
// printf("Local IPv4 address: %.*s\n", MDNS_STRING_FORMAT(addr));
}
}
} else if (unicast->Address.lpSockaddr->sa_family == AF_INET6) {
struct sockaddr_in6* saddr = (struct sockaddr_in6*)unicast->Address.lpSockaddr;
static const unsigned char localhost[] = {0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1};
static const unsigned char localhost_mapped[] = {0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0xff, 0xff, 0x7f, 0, 0, 1};
if ((unicast->DadState == NldsPreferred) &&
memcmp(saddr->sin6_addr.s6_addr, localhost, 16) &&
memcmp(saddr->sin6_addr.s6_addr, localhost_mapped, 16)) {
int log_addr = 0;
if (first_ipv6) {
memcpy(service_address_ipv6, &saddr->sin6_addr, 16);
first_ipv6 = 0;
log_addr = 1;
}
has_ipv6 = 1;
if (num_sockets < max_sockets) {
saddr->sin6_port = htons((unsigned short)port);
int sock = mdns_socket_open_ipv6(saddr);
if (sock >= 0) {
sockets[num_sockets++] = sock;
log_addr = 1;
} else {
log_addr = 0;
}
}
if (log_addr) {
char buffer[128];
mdns_string_t addr = ipv6_address_to_string(buffer, sizeof(buffer), saddr,
sizeof(struct sockaddr_in6));
// printf("Local IPv6 address: %.*s\n", MDNS_STRING_FORMAT(addr));
}
}
}
}
}
free(adapter_address);
#else
struct ifaddrs* ifaddr = 0;
struct ifaddrs* ifa = 0;
if (getifaddrs(&ifaddr) < 0)
printf("Unable to get interface addresses\n");
int first_ipv4 = 1;
int first_ipv6 = 1;
for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
if (!ifa->ifa_addr)
continue;
if (ifa->ifa_addr->sa_family == AF_INET) {
struct sockaddr_in* saddr = (struct sockaddr_in*)ifa->ifa_addr;
if (saddr->sin_addr.s_addr != htonl(INADDR_LOOPBACK)) {
int log_addr = 0;
if (first_ipv4) {
service_address_ipv4 = saddr->sin_addr.s_addr;
first_ipv4 = 0;
log_addr = 1;
}
has_ipv4 = 1;
if (num_sockets < max_sockets) {
saddr->sin_port = htons(port);
int sock = mdns_socket_open_ipv4(saddr);
if (sock >= 0) {
sockets[num_sockets++] = sock;
log_addr = 1;
} else {
log_addr = 0;
}
}
if (log_addr) {
char buffer[128];
mdns_string_t addr = ipv4_address_to_string(buffer, sizeof(buffer), saddr,
sizeof(struct sockaddr_in));
// printf("Local IPv4 address: %.*s\n", MDNS_STRING_FORMAT(addr));
}
}
} else if (ifa->ifa_addr->sa_family == AF_INET6) {
struct sockaddr_in6* saddr = (struct sockaddr_in6*)ifa->ifa_addr;
static const unsigned char localhost[] = {0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1};
static const unsigned char localhost_mapped[] = {0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0xff, 0xff, 0x7f, 0, 0, 1};
if (memcmp(saddr->sin6_addr.s6_addr, localhost, 16) &&
memcmp(saddr->sin6_addr.s6_addr, localhost_mapped, 16)) {
int log_addr = 0;
if (first_ipv6) {
memcpy(service_address_ipv6, &saddr->sin6_addr, 16);
first_ipv6 = 0;
log_addr = 1;
}
has_ipv6 = 1;
if (num_sockets < max_sockets) {
saddr->sin6_port = htons(port);
int sock = mdns_socket_open_ipv6(saddr);
if (sock >= 0) {
sockets[num_sockets++] = sock;
log_addr = 1;
} else {
log_addr = 0;
}
}
if (log_addr) {
char buffer[128];
mdns_string_t addr = ipv6_address_to_string(buffer, sizeof(buffer), saddr,
sizeof(struct sockaddr_in6));
// printf("Local IPv6 address: %.*s\n", MDNS_STRING_FORMAT(addr));
}
}
}
}
freeifaddrs(ifaddr);
#endif
return num_sockets;
}
static int query_callback(int sock,
const struct sockaddr* from,
size_t addrlen,
mdns_entry_type_t entry,
uint16_t transaction_id,
uint16_t rtype,
uint16_t rclass,
uint32_t ttl,
const void* data,
size_t size,
size_t name_offset,
size_t name_length,
size_t offset,
size_t length,
void* user_data) {
// static int query_callback(int sock, const struct sockaddr* from, size_t addrlen,
// mdns_entry_type_t entry, uint16_t transaction_id,
// uint16_t rtype, uint16_t rclass, uint32_t ttl,
// const void* data, size_t size, size_t offset, size_t length,
// void* user_data) {
mdns_string_t fromaddrstr = ip_address_to_string(addrbuffer, sizeof(addrbuffer), from, addrlen);
std::string fromstr = std::string(fromaddrstr.str, fromaddrstr.length);
mdns_string_t entrystr =
mdns_string_extract(data, size, &name_offset, entrybuffer, sizeof(entrybuffer));
const char* entrytype = (entry == MDNS_ENTRYTYPE_ANSWER) ? "answer" :
((entry == MDNS_ENTRYTYPE_AUTHORITY) ? "authority" : "additional");
@ -200,54 +428,57 @@ static int query_callback(int sock, const struct sockaddr* from, size_t addrlen,
}
// [[Rcpp::export]]
std::string int_bnjr_discover(int scan_time = 10L, std::string proto = "ipv4") {
std::string int_bnjr_discover(int scan_time = 10L) {
#ifdef _WIN32
WORD versionWanted = MAKEWORD(1, 1);
WSADATA wsaData;
if (WSAStartup(versionWanted, &wsaData)) {
Rf_warning("Failed to initialize WinSock\n");
return();
}
#endif
if (!((proto == "ipv4") || (proto == "ipv6"))) proto = "ipv4";
size_t capacity = 2048;
void* buffer = malloc(capacity);
//void* user_data = 0;
size_t records;
int sockets[32];
int num_sockets = open_client_sockets(sockets, sizeof(sockets) / sizeof(sockets[0]), 0);
if (num_sockets <= 0) Rf_error("Failed to open any client sockets\n");
std::string out;
std::FILE* tmpf = std::tmpfile();
int port = 0;
int sock = (proto == "ipv4") ? mdns_socket_open_ipv4(port) : mdns_socket_open_ipv6(port);
if (sock < 0) {
Rf_warning("Failed to open socket: %s\n", strerror(errno));
goto quit_int_bnjr_discover;
}
if (mdns_discovery_send(sock)) {
Rf_warning("Failed to send DNS-DS discovery: %s\n", strerror(errno));
goto quit_int_bnjr_discover;
for (int isock = 0; isock < num_sockets; ++isock) {
if ((mdns_discovery_send(sockets[isock])) && (errno != EHOSTUNREACH))
Rf_warning("Failed to send DNS-DS discovery: %s\n", strerror(errno));
}
for (int i = 0; i < scan_time; ++i) {
do {
records = mdns_discovery_recv(
sock, buffer, capacity, query_callback, tmpf
);
} while (records);
if (records) i = 0;
size_t capacity = 2048;
void* buffer = malloc(capacity);
void* user_data = 0;
size_t records;
sleep(1);
int res;
do {
struct timeval timeout;
timeout.tv_sec = scan_time;
timeout.tv_usec = 0;
int nfds;
nfds = 0;
fd_set readfs;
FD_ZERO(&readfs);
for (int isock = 0; isock < num_sockets; ++isock) {
if (sockets[isock] >= nfds)
nfds = sockets[isock] + 1;
FD_SET(sockets[isock], &readfs);
}
}
records = 0;
res = select(nfds, &readfs, 0, 0, &timeout);
if (res > 0) {
for (int isock = 0; isock < num_sockets; ++isock) {
if (FD_ISSET(sockets[isock], &readfs)) {
records += mdns_discovery_recv(sockets[isock],
buffer,
capacity,
query_callback,
tmpf);
}
}
}
} while (res > 0);
std::rewind(tmpf);
@ -259,71 +490,69 @@ std::string int_bnjr_discover(int scan_time = 10L, std::string proto = "ipv4") {
std::fclose(tmpf);
quit_int_bnjr_discover:
free(buffer);
free(buffer);
if (sock >= 0) mdns_socket_close(sock);
#ifdef _WIN32
WSACleanup();
#endif
for (int isock = 0; isock < num_sockets; ++isock){
mdns_socket_close(sockets[isock]);
}
return(out);
}
// [[Rcpp::export]]
std::string int_bnjr_query(std::string q, int scan_time = 5L, std::string proto = "ipv4") {
std::string int_bnjr_query(std::string q, int scan_time = 5L) {
#ifdef _WIN32
WORD versionWanted = MAKEWORD(1, 1);
WSADATA wsaData;
if (WSAStartup(versionWanted, &wsaData)) {
Rf_warning("Failed to initialize WinSock\n");
return();
}
#endif
int sockets[32];
int query_id[32];
if (!((proto == "ipv4") || (proto == "ipv6"))) proto = "ipv4";
int num_sockets = open_client_sockets(sockets, sizeof(sockets) / sizeof(sockets[0]), 0);
if (num_sockets <= 0) Rf_error("Failed to open any client sockets");
size_t capacity = 2048;
void* buffer = malloc(capacity);
//void* user_data = 0;
void* user_data = 0;
size_t records;
std::FILE* tmpf = std::tmpfile();
std::string out;
int port = 0;
int sock = (proto == "ipv4") ? mdns_socket_open_ipv4(port) : mdns_socket_open_ipv6(port);
if (sock < 0) {
Rf_warning("Failed to open socket: %s\n", strerror(errno));
goto quit_int_bnjr_query_send;
}
if (mdns_query_send(sock, MDNS_RECORDTYPE_PTR,
q.c_str(), q.length(),
buffer, capacity)) {
Rf_warning("Failed to send mDNS query: %s\n", strerror(errno));
goto quit_int_bnjr_query_send;
for (int isock = 0; isock < num_sockets; ++isock) {
query_id[isock] = mdns_query_send(sockets[isock], MDNS_RECORDTYPE_PTR, q.c_str(),
q.length(), buffer, capacity, 0);
if ((query_id[isock] < 0) && (errno != EHOSTUNREACH))
Rf_warning("Failed to send mDNS query: %s\n", strerror(errno));
}
for (int i = 0; i < scan_time; ++i) {
do {
records = mdns_query_recv(
sock, buffer, capacity, query_callback, tmpf, 1
);
} while (records);
int res;
if (records) i = 0;
do {
struct timeval timeout;
timeout.tv_sec = scan_time;
timeout.tv_usec = 0;
sleep(1);
int nfds = 0;
fd_set readfs;
FD_ZERO(&readfs);
for (int isock = 0; isock < num_sockets; ++isock) {
if (sockets[isock] >= nfds)
nfds = sockets[isock] + 1;
FD_SET(sockets[isock], &readfs);
}
}
records = 0;
res = select(nfds, &readfs, 0, 0, &timeout);
if (res > 0) {
for (int isock = 0; isock < num_sockets; ++isock) {
if (FD_ISSET(sockets[isock], &readfs)) {
records += mdns_query_recv(sockets[isock], buffer, capacity, query_callback,
tmpf, query_id[isock]);
}
FD_SET(sockets[isock], &readfs);
}
}
} while (res > 0);
std::rewind(tmpf);
@ -335,15 +564,10 @@ std::string int_bnjr_query(std::string q, int scan_time = 5L, std::string proto
std::fclose(tmpf);
quit_int_bnjr_query_send:
free(buffer);
free(buffer);
if (sock >= 0) mdns_socket_close(sock);
#ifdef _WIN32
WSACleanup();
#endif
for (int isock = 0; isock < num_sockets; ++isock)
mdns_socket_close(sockets[isock]);
return(out);

2257
src/mdns.h

File diff suppressed because it is too large
Loading…
Cancel
Save