diff options
| author | 2025-11-25 01:02:31 +0100 | |
|---|---|---|
| committer | 2025-11-25 01:02:31 +0100 | |
| commit | ca85a1829c275635f7b2854887f6490dcb3c5e40 (patch) | |
| tree | d236c9d1329abd6a8f1600ff2c5c742878b716aa | |
| parent | c194db388fb7f1f65ef0a08817f26ed0e8d078b3 (diff) | |
| download | libimobiledevice-ca85a1829c275635f7b2854887f6490dcb3c5e40.tar.gz libimobiledevice-ca85a1829c275635f7b2854887f6490dcb3c5e40.tar.bz2 | |
afc: Improve error handling
| -rw-r--r-- | include/libimobiledevice/afc.h | 1 | ||||
| -rw-r--r-- | src/afc.c | 78 |
2 files changed, 64 insertions, 15 deletions
diff --git a/include/libimobiledevice/afc.h b/include/libimobiledevice/afc.h index 3dcb5da..6e404c3 100644 --- a/include/libimobiledevice/afc.h +++ b/include/libimobiledevice/afc.h | |||
| @@ -64,6 +64,7 @@ typedef enum { | |||
| 64 | AFC_E_NO_MEM = 31, | 64 | AFC_E_NO_MEM = 31, |
| 65 | AFC_E_NOT_ENOUGH_DATA = 32, | 65 | AFC_E_NOT_ENOUGH_DATA = 32, |
| 66 | AFC_E_DIR_NOT_EMPTY = 33, | 66 | AFC_E_DIR_NOT_EMPTY = 33, |
| 67 | AFC_E_SSL_ERROR = 34, | ||
| 67 | AFC_E_FORCE_SIGNED_TYPE = -1 | 68 | AFC_E_FORCE_SIGNED_TYPE = -1 |
| 68 | } afc_error_t; | 69 | } afc_error_t; |
| 69 | 70 | ||
| @@ -59,6 +59,27 @@ static void afc_unlock(afc_client_t client) | |||
| 59 | mutex_unlock(&client->mutex); | 59 | mutex_unlock(&client->mutex); |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | static afc_error_t service_to_afc_error(service_error_t err) | ||
| 63 | { | ||
| 64 | switch (err) { | ||
| 65 | case SERVICE_E_SUCCESS: | ||
| 66 | return AFC_E_SUCCESS; | ||
| 67 | case SERVICE_E_INVALID_ARG: | ||
| 68 | return AFC_E_INVALID_ARG; | ||
| 69 | case SERVICE_E_MUX_ERROR: | ||
| 70 | return AFC_E_MUX_ERROR; | ||
| 71 | case SERVICE_E_SSL_ERROR: | ||
| 72 | return AFC_E_SSL_ERROR; | ||
| 73 | case SERVICE_E_NOT_ENOUGH_DATA: | ||
| 74 | return AFC_E_NOT_ENOUGH_DATA; | ||
| 75 | case SERVICE_E_TIMEOUT: | ||
| 76 | return AFC_E_OP_TIMEOUT; | ||
| 77 | default: | ||
| 78 | break; | ||
| 79 | } | ||
| 80 | return AFC_E_UNKNOWN_ERROR; | ||
| 81 | } | ||
| 82 | |||
| 62 | /** | 83 | /** |
| 63 | * Makes a connection to the AFC service on the device using the given | 84 | * Makes a connection to the AFC service on the device using the given |
| 64 | * connection. | 85 | * connection. |
| @@ -174,11 +195,16 @@ static afc_error_t afc_dispatch_packet(afc_client_t client, uint64_t operation, | |||
| 174 | AFCPacket_to_LE(client->afc_packet); | 195 | AFCPacket_to_LE(client->afc_packet); |
| 175 | debug_buffer((char*)client->afc_packet, sizeof(AFCPacket) + data_length); | 196 | debug_buffer((char*)client->afc_packet, sizeof(AFCPacket) + data_length); |
| 176 | sent = 0; | 197 | sent = 0; |
| 177 | service_send(client->parent, (void*)client->afc_packet, sizeof(AFCPacket) + data_length, &sent); | 198 | afc_error_t err = service_to_afc_error(service_send(client->parent, (void*)client->afc_packet, sizeof(AFCPacket) + data_length, &sent)); |
| 178 | AFCPacket_from_LE(client->afc_packet); | 199 | AFCPacket_from_LE(client->afc_packet); |
| 200 | if (err != AFC_E_SUCCESS) { | ||
| 201 | debug_info("Failed to send packet (sent %i/%i): %s (%d)", sent, sizeof(AFCPacket) + data_length, afc_strerror(err), err); | ||
| 202 | return err; | ||
| 203 | } | ||
| 179 | *bytes_sent += sent; | 204 | *bytes_sent += sent; |
| 180 | if (sent < sizeof(AFCPacket) + data_length) { | 205 | if (sent < sizeof(AFCPacket) + data_length) { |
| 181 | return AFC_E_SUCCESS; | 206 | debug_info("Failed to send entire packet (sent %i/%i)", sent, sizeof(AFCPacket) + data_length); |
| 207 | return AFC_E_NOT_ENOUGH_DATA; | ||
| 182 | } | 208 | } |
| 183 | 209 | ||
| 184 | sent = 0; | 210 | sent = 0; |
| @@ -190,11 +216,16 @@ static afc_error_t afc_dispatch_packet(afc_client_t client, uint64_t operation, | |||
| 190 | debug_info("packet payload follows"); | 216 | debug_info("packet payload follows"); |
| 191 | debug_buffer(payload, payload_length); | 217 | debug_buffer(payload, payload_length); |
| 192 | } | 218 | } |
| 193 | service_send(client->parent, payload, payload_length, &sent); | 219 | err = service_to_afc_error(service_send(client->parent, payload, payload_length, &sent)); |
| 220 | if (err != AFC_E_SUCCESS) { | ||
| 221 | debug_info("Failed to send payload (sent: %i/%i): %s (%d)", sent, payload_length, afc_strerror(err), err); | ||
| 222 | return err; | ||
| 223 | } | ||
| 194 | } | 224 | } |
| 195 | *bytes_sent += sent; | 225 | *bytes_sent += sent; |
| 196 | if (sent < payload_length) { | 226 | if (sent < payload_length) { |
| 197 | return AFC_E_SUCCESS; | 227 | debug_info("Failed to send entire payload (sent: %i/%i): %s (%d)", sent, payload_length, afc_strerror(err), err); |
| 228 | return AFC_E_NOT_ENOUGH_DATA; | ||
| 198 | } | 229 | } |
| 199 | 230 | ||
| 200 | return AFC_E_SUCCESS; | 231 | return AFC_E_SUCCESS; |
| @@ -227,21 +258,28 @@ static afc_error_t afc_receive_data(afc_client_t client, char **bytes, uint32_t | |||
| 227 | } | 258 | } |
| 228 | 259 | ||
| 229 | /* first, read the AFC header */ | 260 | /* first, read the AFC header */ |
| 230 | service_receive(client->parent, (char*)&header, sizeof(AFCPacket), &recv_len); | 261 | afc_error_t err = service_to_afc_error(service_receive(client->parent, (char*)&header, sizeof(AFCPacket), &recv_len)); |
| 231 | AFCPacket_from_LE(&header); | 262 | if (err != AFC_E_SUCCESS) { |
| 263 | debug_info("Failed to receive AFC header: %s (%d)", afc_strerror(err), err); | ||
| 264 | return err; | ||
| 265 | } | ||
| 232 | if (recv_len == 0) { | 266 | if (recv_len == 0) { |
| 233 | debug_info("Just didn't get enough."); | 267 | debug_info("Just didn't get enough."); |
| 234 | return AFC_E_MUX_ERROR; | 268 | return AFC_E_NOT_ENOUGH_DATA; |
| 235 | } | 269 | } |
| 236 | 270 | ||
| 237 | if (recv_len < sizeof(AFCPacket)) { | 271 | if (recv_len < sizeof(AFCPacket)) { |
| 238 | debug_info("Did not even get the AFCPacket header"); | 272 | debug_info("Did not even get the AFCPacket header"); |
| 239 | return AFC_E_MUX_ERROR; | 273 | return AFC_E_NOT_ENOUGH_DATA; |
| 240 | } | 274 | } |
| 241 | 275 | ||
| 276 | /* make sure endianness is correct */ | ||
| 277 | AFCPacket_from_LE(&header); | ||
| 278 | |||
| 242 | /* check if it's a valid AFC header */ | 279 | /* check if it's a valid AFC header */ |
| 243 | if (strncmp(header.magic, AFC_MAGIC, AFC_MAGIC_LEN) != 0) { | 280 | if (strncmp(header.magic, AFC_MAGIC, AFC_MAGIC_LEN) != 0) { |
| 244 | debug_info("Invalid AFC packet received (magic != " AFC_MAGIC ")!"); | 281 | debug_info("Invalid AFC packet received (magic != " AFC_MAGIC ")!"); |
| 282 | return AFC_E_UNKNOWN_PACKET_TYPE; | ||
| 245 | } | 283 | } |
| 246 | 284 | ||
| 247 | /* check if it has the correct packet number */ | 285 | /* check if it has the correct packet number */ |
| @@ -273,16 +311,20 @@ static afc_error_t afc_receive_data(afc_client_t client, char **bytes, uint32_t | |||
| 273 | buf = (char*)malloc(entire_len); | 311 | buf = (char*)malloc(entire_len); |
| 274 | if (this_len > 0) { | 312 | if (this_len > 0) { |
| 275 | recv_len = 0; | 313 | recv_len = 0; |
| 276 | service_receive(client->parent, buf, this_len, &recv_len); | 314 | err = service_to_afc_error(service_receive(client->parent, buf, this_len, &recv_len)); |
| 315 | if (err != AFC_E_SUCCESS) { | ||
| 316 | free(buf); | ||
| 317 | debug_info("Failed to receive data: %s (%d)", afc_strerror(err), err); | ||
| 318 | } | ||
| 277 | if (recv_len <= 0) { | 319 | if (recv_len <= 0) { |
| 278 | free(buf); | 320 | free(buf); |
| 279 | debug_info("Did not get packet contents!"); | 321 | debug_info("Did not get packet contents!"); |
| 280 | return AFC_E_NOT_ENOUGH_DATA; | 322 | return (err == AFC_E_SUCCESS) ? AFC_E_NOT_ENOUGH_DATA : err; |
| 281 | } | 323 | } |
| 282 | if (recv_len < this_len) { | 324 | if (recv_len < this_len) { |
| 283 | free(buf); | 325 | free(buf); |
| 284 | debug_info("Could not receive this_len=%d bytes", this_len); | 326 | debug_info("Could not receive this_len=%d bytes", this_len); |
| 285 | return AFC_E_NOT_ENOUGH_DATA; | 327 | return (err == AFC_E_SUCCESS) ? AFC_E_END_OF_DATA : err; |
| 286 | } | 328 | } |
| 287 | } | 329 | } |
| 288 | 330 | ||
| @@ -291,7 +333,11 @@ static afc_error_t afc_receive_data(afc_client_t client, char **bytes, uint32_t | |||
| 291 | if (entire_len > this_len) { | 333 | if (entire_len > this_len) { |
| 292 | while (current_count < entire_len) { | 334 | while (current_count < entire_len) { |
| 293 | recv_len = 0; | 335 | recv_len = 0; |
| 294 | service_receive(client->parent, buf+current_count, entire_len - current_count, &recv_len); | 336 | err = service_to_afc_error(service_receive(client->parent, buf+current_count, entire_len - current_count, &recv_len)); |
| 337 | if (err != AFC_E_SUCCESS) { | ||
| 338 | debug_info("Error receiving data: %s (%d)", afc_strerror(err), err); | ||
| 339 | break; | ||
| 340 | } | ||
| 295 | if (recv_len <= 0) { | 341 | if (recv_len <= 0) { |
| 296 | debug_info("Error receiving data (recv returned %d)", recv_len); | 342 | debug_info("Error receiving data (recv returned %d)", recv_len); |
| 297 | break; | 343 | break; |
| @@ -299,7 +345,9 @@ static afc_error_t afc_receive_data(afc_client_t client, char **bytes, uint32_t | |||
| 299 | current_count += recv_len; | 345 | current_count += recv_len; |
| 300 | } | 346 | } |
| 301 | if (current_count < entire_len) { | 347 | if (current_count < entire_len) { |
| 302 | debug_info("WARNING: could not receive full packet (read %s, size %d)", current_count, entire_len); | 348 | free(buf); |
| 349 | debug_info("ERROR: Could not receive entire packet (read %i/%i)", current_count, entire_len); | ||
| 350 | return (err == AFC_E_SUCCESS) ? AFC_E_END_OF_DATA : err; | ||
| 303 | } | 351 | } |
| 304 | } | 352 | } |
| 305 | 353 | ||
| @@ -1299,14 +1347,14 @@ const char* afc_strerror(afc_error_t err) | |||
| 1299 | return "Internal error"; | 1347 | return "Internal error"; |
| 1300 | case AFC_E_MUX_ERROR: | 1348 | case AFC_E_MUX_ERROR: |
| 1301 | return "MUX error"; | 1349 | return "MUX error"; |
| 1350 | case AFC_E_SSL_ERROR: | ||
| 1351 | return "SSL error"; | ||
| 1302 | case AFC_E_NO_MEM: | 1352 | case AFC_E_NO_MEM: |
| 1303 | return "Out of memory"; | 1353 | return "Out of memory"; |
| 1304 | case AFC_E_NOT_ENOUGH_DATA: | 1354 | case AFC_E_NOT_ENOUGH_DATA: |
| 1305 | return "Not enough data"; | 1355 | return "Not enough data"; |
| 1306 | case AFC_E_DIR_NOT_EMPTY: | 1356 | case AFC_E_DIR_NOT_EMPTY: |
| 1307 | return "Directory not empty"; | 1357 | return "Directory not empty"; |
| 1308 | case AFC_E_FORCE_SIGNED_TYPE: | ||
| 1309 | return "Force signed type"; | ||
| 1310 | default: | 1358 | default: |
| 1311 | break; | 1359 | break; |
| 1312 | } | 1360 | } |
