/* Queue: pairing */ static int pairing_request_cb(struct http_connection *c, struct http_request *req, struct http_response *r, void *arg) { struct remote_info *ri; struct evbuffer *body; char guid[17]; const char *reason; uint8_t *response; size_t bodylen; int code; int len; int i; int ret; ri = (struct remote_info *)arg; code = http_response_get_status(r, &reason); if (code != HTTP_OK) { DPRINTF(E_LOG, L_REMOTE, "Pairing failed with Remote %s/%s, HTTP response code %d (%s)\n", ri->pi.remote_id, ri->pi.name, code, reason); goto cleanup; } body = http_response_get_body(r); if (!body || (EVBUFFER_LENGTH(body) < 8)) { DPRINTF(E_LOG, L_REMOTE, "Remote %s/%s: pairing response too short\n", ri->pi.remote_id, ri->pi.name); goto cleanup; } bodylen = EVBUFFER_LENGTH(body); response = EVBUFFER_DATA(body); if ((response[0] != 'c') || (response[1] != 'm') || (response[2] != 'p') || (response[3] != 'a')) { DPRINTF(E_LOG, L_REMOTE, "Remote %s/%s: unknown pairing response, expected cmpa\n", ri->pi.remote_id, ri->pi.name); goto cleanup; } len = (response[4] << 24) | (response[5] << 16) | (response[6] << 8) | (response[7]); if (bodylen < 8 + len) { DPRINTF(E_LOG, L_REMOTE, "Remote %s/%s: pairing response truncated (got %d expected %d)\n", ri->pi.remote_id, ri->pi.name, (int)bodylen, len + 8); goto cleanup; } response += 8; for (; len > 0; len--, response++) { if ((response[0] != 'c') || (response[1] != 'm') || (response[2] != 'p') || (response[3] != 'g')) continue; else { len -= 8; response += 8; break; } } if (len < 8) { DPRINTF(E_LOG, L_REMOTE, "Remote %s/%s: cmpg truncated in pairing response\n", ri->pi.remote_id, ri->pi.name); goto cleanup; } for (i = 0; i < 8; i++) sprintf(guid + (2 * i), "%02X", response[i]); ri->pi.guid = strdup(guid); DPRINTF(E_INFO, L_REMOTE, "Pairing succeeded with Remote '%s' (id %s), GUID: %s\n", ri->pi.name, ri->pi.remote_id, guid); ret = db_pool_get(); if (ret < 0) { DPRINTF(E_LOG, L_REMOTE, "Could not acquire database connection; cannot register pairing with %s\n", ri->pi.name); goto cleanup; } ret = db_pairing_add(&ri->pi); db_pool_release(); if (ret < 0) { DPRINTF(E_LOG, L_REMOTE, "Failed to register pairing!\n"); goto cleanup; } cleanup: http_request_free(req); http_client_free(c); return 0; }
/* Thread: main (pairing) */ static void pairing_request_cb(struct evhttp_request *req, void *arg) { struct remote_info *ri; uint8_t *response; char guid[17]; int len; int i; int ret; ri = (struct remote_info *)arg; if (!req) goto cleanup; if (req->response_code != HTTP_OK) { DPRINTF(E_LOG, L_REMOTE, "Pairing failed with Remote %s/%s, HTTP response code %d\n", ri->pi.remote_id, ri->pi.name, req->response_code); goto cleanup; } if (EVBUFFER_LENGTH(req->input_buffer) < 8) { DPRINTF(E_LOG, L_REMOTE, "Remote %s/%s: pairing response too short\n", ri->pi.remote_id, ri->pi.name); goto cleanup; } response = EVBUFFER_DATA(req->input_buffer); if ((response[0] != 'c') || (response[1] != 'm') || (response[2] != 'p') || (response[3] != 'a')) { DPRINTF(E_LOG, L_REMOTE, "Remote %s/%s: unknown pairing response, expected cmpa\n", ri->pi.remote_id, ri->pi.name); goto cleanup; } len = (response[4] << 24) | (response[5] << 16) | (response[6] << 8) | (response[7]); if (EVBUFFER_LENGTH(req->input_buffer) < 8 + len) { DPRINTF(E_LOG, L_REMOTE, "Remote %s/%s: pairing response truncated (got %d expected %d)\n", ri->pi.remote_id, ri->pi.name, (int)EVBUFFER_LENGTH(req->input_buffer), len + 8); goto cleanup; } response += 8; for (; len > 0; len--, response++) { if ((response[0] != 'c') || (response[1] != 'm') || (response[2] != 'p') || (response[3] != 'g')) continue; else { len -= 8; response += 8; break; } } if (len < 8) { DPRINTF(E_LOG, L_REMOTE, "Remote %s/%s: cmpg truncated in pairing response\n", ri->pi.remote_id, ri->pi.name); goto cleanup; } for (i = 0; i < 8; i++) sprintf(guid + (2 * i), "%02X", response[i]); ri->pi.guid = strdup(guid); DPRINTF(E_INFO, L_REMOTE, "Pairing succeeded with Remote '%s' (id %s), GUID: %s\n", ri->pi.name, ri->pi.remote_id, guid); ret = db_pairing_add(&ri->pi); if (ret < 0) { DPRINTF(E_LOG, L_REMOTE, "Failed to register pairing!\n"); goto cleanup; } cleanup: evhttp_connection_free(ri->evcon); free_remote(ri); }