From 6a74e1eb02c3c5ab29238668ed5bc0636e1c8e9e Mon Sep 17 00:00:00 2001 From: hrbrmstr Date: Mon, 4 May 2020 13:35:18 -0400 Subject: [PATCH] SRV, aliases, credit --- DESCRIPTION | 10 ++++++---- NAMESPACE | 2 ++ NEWS.md | 8 ++++++++ R/RcppExports.R | 8 ++++---- R/discover.R | 14 +++++++++++--- R/query.R | 16 ++++++++++++---- README.md | 52 ++++++++++++++++++++++++++-------------------------- man/bnjr_discover.Rd | 15 ++++++++++----- man/bnjr_query.Rd | 13 ++++++++++++- src/RcppExports.cpp | 18 ++++++++++-------- src/bonjour-main.cpp | 37 ++++++++++++++++++++++++------------- src/mdns.h | 22 +++++++++++----------- 12 files changed, 136 insertions(+), 79 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 7daf32c..ef7a35e 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,11 +1,13 @@ Package: bonjour Type: Package Title: Discover and Query Multicast DNS (mDNS)/zeroconf Services -Version: 0.1.0 -Date: 2020-04-29 +Version: 0.2.0 +Date: 2020-05-04 Authors@R: c( - person("Bob", "Rudis", email = "bob@rud.is", role = c("aut", "cre"), - comment = c(ORCID = "0000-0001-5670-2640")) + person("Bob", "Rudis", email = "bob@rud.is", role = c("aut", "cre"), + comment = c(ORCID = "0000-0001-5670-2640")), + person("Mattias", "Jansson", email = "mjansson@gmail.com", role = "aut", + comment = "https://github.com/mjansson/mdns") ) Maintainer: Bob Rudis Description: Multicast DNS (mDNS) provides the ability to perform DNS-like diff --git a/NAMESPACE b/NAMESPACE index 3cda0f4..57bdbcd 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -4,6 +4,8 @@ export(bjr_discover) export(bjr_query) export(bnjr_discover) export(bnjr_query) +export(mdns_discover) +export(mdns_query) importFrom(Rcpp,sourceCpp) importFrom(ndjson,flatten) useDynLib(bonjour, .registration = TRUE) diff --git a/NEWS.md b/NEWS.md index 9b4679b..3fc702b 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,2 +1,10 @@ +0.2.0 +* Added Credit to Mattias Jansson for the mdns C library +* Added in support for SRV records +* Added in support for IPv6 but use @ own risk for now +* Fixed document aliases for `bjr_` aliases +* Adeed `mdns_` aliases b/c I keep trying to use them +* Added return value docs + 0.1.0 * Initial release diff --git a/R/RcppExports.R b/R/RcppExports.R index 867e60c..4c600c7 100644 --- a/R/RcppExports.R +++ b/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) { - .Call(`_bonjour_int_bnjr_discover`, scan_time) +int_bnjr_discover <- function(scan_time = 10L, proto = "ipv4") { + .Call(`_bonjour_int_bnjr_discover`, scan_time, proto) } -int_bnjr_query <- function(q, scan_time = 5L) { - .Call(`_bonjour_int_bnjr_query`, q, scan_time) +int_bnjr_query <- function(q, scan_time = 5L, proto = "ipv4") { + .Call(`_bonjour_int_bnjr_query`, q, scan_time, proto) } diff --git a/R/discover.R b/R/discover.R index a3a8b6b..2c6a414 100644 --- a/R/discover.R +++ b/R/discover.R @@ -2,10 +2,14 @@ #' #' @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) { +bnjr_discover <- function(scan_time = 10L, proto = c("ipv4", "ipv6")) { - res <- int_bnjr_discover(scan_time) + proto <- match.arg(tolower(trimws(proto[1])), c("ipv4", "ipv6")) + + res <- int_bnjr_discover(scan_time, proto = proto) res <- unlist(strsplit(res, "\n")) ndjson::flatten(res, "tbl") @@ -13,4 +17,8 @@ bnjr_discover <- function(scan_time = 10L) { #' @rdname bnjr_discover #' @export -bjr_discover <- bnjr_discover \ No newline at end of file +bjr_discover <- bnjr_discover + +#' @rdname bnjr_discover +#' @export +mdns_discover <- bnjr_discover \ No newline at end of file diff --git a/R/query.R b/R/query.R index 85d4afc..28f0dd7 100644 --- a/R/query.R +++ b/R/query.R @@ -3,15 +3,23 @@ #' @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) { +bnjr_query <- function(query, scan_time = 10L, proto = c("ipv4", "ipv6")) { - res <- int_bnjr_query(query, scan_time) + proto <- match.arg(tolower(trimws(proto[1])), c("ipv4", "ipv6")) + + res <- int_bnjr_query(query, scan_time, proto = proto) res <- unlist(strsplit(res, "\n")) ndjson::flatten(res, "tbl") } -#' @rdname bnjr_discover +#' @rdname bnjr_query +#' @export +bjr_query <- bnjr_query + +#' @rdname bnjr_query #' @export -bjr_query <- bnjr_query \ No newline at end of file +mdns_query <- bnjr_query \ No newline at end of file diff --git a/README.md b/README.md index b80a32f..1210a9a 100644 --- a/README.md +++ b/README.md @@ -61,25 +61,25 @@ library(tidyverse) # current version packageVersion("bonjour") -## [1] '0.1.0' +## [1] '0.2.0' ``` ``` r bnjr_discover() -## # A tibble: 49 x 7 -## entry_type from length name rclass ttl type -## -## 1 answer 10.1.10.59:5353 12 _ssh._tcp.local. 1 10 PTR -## 2 answer 10.1.10.59:5353 12 _sftp-ssh._tcp.local. 1 10 PTR -## 3 answer 10.1.10.59:5353 8 _eppc._tcp.local. 1 10 PTR -## 4 answer 10.1.10.59:5353 7 _rfb._tcp.local. 1 10 PTR -## 5 answer 10.1.10.59:5353 7 _smb._tcp.local. 1 10 PTR -## 6 answer 10.1.10.59:5353 17 _net-assistant._udp.local. 1 10 PTR -## 7 answer 10.1.10.59:5353 18 _companion-link._tcp.local. 1 10 PTR -## 8 answer 10.1.10.192:5353 12 _smb._tcp.local. 1 10 PTR -## 9 answer 10.1.10.20:5353 14 _adisk._tcp.local. 1 10 PTR -## 10 answer 10.1.10.20:5353 7 _ssh._tcp.local. 1 10 PTR -## # … with 39 more rows +## # A tibble: 58 x 7 +## entry_type from length name rclass ttl type +## +## 1 answer 10.1.10.20:5353 14 _adisk._tcp.local. 1 10 PTR +## 2 answer 10.1.10.20:5353 7 _ssh._tcp.local. 1 10 PTR +## 3 answer 10.1.10.20:5353 12 _sftp-ssh._tcp.local. 1 10 PTR +## 4 answer 10.1.10.20:5353 8 _eppc._tcp.local. 1 10 PTR +## 5 answer 10.1.10.20:5353 7 _rfb._tcp.local. 1 10 PTR +## 6 answer 10.1.10.20:5353 7 _smb._tcp.local. 1 10 PTR +## 7 answer 10.1.10.20:5353 7 _nfs._tcp.local. 1 10 PTR +## 8 answer 10.1.10.20:5353 17 _net-assistant._udp.local. 1 10 PTR +## 9 answer 10.1.10.20:5353 18 _companion-link._tcp.local. 1 10 PTR +## 10 answer 10.1.10.20:5353 14 _1password4._tcp.local. 1 10 PTR +## # … with 48 more rows ``` ``` r @@ -89,13 +89,13 @@ bnjr_query("_ssh._tcp.local.") %>% ## # A tibble: 9 x 1 ## addr ## -## 1 fe80::1410:647:b4c1:df43 -## 2 2603:3005:146a:8000:1459:ebc3:42dc:5ae2 -## 3 fe80::1864:a1e2:98b:44d0 -## 4 2603:3005:146a:8000:189b:85a2:64f5:598f -## 5 fe80::18f8:a74b:6a0d:9175 -## 6 2603:3005:146a:8000:c98:42f7:9943:4b73 -## 7 2603:3005:146a:8000:6972:7ff9:9594:5467 +## 1 fe80::1864:a1e2:98b:44d0 +## 2 2603:3005:146a:8000:189b:85a2:64f5:598f +## 3 2603:3005:146a:8000:c98:42f7:9943:4b73 +## 4 fe80::18f8:a74b:6a0d:9175 +## 5 fe80::c24:9c04:594:5f28 +## 6 2603:3005:146a:8000:1459:ebc3:42dc:5ae2 +## 7 2603:3005:146a:8000:14b9:cc5f:f330:90f8 ## 8 fe80::1041:d138:41f8:efd5 ## 9 2603:3005:146a:8000:c95:dcb9:cc3a:d030 ``` @@ -104,10 +104,10 @@ bnjr_query("_ssh._tcp.local.") %>% | Lang | \# Files | (%) | LoC | (%) | Blank lines | (%) | \# Lines | (%) | | :----------- | -------: | ---: | --: | ---: | ----------: | ---: | -------: | ---: | -| C/C++ Header | 1 | 0.11 | 936 | 0.76 | 154 | 0.55 | 87 | 0.47 | -| C++ | 2 | 0.22 | 255 | 0.21 | 97 | 0.35 | 28 | 0.15 | -| R | 5 | 0.56 | 22 | 0.02 | 11 | 0.04 | 38 | 0.21 | -| Rmd | 1 | 0.11 | 13 | 0.01 | 17 | 0.06 | 32 | 0.17 | +| 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 | ## Code of Conduct diff --git a/man/bnjr_discover.Rd b/man/bnjr_discover.Rd index e022b88..feca6a1 100644 --- a/man/bnjr_discover.Rd +++ b/man/bnjr_discover.Rd @@ -1,20 +1,25 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/discover.R, R/query.R +% Please edit documentation in R/discover.R \name{bnjr_discover} \alias{bnjr_discover} \alias{bjr_discover} -\alias{bjr_query} +\alias{mdns_discover} \title{Browse available services} \usage{ -bnjr_discover(scan_time = 10L) +bnjr_discover(scan_time = 10L, proto = c("ipv4", "ipv6")) -bjr_discover(scan_time = 10L) +bjr_discover(scan_time = 10L, proto = c("ipv4", "ipv6")) -bjr_query(query, scan_time = 10L) +mdns_discover(scan_time = 10L, proto = c("ipv4", "ipv6")) } \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 } \description{ Browse available services diff --git a/man/bnjr_query.Rd b/man/bnjr_query.Rd index 09dd0a7..189d165 100644 --- a/man/bnjr_query.Rd +++ b/man/bnjr_query.Rd @@ -2,15 +2,26 @@ % Please edit documentation in R/query.R \name{bnjr_query} \alias{bnjr_query} +\alias{bjr_query} +\alias{mdns_query} \title{Look for a particular service} \usage{ -bnjr_query(query, scan_time = 10L) +bnjr_query(query, scan_time = 10L, proto = c("ipv4", "ipv6")) + +bjr_query(query, scan_time = 10L, proto = c("ipv4", "ipv6")) + +mdns_query(query, scan_time = 10L, proto = c("ipv4", "ipv6")) } \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 } \description{ Look for a particular service diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp index 13b8767..d1446b1 100644 --- a/src/RcppExports.cpp +++ b/src/RcppExports.cpp @@ -6,32 +6,34 @@ using namespace Rcpp; // int_bnjr_discover -std::string int_bnjr_discover(int scan_time); -RcppExport SEXP _bonjour_int_bnjr_discover(SEXP scan_timeSEXP) { +std::string int_bnjr_discover(int scan_time, std::string proto); +RcppExport SEXP _bonjour_int_bnjr_discover(SEXP scan_timeSEXP, SEXP protoSEXP) { BEGIN_RCPP Rcpp::RObject rcpp_result_gen; Rcpp::RNGScope rcpp_rngScope_gen; Rcpp::traits::input_parameter< int >::type scan_time(scan_timeSEXP); - rcpp_result_gen = Rcpp::wrap(int_bnjr_discover(scan_time)); + Rcpp::traits::input_parameter< std::string >::type proto(protoSEXP); + rcpp_result_gen = Rcpp::wrap(int_bnjr_discover(scan_time, proto)); return rcpp_result_gen; END_RCPP } // int_bnjr_query -std::string int_bnjr_query(std::string q, int scan_time); -RcppExport SEXP _bonjour_int_bnjr_query(SEXP qSEXP, SEXP scan_timeSEXP) { +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) { 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_result_gen = Rcpp::wrap(int_bnjr_query(q, scan_time)); + Rcpp::traits::input_parameter< std::string >::type proto(protoSEXP); + rcpp_result_gen = Rcpp::wrap(int_bnjr_query(q, scan_time, proto)); return rcpp_result_gen; END_RCPP } static const R_CallMethodDef CallEntries[] = { - {"_bonjour_int_bnjr_discover", (DL_FUNC) &_bonjour_int_bnjr_discover, 1}, - {"_bonjour_int_bnjr_query", (DL_FUNC) &_bonjour_int_bnjr_query, 2}, + {"_bonjour_int_bnjr_discover", (DL_FUNC) &_bonjour_int_bnjr_discover, 2}, + {"_bonjour_int_bnjr_query", (DL_FUNC) &_bonjour_int_bnjr_query, 3}, {NULL, NULL, 0} }; diff --git a/src/bonjour-main.cpp b/src/bonjour-main.cpp index 3410394..b45413b 100644 --- a/src/bonjour-main.cpp +++ b/src/bonjour-main.cpp @@ -19,7 +19,7 @@ using namespace Rcpp; static char addrbuffer[64]; static char namebuffer[256]; -static char sendbuffer[256]; +//static char sendbuffer[256]; static mdns_record_txt_t txtbuffer[128]; typedef struct { @@ -110,6 +110,13 @@ static int query_callback(int sock, const struct sockaddr* from, size_t addrlen, mdns_record_srv_t srv = mdns_record_parse_srv(data, size, offset, length, namebuffer, sizeof(namebuffer)); + + rec = rec + ", \"type\": \"SRV\""; + rec = rec + ", \"srv_name\": \"" + std::string(srv.name.str, srv.name.length) + "\""; + rec = rec + ", \"srv_priority\": " + std::to_string(srv.priority) + ""; + rec = rec + ", \"srv_weight\": " + std::to_string(srv.weight) + ""; + rec = rec + ", \"srv_port\": " + std::to_string(srv.port) + ""; + // printf("%.*s : %s SRV %.*s priority %d weight %d port %d\n", // MDNS_STRING_FORMAT(fromaddrstr), entrytype, // MDNS_STRING_FORMAT(srv.name), srv.priority, srv.weight, srv.port); @@ -193,20 +200,22 @@ 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 int_bnjr_discover(int scan_time = 10L, std::string proto = "ipv4") { #ifdef _WIN32 WORD versionWanted = MAKEWORD(1, 1); WSADATA wsaData; if (WSAStartup(versionWanted, &wsaData)) { - printf("Failed to initialize WinSock\n"); + 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; + //void* user_data = 0; size_t records; std::string out; @@ -214,15 +223,15 @@ std::string int_bnjr_discover(int scan_time = 10L) { std::FILE* tmpf = std::tmpfile(); int port = 0; - int sock = mdns_socket_open_ipv4(port); + int sock = (proto == "ipv4") ? mdns_socket_open_ipv4(port) : mdns_socket_open_ipv6(port); if (sock < 0) { - printf("Failed to open socket: %s\n", strerror(errno)); + Rf_warning("Failed to open socket: %s\n", strerror(errno)); goto quit_int_bnjr_discover; } if (mdns_discovery_send(sock)) { - printf("Failed to send DNS-DS discovery: %s\n", strerror(errno)); + Rf_warning("Failed to send DNS-DS discovery: %s\n", strerror(errno)); goto quit_int_bnjr_discover; } @@ -265,20 +274,22 @@ std::string int_bnjr_discover(int scan_time = 10L) { } // [[Rcpp::export]] -std::string int_bnjr_query(std::string q, int scan_time = 5L) { +std::string int_bnjr_query(std::string q, int scan_time = 5L, std::string proto = "ipv4") { #ifdef _WIN32 WORD versionWanted = MAKEWORD(1, 1); WSADATA wsaData; if (WSAStartup(versionWanted, &wsaData)) { - printf("Failed to initialize WinSock\n"); + 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; + //void* user_data = 0; size_t records; std::FILE* tmpf = std::tmpfile(); @@ -286,17 +297,17 @@ std::string int_bnjr_query(std::string q, int scan_time = 5L) { std::string out; int port = 0; - int sock = mdns_socket_open_ipv4(port); + int sock = (proto == "ipv4") ? mdns_socket_open_ipv4(port) : mdns_socket_open_ipv6(port); if (sock < 0) { - printf("Failed to open socket: %s\n", strerror(errno)); + 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)) { - printf("Failed to send mDNS query: %s\n", strerror(errno)); + Rf_warning("Failed to send mDNS query: %s\n", strerror(errno)); goto quit_int_bnjr_query_send; } diff --git a/src/mdns.h b/src/mdns.h index 5f8150a..b31e859 100644 --- a/src/mdns.h +++ b/src/mdns.h @@ -732,10 +732,10 @@ mdns_discovery_recv(int sock, void* buffer, size_t capacity, size_t offset = (size_t)((char*)data - (char*)buffer); records += mdns_records_parse(sock, saddr, addrlen, buffer, data_size, &offset, - MDNS_ENTRYTYPE_AUTHORITY, transaction_id, authority_rrs, + MDNS_ENTRYTYPE_AUTHORITY, transaction_id, authority_rrs, callback, user_data); records += mdns_records_parse(sock, saddr, addrlen, buffer, data_size, &offset, - MDNS_ENTRYTYPE_ADDITIONAL, transaction_id, additional_rrs, + MDNS_ENTRYTYPE_ADDITIONAL, transaction_id, additional_rrs, callback, user_data); return records; @@ -757,15 +757,15 @@ mdns_socket_listen(int sock, void* buffer, size_t capacity, return 0; size_t data_size = (size_t)ret; - size_t records = 0; + //size_t records = 0; uint16_t* data = (uint16_t*)buffer; uint16_t transaction_id = ntohs(*data++); uint16_t flags = ntohs(*data++); uint16_t questions = ntohs(*data++); - uint16_t answer_rrs = ntohs(*data++); - uint16_t authority_rrs = ntohs(*data++); - uint16_t additional_rrs = ntohs(*data++); + //uint16_t answer_rrs = ntohs(*data++); + //uint16_t authority_rrs = ntohs(*data++); + //uint16_t additional_rrs = ntohs(*data++); size_t parsed = 0; for (int iquestion = 0; iquestion < questions; ++iquestion) { @@ -918,13 +918,13 @@ mdns_query_recv(int sock, void* buffer, size_t capacity, size_t records = 0; size_t offset = MDNS_POINTER_DIFF(data, buffer); records += mdns_records_parse(sock, saddr, addrlen, buffer, data_size, &offset, - MDNS_ENTRYTYPE_ANSWER, transaction_id, answer_rrs, + MDNS_ENTRYTYPE_ANSWER, transaction_id, answer_rrs, callback, user_data); records += mdns_records_parse(sock, saddr, addrlen, buffer, data_size, &offset, - MDNS_ENTRYTYPE_AUTHORITY, transaction_id, authority_rrs, + MDNS_ENTRYTYPE_AUTHORITY, transaction_id, authority_rrs, callback, user_data); records += mdns_records_parse(sock, saddr, addrlen, buffer, data_size, &offset, - MDNS_ENTRYTYPE_ADDITIONAL, transaction_id, additional_rrs, + MDNS_ENTRYTYPE_ADDITIONAL, transaction_id, additional_rrs, callback, user_data); return records; } @@ -965,7 +965,7 @@ mdns_query_answer(int sock, const void* address, size_t address_size, void* buff *udata++ = htons(MDNS_CLASS_IN); data = udata; remain = capacity - MDNS_POINTER_DIFF(data, buffer); - + //Fill in answers //PTR record for service data = mdns_string_make_ref(data, remain, service_offset); @@ -1165,7 +1165,7 @@ mdns_record_parse_txt(const void* buffer, size_t size, size_t offset, size_t len ++parsed; } - return parsed; + return parsed; } #ifdef _WIN32