27 #include <sys/select.h> 28 #include <sys/types.h> 29 #include <sys/socket.h> 30 #include <netinet/in.h> 31 #include <arpa/inet.h> 45 #define ADV_MESSAGE_SIZE 128 48 #define DISC_PORT 19020 51 #define DISC_MESSAGE_SIZE 64 54 #define DISC_TIMEOUT 20 119 if (memcmp(buffer,
"Found", 5) != 0)
126 memcpy(&in, buffer + 16, 4);
154 struct sockaddr_in *
addr,
const uint8_t *
buffer)
163 log_dbg(ctx,
"Received advertisement message (IPv4 address = %s).",
164 inet_ntoa(addr->sin_addr));
167 log_dbg(ctx,
"Received invalid advertisement message.");
172 log_dbg(ctx,
"Device: MAC address = %02x:%02x:%02x:%02x:%02x:%02x.",
186 log_dbg(ctx,
"Ignoring already discovered device.");
193 log_dbg(ctx,
"Using existing device instance.");
197 log_dbg(ctx,
"Allocating new device instance.");
202 log_warn(ctx,
"Device instance malloc failed.");
235 struct sockaddr_in addr;
238 uint8_t buf[ADV_MESSAGE_SIZE];
243 sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
246 log_err(ctx,
"Failed to create discovery socket.");
253 sizeof(opt_value))) {
254 log_err(ctx,
"Failed to enable broadcast option for discovery " 260 memset(&addr, 0,
sizeof(
struct sockaddr_in));
261 addr.sin_family = AF_INET;
262 addr.sin_port = htons(DISC_PORT);
263 addr.sin_addr.s_addr = INADDR_ANY;
266 sizeof(
struct sockaddr_in))) {
267 log_err(ctx,
"Failed to bind discovery socket.");
272 addr.sin_family = AF_INET;
273 addr.sin_port = htons(DISC_PORT);
274 addr.sin_addr.s_addr = INADDR_BROADCAST;
276 memset(buf, 0, DISC_MESSAGE_SIZE);
277 memcpy(buf,
"Discover", 8);
279 log_dbg(ctx,
"Sending discovery message.");
281 length = DISC_MESSAGE_SIZE;
284 (
const struct sockaddr *)&addr,
sizeof(addr))) {
285 log_err(ctx,
"Failed to send discovery message.");
290 if (length < DISC_MESSAGE_SIZE) {
291 log_err(ctx,
"Only sent %zu bytes of discovery message.",
297 timeout.
tv_sec = DISC_TIMEOUT / 1000;
298 timeout.
tv_usec = (DISC_TIMEOUT % 1000) * 1000;
306 ret = select(sock + 1, &rfds,
NULL,
NULL, &timeout);
311 if (!FD_ISSET(sock, &rfds))
314 length = ADV_MESSAGE_SIZE;
315 addr_length =
sizeof(
struct sockaddr_in);
318 (
struct sockaddr *)&addr, &addr_length)) {
319 log_warn(ctx,
"Failed to receive advertisement " 328 if (length != ADV_MESSAGE_SIZE)
343 log_err(ctx,
"select() failed.");
347 log_dbg(ctx,
"Found %zu TCP/IP device(s).", num_devs);
static struct jaylink_device * find_device(struct list *list, const struct jaylink_device *dev)
bool has_mac_address
Indicates whether the MAC address is available.
JAYLINK_PRIV struct jaylink_device * device_allocate(struct jaylink_context *ctx)
char ipv4_address[INET_ADDRSTRLEN]
IPv4 address.
struct list * discovered_devs
List of recently discovered devices.
char product_name[JAYLINK_PRODUCT_NAME_MAX_LENGTH]
Product name.
JAYLINK_PRIV void log_err(const struct jaylink_context *ctx, const char *format,...)
static struct jaylink_device * probe_device(struct jaylink_context *ctx, struct sockaddr_in *addr, const uint8_t *buffer)
bool has_serial_number
Indicates whether the serial number is available.
uint8_t minor
Minor version.
#define JAYLINK_NICKNAME_MAX_LENGTH
Maximum length of a device's nickname including trailing null-terminator in bytes.
JAYLINK_PRIV uint32_t buffer_get_u32(const uint8_t *buffer, size_t offset)
Read a 32-bit unsigned integer value from a buffer.
Opaque structure representing a device.
struct list * devs
List of allocated device instances.
JAYLINK_API struct jaylink_device * jaylink_ref_device(struct jaylink_device *dev)
Increment the reference count of a device.
JAYLINK_PRIV struct list * list_find_custom(struct list *list, list_compare_callback callback, const void *user_data)
uint8_t major
Major version.
Opaque structure representing a libjaylink context.
static bool parse_adv_message(struct jaylink_device *dev, const uint8_t *buffer)
#define JAYLINK_PRIV
Macro to mark private libjaylink symbol.
static bool compare_devices(const void *a, const void *b)
Internal libjaylink header file.
JAYLINK_PRIV void log_dbg(const struct jaylink_context *ctx, const char *format,...)
bool has_nickname
Indicates whether the nickname is available.
struct jaylink_context * ctx
libjaylink context.
char nickname[JAYLINK_NICKNAME_MAX_LENGTH]
Nickname.
struct jaylink_hardware_version hw_version
Hardware version.
Transmission Control Protocol (TCP).
enum jaylink_host_interface iface
Host interface.
JAYLINK_PRIV bool socket_sendto(int sock, const void *buffer, size_t *length, int flags, const struct sockaddr *address, size_t address_length)
Send a message on a socket.
uint8_t revision
Revision number.
uint8_t mac_address[JAYLINK_MAC_ADDRESS_LENGTH]
Media Access Control (MAC) address.
#define JAYLINK_PRODUCT_NAME_MAX_LENGTH
Maximum length of a device's product name including trailing null-terminator in bytes.
JAYLINK_PRIV int discovery_tcp_scan(struct jaylink_context *ctx)
JAYLINK_PRIV void log_warn(const struct jaylink_context *ctx, const char *format,...)
Public libjaylink header file to be used by applications.
JAYLINK_PRIV bool socket_recvfrom(int sock, void *buffer, size_t *length, int flags, struct sockaddr *address, size_t *address_length)
Receive a message from a socket.
JAYLINK_PRIV bool socket_bind(int sock, const struct sockaddr *address, size_t length)
Bind an address to a socket.
enum jaylink_hardware_type type
Hardware type.
uint32_t serial_number
Serial number of the device.
bool has_hw_version
Indicates whether the hardware version is available.
JAYLINK_PRIV struct list * list_prepend(struct list *list, void *data)
bool has_product_name
Indicates whether the product name is available.
JAYLINK_PRIV bool socket_close(int sock)
Close a socket.
JAYLINK_PRIV bool socket_set_option(int sock, int level, int option, const void *value, size_t length)
Set an option on a socket.