Пример #1
0
/*
 * High-level handling of logout requests
 * FIXME: Do we need to send some kind of "goodbye" packet first?
 *
 * FIXME: The official library attempts to finish up things for a few
 *        seconds before forcing a logout.
 *        An example is when playlists are modified. They're modified 
 *        on the local side immediately but syncing the changes to the
 *        server might take additional time.
 */
static int process_logout_request(sp_session *session, struct request *req) {

	/* FIXME: We should probably cancel all requests in flight aswell */

	/* If a login is still in process, cancel it here */
        if(session->login) {
		/*
		 * We ought to cancel a pending login request here.
		 * Instead we rely on process_login_request() to detect
		 * that session->login became NULL
		 *
		 */
                login_release(session->login);
                session->login = NULL;
        }

	/* Get rid of our identity */
        if(session->user) {
                user_release(session->user);
                session->user = NULL;
        }

	memset(session->country, 0, sizeof(session->country));


	if(session->sock != -1) {
#ifdef _WIN32
		closesocket(session->sock);
#else
		close(session->sock);
#endif
		session->sock = -1;
	}

	session->connectionstate = SP_CONNECTION_STATE_LOGGED_OUT;

	/* Unregister all channels */
	channel_fail_and_unregister_all(session);

	return request_set_result(session, req, SP_ERROR_OK, NULL);
}
Пример #2
0
/*
 * High-level handling of login requests
 * Uses login specific routines from login.c
 *
 */
static int process_login_request(sp_session *s, struct request *req) {
	int ret;
	sp_error error;
	unsigned char key_recv[32], key_send[32];

	if(req->state == REQ_STATE_NEW) {
		req->state = REQ_STATE_RUNNING;

		s->login = login_create(s->username, s->password);
		if(s->login == NULL)
			return request_set_result(s, req, SP_ERROR_OTHER_TRANSIENT, NULL);
	}

	/*
	 * A call to sp_session_logout() will post a REQ_TYPE_LOGOUT
	 * It will trigger a call to process_logout_request() which in turn
	 * will call login_release() on s->login and set it to NULL.
	 * 
	 * We check for this condition here and return SP_ERROR_OTHER_TRANSIENT
	 *
	 */
	if(s->login == NULL) {
		/* Fail login with SP_ERROR_OTHER_TRANSIENT */
		return request_set_result(s, req, SP_ERROR_OTHER_TRANSIENT, NULL);
	}

	ret = login_process(s->login);
	if(ret == 0)
		return 0;
	else if(ret == 1) {
		login_export_session(s->login, &s->sock, key_recv, key_send);
		login_release(s->login);
		s->login = NULL;

		shn_key(&s->shn_recv, key_recv, sizeof(key_recv));
		s->key_recv_IV = 0;

		shn_key(&s->shn_send, key_send, sizeof(key_send));
		s->key_send_IV = 0;

		s->connectionstate = SP_CONNECTION_STATE_LOGGED_IN;

		DSFYDEBUG("Logged in\n");
		return request_set_result(s, req, SP_ERROR_OK, NULL);
	}

	switch(s->login->error) {
	case SP_LOGIN_ERROR_DNS_FAILURE:
	case SP_LOGIN_ERROR_NO_MORE_SERVERS:
		error = SP_ERROR_UNABLE_TO_CONTACT_SERVER;
		break;

	case SP_LOGIN_ERROR_UPGRADE_REQUIRED:
		error = SP_ERROR_CLIENT_TOO_OLD;
		break;

	case SP_LOGIN_ERROR_USER_BANNED:
		error = SP_ERROR_USER_BANNED;
		break;

	case SP_LOGIN_ERROR_USER_NOT_FOUND:
	case SP_LOGIN_ERROR_BAD_PASSWORD:
		error = SP_ERROR_BAD_USERNAME_OR_PASSWORD;
		break;

	case SP_LOGIN_ERROR_USER_NEED_TO_COMPLETE_DETAILS:
	case SP_LOGIN_ERROR_USER_COUNTRY_MISMATCH:
	case SP_LOGIN_ERROR_OTHER_PERMANENT:
		error = SP_ERROR_OTHER_PERMANENT;
		break;

	case SP_LOGIN_ERROR_SOCKET_ERROR:
	default:
		error = SP_ERROR_OTHER_TRANSIENT;
		break;
	}

	login_release(s->login);
	s->login = NULL;

	DSFYDEBUG("Login failed with error: %s\n", sp_error_message(error));
	return request_set_result(s, req, error, NULL);
}
Пример #3
0
/*
 * Not present in the official library
 * XXX - Might not be thread safe?
 *
 */
SP_LIBEXPORT(sp_error) sp_session_release (sp_session *session) {

	/* Unregister channels */
	DSFYDEBUG("Unregistering any active channels\n");
	channel_fail_and_unregister_all(session);

	/* Kill player thread */
	player_free(session);

	/* Kill networking thread */
	DSFYDEBUG("Terminating network thread\n");
#ifdef _WIN32
	TerminateThread(session->thread_io, 0);
	session->thread_io = (HANDLE)0;
	CloseHandle(session->idle_wakeup);
	CloseHandle(session->request_mutex);
#else

	pthread_cancel(session->thread_io);
	pthread_join(session->thread_io, NULL);
	session->thread_io = (pthread_t)0;
	pthread_mutex_destroy(&session->request_mutex);
	pthread_cond_destroy(&session->idle_wakeup);
#endif

	if(session->packet)
		buf_free(session->packet);

	if(session->login)
		login_release(session->login);

	playlistcontainer_release(session);

	if(session->hashtable_albums)
		hashtable_free(session->hashtable_albums);

	if(session->hashtable_artists)
		hashtable_free(session->hashtable_artists);

	if(session->hashtable_images)
		hashtable_free(session->hashtable_images);
	
	if(session->hashtable_tracks)
		hashtable_free(session->hashtable_tracks);

	if(session->user)
		user_release(session->user);
	
	if(session->hashtable_users)
		hashtable_free(session->hashtable_users);
	
	free(session->callbacks);

	/* Helper function for sp_link_create_from_string() */
	libopenspotify_link_release();

	free(session);

	DSFYDEBUG("Session released\n");

	return SP_ERROR_OK;
}