diff --git a/cheevos.c b/cheevos.c index 72de7d4037..60433ecf52 100644 --- a/cheevos.c +++ b/cheevos.c @@ -1130,76 +1130,6 @@ void cheevos_unload( void ) Load achievements from retroachievements.org. *****************************************************************************/ -static const char* cheevos_http_get( const char* url, size_t* size ) -{ - struct http_connection_t* conn; - struct http_t* http; - uint8_t* data; - size_t length; - char* result; - - RARCH_LOG( "CHEEVOS http get %s\n", url ); - conn = net_http_connection_new( url ); - - if ( !conn ) - { - return NULL; - } - - while ( !net_http_connection_iterate( conn ) ) - { - /* nothing */ - } - - if ( !net_http_connection_done( conn ) ) - { -error1: - net_http_connection_free( conn ); - return NULL; - } - - http = net_http_new( conn ); - - if ( !http ) - { - goto error1; - } - - while ( !net_http_update( http, NULL, NULL ) ) - { - /* nothing */ - } - - data = net_http_data( http, &length, false ); - - if ( data ) - { - result = (char*)malloc( length + 1 ); - - if ( result ) - { - memcpy( (void*)result, (void*)data, length ); - result[ length ] = 0; - } - } - else - { - result = NULL; - } - - net_http_delete( http ); - net_http_connection_free( conn ); - - RARCH_LOG( "CHEEVOS http result is %s\n", result ); - - if ( size ) - { - *size = length; - } - - return (char*)result; -} - typedef struct { unsigned key_hash; @@ -1294,7 +1224,7 @@ static int cheevos_get_value( const char* json, unsigned key_hash, char* value, return -1; } -static int cheevos_login( void ) +static int cheevos_login( retro_time_t* timeout ) { char request[ 256 ]; const char* json; @@ -1309,9 +1239,8 @@ static int cheevos_login( void ) ); request[ sizeof( request ) - 1 ] = 0; - json = cheevos_http_get( request, NULL ); - if ( json ) + if ( !net_http_get( &json, NULL, request, timeout ) ) { res = cheevos_get_value( json, 0x0e2dbd26U /* Token */, token, sizeof( token ) ); free( (void*)json ); @@ -1329,7 +1258,7 @@ static int cheevos_login( void ) return -1; } -int cheevos_get_by_game_id( const char** json, unsigned game_id ) +static int cheevos_get_by_game_id( const char** json, unsigned game_id, retro_time_t* timeout ) { char request[ 256 ]; @@ -1339,7 +1268,7 @@ int cheevos_get_by_game_id( const char** json, unsigned game_id ) return 0; } - if ( !cheevos_login() ) + if ( !cheevos_login( timeout ) ) { snprintf( request, sizeof( request ), @@ -1348,9 +1277,8 @@ int cheevos_get_by_game_id( const char** json, unsigned game_id ) ); request[ sizeof( request ) - 1 ] = 0; - *json = cheevos_http_get( request, NULL ); - if ( *json ) + if ( !net_http_get( json, NULL, request, timeout ) ) { RARCH_LOG( "CHEEVOS got achievements for game id %u\n", game_id ); return 0; @@ -1362,7 +1290,7 @@ int cheevos_get_by_game_id( const char** json, unsigned game_id ) return -1; } -static unsigned cheevos_get_game_id( unsigned char* hash ) +static unsigned cheevos_get_game_id( unsigned char* hash, retro_time_t* timeout ) { char request[ 256 ]; const char* json; @@ -1380,9 +1308,8 @@ static unsigned cheevos_get_game_id( unsigned char* hash ) ); request[ sizeof( request ) - 1 ] = 0; - json = cheevos_http_get( request, NULL ); - if ( json ) + if ( !net_http_get( &json, NULL, request, timeout ) ) { res = cheevos_get_value( json, 0xb4960eecU /* GameID */, game_id, sizeof( game_id ) ); free( (void*)json ); @@ -1403,6 +1330,7 @@ static unsigned cheevos_get_game_id( unsigned char* hash ) int cheevos_get_by_content( const char** json, const void* data, size_t size ) { MD5_CTX ctx, saved_ctx; + retro_time_t timeout; char buffer[ 4096 ]; size_t len; unsigned char hash[ 16 ]; @@ -1421,7 +1349,8 @@ int cheevos_get_by_content( const char** json, const void* data, size_t size ) saved_ctx = ctx; MD5_Final( hash, &ctx ); - game_id = cheevos_get_game_id( hash ); + timeout = 15000000; + game_id = cheevos_get_game_id( hash, &timeout ); if ( !game_id && size < CHEEVOS_EIGHT_MB ) { @@ -1445,8 +1374,8 @@ int cheevos_get_by_content( const char** json, const void* data, size_t size ) MD5_Final( hash, &saved_ctx ); - game_id = cheevos_get_game_id( hash ); + game_id = cheevos_get_game_id( hash, &timeout ); } - return game_id ? cheevos_get_by_game_id( json, game_id ) : -1; + return game_id ? cheevos_get_by_game_id( json, game_id, &timeout ) : -1; } diff --git a/cheevos.h b/cheevos.h index 6633da316f..321d0545a7 100644 --- a/cheevos.h +++ b/cheevos.h @@ -17,13 +17,11 @@ #ifndef __RARCH_CHEEVOS_H #define __RARCH_CHEEVOS_H -int cheevos_load(const char* json); +int cheevos_load( const char *json ); -void cheevos_test(void); +void cheevos_test( void ); -void cheevos_unload(void); - -int cheevos_get_by_game_id( const char **json, unsigned game_id ); +void cheevos_unload( void ); int cheevos_get_by_content( const char **json, const void *data, size_t size ); diff --git a/libretro-common/include/net/net_http.h b/libretro-common/include/net/net_http.h index b6b6b3a1e2..44f976f0bd 100644 --- a/libretro-common/include/net/net_http.h +++ b/libretro-common/include/net/net_http.h @@ -21,6 +21,8 @@ #include #include +#include + #ifdef __cplusplus extern "C" { #endif @@ -58,6 +60,9 @@ uint8_t* net_http_data(struct http_t *state, size_t* len, bool accept_error); /* Cleans up all memory. */ void net_http_delete(struct http_t *state); +/* Does a HTTP GET and returns whatever the server sends back. */ +int net_http_get(const char **result, size_t *size, const char *url, retro_time_t *timeout); + #ifdef __cplusplus } #endif diff --git a/libretro-common/net/net_http.c b/libretro-common/net/net_http.c index 9f94465525..05cf49d17c 100644 --- a/libretro-common/net/net_http.c +++ b/libretro-common/net/net_http.c @@ -559,3 +559,86 @@ void net_http_delete(struct http_t *state) free(state->data); free(state); } + +int net_http_get(const char **result, size_t *size, const char *url, retro_time_t *timeout) +{ + struct http_connection_t* conn = NULL; + struct http_t* http = NULL; + int ret = -1; + retro_time_t t0; + uint8_t* data; + size_t length; + char* res; + + *result = NULL; + t0 = retro_get_time_usec(); + conn = net_http_connection_new(url); + + /* Error creating the connection descriptor. */ + if (!conn) + goto error; + + /* Don't bother with timeouts here, it's just a string scan. */ + while (!net_http_connection_iterate(conn)) {} + + /* Error finishing the connection descriptor. */ + if (!net_http_connection_done(conn)) + goto error; + + http = net_http_new(conn); + + /* Error connecting to the endpoint. */ + if (!http) + goto error; + + while (!net_http_update(http, NULL, NULL)) + { + /* Timeout error. */ + if (timeout && (retro_get_time_usec() - t0) > *timeout) + goto error; + } + + data = net_http_data(http, &length, false); + + if (data) + { + res = (char*)malloc(length + 1); + + /* Allocation error. */ + if ( !res ) + goto error; + + memcpy((void*)res, (void*)data, length); + res[length] = 0; + *result = res; + } + else + { + length = 0; + *result = NULL; + } + + if (size) + *size = length; + + ret = 0; + +error: + if ( http ) + net_http_delete( http ); + + if ( conn ) + net_http_connection_free( conn ); + + if (timeout) + { + t0 = retro_get_time_usec() - t0; + + if (t0 < *timeout) + *timeout -= t0; + else + *timeout = 0; + } + + return ret; +}