commit 9a8104302de5e95a8e74a79ce3df48fbd98e7167
Author: Hector Martin <[email protected]>
Date: Tue Oct 20 19:16:07 2009 +0200
Fix sync notifications
Correctly handles sync locking, quits iPod app at sync start, and has
saner error handling.
Note: the repeated sync retries are required. The iPod app will fade-out
and take over 4 seconds if sync starts while music is playing. The
current timeout is 50*200ms = 10 seconds, which should be reasonable.
src/itdb_iphone.c | 212 +++++++++++++++++++++++++++++-----------------------
1 files changed, 118 insertions(+), 94 deletions(-)
---
diff --git a/src/itdb_iphone.c b/src/itdb_iphone.c
index 4f2cea2..fc8aebe 100644
--- a/src/itdb_iphone.c
+++ b/src/itdb_iphone.c
@@ -21,6 +21,7 @@
#include <itdb_private.h>
#include <errno.h>
#include <stdio.h>
+#include <unistd.h>
#ifdef HAVE_LIBIPHONE
#include <libiphone/libiphone.h>
#include <libiphone/lockdown.h>
@@ -34,17 +35,50 @@ struct itdbprep_int {
};
typedef struct itdbprep_int *itdbprep_t;
+#define LOCK_ATTEMPTS 50
+#define LOCK_WAIT 200000
+
+
+/* libiphone should probably be reworked so we don't have to reopen a
connection
+ to notification_proxy for every notification... */
+static int itdb_iphone_post_notification(iphone_device_t device,
+ lockdownd_client_t client,
+ const char *notification)
+{
+ np_client_t np = NULL;
+ int nport = 0;
+
+ lockdownd_start_service(client, "com.apple.mobile.notification_proxy",
&nport);
+ if (!nport) {
+ fprintf(stderr, "notification_proxy could not be started!\n");
+ return -1;
+ }
+
+ np_client_new(device, nport, &np);
+ if(!np) {
+ fprintf(stderr, "connection to notification_proxy failed!\n");
+ return -1;
+ }
+
+ if(np_post_notification(np, notification)) {
+ fprintf(stderr, "failed to post notification!\n");
+ np_client_free(np);
+ return -1;
+ }
+
+ np_client_free(np);
+ return 0;
+}
+
int itdb_iphone_start_sync(Itdb_Device *device, void **prepdata)
{
int res = 0;
- int sync_started = 0;
+ int sync_starting = 0;
itdbprep_t pdata_loc = NULL;
const char *uuid;
lockdownd_client_t client = NULL;
int afcport = 0;
- np_client_t np = NULL;
- int nport = 0;
-
+ int i;
uuid = itdb_device_get_uuid (device);
@@ -83,49 +117,15 @@ int itdb_iphone_start_sync(Itdb_Device *device, void
**prepdata)
goto leave_with_err;
}
- /* before we try to launch the 'sync in progress...' screen, we'll try
- * if the lockfile is lockable. If not, abort.
- */
- afc_file_open(pdata_loc->afc, "/com.apple.itunes.lock_sync", AFC_FOPEN_RW,
&pdata_loc->lockfile);
-
- if (!pdata_loc->lockfile) {
- fprintf(stderr, "could not open lockfile in first place\n");
+ if (itdb_iphone_post_notification(pdata_loc->device, client,
NP_SYNC_WILL_START)) {
+ fprintf(stderr, "could not post syncWillStart notification!\n");
res = -1;
goto leave_with_err;
}
+ printf("%s: posted syncWillStart\n", __func__);
+ sync_starting = 1;
- if (afc_file_lock(pdata_loc->afc, pdata_loc->lockfile, AFC_LOCK_EX) !=
IPHONE_E_SUCCESS) {
- fprintf(stderr, "ERROR: could not lock file in first place!\n");
- afc_file_close(pdata_loc->afc, pdata_loc->lockfile);
- pdata_loc->lockfile = 0;
- goto leave_with_err;
- }
-
- if (afc_file_lock(pdata_loc->afc, pdata_loc->lockfile, AFC_LOCK_UN) !=
IPHONE_E_SUCCESS) {
- fprintf(stderr, "ERROR: could not unlock file in first place!\n");
- }
- afc_file_close(pdata_loc->afc, pdata_loc->lockfile);
- pdata_loc->lockfile = 0;
-
- lockdownd_start_service(client, "com.apple.mobile.notification_proxy",
&nport);
- if (nport) {
- np_client_new(pdata_loc->device, nport, &np);
- if (np) {
- np_post_notification(np, NP_SYNC_WILL_START);
- sync_started = 1;
- }
- }
- if (!nport || !np) {
- fprintf(stderr, "notification_proxy could not be started!\n");
- res = -1;
- goto leave_with_err;
- }
- np_client_free(np);
-
- nport = 0;
- np = NULL;
-
- /* OPEN AND LOCK /com.apple.itunes.lock_sync */
+ /* OPEN AND LOCK /com.apple.itunes.lock_sync */
afc_file_open(pdata_loc->afc, "/com.apple.itunes.lock_sync", AFC_FOPEN_RW,
&pdata_loc->lockfile);
if (!pdata_loc->lockfile) {
@@ -134,29 +134,39 @@ int itdb_iphone_start_sync(Itdb_Device *device, void
**prepdata)
goto leave_with_err;
}
- if (afc_file_lock(pdata_loc->afc, pdata_loc->lockfile, AFC_LOCK_EX) !=
IPHONE_E_SUCCESS) {
- fprintf(stderr, "ERROR: could not lock file!\n");
- afc_file_close(pdata_loc->afc, pdata_loc->lockfile);
- pdata_loc->lockfile = 0;
+ if (itdb_iphone_post_notification(pdata_loc->device, client,
"com.apple.itunes-mobdev.syncLockRequest")) {
+ fprintf(stderr, "could not post syncLockRequest\n");
+ res = -1;
goto leave_with_err;
}
-
- lockdownd_start_service(client, "com.apple.mobile.notification_proxy",
&nport);
- if (nport) {
- np_client_new(pdata_loc->device, nport, &np);
- if (np) {
- np_post_notification(np, NP_SYNC_DID_START);
+ printf("%s: posted syncLockRequest\n", __func__);
+
+ for (i=0; i<LOCK_ATTEMPTS; i++) {
+ fprintf(stderr, "Locking for sync, attempt %d...\n", i);
+ res = afc_file_lock(pdata_loc->afc, pdata_loc->lockfile, AFC_LOCK_EX);
+ if (res == AFC_E_SUCCESS) {
+ break;
+ } else if (res == AFC_E_OP_WOULD_BLOCK) {
+ usleep(LOCK_WAIT);
+ continue;
+ } else {
+ fprintf(stderr, "ERROR: could not lock file! error code: %d\n",
res);
+ res = -1;
+ goto leave_with_err;
}
}
- if (!nport || !np) {
- fprintf(stderr, "notification_proxy could not be started!\n");
+ if (i == LOCK_ATTEMPTS) {
+ fprintf(stderr, "ERROR: timeout while locking for sync\n");
res = -1;
- afc_file_lock(pdata_loc->afc, pdata_loc->lockfile, AFC_LOCK_UN);
- afc_file_close(pdata_loc->afc, pdata_loc->lockfile);
- pdata_loc->lockfile = 0;
goto leave_with_err;
}
- np_client_free(np);
+
+ if (itdb_iphone_post_notification(pdata_loc->device, client,
NP_SYNC_DID_START)) {
+ fprintf(stderr, "could not post syncDidStart\n");
+ res = -1;
+ goto leave_with_err;
+ }
+ printf("%s: posted syncDidStart\n", __func__);
lockdownd_client_free(client);
client = NULL;
@@ -166,41 +176,44 @@ int itdb_iphone_start_sync(Itdb_Device *device, void
**prepdata)
return 0;
leave_with_err:
- if (client && sync_started) {
- nport = 0;
- np = NULL;
- lockdownd_start_service(client, "com.apple.mobile.notification_proxy",
&nport);
- if (nport) {
- np_client_new(pdata_loc->device, nport, &np);
- if (np) {
- np_post_notification(np, NP_SYNC_DID_FINISH);
- }
- }
- if (!nport || !np) {
- fprintf(stderr, "notification_proxy could not be started!\n");
- res = -1;
- }
- np_client_free(np);
-
- lockdownd_client_free(client);
+ if (client && sync_starting) {
+ itdb_iphone_post_notification(pdata_loc->device, client,
"com.apple.itunes-mobdev.syncFailedToStart");
+ printf("%s: posted syncFailedToStart\n", __func__);
}
+
if (pdata_loc) {
if (pdata_loc->afc) {
+ if (pdata_loc->lockfile) {
+ afc_file_lock(pdata_loc->afc, pdata_loc->lockfile, AFC_LOCK_UN);
+ afc_file_close(pdata_loc->afc, pdata_loc->lockfile);
+ pdata_loc->lockfile = 0;
+ }
afc_client_free(pdata_loc->afc);
+ pdata_loc->afc = NULL;
}
if (pdata_loc->device) {
iphone_device_free(pdata_loc->device);
+ pdata_loc->device = NULL;
}
g_free(pdata_loc);
+ pdata_loc = NULL;
+ }
+
+ if (client) {
+ lockdownd_client_free(client);
+ client = NULL;
}
+ *prepdata = NULL;
+
return res;
}
int itdb_iphone_stop_sync(void *sync_ctx)
{
-
+ lockdownd_client_t client = NULL;
itdbprep_t prepdata = sync_ctx;
+
printf("libitdbprep: %s called\n", __func__);
if (!prepdata) {
@@ -210,33 +223,44 @@ int itdb_iphone_stop_sync(void *sync_ctx)
if (!prepdata->afc) {
printf("%s called but prepdata->afc is NULL!\n", __func__);
+ } else {
+ /* remove .status-com.apple.itdbprep.command.runPostProcess */
+ if (afc_remove_path(prepdata->afc, "/iTunes_Control/iTunes/iTunes
Library.itlp/DBTemp/.status-com.apple.itdprep.command.runPostProcess") !=
IPHONE_E_SUCCESS) {
+ fprintf(stderr, "Could not delete
'.status-com.apple.itdprep.command.runPostProcess'\n");
+ }
+ /* remove ddd.itdbm */
+ if (afc_remove_path(prepdata->afc, "/iTunes_Control/iTunes/iTunes
Library.itlp/DBTemp/ddd.itdbm") != IPHONE_E_SUCCESS) {
+ fprintf(stderr, "Could not delete 'ddd.itdbm'\n");
+ }
+ if (prepdata->lockfile) {
+ afc_file_lock(prepdata->afc, prepdata->lockfile, AFC_LOCK_UN);
+ afc_file_close(prepdata->afc, prepdata->lockfile);
+ prepdata->lockfile = 0;
+ } else {
+ printf("%s called but lockfile is 0\n", __func__);
+ }
+ afc_client_free(prepdata->afc);
+ prepdata->afc = NULL;
}
- /* remove .status-com.apple.itdbprep.command.runPostProcess */
- if (afc_remove_path(prepdata->afc, "/iTunes_Control/iTunes/iTunes
Library.itlp/DBTemp/.status-com.apple.itdprep.command.runPostProcess") !=
IPHONE_E_SUCCESS) {
- fprintf(stderr, "Could not delete
'.status-com.apple.itdprep.command.runPostProcess'\n");
- }
- /* remove ddd.itdbm */
- if (afc_remove_path(prepdata->afc, "/iTunes_Control/iTunes/iTunes
Library.itlp/DBTemp/ddd.itdbm") != IPHONE_E_SUCCESS) {
- fprintf(stderr, "Could not delete 'ddd.itdbm'\n");
+ if (LOCKDOWN_E_SUCCESS != lockdownd_client_new(prepdata->device, &client))
{
+ fprintf(stderr, "Error: Could not establish lockdownd connection!\n");
+ goto leave;
}
- if (prepdata->lockfile) {
- afc_file_lock(prepdata->afc, prepdata->lockfile, AFC_LOCK_UN);
- afc_file_close(prepdata->afc, prepdata->lockfile);
- prepdata->lockfile = 0;
- } else {
- printf("%s called but lockfile is 0\n", __func__);
- }
- if (prepdata->afc) {
- afc_client_free(prepdata->afc);
- prepdata->afc = NULL;
+ if(itdb_iphone_post_notification(prepdata->device, client,
NP_SYNC_DID_FINISH)) {
+ fprintf(stderr, "failed to post syncDidFinish\n");
}
+ printf("%s: posted syncDidFinish\n", __func__);
+ lockdownd_client_free(client);
+
+leave:
iphone_device_free(prepdata->device);
g_free(prepdata);
return 0;
+
}
#endif
------------------------------------------------------------------------------
Return on Information:
Google Enterprise Search pays you back
Get the facts.
http://p.sf.net/sfu/google-dev2dev
_______________________________________________
gtkpod-cvs2 mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/gtkpod-cvs2