Esempio n. 1
0
/*
 * Route request handling to the appropriate handlers
 *
 */
static int process_request(sp_session *session, struct request *req) {
	int now = get_millisecs();

	if(session->connectionstate != SP_CONNECTION_STATE_LOGGED_IN
		&& (req->type != REQ_TYPE_LOGIN && req->type != REQ_TYPE_LOGOUT)) {
		if(req->state == REQ_STATE_NEW) {
			DSFYDEBUG("Postponing request <type %s, state %s, input %p> 10 seconds due to not logged in\n",
					REQUEST_TYPE_STR(req->type), REQUEST_STATE_STR(req->state), req->input);
			req->next_timeout = now + 10*1000;

			return 0;
		}
		else if(req->state == REQ_STATE_RUNNING) {
			DSFYDEBUG("Failing request <type %s, state %s, input %p> due to not logged in\n",
					REQUEST_TYPE_STR(req->type), REQUEST_STATE_STR(req->state), req->input);
			return request_set_result(session, req, SP_ERROR_OTHER_TRANSIENT, NULL);
		}
	}
	else if(req->state == REQ_STATE_NEW && session->num_channels >= 16) {
		DSFYDEBUG("%d channels active, postponing request <type %s, state %s, input %p>\n",
			  session->num_channels, REQUEST_TYPE_STR(req->type),
			  REQUEST_STATE_STR(req->state), req->input);

		if(req->next_timeout < now + 100)
			req->next_timeout = now + 100;
		
		return 0;
	}

	
	switch(req->type) {
	case REQ_TYPE_LOGIN:
		return process_login_request(session, req);
		break;

	case REQ_TYPE_LOGOUT:
		return process_logout_request(session, req);
		break;
	
	case REQ_TYPE_PC_LOAD:
	case REQ_TYPE_PLAYLIST_LOAD:
	case REQ_TYPE_PLAYLIST_CHANGE:
		return playlist_process(session, req);
		break;
	
	case REQ_TYPE_TOPLISTBROWSE:
		return toplistbrowse_process_request(session, req);
		break;

	case REQ_TYPE_SEARCH:
		return search_process_request(session, req);
		break;

	case REQ_TYPE_USER:
		return user_process_request(session, req);
		break;

	case REQ_TYPE_IMAGE:
		return osfy_image_process_request(session, req);
		break;

	case REQ_TYPE_ALBUMBROWSE:
	case REQ_TYPE_ARTISTBROWSE:
	case REQ_TYPE_BROWSE_ALBUM:
	case REQ_TYPE_BROWSE_ARTIST:
	case REQ_TYPE_BROWSE_PLAYLIST_TRACKS:
	case REQ_TYPE_BROWSE_TRACK:
		return browse_process(session, req);
		break;

	case REQ_TYPE_PLAYER_KEY:
	case REQ_TYPE_PLAYER_SUBSTREAM:
	case REQ_TYPE_PLAY_TOKEN_ACQUIRE:
	case REQ_TYPE_PLAY_TOKEN_LOST:
		return player_process_request(session, req);
		break;

	case REQ_TYPE_CACHE_PERIODIC:
		return cache_process(session, req);
		break;

	default:
		DSFYDEBUG("BUG: Unhandled request type '%s'\n", REQUEST_TYPE_STR(req->type));
		break;
	}

	return 0;
}
Esempio n. 2
0
DWORD WINAPI iothread(LPVOID data) {
#else
void *iothread(void *data) {
#endif
	sp_session *s = (sp_session *)data;
	struct request *req;
	int ret;
	int now;

#ifdef _WIN32
	/* Initialize Winsock */
	WSADATA wsadata;
	WSAStartup(MAKEWORD(2,2), &wsadata);
#endif

	for(;;) {
		request_cleanup(s);

		/* No locking needed since we're in control of request_cleanup() */
		now = get_millisecs();
		for(req = s->requests; req; req = req->next) {
			if(req->state != REQ_STATE_NEW && req->state != REQ_STATE_RUNNING)
				continue;

			if(req->next_timeout > now)
				continue;

			DSFYDEBUG("Processing request <type %s, state %s, input %p, timeout %d>\n",
					REQUEST_TYPE_STR(req->type), REQUEST_STATE_STR(req->state),
					req->input, req->next_timeout);
			ret = process_request(s, req);
			DSFYDEBUG("Request processing returned %d\n", ret);

			/* FIXME: Drop connection on errors! */
			if(ret != 0) {
				DSFYDEBUG("Request failed, good bye\n");
#ifdef _WIN32
#else
				exit(1);
#endif
			}
		}


		/* Packets can only be processed once we're logged in */
		if(s->connectionstate != SP_CONNECTION_STATE_LOGGED_IN) {
#ifdef _WIN32
			WaitForSingleObject(s->request_mutex, INFINITE);
#else
			pthread_mutex_lock(&s->request_mutex);
#endif
			if(s->requests == NULL) {
				DSFYDEBUG("Sleeping because there's nothing to do\n");
#ifdef _WIN32
				ReleaseMutex(s->request_mutex);
				WaitForSingleObject(s->idle_wakeup, INFINITE);
				WaitForSingleObject(s->request_mutex, INFINITE);
#else
				pthread_cond_wait(&s->idle_wakeup, &s->request_mutex);
#endif
				DSFYDEBUG("Woke up, a new request was posted\n");
			}
#ifdef _WIN32
			ReleaseMutex(s->request_mutex);
#else
			pthread_mutex_unlock(&s->request_mutex);
#endif

			continue;
		}


		/*
		 * Read and process zero or more packets
		 * Will sleep somewhere around 64ms if no
		 * data is available
		 */
		ret = packet_read_and_process(s);
		if(ret < 0) {
			DSFYDEBUG("process_packets() returned %d, disconnecting!\n", ret);
#ifdef _WIN32
			closesocket(s->sock);
#else
			close(s->sock);
#endif
			s->sock = -1;

			s->connectionstate = SP_CONNECTION_STATE_DISCONNECTED;

			request_post_result(s, REQ_TYPE_LOGOUT, SP_ERROR_OTHER_TRANSIENT, NULL);
		}
	}


}
Esempio n. 3
0
SP_LIBEXPORT(void) sp_session_process_events(sp_session *session, int *next_timeout) {
	struct request *request;
	sp_albumbrowse *alb;
	sp_artistbrowse *arb;
	sp_toplistbrowse *toplistbrowse;
	sp_search *search;
	sp_image *image;
	sp_playlist *playlist;
	sp_playlistcontainer *pc;
	int i, value;

	while((request = request_fetch_next_result(session, next_timeout)) != NULL) {
		DSFYDEBUG("Event processing for request <type %s, state %s, input %p, timeout %d>"
				" with output <error %d, output %p>\n",
				REQUEST_TYPE_STR(request->type),
				REQUEST_STATE_STR(request->state),
				request->input, request->next_timeout,
				request->error, request->output);


		/* FIXME: Verify that these callbacks are indeed called from the main thread! */
		switch(request->type) {
		case REQ_TYPE_LOGIN:
			if(session->callbacks->logged_in == NULL)
				break;

			session->callbacks->logged_in(session, request->error);
			break;
			
		case REQ_TYPE_LOGOUT:
			if(session->callbacks->logged_out == NULL)
				break;

			session->callbacks->logged_out(session);
			break;

		case REQ_TYPE_PLAY_TOKEN_LOST:
			if(session->callbacks->play_token_lost == NULL)
				break;

			session->callbacks->play_token_lost(session);
			break;

		case REQ_TYPE_NOTIFY:
			if(session->callbacks->message_to_user == NULL)
				break;

			/* We'll leak memory here for each login made :( */
			session->callbacks->message_to_user(session, request->output);
			break;
				
		case REQ_TYPE_PC_LOAD:
			pc = session->playlistcontainer;
			for(i = 0; i < pc->num_callbacks; i++)
				if(pc->callbacks[i]->container_loaded)
					pc->callbacks[i]->container_loaded(pc, pc->userdata[i]);
			break;

		case REQ_TYPE_PC_PLAYLIST_ADD:
			value = *(int *)request->output; /* position */
			pc = session->playlistcontainer;
			playlist = pc->playlists[value];
			for(i = 0; i < pc->num_callbacks; i++)
				if(pc->callbacks[i]->playlist_added)
					pc->callbacks[i]->playlist_added(pc, playlist, value, pc->userdata[i]);

			break;
				
		case REQ_TYPE_PLAYLIST_RENAME:
			pc = session->playlistcontainer;
			playlist = (sp_playlist *)request->output;
			for(i = 0; i < playlist->num_callbacks; i++)
				if(playlist->callbacks[i]->playlist_renamed)
					playlist->callbacks[i]->playlist_renamed(playlist, playlist->userdata[i]);
			
			break;

		case REQ_TYPE_PLAYLIST_STATE_CHANGED:
			pc = session->playlistcontainer;
			playlist = NULL;
			for(i = 0; i < pc->num_playlists; i++) {
				if(memcmp(pc->playlists[i]->id, request->output, 17))
					continue;
				playlist = pc->playlists[i];
				break;
			}

			if(!playlist)
				break;

			for(i = 0; i < playlist->num_callbacks; i++)
				if(playlist->callbacks[i]->playlist_state_changed)
					playlist->callbacks[i]->playlist_state_changed(playlist, playlist->userdata[i]);
			break;
				
		case REQ_TYPE_PLAYLIST_LOAD:
			pc = session->playlistcontainer;
			playlist = (sp_playlist *)request->output;
			for(i = 0; i < playlist->num_callbacks; i++)
				if(playlist->callbacks[i]->tracks_added)
					playlist->callbacks[i]->tracks_added(playlist, (sp_track *const *)playlist->tracks, playlist->num_tracks, 0, playlist->userdata[i]);
			
			break;
				
		case REQ_TYPE_ALBUMBROWSE:
			alb = (sp_albumbrowse *)request->output;
			if(alb->callback)
				alb->callback(alb, alb->userdata);

			break;

		case REQ_TYPE_ARTISTBROWSE:
	                arb = (sp_artistbrowse *)request->output;
	                if(arb->callback)
	                        arb->callback(arb, arb->userdata);

			break;

		case REQ_TYPE_BROWSE_ALBUM:
		case REQ_TYPE_BROWSE_ARTIST:
		case REQ_TYPE_BROWSE_TRACK:
		case REQ_TYPE_BROWSE_PLAYLIST_TRACKS:
			DSFYDEBUG("Metadata updated for request <type %s, state %s, input %p> in main thread\n",
				  REQUEST_TYPE_STR(request->type), REQUEST_STATE_STR(request->type), request->input);
				
			if(session->callbacks->metadata_updated != NULL)
				session->callbacks->metadata_updated(session);
			break;

		case REQ_TYPE_TOPLISTBROWSE:
	                toplistbrowse = (sp_toplistbrowse *)request->output;
	                if(toplistbrowse->callback)
	                        toplistbrowse->callback(toplistbrowse, toplistbrowse->userdata);

			break;

		case REQ_TYPE_SEARCH:
	                search = (sp_search *)request->output;
	                if(search->callback)
	                        search->callback(search, search->userdata);

			break;

		case REQ_TYPE_IMAGE:
			image = (sp_image *)request->output;
			if(image->callback)
				image->callback(image, image->userdata);
			break;

		default:
			break;
		}


		/* Now that we've delievered the result, mark it for deletion */
		request_mark_processed(session, request);
	}

}