Example #1
0
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;
}
Example #2
0
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;
}