This commit is contained in:
Dale Whinham
2022-04-01 16:59:05 +01:00
parent 26659782b1
commit 6298cee4de
12 changed files with 914 additions and 20 deletions

View File

@@ -86,4 +86,6 @@ FLUIDSYNTHLIB=$(FLUIDSYNTHBUILDDIR)/src/libfluidsynth.a
INIHHOME=$(realpath external/inih)
MDNSHOME=$(realpath external/mdns)
-include $(CIRCLE_STDLIB_CONFIG)

View File

@@ -24,6 +24,7 @@ OBJS := src/config.o \
src/net/applemidi.o \
src/net/ftpdaemon.o \
src/net/ftpworker.o \
src/net/mdnsresponder.o \
src/net/udpmidi.o \
src/pisound.o \
src/power.o \
@@ -48,6 +49,11 @@ INCLUDE += -I $(INIHHOME)
EXTRACLEAN += $(INIHHOME)/ini.d \
$(INIHHOME)/ini.o
#
# mdns
#
INCLUDE += -I $(MDNSHOME)
include $(CIRCLEHOME)/Rules.mk
CFLAGS += -Werror -Wextra -Wno-unused-parameter

View File

@@ -5,7 +5,7 @@
include Config.mk
.DEFAULT_GOAL=all
.PHONY: circle-stdlib mt32emu fluidsynth all clean veryclean
.PHONY: circle-stdlib mdns mt32emu fluidsynth all clean veryclean
#
# Functions to apply/reverse patches only if not completely applied/reversed already
@@ -36,7 +36,7 @@ $(CIRCLE_STDLIB_CONFIG) $(CIRCLE_CONFIG)&:
# Apply patches
@${APPLY_PATCH} $(CIRCLEHOME) patches/circle-45-minimal-usb-drivers.patch
@${APPLY_PATCH} $(CIRCLEHOME) patches/circle-45-cp210x-remove-partnum-check.patch
@${APPLY_PATCH} $(CIRCLEHOME) patches/circle-44-multicast.patch
@${APPLY_PATCH} $(CIRCLEHOME) patches/circle-45-multicast.patch
ifeq ($(strip $(GC_SECTIONS)),1)
# Enable function/data sections for circle-stdlib
@@ -64,6 +64,15 @@ $(CIRCLESTDLIBHOME)/.done: $(CIRCLE_STDLIB_CONFIG)
@$(MAKE) -C $(CIRCLESTDLIBHOME)
touch $@
#
# Patch mdns
#
mdns: $(MDNSHOME)/.done
$(MDNSHOME)/.done:
@${APPLY_PATCH} $(MDNSHOME) patches/mdns-1.4.2-circle.patch
touch $@
#
# Build mt32emu
#
@@ -127,7 +136,7 @@ $(FLUIDSYNTHBUILDDIR)/.done: $(CIRCLESTDLIBHOME)/.done
#
# Build kernel itself
#
all: circle-stdlib mt32emu fluidsynth
all: circle-stdlib mdns mt32emu fluidsynth
@$(MAKE) -f Kernel.mk $(KERNEL).img $(KERNEL).hex
#
@@ -145,11 +154,15 @@ veryclean: clean
@${REVERSE_PATCH} $(CIRCLEHOME) patches/circle-45-cp210x-remove-partnum-check.patch
@${REVERSE_PATCH} $(CIRCLEHOME) patches/circle-45-minimal-usb-drivers.patch
@${REVERSE_PATCH} $(FLUIDSYNTHHOME) patches/fluidsynth-2.3.1-circle.patch
@${REVERSE_PATCH} $(MDNSHOME) patches/mdns-1.4.2-circle.patch
# Clean circle-stdlib
@$(MAKE) -C $(CIRCLESTDLIBHOME) mrproper
@$(RM) $(CIRCLESTDLIBHOME)/.done
# Clean mdns
@$(RM) $(MDNSHOME)/.done
# Clean mt32emu
@$(RM) -r $(MT32EMUBUILDDIR)

View File

@@ -55,6 +55,7 @@
#include "midiparser.h"
#include "net/applemidi.h"
#include "net/ftpdaemon.h"
#include "net/mdnsresponder.h"
#include "net/udpmidi.h"
#include "pisound.h"
#include "power.h"
@@ -161,6 +162,7 @@ private:
CBcm4343Device m_WLAN;
CWPASupplicant m_WPASupplicant;
bool m_bNetworkReady;
CMDNSResponder* m_pMDNSResponder;
CAppleMIDIParticipant* m_pAppleMIDIParticipant;
CUDPMIDIReceiver* m_pUDPMIDIReceiver;
CFTPDaemon* m_pFTPDaemon;

View File

@@ -0,0 +1,59 @@
//
// mdnsresponder.h
//
// mt32-pi - A baremetal MIDI synthesizer for Raspberry Pi
// Copyright (C) 2020-2022 Dale Whinham <daleyo@gmail.com>
//
// This file is part of mt32-pi.
//
// mt32-pi is free software: you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the Free Software
// Foundation, either version 3 of the License, or (at your option) any later
// version.
//
// mt32-pi is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// mt32-pi. If not, see <http://www.gnu.org/licenses/>.
//
#ifndef _mdnsresponder_h
#define _mdnsresponder_h
#include <circle/net/socket.h>
#include <circle/sched/task.h>
class CMDNSResponder : protected CTask
{
public:
CMDNSResponder();
virtual ~CMDNSResponder() override;
bool Initialize();
virtual void Run() override;
private:
void Probe();
void Announce();
void Goodbye();
static constexpr size_t MaxMDNSNameLength = 256;
// UDP socket
CSocket* m_pSocket;
// Socket receive buffer
u8 m_Buffer[FRAME_BUFFER_SIZE];
char m_DNSName[MaxMDNSNameLength];
// static int MDNSServiceCallback(mdns_socket_t sock, const struct sockaddr* from, size_t addrlen, mdns_entry_type_t entry,
// uint16_t query_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 record_offset,
// size_t record_length, void* user_data);
};
#endif

