/**
 * Receives a DL* message plist
 *
 * @param client The connected device link service client used for receiving.
 * @param msg_plist Pointer to a plist that will be set to the contents of the
 *    message plist upon successful return.
 * @param dlmessage A pointer that will be set to a newly allocated char*
 *     containing the DL* string from the given plist. It is up to the caller
 *     to free the allocated memory. If this parameter is NULL
 *     it will be ignored.
 *
 * @return DEVICE_LINK_SERVICE_E_SUCCESS if a DL* message was received,
 *    DEVICE_LINK_SERVICE_E_INVALID_ARG if client or message is invalid,
 *    DEVICE_LINK_SERVICE_E_PLIST_ERROR if the received plist is invalid
 *    or is not a DL* message plist, or DEVICE_LINK_SERVICE_E_MUX_ERROR if
 *    receiving from the device failed.
 */
device_link_service_error_t device_link_service_receive_message(device_link_service_client_t client, plist_t *msg_plist, char **dlmessage)
{
	if (!client || !client->parent || !msg_plist)
		return DEVICE_LINK_SERVICE_E_INVALID_ARG;

	*msg_plist = NULL;
	if (property_list_service_receive_plist(client->parent, msg_plist) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
		return DEVICE_LINK_SERVICE_E_MUX_ERROR;
	}

	if (!device_link_service_get_message(*msg_plist, dlmessage)) {
		debug_info("Did not receive a DL* message as expected!");
		return DEVICE_LINK_SERVICE_E_PLIST_ERROR;
	}
	return DEVICE_LINK_SERVICE_E_SUCCESS;
}
/**
 * Receives a DLMessageProcessMessage plist.
 *
 * @param client The connected device link service client used for receiving.
 * @param message Pointer to a plist that will be set to the contents of the
 *    message contents upon successful return.
 *
 * @return DEVICE_LINK_SERVICE_E_SUCCESS when a DLMessageProcessMessage was
 *    received, DEVICE_LINK_SERVICE_E_INVALID_ARG when client or message is
 *    invalid, DEVICE_LINK_SERVICE_E_PLIST_ERROR if the received plist is
 *    invalid or is not a DLMessageProcessMessage,
 *    or DEVICE_LINK_SERVICE_E_MUX_ERROR if receiving from device fails.
 */
device_link_service_error_t device_link_service_receive_process_message(device_link_service_client_t client, plist_t *message)
{
	if (!client || !client->parent || !message)
		return DEVICE_LINK_SERVICE_E_INVALID_ARG;

	plist_t pmsg = NULL;
	if (property_list_service_receive_plist(client->parent, &pmsg) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
		return DEVICE_LINK_SERVICE_E_MUX_ERROR;
	}

	device_link_service_error_t err = DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR;

	char *msg = NULL;
	device_link_service_get_message(pmsg, &msg);
	if (!msg || strcmp(msg, "DLMessageProcessMessage")) {
		debug_info("Did not receive DLMessageProcessMessage as expected!");
		err = DEVICE_LINK_SERVICE_E_PLIST_ERROR;
		goto leave;
	}

	if (plist_array_get_size(pmsg) != 2) {
		debug_info("Malformed plist received for DLMessageProcessMessage");
		err = DEVICE_LINK_SERVICE_E_PLIST_ERROR;
		goto leave;
	}

	plist_t msg_loc = plist_array_get_item(pmsg, 1);
	if (msg_loc) {
		*message = plist_copy(msg_loc);
		err = DEVICE_LINK_SERVICE_E_SUCCESS;
	} else {
		*message = NULL;
		err = DEVICE_LINK_SERVICE_E_PLIST_ERROR;
	}

leave:
	if (msg)
		free(msg);
	if (pmsg)
		plist_free(pmsg);

	return err;
}
Exemplo n.º 3
0
/**
 * Performs the DLMessageVersionExchange with the connected device.
 * This should be the first operation to be executed by an implemented
 * device link service client.
 *
 * @param client The device_link_service client to use.
 * @param version_major The major version number to check.
 * @param version_minor The minor version number to check.
 *
 * @return DEVICE_LINK_SERVICE_E_SUCCESS on success,
 *     DEVICE_LINK_SERVICE_E_INVALID_ARG when client is NULL,
 *     DEVICE_LINK_SERVICE_E_MUX_ERROR when a communication error occurs,
 *     DEVICE_LINK_SERVICE_E_PLIST_ERROR when the received plist has not the
 *     expected contents, DEVICE_LINK_SERVICE_E_BAD_VERSION when the version
 *     given by the device is larger than the given version,
 *     or DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR otherwise.
 */
