/** * 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; }
/** * 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; }