View File

@@ -23,7 +23,6 @@
#ifndef _udpmidi_h
#define _udpmidi_h
#include <circle/net/ipaddress.h>
#include <circle/net/socket.h>
#include <circle/sched/task.h>
@@ -44,11 +43,11 @@ public:
virtual void Run() override;
private:
// UDP sockets
CSocket* m_pMIDISocket;
// UDP socket
CSocket* m_pSocket;
// Socket receive buffer
u8 m_MIDIBuffer[FRAME_BUFFER_SIZE];
u8 m_ReceiveBuffer[FRAME_BUFFER_SIZE];
// Callback handler
CUDPMIDIHandler* m_pHandler;

View File

@@ -98,6 +98,11 @@ namespace Utility
return nTicks / 1000;
}
constexpr u32 IPAddressToInteger(u8 nA, u8 nB, u8 nC, u8 nD)
{
return nA | (nB << 8) | (nC << 16) | (nD << 24);
}
// Computes the Roland checksum
constexpr u8 RolandChecksum(const u8* pData, size_t nSize)
{

View File

@@ -0,0 +1,553 @@
diff --git a/mdns.h b/mdns.h
index 4b3b03d..96c76ec 100644
--- a/mdns.h
+++ b/mdns.h
@@ -24,6 +24,10 @@
#include <Winsock2.h>
#include <Ws2tcpip.h>
#define strncasecmp _strnicmp
+#elif defined(__circle__)
+#include <circle/net/ipaddress.h>
+#include <circle/net/socket.h>
+#include <circle/util.h>
#else
#include <unistd.h>
#include <sys/socket.h>
@@ -74,11 +78,46 @@ enum mdns_entry_type {
enum mdns_class { MDNS_CLASS_IN = 1, MDNS_CLASS_ANY = 255 };
+#ifdef __circle__
+#define htons(VALUE) __builtin_bswap16(VALUE)
+#define htonl(VALUE) __builtin_bswap32(VALUE)
+#define ntohs(VALUE) __builtin_bswap16(VALUE)
+#define ntohl(VALUE) __builtin_bswap32(VALUE)
+
+#define AF_INET 2
+typedef CSocket* mdns_socket_t;
+
+typedef u32 in_addr_t;
+typedef u8 sa_family_t;
+typedef u16 in_port_t;
+
+struct in_addr
+{
+ in_addr_t s_addr;
+};
+
+struct sockaddr_in
+{
+ sa_family_t sin_family;
+ in_port_t sin_port;
+ struct in_addr sin_addr;
+};
+
+struct sockaddr {
+ sa_family_t sa_family;
+ char sa_data[14];
+};
+
+typedef size_t socklen_t;
+#else
+typedef int mdns_socket_t;
+#endif
+
typedef enum mdns_record_type mdns_record_type_t;
typedef enum mdns_entry_type mdns_entry_type_t;
typedef enum mdns_class mdns_class_t;
-typedef int (*mdns_record_callback_fn)(int sock, const struct sockaddr* from, size_t addrlen,
+typedef int (*mdns_record_callback_fn)(mdns_socket_t sock, const struct sockaddr* from, size_t addrlen,
mdns_entry_type_t entry, uint16_t query_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 record_offset,
@@ -136,9 +175,11 @@ struct mdns_record_a_t {
struct sockaddr_in addr;
};
+#ifndef __circle__
struct mdns_record_aaaa_t {
struct sockaddr_in6 addr;
};
+#endif
struct mdns_record_txt_t {
mdns_string_t key;
@@ -152,7 +193,9 @@ struct mdns_record_t {
mdns_record_ptr_t ptr;
mdns_record_srv_t srv;
mdns_record_a_t a;
+#ifndef __circle__
mdns_record_aaaa_t aaaa;
+#endif
mdns_record_txt_t txt;
} data;
uint16_t rclass;
@@ -176,12 +219,13 @@ struct mdns_query_t {
// mDNS/DNS-SD public API
+#ifndef __circle__
//! Open and setup a IPv4 socket for mDNS/DNS-SD. To bind the socket to a specific interface, pass
//! in the appropriate socket address in saddr, otherwise pass a null pointer for INADDR_ANY. To
//! send one-shot discovery requests and queries pass a null pointer or set 0 as port to assign a
//! random user level ephemeral port. To run discovery service listening for incoming discoveries
//! and queries, you must set MDNS_PORT as port.
-static inline int
+static inline mdns_socket_t
mdns_socket_open_ipv4(const struct sockaddr_in* saddr);
//! Setup an already opened IPv4 socket for mDNS/DNS-SD. To bind the socket to a specific interface,
@@ -190,14 +234,14 @@ mdns_socket_open_ipv4(const struct sockaddr_in* saddr);
//! random user level ephemeral port. To run discovery service listening for incoming discoveries
//! and queries, you must set MDNS_PORT as port.
static inline int
-mdns_socket_setup_ipv4(int sock, const struct sockaddr_in* saddr);
+mdns_socket_setup_ipv4(mdns_socket_t sock, const struct sockaddr_in* saddr);
//! Open and setup a IPv6 socket for mDNS/DNS-SD. To bind the socket to a specific interface, pass
//! in the appropriate socket address in saddr, otherwise pass a null pointer for in6addr_any. To
//! send one-shot discovery requests and queries pass a null pointer or set 0 as port to assign a
//! random user level ephemeral port. To run discovery service listening for incoming discoveries
//! and queries, you must set MDNS_PORT as port.
-static inline int
+static inline mdns_socket_t
mdns_socket_open_ipv6(const struct sockaddr_in6* saddr);
//! Setup an already opened IPv6 socket for mDNS/DNS-SD. To bind the socket to a specific interface,
@@ -206,30 +250,31 @@ mdns_socket_open_ipv6(const struct sockaddr_in6* saddr);
//! random user level ephemeral port. To run discovery service listening for incoming discoveries
//! and queries, you must set MDNS_PORT as port.
static inline int
-mdns_socket_setup_ipv6(int sock, const struct sockaddr_in6* saddr);
+mdns_socket_setup_ipv6(mdns_socket_t sock, const struct sockaddr_in6* saddr);
//! Close a socket opened with mdns_socket_open_ipv4 and mdns_socket_open_ipv6.
static inline void
-mdns_socket_close(int sock);
+mdns_socket_close(mdns_socket_t sock);
+#endif
//! Listen for incoming multicast DNS-SD and mDNS query requests. The socket should have been opened
//! on port MDNS_PORT using one of the mdns open or setup socket functions. Buffer must be 32 bit
//! aligned. Parsing is stopped when callback function returns non-zero. Returns the number of
//! queries parsed.
static inline size_t
-mdns_socket_listen(int sock, void* buffer, size_t capacity, mdns_record_callback_fn callback,
+mdns_socket_listen(mdns_socket_t sock, void* buffer, size_t capacity, mdns_record_callback_fn callback,
void* user_data);
//! Send a multicast DNS-SD reqeuest on the given socket to discover available services. Returns 0
//! on success, or <0 if error.
static inline int
-mdns_discovery_send(int sock);
+mdns_discovery_send(mdns_socket_t sock);
//! Recieve unicast responses to a DNS-SD sent with mdns_discovery_send. Any data will be piped to
//! the given callback for parsing. Buffer must be 32 bit aligned. Parsing is stopped when callback
//! function returns non-zero. Returns the number of responses parsed.
static inline size_t
-mdns_discovery_recv(int sock, void* buffer, size_t capacity, mdns_record_callback_fn callback,
+mdns_discovery_recv(mdns_socket_t sock, void* buffer, size_t capacity, mdns_record_callback_fn callback,
void* user_data);
//! Send a multicast mDNS query on the given socket for the given service name. The supplied buffer
@@ -239,7 +284,7 @@ mdns_discovery_recv(int sock, void* buffer, size_t capacity, mdns_record_callbac
//! ephemeral port, or a multicast response if the socket is bound to mDNS port 5353. Returns the
//! used query ID, or <0 if error.
static inline int
-mdns_query_send(int sock, mdns_record_type_t type, const char* name, size_t length, void* buffer,
+mdns_query_send(mdns_socket_t sock, mdns_record_type_t type, const char* name, size_t length, void* buffer,
size_t capacity, uint16_t query_id);
//! Send a multicast mDNS query on the given socket for the given service names. The supplied buffer
@@ -251,7 +296,7 @@ mdns_query_send(int sock, mdns_record_type_t type, const char* name, size_t leng
//! unicast response if the socket is bound to an ephemeral port, or a multicast response if the
//! socket is bound to mDNS port 5353. Returns the used query ID, or <0 if error.
static inline int
-mdns_multiquery_send(int sock, const mdns_query_t* query, size_t count, void* buffer,
+mdns_multiquery_send(mdns_socket_t sock, const mdns_query_t* query, size_t count, void* buffer,
size_t capacity, uint16_t query_id);
//! Receive unicast responses to a mDNS query sent with mdns_discovery_recv, optionally filtering
@@ -260,7 +305,7 @@ mdns_multiquery_send(int sock, const mdns_query_t* query, size_t count, void* bu
//! given callback for parsing. Buffer must be 32 bit aligned. Parsing is stopped when callback
//! function returns non-zero. Returns the number of responses parsed.
static inline size_t
-mdns_query_recv(int sock, void* buffer, size_t capacity, mdns_record_callback_fn callback,
+mdns_query_recv(mdns_socket_t sock, void* buffer, size_t capacity, mdns_record_callback_fn callback,
void* user_data, int query_id);
//! Send a variable unicast mDNS query answer to any question with variable number of records to the
@@ -269,7 +314,7 @@ mdns_query_recv(int sock, void* buffer, size_t capacity, mdns_record_callback_fn
//! Buffer must be 32 bit aligned. The record type and name should match the data from the query
//! recieved. Returns 0 if success, or <0 if error.
static inline int
-mdns_query_answer_unicast(int sock, const void* address, size_t address_size, void* buffer,
+mdns_query_answer_unicast(mdns_socket_t sock, const void* address, size_t address_size, void* buffer,
size_t capacity, uint16_t query_id, mdns_record_type_t record_type,
const char* name, size_t name_length, mdns_record_t answer,
const mdns_record_t* authority, size_t authority_count,
@@ -280,7 +325,7 @@ mdns_query_answer_unicast(int sock, const void* address, size_t address_size, vo
//! if the answer should be sent unicast (bit set) or multicast (bit not set). Buffer must be 32 bit
//! aligned. Returns 0 if success, or <0 if error.
static inline int
-mdns_query_answer_multicast(int sock, void* buffer, size_t capacity, mdns_record_t answer,
+mdns_query_answer_multicast(mdns_socket_t sock, void* buffer, size_t capacity, mdns_record_t answer,
const mdns_record_t* authority, size_t authority_count,
const mdns_record_t* additional, size_t additional_count);
@@ -288,14 +333,14 @@ mdns_query_answer_multicast(int sock, void* buffer, size_t capacity, mdns_record
//! records.Buffer must be 32 bit aligned. Returns 0 if success, or <0 if error. Use this on service
//! startup to announce your instance to the local network.
static inline int
-mdns_announce_multicast(int sock, void* buffer, size_t capacity, mdns_record_t answer,
+mdns_announce_multicast(mdns_socket_t sock, void* buffer, size_t capacity, mdns_record_t answer,
const mdns_record_t* authority, size_t authority_count,
const mdns_record_t* additional, size_t additional_count);
//! Send a variable multicast mDNS announcement. Use this on service end for removing the resource
//! from the local network. The records must be identical to the according announcement.
static inline int
-mdns_goodbye_multicast(int sock, void* buffer, size_t capacity, mdns_record_t answer,
+mdns_goodbye_multicast(mdns_socket_t sock, void* buffer, size_t capacity, mdns_record_t answer,
const mdns_record_t* authority, size_t authority_count,
const mdns_record_t* additional, size_t additional_count);
@@ -316,10 +361,12 @@ static inline struct sockaddr_in*
mdns_record_parse_a(const void* buffer, size_t size, size_t offset, size_t length,
struct sockaddr_in* addr);
+#ifndef __circle__
//! Parse an AAAA record, returns the IPv6 address in the record
static inline struct sockaddr_in6*
mdns_record_parse_aaaa(const void* buffer, size_t size, size_t offset, size_t length,
struct sockaddr_in6* addr);
+#endif
//! Parse a TXT record, returns the number of key=value records parsed and stores the key-value
//! pairs in the supplied buffer
@@ -383,9 +430,10 @@ mdns_htonl(void* data, uint32_t val) {
return MDNS_POINTER_OFFSET(data, sizeof(uint32_t));
}
-static inline int
+#ifndef __circle__
+static inline mdns_socket_t
mdns_socket_open_ipv4(const struct sockaddr_in* saddr) {
- int sock = (int)socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ mdns_socket_t sock = (int)socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock < 0)
return -1;
if (mdns_socket_setup_ipv4(sock, saddr)) {
@@ -396,7 +444,7 @@ mdns_socket_open_ipv4(const struct sockaddr_in* saddr) {
}
static inline int
-mdns_socket_setup_ipv4(int sock, const struct sockaddr_in* saddr) {
+mdns_socket_setup_ipv4(mdns_socket_t sock, const struct sockaddr_in* saddr) {
unsigned char ttl = 1;
unsigned char loopback = 1;
unsigned int reuseaddr = 1;
@@ -447,9 +495,9 @@ mdns_socket_setup_ipv4(int sock, const struct sockaddr_in* saddr) {
return 0;
}
-static inline int
+static inline mdns_socket_t
mdns_socket_open_ipv6(const struct sockaddr_in6* saddr) {
- int sock = (int)socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+ mdns_socket_t sock = (int)socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
if (sock < 0)
return -1;
if (mdns_socket_setup_ipv6(sock, saddr)) {
@@ -460,7 +508,7 @@ mdns_socket_open_ipv6(const struct sockaddr_in6* saddr) {
}
static inline int
-mdns_socket_setup_ipv6(int sock, const struct sockaddr_in6* saddr) {
+mdns_socket_setup_ipv6(mdns_socket_t sock, const struct sockaddr_in6* saddr) {
int hops = 1;
unsigned int loopback = 1;
unsigned int reuseaddr = 1;
@@ -512,13 +560,14 @@ mdns_socket_setup_ipv6(int sock, const struct sockaddr_in6* saddr) {
}
static inline void
-mdns_socket_close(int sock) {
+mdns_socket_close(mdns_socket_t sock) {
#ifdef _WIN32
closesocket(sock);
#else
close(sock);
#endif
}
+#endif
static inline int
mdns_is_string_ref(uint8_t val) {
@@ -773,7 +822,7 @@ mdns_string_make(void* buffer, size_t capacity, void* data, const char* name, si
}
static inline size_t
-mdns_records_parse(int sock, const struct sockaddr* from, size_t addrlen, const void* buffer,
+mdns_records_parse(mdns_socket_t sock, const struct sockaddr* from, size_t addrlen, const void* buffer,
size_t size, size_t* offset, mdns_entry_type_t type, uint16_t query_id,
size_t records, mdns_record_callback_fn callback, void* user_data) {
size_t parsed = 0;
@@ -807,16 +856,30 @@ mdns_records_parse(int sock, const struct sockaddr* from, size_t addrlen, const
}
static inline int
-mdns_unicast_send(int sock, const void* address, size_t address_size, const void* buffer,
+mdns_unicast_send(mdns_socket_t sock, const void* address, size_t address_size, const void* buffer,
size_t size) {
+#ifdef __circle__
+ const sockaddr_in* addr = (const struct sockaddr_in*)address;
+ CIPAddress ipaddr(addr->sin_addr.s_addr);
+ u16 port = addr->sin_port;
+
+ if (sock->SendTo(buffer, size, 0, ipaddr, port) < 0)
+ return -1;
+#else
if (sendto(sock, (const char*)buffer, (mdns_size_t)size, 0, (const struct sockaddr*)address,
(socklen_t)address_size) < 0)
return -1;
+#endif
return 0;
}
static inline int
-mdns_multicast_send(int sock, const void* buffer, size_t size) {
+mdns_multicast_send(mdns_socket_t sock, const void* buffer, size_t size) {
+#ifdef __circle__
+ CIPAddress ipaddr(htonl((((uint32_t)224U) << 24U) | ((uint32_t)251U)));
+ if (sock->SendTo(buffer, size, 0, ipaddr, MDNS_PORT) < 0)
+ return -1;
+#else
struct sockaddr_storage addr_storage;
struct sockaddr_in addr;
struct sockaddr_in6 addr6;
@@ -850,6 +913,7 @@ mdns_multicast_send(int sock, const void* buffer, size_t size) {
if (sendto(sock, (const char*)buffer, (mdns_size_t)size, 0, saddr, saddrlen) < 0)
return -1;
+#endif
return 0;
}
@@ -871,13 +935,28 @@ static const uint8_t mdns_services_query[] = {
0x80, MDNS_CLASS_IN};
static inline int
-mdns_discovery_send(int sock) {
+mdns_discovery_send(mdns_socket_t sock) {
return mdns_multicast_send(sock, mdns_services_query, sizeof(mdns_services_query));
}
static inline size_t
-mdns_discovery_recv(int sock, void* buffer, size_t capacity, mdns_record_callback_fn callback,
+mdns_discovery_recv(mdns_socket_t sock, void* buffer, size_t capacity, mdns_record_callback_fn callback,
void* user_data) {
+#ifdef __circle__
+ struct sockaddr_in addr;
+ struct sockaddr* saddr = (struct sockaddr*)&addr;
+ socklen_t addrlen = sizeof(addr);
+
+ CIPAddress ipaddr;
+ u16 port;
+ mdns_ssize_t ret = sock->ReceiveFrom(buffer, capacity, 0, &ipaddr, &port);
+ if (ret <= 0)
+ return 0;
+
+ addr.sin_family = AF_INET;
+ addr.sin_port = port;
+ addr.sin_addr.s_addr = (u32)ipaddr;
+#else
struct sockaddr_in6 addr;
struct sockaddr* saddr = (struct sockaddr*)&addr;
socklen_t addrlen = sizeof(addr);
@@ -888,6 +967,7 @@ mdns_discovery_recv(int sock, void* buffer, size_t capacity, mdns_record_callbac
mdns_ssize_t ret = recvfrom(sock, (char*)buffer, (mdns_size_t)capacity, 0, saddr, &addrlen);
if (ret <= 0)
return 0;
+#endif
size_t data_size = (size_t)ret;
size_t records = 0;
@@ -980,8 +1060,23 @@ mdns_discovery_recv(int sock, void* buffer, size_t capacity, mdns_record_callbac
}
static inline size_t
-mdns_socket_listen(int sock, void* buffer, size_t capacity, mdns_record_callback_fn callback,
+mdns_socket_listen(mdns_socket_t sock, void* buffer, size_t capacity, mdns_record_callback_fn callback,
void* user_data) {
+#ifdef __circle__
+ struct sockaddr_in addr;
+ struct sockaddr* saddr = (struct sockaddr*)&addr;
+ socklen_t addrlen = sizeof(addr);
+
+ CIPAddress ipaddr;
+ u16 port;
+ mdns_ssize_t ret = sock->ReceiveFrom(buffer, capacity, 0, &ipaddr, &port);
+ if (ret <= 0)
+ return 0;
+
+ addr.sin_family = AF_INET;
+ addr.sin_port = port;
+ addr.sin_addr.s_addr = (u32)ipaddr;
+#else
struct sockaddr_in6 addr;
struct sockaddr* saddr = (struct sockaddr*)&addr;
socklen_t addrlen = sizeof(addr);
@@ -992,6 +1087,7 @@ mdns_socket_listen(int sock, void* buffer, size_t capacity, mdns_record_callback
mdns_ssize_t ret = recvfrom(sock, (char*)buffer, (mdns_size_t)capacity, 0, saddr, &addrlen);
if (ret <= 0)
return 0;
+#endif
size_t data_size = (size_t)ret;
const uint16_t* data = (const uint16_t*)buffer;
@@ -1061,7 +1157,7 @@ mdns_socket_listen(int sock, void* buffer, size_t capacity, mdns_record_callback
}
static inline int
-mdns_query_send(int sock, mdns_record_type_t type, const char* name, size_t length, void* buffer,
+mdns_query_send(mdns_socket_t sock, mdns_record_type_t type, const char* name, size_t length, void* buffer,
size_t capacity, uint16_t query_id) {
mdns_query_t query;
query.type = type;
@@ -1071,11 +1167,15 @@ mdns_query_send(int sock, mdns_record_type_t type, const char* name, size_t leng
}
static inline int
-mdns_multiquery_send(int sock, const mdns_query_t* query, size_t count, void* buffer, size_t capacity,
+mdns_multiquery_send(mdns_socket_t sock, const mdns_query_t* query, size_t count, void* buffer, size_t capacity,
uint16_t query_id) {
if (!count || (capacity < (sizeof(struct mdns_header_t) + (6 * count))))
return -1;
+#ifdef __circle__
+ // Only multicast response supported
+ uint16_t rclass = MDNS_CLASS_IN;
+#else
// Ask for a unicast response since it's a one-shot query
uint16_t rclass = MDNS_CLASS_IN | MDNS_UNICAST_RESPONSE;
@@ -1090,6 +1190,7 @@ mdns_multiquery_send(int sock, const mdns_query_t* query, size_t count, void* bu
(ntohs(((struct sockaddr_in6*)saddr)->sin6_port) == MDNS_PORT))
rclass &= ~MDNS_UNICAST_RESPONSE;
}
+#endif
struct mdns_header_t* header = (struct mdns_header_t*)buffer;
// Query ID
@@ -1122,8 +1223,23 @@ mdns_multiquery_send(int sock, const mdns_query_t* query, size_t count, void* bu
}
static inline size_t
-mdns_query_recv(int sock, void* buffer, size_t capacity, mdns_record_callback_fn callback,
+mdns_query_recv(mdns_socket_t sock, void* buffer, size_t capacity, mdns_record_callback_fn callback,
void* user_data, int only_query_id) {
+#ifdef __circle__
+ struct sockaddr_in addr;
+ struct sockaddr* saddr = (struct sockaddr*)&addr;
+ socklen_t addrlen = sizeof(addr);
+
+ CIPAddress ipaddr;
+ u16 port;
+ mdns_ssize_t ret = sock->ReceiveFrom(buffer, capacity, 0, &ipaddr, &port);
+ if (ret <= 0)
+ return 0;
+
+ addr.sin_family = AF_INET;
+ addr.sin_port = port;
+ addr.sin_addr.s_addr = (u32)ipaddr;
+#else
struct sockaddr_in6 addr;
struct sockaddr* saddr = (struct sockaddr*)&addr;
socklen_t addrlen = sizeof(addr);
@@ -1134,6 +1250,7 @@ mdns_query_recv(int sock, void* buffer, size_t capacity, mdns_record_callback_fn
mdns_ssize_t ret = recvfrom(sock, (char*)buffer, (mdns_size_t)capacity, 0, saddr, &addrlen);
if (ret <= 0)
return 0;
+#endif
size_t data_size = (size_t)ret;
const uint16_t* data = (const uint16_t*)buffer;
@@ -1264,12 +1381,14 @@ mdns_answer_add_record(void* buffer, size_t capacity, void* data, mdns_record_t
data = MDNS_POINTER_OFFSET(data, 4);
break;
+#ifndef __circle__
case MDNS_RECORDTYPE_AAAA:
if (remain < 16)
return 0;
memcpy(data, &record.data.aaaa.addr.sin6_addr, 16); // ipv6 address
data = MDNS_POINTER_OFFSET(data, 16);
break;
+#endif
default:
break;
@@ -1360,7 +1479,7 @@ mdns_answer_get_record_count(const mdns_record_t* records, size_t record_count)
}
static inline int
-mdns_query_answer_unicast(int sock, const void* address, size_t address_size, void* buffer,
+mdns_query_answer_unicast(mdns_socket_t sock, const void* address, size_t address_size, void* buffer,
size_t capacity, uint16_t query_id, mdns_record_type_t record_type,
const char* name, size_t name_length, mdns_record_t answer,
const mdns_record_t* authority, size_t authority_count,
@@ -1424,7 +1543,7 @@ mdns_query_answer_unicast(int sock, const void* address, size_t address_size, vo
}
static inline int
-mdns_answer_multicast_rclass_ttl(int sock, void* buffer, size_t capacity, mdns_record_t answer,
+mdns_answer_multicast_rclass_ttl(mdns_socket_t sock, void* buffer, size_t capacity, mdns_record_t answer,
const mdns_record_t* authority, size_t authority_count,
const mdns_record_t* additional, size_t additional_count,
uint16_t rclass, uint32_t ttl) {
@@ -1473,7 +1592,7 @@ mdns_answer_multicast_rclass_ttl(int sock, void* buffer, size_t capacity, mdns_r
}
static inline int
-mdns_query_answer_multicast(int sock, void* buffer, size_t capacity, mdns_record_t answer,
+mdns_query_answer_multicast(mdns_socket_t sock, void* buffer, size_t capacity, mdns_record_t answer,
const mdns_record_t* authority, size_t authority_count,
const mdns_record_t* additional, size_t additional_count) {
return mdns_answer_multicast_rclass_ttl(sock, buffer, capacity, answer, authority,
@@ -1482,7 +1601,7 @@ mdns_query_answer_multicast(int sock, void* buffer, size_t capacity, mdns_record
}
static inline int
-mdns_announce_multicast(int sock, void* buffer, size_t capacity, mdns_record_t answer,
+mdns_announce_multicast(mdns_socket_t sock, void* buffer, size_t capacity, mdns_record_t answer,
const mdns_record_t* authority, size_t authority_count,
const mdns_record_t* additional, size_t additional_count) {
return mdns_answer_multicast_rclass_ttl(sock, buffer, capacity, answer, authority,
@@ -1491,7 +1610,7 @@ mdns_announce_multicast(int sock, void* buffer, size_t capacity, mdns_record_t a
}
static inline int
-mdns_goodbye_multicast(int sock, void* buffer, size_t capacity, mdns_record_t answer,
+mdns_goodbye_multicast(mdns_socket_t sock, void* buffer, size_t capacity, mdns_record_t answer,
const mdns_record_t* authority, size_t authority_count,
const mdns_record_t* additional, size_t additional_count) {
// Goodbye should have ttl of 0
@@ -1545,6 +1664,7 @@ mdns_record_parse_a(const void* buffer, size_t size, size_t offset, size_t lengt
return addr;
}
+#ifndef __circle__
static inline struct sockaddr_in6*
mdns_record_parse_aaaa(const void* buffer, size_t size, size_t offset, size_t length,
struct sockaddr_in6* addr) {
@@ -1557,6 +1677,7 @@ mdns_record_parse_aaaa(const void* buffer, size_t size, size_t offset, size_t le
memcpy(&addr->sin6_addr, MDNS_POINTER_OFFSET(buffer, offset), 16);
return addr;
}
+#endif
static inline size_t
mdns_record_parse_txt(const void* buffer, size_t size, size_t offset, size_t length,

View File

@@ -82,6 +82,7 @@ CMT32Pi::CMT32Pi(CI2CMaster* pI2CMaster, CSPIMaster* pSPIMaster, CInterruptSyste
m_WLAN(WLANFirmwarePath),
m_WPASupplicant(WLANConfigFile),
m_bNetworkReady(false),
m_pMDNSResponder(nullptr),
m_pAppleMIDIParticipant(nullptr),
m_pUDPMIDIReceiver(nullptr),
m_pFTPDaemon(nullptr),
@@ -901,6 +902,14 @@ void CMT32Pi::UpdateNetwork()
else
m_pLogger->Write(MT32PiName, LogNotice, "FTP daemon initialized");
}
m_pMDNSResponder = new CMDNSResponder();
if (!m_pMDNSResponder->Initialize())
{
m_pLogger->Write(MT32PiName, LogError, "Failed to init mDNS responder");
delete m_pMDNSResponder;
m_pMDNSResponder = nullptr;
}
}
else if (m_bNetworkReady && !bNetIsRunning)
{

246
src/net/mdnsresponder.cpp Normal file
View File

@@ -0,0 +1,246 @@
//
// mdsnresponder.cpp
//
// mt32-pi - A baremetal MIDI synthesizer for Raspberry Pi
// Copyright (C) 2020-2022 Dale Whinham <daleyo@gmail.com>
//
// This file is part of mt32-pi.
//
// mt32-pi is free software: you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the Free Software
// Foundation, either version 3 of the License, or (at your option) any later
// version.
//
// mt32-pi is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// mt32-pi. If not, see <http://www.gnu.org/licenses/>.
//
#include <cstdio>
#include <circle/logger.h>
#include <circle/net/in.h>
#include <circle/net/netsubsystem.h>
#include <circle/sched/scheduler.h>
#include <mdns.h>
#include "net/mdnsresponder.h"
#include "utility.h"
constexpr u32 MDNSAddress = Utility::IPAddressToInteger(224, 0, 0, 251);
constexpr u16 MDNSPort = 5353;
const char MDNSResponderName[] = "mdns";
struct TDNSHeader
{
u16 nID;
u16 nFlags;
#define DNS_FLAGS_QR 0x8000
#define DNS_FLAGS_OPCODE 0x7800
#define DNS_FLAGS_OPCODE_QUERY 0x0000
#define DNS_FLAGS_OPCODE_IQUERY 0x0800
#define DNS_FLAGS_OPCODE_STATUS 0x1000
#define DNS_FLAGS_AA 0x0400
#define DNS_FLAGS_TC 0x0200
#define DNS_FLAGS_RD 0x0100
#define DNS_FLAGS_RA 0x0080
#define DNS_FLAGS_RCODE 0x000F
#define DNS_RCODE_SUCCESS 0x0000
#define DNS_RCODE_FORMAT_ERROR 0x0001
#define DNS_RCODE_SERVER_FAILURE 0x0002
#define DNS_RCODE_NAME_ERROR 0x0003
#define DNS_RCODE_NOT_IMPLEMENTED 0x0004
#define DNS_RCODE_REFUSED 0x0005
u16 nQDCount;
u16 nANCount;
u16 nNSCount;
u16 nARCount;
}
PACKED;
struct TDNSResourceRecordTrailerAIN
{
u16 nType;
u16 nClass;
u32 nTTL;
u16 nRDLength;
#define DNS_RDLENGTH_AIN 4
unsigned char RData[DNS_RDLENGTH_AIN];
}
PACKED;
CMDNSResponder::CMDNSResponder()
: CTask(TASK_STACK_SIZE, true),
m_pSocket(nullptr),
m_Buffer{0}
{
snprintf(m_DNSName, sizeof(m_DNSName), "_%s", "mt32-pi");
}
CMDNSResponder::~CMDNSResponder()
{
if (m_pSocket)
delete m_pSocket;
}
bool CMDNSResponder::Initialize()
{
assert(m_pSocket == nullptr);
CLogger* const pLogger = CLogger::Get();
CNetSubSystem* const pNet = CNetSubSystem::Get();
if ((m_pSocket = new CSocket(pNet, IPPROTO_UDP)) == nullptr)
return false;
if (m_pSocket->Bind(MDNSPort) != 0)
{
pLogger->Write(MDNSResponderName, LogError, "Couldn't bind to port %d", MDNSPort);
return false;
}
if (m_pSocket->SetOptionBroadcast(true) != 0)
{
pLogger->Write(MDNSResponderName, LogError, "Couldn't enable broadcast packet for socket");
return false;
}
// We started as a suspended task; run now that initialization is successful
Start();
return true;
}
void CMDNSResponder::Run()
{
assert(m_pSocket != nullptr);
//CLogger* const pLogger = CLogger::Get();
CScheduler* const pScheduler = CScheduler::Get();
// CIPAddress MDNSIPAddress(MDNSAddress);//Utility::IPAddressToInteger(192, 168, 175, 30));
// char buf[] = "hello world";
// while (true)
// {
// m_pSocket->SendTo(buf, sizeof(buf), 0, MDNSIPAddress, MDNSPort);
// pScheduler->Sleep(1);
// }
// return;
// mdns_record_t Record =
// {
// { "_applemidi", 10 },
// MDNS_RECORDTYPE_PTR,
// {
// .ptr.name = ""
// }
// };
// mdns_record_t Record;
// Record.name = { MDNS_STRING_CONST("_applemidi._udp.local.") };
// Record.type = MDNS_RECORDTYPE_PTR;
// Record.data.ptr.name = { MDNS_STRING_CONST("mt32-pi._applemidi._udp.local.") };
// Record.rclass = 0;
// Record.ttl = 0;
return;
while (true)
{
// char buf[] = "hello world";
// CIPAddress MDNSIPAddress(MDNSAddress);
// m_pSocket->SendTo(buf, sizeof(buf), 0, MDNSIPAddress, MDNSPort);
// pScheduler->Sleep(1);
mdns_record_t Record =
{
.name = { MDNS_STRING_CONST("_apple-midi._udp.local.") },
.type = MDNS_RECORDTYPE_PTR,
.data = { .ptr = { .name = { MDNS_STRING_CONST("mt32-pi._apple-midi._udp.local.") } } },
.rclass = 0,
.ttl = 0
};
assert(mdns_announce_multicast(m_pSocket, m_Buffer, sizeof(m_Buffer), Record, nullptr, 0, nullptr, 0) == 0);
pScheduler->Sleep(2);
assert(mdns_announce_multicast(m_pSocket, m_Buffer, sizeof(m_Buffer), Record, nullptr, 0, nullptr, 0) == 0);
pScheduler->Sleep(10);
assert(mdns_announce_multicast(m_pSocket, m_Buffer, sizeof(m_Buffer), Record, nullptr, 0, nullptr, 0) == 0);
pScheduler->Sleep(20);
assert(mdns_goodbye_multicast(m_pSocket, m_Buffer, sizeof(m_Buffer), Record, nullptr, 0, nullptr, 0) == 0);
pScheduler->Sleep(2);
// // Non-blocking call
// const int nResult = m_pSocket->Receive(m_ReceiveBuffer, sizeof(m_ReceiveBuffer), MSG_DONTWAIT);
// m_pSocket->ReceiveFrom()
// if (nResult < 0)
// pLogger->Write(MDNSResponderName, LogError, "Socket receive error: %d", nResult);
// else if (nResult > 0)
// {
// pLogger->Write(MDNSResponderName, LogDebug, "Received something of size %d", nResult);
// }
// TDNSHeader* Header = reinterpret_cast<TDNSHeader*>(m_ReceiveBuffer);
// Header->nID = htons(0);
// Header->nFlags = htons(DNS_FLAGS_QR | DNS_FLAGS_AA);
// Header->nQDCount = htons(0);
// Header->nANCount = htons(1);
// Header->nNSCount = htons(0);
// Header->nARCount = htons(0);
// u8* pPtr = m_ReceiveBuffer + sizeof(TDNSHeader);
// *pPtr++ = 0x0B;
// *pPtr++ = '_';
// *pPtr++ = 'a';
// *pPtr++ = 'p';
// *pPtr++ = 'p';
// *pPtr++ = 'l';
// *pPtr++ = 'e';
// *pPtr++ = '-';
// *pPtr++ = 'm';
// *pPtr++ = 'i';
// *pPtr++ = 'd';
// *pPtr++ = 'i';
// *pPtr++ = 0x04;
// *pPtr++ = '_';
// *pPtr++ = 'u';
// *pPtr++ = 'd';
// *pPtr++ = 'p';
// *pPtr++ = 0x05;
// *pPtr++ = 'l';
// *pPtr++ = 'o';
// *pPtr++ = 'c';
// *pPtr++ = 'a';
// *pPtr++ = 'l';
// *pPtr++ = '\0';
// TDNSResourceRecordTrailerAIN* Record = reinterpret_cast<TDNSResourceRecordTrailerAIN*>(pPtr);
// Record->nType = 0x0C;
// Record->nClass = 0x01;
// Record->nTTL = 120;
// //Record->nRDLength
// const u8 nNameLength = strlen(m_DNSName);
// *pPtr++ = nNameLength;
// memcpy(reinterpret_cast<char*>(pPtr), m_DNSName, nNameLength);//, sizeof(m_ReceiveBuffer) - (pPtr - m_ReceiveBuffer));
// pPtr += nNameLength;
// // Allow other tasks to run
// //pScheduler->Yield();
// pScheduler->Sleep(10);
}
}

View File

@@ -33,29 +33,29 @@ const char UDPMIDIName[] = "udpmidi";
CUDPMIDIReceiver::CUDPMIDIReceiver(CUDPMIDIHandler* pHandler)
: CTask(TASK_STACK_SIZE, true),
m_pMIDISocket(nullptr),
m_MIDIBuffer{0},
m_pSocket(nullptr),
m_ReceiveBuffer{0},
m_pHandler(pHandler)
{
}
CUDPMIDIReceiver::~CUDPMIDIReceiver()
{
if (m_pMIDISocket)
delete m_pMIDISocket;
if (m_pSocket)
delete m_pSocket;
}
bool CUDPMIDIReceiver::Initialize()
{
assert(m_pMIDISocket == nullptr);
assert(m_pSocket == nullptr);
CLogger* const pLogger = CLogger::Get();
CNetSubSystem* const pNet = CNetSubSystem::Get();
if ((m_pMIDISocket = new CSocket(pNet, IPPROTO_UDP)) == nullptr)
if ((m_pSocket = new CSocket(pNet, IPPROTO_UDP)) == nullptr)
return false;
if (m_pMIDISocket->Bind(MIDIPort) != 0)
if (m_pSocket->Bind(MIDIPort) != 0)
{
pLogger->Write(UDPMIDIName, LogError, "Couldn't bind to port %d", MIDIPort);
return false;
@@ -70,7 +70,7 @@ bool CUDPMIDIReceiver::Initialize()
void CUDPMIDIReceiver::Run()
{
assert(m_pHandler != nullptr);
assert(m_pMIDISocket != nullptr);
assert(m_pSocket != nullptr);
CLogger* const pLogger = CLogger::Get();
CScheduler* const pScheduler = CScheduler::Get();
@@ -78,12 +78,12 @@ void CUDPMIDIReceiver::Run()
while (true)
{
// Blocking call
const int nMIDIResult = m_pMIDISocket->Receive(m_MIDIBuffer, sizeof(m_MIDIBuffer), 0);
const int nResult = m_pSocket->Receive(m_ReceiveBuffer, sizeof(m_ReceiveBuffer), 0);
if (nMIDIResult < 0)
pLogger->Write(UDPMIDIName, LogError, "MIDI socket receive error: %d", nMIDIResult);
else if (nMIDIResult > 0)
m_pHandler->OnUDPMIDIDataReceived(m_MIDIBuffer, nMIDIResult);
if (nResult < 0)
pLogger->Write(UDPMIDIName, LogError, "Socket receive error: %d", nResult);
else if (nResult > 0)
m_pHandler->OnUDPMIDIDataReceived(m_ReceiveBuffer, nResult);
// Allow other tasks to run
pScheduler->Yield();