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.