struct iio_context * network_create_context(const char *host) { struct addrinfo hints, *res; struct iio_context *ctx; struct iio_context_pdata *pdata; size_t i, len; int fd, ret; char *description; #ifdef _WIN32 WSADATA wsaData; ret = WSAStartup(MAKEWORD(2, 0), &wsaData); if (ret < 0) { ERROR("WSAStartup failed with error %i\n", ret); errno = -ret; return NULL; } #endif memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; #ifdef HAVE_AVAHI if (!host) { char addr_str[AVAHI_ADDRESS_STR_MAX]; char port_str[6]; AvahiAddress address; uint16_t port = IIOD_PORT; memset(&address, 0, sizeof(address)); ret = discover_host(&address, &port); if (ret < 0) { DEBUG("Unable to find host: %s\n", strerror(-ret)); errno = -ret; return NULL; } avahi_address_snprint(addr_str, sizeof(addr_str), &address); snprintf(port_str, sizeof(port_str), "%hu", port); ret = getaddrinfo(addr_str, port_str, &hints, &res); } else #endif { ret = getaddrinfo(host, IIOD_PORT_STR, &hints, &res); } if (ret) { ERROR("Unable to find host: %s\n", gai_strerror(ret)); #ifndef _WIN32 if (ret != EAI_SYSTEM) errno = ret; #endif return NULL; } fd = create_socket(res); if (fd < 0) { errno = fd; goto err_free_addrinfo; } pdata = calloc(1, sizeof(*pdata)); if (!pdata) { errno = ENOMEM; goto err_close_socket; } pdata->fd = fd; pdata->addrinfo = res; pdata->lock = iio_mutex_create(); if (!pdata->lock) { errno = ENOMEM; goto err_free_pdata; } pdata->iiod_client = iiod_client_new(pdata, pdata->lock, &network_iiod_client_ops); if (!pdata->iiod_client) goto err_destroy_mutex; DEBUG("Creating context...\n"); ctx = iiod_client_create_context(pdata->iiod_client, fd); if (!ctx) goto err_destroy_iiod_client; /* Override the name and low-level functions of the XML context * with those corresponding to the network context */ ctx->name = "network"; ctx->ops = &network_ops; ctx->pdata = pdata; #ifdef HAVE_IPV6 len = INET6_ADDRSTRLEN + IF_NAMESIZE + 2; #else len = INET_ADDRSTRLEN + 1; #endif description = malloc(len); if (!description) { ret = -ENOMEM; goto err_network_shutdown; } description[0] = '\0'; #ifdef HAVE_IPV6 if (res->ai_family == AF_INET6) { struct sockaddr_in6 *in = (struct sockaddr_in6 *) res->ai_addr; char *ptr; inet_ntop(AF_INET6, &in->sin6_addr, description, INET6_ADDRSTRLEN); ptr = if_indextoname(in->sin6_scope_id, description + strlen(description) + 1); if (!ptr) { ret = -errno; ERROR("Unable to lookup interface of IPv6 address\n"); goto err_free_description; } *(ptr - 1) = '%'; } #endif if (res->ai_family == AF_INET) { struct sockaddr_in *in = (struct sockaddr_in *) res->ai_addr; #if (!_WIN32 || _WIN32_WINNT >= 0x600) inet_ntop(AF_INET, &in->sin_addr, description, INET_ADDRSTRLEN); #else char *tmp = inet_ntoa(in->sin_addr); strncpy(description, tmp, len); #endif } for (i = 0; i < ctx->nb_devices; i++) { struct iio_device *dev = ctx->devices[i]; dev->pdata = calloc(1, sizeof(*dev->pdata)); if (!dev->pdata) { ret = -ENOMEM; goto err_free_description; } dev->pdata->fd = -1; #ifdef WITH_NETWORK_GET_BUFFER dev->pdata->memfd = -1; #endif dev->pdata->lock = iio_mutex_create(); if (!dev->pdata->lock) { ret = -ENOMEM; goto err_free_description; } } ret = iio_context_init(ctx); if (ret < 0) goto err_free_description; if (ctx->description) { size_t desc_len = strlen(description); size_t new_size = desc_len + strlen(ctx->description) + 2; char *ptr, *new_description = realloc(description, new_size); if (!new_description) { ret = -ENOMEM; goto err_free_description; } ptr = strrchr(new_description, '\0'); snprintf(ptr, new_size - desc_len, " %s", ctx->description); free(ctx->description); ctx->description = new_description; } else { ctx->description = description; } iiod_client_set_timeout(pdata->iiod_client, fd, calculate_remote_timeout(DEFAULT_TIMEOUT_MS)); return ctx; err_free_description: free(description); err_network_shutdown: iio_context_destroy(ctx); errno = -ret; return NULL; err_destroy_iiod_client: iiod_client_destroy(pdata->iiod_client); err_destroy_mutex: iio_mutex_destroy(pdata->lock); err_free_pdata: free(pdata); err_close_socket: close(fd); err_free_addrinfo: freeaddrinfo(res); return NULL; }
DirectResult voodoo_client_create( const char *host, int port, VoodooClient **ret_client ) { DirectResult ret; VoodooPlayInfo info; VoodooClient *client; VoodooPlayer *player; char buf[100] = { 0 }; const char *hostname = host; bool raw = true; D_ASSERT( ret_client != NULL ); if (!host) host = ""; if (!port) port = 2323; D_DEBUG_AT( Voodoo_Client, "%s( '%s', %d )\n", __FUNCTION__, host, port ); if (port != 2323) { D_DEBUG_AT( Voodoo_Client, " -> port != 2323, using PACKET mode right away\n" ); raw = false; } direct_list_foreach (client, m_clients) { if (!strcmp( client->host, host ) && client->port == port) { D_INFO( "Voodoo/Client: Reconnecting to '%s', increasing ref count of existing connection!\n", host ); client->refs++; *ret_client = client; return DR_OK; } } /* * Get the player singleton */ ret = voodoo_player_create( NULL, &player ); if (ret) { D_DERROR( ret, "Voodoo/Client: Could not create the player!\n" ); return ret; } /* * If we got a hostname or address try to lookup the player info */ // FIXME: resolve first, not late in voodoo_link_init_connect if (hostname && hostname[0]) { ret = voodoo_player_lookup_by_address( player, hostname, &info ); if (ret == DR_OK) { if (info.flags & VPIF_PACKET) raw = false; } } else { /* * Start discovery and use first host visible */ ret = discover_host( player, NULL, &info, buf, sizeof(buf) ); if (ret == DR_OK) { if (info.flags & VPIF_PACKET) raw = false; hostname = buf; } } if (!hostname || !hostname[0]) { D_ERROR( "Voodoo/Client: Did not find any other player!\n" ); return DR_ITEMNOTFOUND; } /* Allocate client structure. */ client = D_CALLOC( 1, sizeof(VoodooClient) ); if (!client) return D_OOM(); raw = !voodoo_config->link_packet && (voodoo_config->link_raw || raw); /* Create a link to the other player. */ ret = voodoo_link_init_connect( &client->vl, hostname, port, raw ); if (ret) { D_DERROR( ret, "Voodoo/Client: Failed to initialize Voodoo Link!\n" ); D_FREE( client ); return ret; } D_INFO( "Voodoo/Client: Fetching player information...\n" ); if (raw) { // FIXME: send_discover_and_receive_info() only does RAW, but we don't need it for packet connection, yet VoodooPlayVersion version; VoodooPlayInfo info; ret = send_discover_and_receive_info( &client->vl, &version, &info ); if (ret) { D_DEBUG_AT( Voodoo_Client, " -> Failed to receive player info via TCP!\n" ); D_INFO( "Voodoo/Client: No player information from '%s', trying to discover via UDP!\n", host ); /* * Fallback to UDP discovery */ ret = discover_host( player, hostname, &info, buf, sizeof(buf) ); if (ret == DR_OK) { if (info.flags & VPIF_PACKET) raw = false; } } else { D_INFO( "Voodoo/Client: Connected to '%s' (%-15s) %s " "=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x= " "(vendor: %s, model: %s)\n", info.name, host, (info.flags & VPIF_LEVEL2) ? "*" : " ", info.uuid[0], info.uuid[1], info.uuid[2], info.uuid[3], info.uuid[4], info.uuid[5], info.uuid[6], info.uuid[7], info.uuid[8], info.uuid[9], info.uuid[10], info.uuid[11], info.uuid[12], info.uuid[13], info.uuid[14], info.uuid[15], info.vendor, info.model ); if (raw && !voodoo_config->link_raw) { /* * Switch to packet mode? */ if (info.flags & VPIF_PACKET) raw = false; } } /* * Switch to packet mode? */ if (!raw) { D_INFO( "Voodoo/Client: Switching to packet mode!\n" ); client->vl.Close( &client->vl ); /* Create another link to the other player. */ ret = voodoo_link_init_connect( &client->vl, hostname, port, false ); if (ret) { D_DERROR( ret, "Voodoo/Client: Failed to initialize second Voodoo Link!\n" ); D_FREE( client ); return ret; } } } /* Create the manager. */ ret = voodoo_manager_create( &client->vl, client, NULL, &client->manager ); if (ret) { client->vl.Close( &client->vl ); D_FREE( client ); return ret; } client->refs = 1; client->host = D_STRDUP( host ); client->port = port; direct_list_prepend( &m_clients, &client->link ); /* Return the new client. */ *ret_client = client; D_DEBUG_AT( Voodoo_Client, " => client %p\n", client ); return DR_OK; }