device_link_service_error_t device_link_service_version_exchange(device_link_service_client_t client, uint64_t version_major, uint64_t version_minor)
{
    if (!client)
        return DEVICE_LINK_SERVICE_E_INVALID_ARG;

    device_link_service_error_t err = DEVICE_LINK_SERVICE_E_UNKNOWN_ERROR;

    /* perform version exchange */
    plist_t array = NULL;
    char *msg = NULL;

    /* receive DLMessageVersionExchange from device */
    if (property_list_service_receive_plist(client->parent, &array) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
        debug_info("Did not receive initial message from device!");
        err = DEVICE_LINK_SERVICE_E_MUX_ERROR;
        goto leave;
    }
    msg = device_link_service_get_message(array);
    if (!msg || strcmp(msg, "DLMessageVersionExchange")) {
        debug_info("Did not receive DLMessageVersionExchange from device!");
        err = DEVICE_LINK_SERVICE_E_PLIST_ERROR;
        goto leave;
    }
    free(msg);
    msg = NULL;

    /* get major and minor version number */
    if (plist_array_get_size(array) < 3) {
        debug_info("DLMessageVersionExchange has unexpected format!");
        err = DEVICE_LINK_SERVICE_E_PLIST_ERROR;
        goto leave;
    }
    plist_t maj = plist_array_get_item(array, 1);
    plist_t min = plist_array_get_item(array, 2);
    uint64_t vmajor = 0;
    uint64_t vminor = 0;
    if (maj) {
        plist_get_uint_val(maj, &vmajor);
    }
    if (min) {
        plist_get_uint_val(min, &vminor);
    }
    if (vmajor > version_major) {
        debug_info("Version mismatch: device=(%lld,%lld) > expected=(%lld,%lld)", vmajor, vminor, version_major, version_minor);
        err = DEVICE_LINK_SERVICE_E_BAD_VERSION;
        goto leave;
    } else if ((vmajor == version_major) && (vminor > version_minor)) {
        debug_info("WARNING: Version mismatch: device=(%lld,%lld) > expected=(%lld,%lld)", vmajor, vminor, version_major, version_minor);
        err = DEVICE_LINK_SERVICE_E_BAD_VERSION;
        goto leave;
    }
    plist_free(array);

    /* version is ok, send reply */
    array = plist_new_array();
    plist_array_append_item(array, plist_new_string("DLMessageVersionExchange"));
    plist_array_append_item(array, plist_new_string("DLVersionsOk"));
    plist_array_append_item(array, plist_new_uint(version_major));
    if (property_list_service_send_binary_plist(client->parent, array) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
        debug_info("Error when sending DLVersionsOk");
        err = DEVICE_LINK_SERVICE_E_MUX_ERROR;
        goto leave;
    }
    plist_free(array);

    /* receive DeviceReady message */
    array = NULL;
    if (property_list_service_receive_plist(client->parent, &array) != PROPERTY_LIST_SERVICE_E_SUCCESS) {
        debug_info("Error when receiving DLMessageDeviceReady!");
        err = DEVICE_LINK_SERVICE_E_MUX_ERROR;
        goto leave;
    }
    msg = device_link_service_get_message(array);
    if (!msg || strcmp(msg, "DLMessageDeviceReady")) {
        debug_info("Did not get DLMessageDeviceReady!");
        err = DEVICE_LINK_SERVICE_E_PLIST_ERROR;
        goto leave;
    }
    err = DEVICE_LINK_SERVICE_E_SUCCESS;

leave:
    if (msg) {
        free(msg);
    }
    if (array) {
        plist_free(array);
    }
    return err;
}