From 37ece1613d957f6b717826e0ca44bc676ff20e0b Mon Sep 17 00:00:00 2001 From: Michał Cichoń Date: Wed, 26 Aug 2015 19:16:08 +0200 Subject: Drop curl in favor of WinHTTP Abstract out HTTP comunication and replace libcurl with WinHTTP. --- src/http.c | 486 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/http.h | 46 ++++++ src/main.c | 52 +++--- src/main.h | 6 +- src/settings.c | 2 + src/ui.c | 116 ++------------ src/ui.h | 4 +- src/ui_act.c | 22 +-- 8 files changed, 575 insertions(+), 159 deletions(-) create mode 100644 src/http.c create mode 100644 src/http.h diff --git a/src/http.c b/src/http.c new file mode 100644 index 0000000..4a06cc7 --- /dev/null +++ b/src/http.c @@ -0,0 +1,486 @@ +/* +Copyright (c) 2015 + Michał Cichoń + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/* receive/play audio stream */ + +/* based on DShow example player */ + +#include "config.h" +#include "http.h" +#include +#include +#pragma comment(lib, "winhttp.lib") + +struct _http_t { + HINTERNET session; + HINTERNET connection; + wchar_t* endpoint; + wchar_t* securePort; + wchar_t* autoProxy; + wchar_t* proxy; + wchar_t* proxyUsername; + wchar_t* proxyPassword; + char* error; +}; + +static char* HttpToString(const wchar_t* wideString, int size); +static wchar_t* HttpToWideString(const char* string, int size); +static bool HttpCreateConnection (http_t http); +static void HttpCloseConnection (http_t http); +static void HttpSetLastError (http_t http, const char* message); +static void HttpSetLastErrorFromWinHttp (http_t http); +static char* HttpFormatWinApiError (DWORD errorCode, HINSTANCE module); +static char* HttpFormatWinHttpError (DWORD errorCode); +static void HttpClearProxy (http_t http); + +# define WINHTTP_SAFE(condition) do { if (condition) break; HttpSetLastErrorFromWinHttp (http); return false; } while (false) +# define WINHTTP_SAFE_DONE(condition) do { if (condition) break; HttpSetLastErrorFromWinHttp (http); goto done; } while (false) + +static char* HttpToString(const wchar_t* wideString, int size) { + int utfSize = WideCharToMultiByte(CP_UTF8, 0, wideString, size, NULL, 0, NULL, NULL); + char* utfMessage = malloc(utfSize + 1); + if (utfMessage) { + utfMessage[utfSize] = 0; + WideCharToMultiByte(CP_UTF8, 0, wideString, size, utfMessage, utfSize, NULL, NULL); + } + return utfMessage; +} + +static wchar_t* HttpToWideString(const char* string, int size) { + int wideSize = MultiByteToWideChar(CP_UTF8, 0, string, size, NULL, 0); + int wideBytes = (wideSize + 1) * sizeof(wchar_t); + wchar_t* wideMessage = malloc(wideBytes); + if (wideMessage) { + wideMessage[wideSize] = 0; + MultiByteToWideChar(CP_UTF8, 0, string, size, wideMessage, wideSize); + } + return wideMessage; +} + + +static bool HttpCreateConnection (http_t http) { + INTERNET_PORT defaultPort = INTERNET_DEFAULT_PORT; + + HttpCloseConnection (http); + + http->session = WinHttpOpen( + L"WinHTTP/1.0", + WINHTTP_ACCESS_TYPE_NO_PROXY, + WINHTTP_NO_PROXY_NAME, + WINHTTP_NO_PROXY_BYPASS, + 0); + WINHTTP_SAFE(http->session != NULL); + + WinHttpSetTimeouts(http->session, + 60 * 1000, // DNS time-out + 60 * 1000, // connect time-out + 30 * 1000, // send time-out + 30 * 1000); // receive time-out + + http->connection = WinHttpConnect( + http->session, + http->endpoint, + defaultPort, + 0); + WINHTTP_SAFE(http->connection != NULL); + + return true; +} + +static void HttpCloseConnection (http_t http) { + if (http->connection) { + WinHttpCloseHandle(http->connection); + http->connection = NULL; + } + + if (http->session) { + WinHttpCloseHandle(http->session); + http->session = NULL; + } +} + +static void HttpSetLastError (http_t http, const char* message) { + free(http->error); + http->error = NULL; + + if (message) + http->error = strdup(message); +} + +static void HttpSetLastErrorFromWinHttp (http_t http) { + free(http->error); + http->error = NULL; + + DWORD error = GetLastError(); + if (error) + http->error = HttpFormatWinHttpError(error); +} + +static char* HttpFormatWinApiError (DWORD errorCode, HINSTANCE module) { + const int source_flag = module ? FORMAT_MESSAGE_FROM_HMODULE : FORMAT_MESSAGE_FROM_SYSTEM; + + HLOCAL buffer = NULL; + int bufferLength = FormatMessageW( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | source_flag, + (void*)module, + errorCode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPWSTR)&buffer, + 0, + NULL); + + if (bufferLength > 0) { + char* message; + + wchar_t* wideMessage = (wchar_t*)buffer; + + /* Drop new line from the end. */ + wchar_t* wideMessageBack = wideMessage + bufferLength - 1; + while (wideMessageBack > wideMessage && (*wideMessageBack == '\r' || *wideMessageBack == '\n')) + --wideMessageBack; + + message = HttpToString (wideMessage, wideMessageBack - wideMessage + 1); + + LocalFree(buffer); + + return message; + } + else + return NULL; +} + +static char* HttpFormatWinHttpError (DWORD errorCode) { + if (errorCode >= WINHTTP_ERROR_BASE && errorCode <= WINHTTP_ERROR_LAST) { + HMODULE module = GetModuleHandleW(L"WinHTTP.dll"); + if (module) { + char* message = HttpFormatWinApiError(errorCode, module); + if (message) + return message; + } + } + + return HttpFormatWinApiError(errorCode, NULL); +} + +bool HttpInit(http_t* http, const char* endpoint, const char* securePort) { + http_t out = malloc(sizeof(struct _http_t)); + if (!out) + return false; + memset(out, 0, sizeof(struct _http_t)); + + out->endpoint = HttpToWideString(endpoint, -1); + out->securePort = HttpToWideString(securePort, -1); + + if (!HttpCreateConnection (out)) { + HttpDestroy (out); + return false; + } + + *http = out; + return true; +} + +void HttpDestroy(http_t http) { + if (http) { + free(http->endpoint); + free(http->securePort); + http->endpoint = NULL; + http->securePort = NULL; + HttpCloseConnection (http); + HttpClearProxy (http); + } + free(http); +} + +static void HttpClearProxy (http_t http) { + if (http->autoProxy) { + free(http->autoProxy); + http->autoProxy = NULL; + } + + if (http->proxy) { + free(http->proxy); + http->proxy = NULL; + } + + if (http->proxyUsername) { + free(http->proxyUsername); + http->proxyUsername = NULL; + } + + if (http->proxyPassword) { + free(http->proxyPassword); + http->proxyPassword = NULL; + } +} + +bool HttpSetAutoProxy (http_t http, const char* url) { + HttpClearProxy (http); + if (HttpSetProxy (http, url)) { + http->autoProxy = http->proxy; + http->proxy = NULL; + return true; + } + else + return false; +} + +bool HttpSetProxy (http_t http, const char* url) { + URL_COMPONENTS urlComponents; + DWORD wideUrlLength; + wchar_t* wideUrl = NULL; + wchar_t* wideUrl2 = NULL; + wchar_t* wideUsername = NULL; + wchar_t* widePassword = NULL; + + ZeroMemory(&urlComponents, sizeof(urlComponents)); + urlComponents.dwStructSize = sizeof(urlComponents); + urlComponents.dwUserNameLength = -1; + urlComponents.dwPasswordLength = -1; + + wideUrl = HttpToWideString(url, -1); + if (WinHttpCrackUrl(wideUrl, wcslen(wideUrl), 0, &urlComponents)) { + if (urlComponents.lpszUserName && urlComponents.dwUserNameLength > 0) { + wideUsername = wcsdup(urlComponents.lpszUserName); + wideUsername[urlComponents.dwUserNameLength] = 0; + } + if (urlComponents.lpszPassword && urlComponents.dwPasswordLength > 0) { + widePassword = wcsdup(urlComponents.lpszPassword); + widePassword[urlComponents.dwPasswordLength] = 0; + } + } + + ZeroMemory(&urlComponents, sizeof(urlComponents)); + urlComponents.dwStructSize = sizeof(urlComponents); + urlComponents.dwHostNameLength = -1; + urlComponents.dwUrlPathLength = -1; + + if (!WinHttpCrackUrl(wideUrl, wcslen(wideUrl), 0, &urlComponents)) { + free(wideUsername); + free(widePassword); + return false; + } + + if (urlComponents.lpszHostName && urlComponents.dwHostNameLength > 0) { + wideUrl2 = wcsdup(urlComponents.lpszHostName); + wideUrl2[urlComponents.lpszUrlPath - urlComponents.lpszHostName] = 0; + } + + free(wideUrl); + + HttpClearProxy(http); + http->proxy = wideUrl2; + http->proxyUsername = wideUsername; + http->proxyPassword = widePassword; + return true; +} + +bool HttpRequest(http_t http, PianoRequest_t * const request) { + HINTERNET handle = NULL; + wchar_t* wideQuery = NULL; + bool requestSent = false; + bool complete = false; + int retryLimit = 3; + size_t responseDataSize; + + wideQuery = HttpToWideString(request->urlPath, -1); + WINHTTP_SAFE_DONE(wideQuery != NULL); + + handle = WinHttpOpenRequest( + http->connection, + L"POST", + wideQuery, + L"HTTP/1.1", + WINHTTP_NO_REFERER, + WINHTTP_DEFAULT_ACCEPT_TYPES, + request->secure ? WINHTTP_FLAG_SECURE : 0); + WINHTTP_SAFE_DONE(handle != NULL); + + if (http->proxy || http->autoProxy) { + wchar_t* fullUrl; + DWORD fullUrlSize = 0; + WINHTTP_PROXY_INFO proxyInfo; + bool success; + + if (http->autoProxy) { + WINHTTP_AUTOPROXY_OPTIONS proxyOptions = { 0 }; + + success = WinHttpQueryOption(request, WINHTTP_OPTION_URL, NULL, &fullUrlSize); + WINHTTP_SAFE(!success && GetLastError() == ERROR_INSUFFICIENT_BUFFER); + fullUrl = calloc(1, fullUrlSize + 1); + success = WinHttpQueryOption(request, WINHTTP_OPTION_URL, fullUrl, &fullUrlSize); + if (!success) { + free(fullUrl); + WINHTTP_SAFE(success); + } + + proxyOptions.lpszAutoConfigUrl = http->autoProxy; + proxyOptions.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL; + + if (!(success = WinHttpGetProxyForUrl(http->session, fullUrl, &proxyOptions, &proxyInfo))) { + proxyOptions.fAutoLogonIfChallenged = true; + success = WinHttpGetProxyForUrl(http->session, fullUrl, &proxyOptions, &proxyInfo); + } + + if (!success) { + free(fullUrl); + WINHTTP_SAFE(success); + } + } + else { + proxyInfo.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY; + proxyInfo.lpszProxy = http->proxy; + proxyInfo.lpszProxyBypass = NULL; + } + + WINHTTP_SAFE(WinHttpSetOption(handle, + WINHTTP_OPTION_PROXY, + &proxyInfo, sizeof(proxyInfo))); + + if (http->proxyUsername && http->proxyPassword) { + WINHTTP_SAFE(WinHttpSetCredentials(handle, + WINHTTP_AUTH_TARGET_PROXY, + WINHTTP_AUTH_SCHEME_BASIC, + http->proxyUsername, + http->proxyPassword, + NULL)); + } + } + + while (retryLimit > 0) { + DWORD errorCode, statusCode, statusCodeSize; + bool succeeded = false; + bool retry = false; + + if (!requestSent) { + size_t postDataSize = strlen(request->postData); + succeeded = WinHttpSendRequest(handle, + WINHTTP_NO_ADDITIONAL_HEADERS, + 0, + request->postData, + postDataSize, + postDataSize, + 0); + + if (succeeded) + requestSent = true; + } + + if (requestSent) + succeeded = WinHttpReceiveResponse(handle, NULL); + + errorCode = GetLastError(); + + statusCode = 0; + statusCodeSize = sizeof(statusCode); + if (!WinHttpQueryHeaders(handle, + WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, + WINHTTP_HEADER_NAME_BY_INDEX, + &statusCode, &statusCodeSize, WINHTTP_NO_HEADER_INDEX)) { + statusCode = 0; + } + + if (succeeded && statusCode == 407) { + requestSent = false; + retry = true; + } + else { + if (errorCode == ERROR_SUCCESS) + break; + + switch (errorCode) { + case ERROR_WINHTTP_RESEND_REQUEST: + requestSent = false; + /* pass trough */ + + case ERROR_WINHTTP_NAME_NOT_RESOLVED: + case ERROR_WINHTTP_CANNOT_CONNECT: + case ERROR_WINHTTP_TIMEOUT: + retry = true; + break; + + default: + HttpSetLastErrorFromWinHttp (http); + goto done; + } + } + + if (retry) + --retryLimit; + } + + responseDataSize = 0; + while (retryLimit > 0) + { + DWORD bytesLeft; + char* writePtr; + + DWORD bytesAvailable = 0; + if (!WinHttpQueryDataAvailable(handle, &bytesAvailable)) { + WINHTTP_SAFE(GetLastError() == ERROR_WINHTTP_TIMEOUT); + --retryLimit; + continue; + } + + if (0 == bytesAvailable) + break; + + responseDataSize += bytesAvailable; + request->responseData = realloc(request->responseData, responseDataSize + 1); + + writePtr = request->responseData + responseDataSize - bytesAvailable; + writePtr[bytesAvailable] = 0; + + bytesLeft = bytesAvailable; + while (bytesLeft > 0) + { + DWORD bytesRead = 0; + if (!WinHttpReadData(handle, writePtr, bytesLeft, &bytesRead)) + { + WINHTTP_SAFE(GetLastError() == ERROR_WINHTTP_TIMEOUT); + if (--retryLimit == 0) + break; + + continue; + } + + bytesLeft -= bytesRead; + writePtr += bytesRead; + } + + if (bytesLeft > 0) + HttpSetLastError (http, "Maximum retries count exceeded"); + } + + complete = true; + + HttpSetLastError (http, NULL); + +done: + free(wideQuery); + return complete; +} + +const char* HttpGetError(http_t http) { + return http->error; +} diff --git a/src/http.h b/src/http.h new file mode 100644 index 0000000..a321cd3 --- /dev/null +++ b/src/http.h @@ -0,0 +1,46 @@ +/* +Copyright (c) 2015 + Michał Cichoń + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef SRC_HTTP_H_CN979RE9 +#define SRC_HTTP_H_CN979RE9 + +#include "config.h" + +#include + +#include "piano.h" +#include "settings.h" + +typedef struct _http_t *http_t; + +bool HttpInit (http_t*, const char*, const char*); +void HttpDestroy (http_t); + +bool HttpSetAutoProxy (http_t, const char*); +bool HttpSetProxy(http_t, const char*); + +bool HttpRequest (http_t, PianoRequest_t * const); +const char* HttpGetError (http_t); + +#endif /* SRC_HTTP_H_CN979RE9 */ + diff --git a/src/main.c b/src/main.c index 7c6ac08..900e56e 100644 --- a/src/main.c +++ b/src/main.c @@ -36,7 +36,6 @@ THE SOFTWARE. */ static bool BarMainLoginUser (BarApp_t *app) { PianoReturn_t pRet; - CURLcode wRet; PianoRequestDataLogin_t reqData; bool ret; @@ -45,9 +44,9 @@ static bool BarMainLoginUser (BarApp_t *app) { reqData.step = 0; BarUiMsg (&app->settings, MSG_INFO, "Login... "); - ret = BarUiPianoCall (app, PIANO_REQUEST_LOGIN, &reqData, &pRet, &wRet); + ret = BarUiPianoCall (app, PIANO_REQUEST_LOGIN, &reqData, &pRet); BarUiStartEventCmd (&app->settings, "userlogin", NULL, NULL, &app->player, - NULL, pRet, wRet); + NULL, pRet); return ret; } @@ -139,13 +138,12 @@ static bool BarMainGetLoginCredentials (BarSettings_t *settings, */ static bool BarMainGetStations (BarApp_t *app) { PianoReturn_t pRet; - CURLcode wRet; bool ret; BarUiMsg (&app->settings, MSG_INFO, "Get stations... "); - ret = BarUiPianoCall (app, PIANO_REQUEST_GET_STATIONS, NULL, &pRet, &wRet); + ret = BarUiPianoCall (app, PIANO_REQUEST_GET_STATIONS, NULL, &pRet); BarUiStartEventCmd (&app->settings, "usergetstations", NULL, NULL, &app->player, - app->ph.stations, pRet, wRet); + app->ph.stations, pRet); return ret; } @@ -186,14 +184,13 @@ static void BarMainHandleUserInput (BarApp_t *app) { */ static void BarMainGetPlaylist (BarApp_t *app) { PianoReturn_t pRet; - CURLcode wRet; PianoRequestDataGetPlaylist_t reqData; reqData.station = app->curStation; reqData.quality = app->settings.audioQuality; BarUiMsg (&app->settings, MSG_INFO, "Receiving new playlist... "); if (!BarUiPianoCall (app, PIANO_REQUEST_GET_PLAYLIST, - &reqData, &pRet, &wRet)) { + &reqData, &pRet)) { app->curStation = NULL; } else { app->playlist = reqData.retPlaylist; @@ -204,7 +201,7 @@ static void BarMainGetPlaylist (BarApp_t *app) { } BarUiStartEventCmd (&app->settings, "stationfetchplaylist", app->curStation, app->playlist, &app->player, app->ph.stations, - pRet, wRet); + pRet); } /* start new player thread @@ -225,16 +222,18 @@ static void BarMainStartPlayback (BarApp_t *app) { strncmp (curSong->audioUrl, httpPrefix, strlen (httpPrefix)) != 0) { BarUiMsg (&app->settings, MSG_ERR, "Invalid song url.\n"); } else { - BarPlayer2Finish(app->player); BarPlayer2SetGain(app->player, curSong->fileGain); BarPlayer2Open(app->player, curSong->audioUrl); /* throw event */ BarUiStartEventCmd (&app->settings, "songstart", app->curStation, curSong, &app->player, app->ph.stations, - PIANO_RET_OK, CURLE_OK); + PIANO_RET_OK); - BarPlayer2Play(app->player); + if (!BarPlayer2Play(app->player)) + ++app->playerErrors; + else + app->playerErrors = 0; } } @@ -242,24 +241,17 @@ static void BarMainStartPlayback (BarApp_t *app) { */ static void BarMainPlayerCleanup (BarApp_t *app) { BarUiStartEventCmd (&app->settings, "songfinish", app->curStation, - app->playlist, &app->player, app->ph.stations, PIANO_RET_OK, - CURLE_OK); + app->playlist, &app->player, app->ph.stations, PIANO_RET_OK); BarPlayer2Finish(app->player); BarConsoleSetTitle (TITLE); - //if (threadRet == (void *) PLAYER_RET_OK) { - // app->playerErrors = 0; - //} else if (threadRet == (void *) PLAYER_RET_SOFTFAIL) { - // ++app->playerErrors; - // if (app->playerErrors >= app->settings.maxPlayerErrors) { - // /* don't continue playback if thread reports too many error */ - // app->curStation = NULL; - // } - //} else { - // app->curStation = NULL; - //} + if (app->playerErrors >= app->settings.maxPlayerErrors) { + /* don't continue playback if thread reports too many error */ + app->curStation = NULL; + app->playerErrors = 0; + } } /* print song duration @@ -369,9 +361,10 @@ int main (int argc, char **argv) { app.settings.keys[BAR_KS_HELP]); } - curl_global_init (CURL_GLOBAL_DEFAULT); - app.http = curl_easy_init (); - assert (app.http != NULL); + HttpInit(&app.http2, app.settings.rpcHost, app.settings.rpcTlsPort); + if (app.settings.controlProxy) + HttpSetProxy(app.http2, app.settings.controlProxy); + BarReadlineInit (&app.rl); @@ -385,8 +378,7 @@ int main (int argc, char **argv) { PianoDestroy (&app.ph); PianoDestroyPlaylist (app.songHistory); PianoDestroyPlaylist (app.playlist); - curl_easy_cleanup (app.http); - curl_global_cleanup (); + HttpDestroy (app.http2); BarPlayer2Destroy (app.player); BarSettingsDestroy (&app.settings); BarConsoleDestroy (); diff --git a/src/main.h b/src/main.h index 41413d9..f16a168 100644 --- a/src/main.h +++ b/src/main.h @@ -24,17 +24,19 @@ THE SOFTWARE. #ifndef SRC_MAIN_H_4ZGSCG6X #define SRC_MAIN_H_4ZGSCG6X -#include +//#include #include #include "player2.h" +#include "http.h" #include "settings.h" #include "ui_readline.h" typedef struct { PianoHandle_t ph; - CURL *http; + //CURL *http; + http_t http2; player2_t player; BarSettings_t settings; /* first item is current song */ diff --git a/src/settings.c b/src/settings.c index 6ce55c9..d58eb5c 100644 --- a/src/settings.c +++ b/src/settings.c @@ -30,6 +30,8 @@ THE SOFTWARE. #include "ui_dispatch.h" #include #include +#include +#include #define PACKAGE_CONFIG PACKAGE ".cfg" #define PACKAGE_STATE PACKAGE ".state" diff --git a/src/ui.c b/src/ui.c index 023a849..aaa83ae 100644 --- a/src/ui.c +++ b/src/ui.c @@ -29,6 +29,7 @@ THE SOFTWARE. #include "ui_readline.h" #include "console.h" #include +#include typedef int (*BarSortFunc_t) (const void *, const void *); @@ -147,103 +148,12 @@ void BarUiMsg (const BarSettings_t *settings, const BarUiMsg_t type, fflush (stdout); } -typedef struct { - char *data; - size_t pos; -} buffer; - -static size_t httpFetchCb (char *ptr, size_t size, size_t nmemb, - void *userdata) { - buffer * const buffer = userdata; - size_t recvSize = size * nmemb; - - if (buffer->data == NULL) { - if ((buffer->data = malloc (sizeof (*buffer->data) * - (recvSize + 1))) == NULL) { - return 0; - } - } else { - char *newbuf; - if ((newbuf = realloc (buffer->data, sizeof (*buffer->data) * - (buffer->pos + recvSize + 1))) == NULL) { - free (buffer->data); - return 0; - } - buffer->data = newbuf; - } - memcpy (buffer->data + buffer->pos, ptr, recvSize); - buffer->pos += recvSize; - buffer->data[buffer->pos] = '\0'; - - return recvSize; -} - -#define setAndCheck(k,v) \ - httpret = curl_easy_setopt (http, k, v); \ - assert (httpret == CURLE_OK); - -static CURLcode BarPianoHttpRequest (CURL * const http, - const BarSettings_t * const settings, PianoRequest_t * const req) { - buffer buffer = {NULL, 0}; - char url[2048]; - int ret = snprintf (url, sizeof (url), "%s://%s:%s%s", - req->secure ? "https" : "http", - settings->rpcHost, - req->secure ? settings->rpcTlsPort : "80", - req->urlPath); - assert (ret >= 0 && ret <= (int) sizeof (url)); - - curl_easy_reset (http); - CURLcode httpret; - setAndCheck (CURLOPT_URL, url); - setAndCheck (CURLOPT_USERAGENT, PACKAGE "-" VERSION); - setAndCheck (CURLOPT_POSTFIELDS, req->postData); - setAndCheck (CURLOPT_WRITEFUNCTION, httpFetchCb); - setAndCheck (CURLOPT_WRITEDATA, &buffer); - setAndCheck (CURLOPT_POST, 1); - setAndCheck (CURLOPT_TIMEOUT, 30); - if (settings->caBundle != NULL) { - setAndCheck (CURLOPT_CAINFO, settings->caBundle); - } - - /* set up proxy (control proxy for non-us citizen or global proxy for poor - * firewalled fellows) */ - if (settings->controlProxy != NULL) { - /* control proxy overrides global proxy */ - if (curl_easy_setopt (http, CURLOPT_PROXY, - settings->controlProxy) != CURLE_OK) { - /* if setting proxy fails, url is invalid */ - BarUiMsg (settings, MSG_ERR, "Control proxy (%s) is invalid!\n", - settings->controlProxy); - } - } else if (settings->proxy != NULL && strlen (settings->proxy) > 0) { - if (curl_easy_setopt (http, CURLOPT_PROXY, - settings->proxy) != CURLE_OK) { - /* if setting proxy fails, url is invalid */ - BarUiMsg (settings, MSG_ERR, "Proxy (%s) is invalid!\n", - settings->proxy); - } - } - - struct curl_slist *list = NULL; - list = curl_slist_append (list, "Content-Type: text/plain"); - setAndCheck (CURLOPT_HTTPHEADER, list); - - httpret = curl_easy_perform (http); - - curl_slist_free_all (list); - - req->responseData = buffer.data; - - return httpret; -} - /* piano wrapper: prepare/execute http request and pass result back to * libpiano (updates data structures) * @return 1 on success, 0 otherwise */ int BarUiPianoCall (BarApp_t * const app, PianoRequestType_t type, - void *data, PianoReturn_t *pRet, CURLcode *wRet) { + void *data, PianoReturn_t *pRet) { PianoRequest_t req; memset (&req, 0, sizeof (req)); @@ -259,14 +169,13 @@ int BarUiPianoCall (BarApp_t * const app, PianoRequestType_t type, return 0; } - *wRet = BarPianoHttpRequest (app->http, &app->settings, &req); - if (*wRet != CURLE_OK) { - BarUiMsg (&app->settings, MSG_NONE, "Network error: %s\n", - curl_easy_strerror (*wRet)); + if (!HttpRequest(app->http2, &req)) { + BarUiMsg(&app->settings, MSG_NONE, "Network error: %s\n", + HttpGetError(app->http2)); if (req.responseData != NULL) { - free (req.responseData); + free(req.responseData); } - PianoDestroyRequest (&req); + PianoDestroyRequest(&req); return 0; } @@ -277,17 +186,14 @@ int BarUiPianoCall (BarApp_t * const app, PianoRequestType_t type, type != PIANO_REQUEST_LOGIN) { /* reauthenticate */ PianoReturn_t authpRet; - CURLcode authwRet; PianoRequestDataLogin_t reqData; reqData.user = app->settings.username; reqData.password = app->settings.password; reqData.step = 0; BarUiMsg (&app->settings, MSG_NONE, "Reauthentication required... "); - if (!BarUiPianoCall (app, PIANO_REQUEST_LOGIN, &reqData, &authpRet, - &authwRet)) { + if (!BarUiPianoCall (app, PIANO_REQUEST_LOGIN, &reqData, &authpRet)) { *pRet = authpRet; - *wRet = authwRet; if (req.responseData != NULL) { free (req.responseData); } @@ -569,14 +475,12 @@ char *BarUiSelectMusicId (BarApp_t *app, PianoStation_t *station, if (BarReadlineStr (lineBuf, sizeof (lineBuf), app->rl, BAR_RL_DEFAULT) > 0) { PianoReturn_t pRet; - CURLcode wRet; PianoRequestDataSearch_t reqData; reqData.searchStr = lineBuf; BarUiMsg (&app->settings, MSG_INFO, "Searching... "); - if (!BarUiPianoCall (app, PIANO_REQUEST_SEARCH, &reqData, &pRet, - &wRet)) { + if (!BarUiPianoCall (app, PIANO_REQUEST_SEARCH, &reqData, &pRet)) { return NULL; } memcpy (&searchResult, &reqData.searchResult, sizeof (searchResult)); @@ -776,7 +680,7 @@ size_t BarUiListSongs (const BarSettings_t *settings, void BarUiStartEventCmd (const BarSettings_t *settings, const char *type, const PianoStation_t *curStation, const PianoSong_t *curSong, const player2_t * const player, PianoStation_t *stations, - PianoReturn_t pRet, CURLcode wRet) { + PianoReturn_t pRet) { //pid_t chld; //int pipeFd[2]; diff --git a/src/ui.h b/src/ui.h index 67b6155..c9b3d70 100644 --- a/src/ui.h +++ b/src/ui.h @@ -49,9 +49,9 @@ void BarUiPrintSong (const BarSettings_t *, const PianoSong_t *, size_t BarUiListSongs (const BarSettings_t *, const PianoSong_t *, const char *); void BarUiStartEventCmd (const BarSettings_t *, const char *, const PianoStation_t *, const PianoSong_t *, const player2_t * const, - PianoStation_t *, PianoReturn_t, CURLcode); + PianoStation_t *, PianoReturn_t); int BarUiPianoCall (BarApp_t * const, PianoRequestType_t, - void *, PianoReturn_t *, CURLcode *); + void *, PianoReturn_t *); void BarUiHistoryPrepend (BarApp_t *app, PianoSong_t *song); #endif /* SRC_UI_H_46P20TS0 */ diff --git a/src/ui_act.c b/src/ui_act.c index 64c756b..c8a808f 100644 --- a/src/ui_act.c +++ b/src/ui_act.c @@ -37,12 +37,12 @@ THE SOFTWARE. */ #define BarUiActDefaultEventcmd(name) BarUiStartEventCmd (&app->settings, \ name, selStation, selSong, &app->player, app->ph.stations, \ - pRet, wRet) + pRet) /* standard piano call */ #define BarUiActDefaultPianoCall(call, arg) BarUiPianoCall (app, \ - call, arg, &pRet, &wRet) + call, arg, &pRet) /* helper to _really_ skip a song (unlock mutex, quit player) * @param player handle @@ -60,7 +60,6 @@ static inline void BarUiDoSkipSong (player2_t player) { */ static int BarTransformIfShared (BarApp_t *app, PianoStation_t *station) { PianoReturn_t pRet; - CURLcode wRet; assert (station != NULL); @@ -68,7 +67,7 @@ static int BarTransformIfShared (BarApp_t *app, PianoStation_t *station) { if (!station->isCreator) { BarUiMsg (&app->settings, MSG_INFO, "Transforming station... "); if (!BarUiPianoCall (app, PIANO_REQUEST_TRANSFORM_STATION, station, - &pRet, &wRet)) { + &pRet)) { return 0; } } @@ -93,7 +92,6 @@ BarUiActCallback(BarUiActHelp) { */ BarUiActCallback(BarUiActAddMusic) { PianoReturn_t pRet; - CURLcode wRet; PianoRequestDataAddSeed_t reqData; assert (selStation != NULL); @@ -119,7 +117,6 @@ BarUiActCallback(BarUiActAddMusic) { */ BarUiActCallback(BarUiActBanSong) { PianoReturn_t pRet; - CURLcode wRet; PianoStation_t *realStation; assert (selStation != NULL); @@ -151,7 +148,6 @@ BarUiActCallback(BarUiActBanSong) { */ BarUiActCallback(BarUiActCreateStation) { PianoReturn_t pRet; - CURLcode wRet; PianoRequestDataCreateStation_t reqData; reqData.type = PIANO_MUSICTYPE_INVALID; @@ -169,7 +165,6 @@ BarUiActCallback(BarUiActCreateStation) { */ BarUiActCallback(BarUiActCreateStationFromSong) { PianoReturn_t pRet; - CURLcode wRet; PianoRequestDataCreateStation_t reqData; char selectBuf[2]; @@ -199,7 +194,6 @@ BarUiActCallback(BarUiActCreateStationFromSong) { */ BarUiActCallback(BarUiActAddSharedStation) { PianoReturn_t pRet; - CURLcode wRet; char stationId[50]; PianoRequestDataCreateStation_t reqData; @@ -219,7 +213,6 @@ BarUiActCallback(BarUiActAddSharedStation) { */ BarUiActCallback(BarUiActDeleteStation) { PianoReturn_t pRet; - CURLcode wRet; assert (selStation != NULL); @@ -244,7 +237,6 @@ BarUiActCallback(BarUiActDeleteStation) { */ BarUiActCallback(BarUiActExplain) { PianoReturn_t pRet; - CURLcode wRet; PianoRequestDataExplain_t reqData; assert (selSong != NULL); @@ -263,7 +255,6 @@ BarUiActCallback(BarUiActExplain) { */ BarUiActCallback(BarUiActStationFromGenre) { PianoReturn_t pRet; - CURLcode wRet; const PianoGenreCategory_t *curCat; const PianoGenre_t *curGenre; int i; @@ -373,7 +364,6 @@ BarUiActCallback(BarUiActDebug) { */ BarUiActCallback(BarUiActLoveSong) { PianoReturn_t pRet; - CURLcode wRet; PianoStation_t *realStation; assert (selStation != NULL); @@ -429,7 +419,6 @@ BarUiActCallback(BarUiActTogglePause) { */ BarUiActCallback(BarUiActRenameStation) { PianoReturn_t pRet; - CURLcode wRet; char lineBuf[100]; assert (selStation != NULL); @@ -472,7 +461,6 @@ BarUiActCallback(BarUiActSelectStation) { */ BarUiActCallback(BarUiActTempBanSong) { PianoReturn_t pRet; - CURLcode wRet; assert (selSong != NULL); @@ -538,7 +526,6 @@ static void BarUiActQuickmixCallback (BarApp_t *app, char *buf) { */ BarUiActCallback(BarUiActSelectQuickMix) { PianoReturn_t pRet; - CURLcode wRet; assert (selStation != NULL); @@ -607,7 +594,6 @@ BarUiActCallback(BarUiActHistory) { */ BarUiActCallback(BarUiActBookmark) { PianoReturn_t pRet; - CURLcode wRet; char selectBuf[2]; assert (selSong != NULL); @@ -655,7 +641,6 @@ static const char *boolToYesNo (const bool value) { */ BarUiActCallback(BarUiActSettings) { PianoReturn_t pRet; - CURLcode wRet; PianoSettings_t settings; PianoRequestDataChangeSettings_t reqData; bool modified = false; @@ -751,7 +736,6 @@ BarUiActCallback(BarUiActSettings) { */ BarUiActCallback(BarUiActManageStation) { PianoReturn_t pRet; - CURLcode wRet; PianoRequestDataGetStationInfo_t reqData; char selectBuf[2], allowedActions[6], *allowedPos = allowedActions; char question[64]; -- cgit v1.2.3