aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar bigfoot547 <[email protected]>2024-01-03 05:18:11 -0600
committerLibravatar bigfoot547 <[email protected]>2024-01-03 05:18:11 -0600
commitce87d368bd3e9b6c05ed9f6fdbb97580f105bbcf (patch)
tree7b7441d6891aff7080cae3b0b08cd577761a1f1c
parentdownloads client jar (diff)
refactor and download asset index
-rw-r--r--src/assets.c64
-rw-r--r--src/assets.h4
-rw-r--r--src/cmd-version.c14
-rw-r--r--src/l2su.h5
-rw-r--r--src/launcherutil.c176
-rw-r--r--src/meson.build2
-rw-r--r--src/version.c160
-rw-r--r--src/version.h2
8 files changed, 271 insertions, 156 deletions
diff --git a/src/assets.c b/src/assets.c
new file mode 100644
index 0000000..57624ae
--- /dev/null
+++ b/src/assets.c
@@ -0,0 +1,64 @@
+#include "assets.h"
+#include "version.h"
+#include "l2su.h"
+
+#include <jansson.h>
+
+int l2_assets__download_index(json_t *version, char **path)
+{
+ const char *url = NULL;
+ const char *id = NULL;
+ const char *digeststr = NULL;
+ json_int_t jsize = 0;
+
+ l2_sha1_digest_t expect_digest;
+
+ if (json_unpack(version, "{s:{s?:s, s:s, s:I, s:s}}", "assetIndex", "url", &url, "id", &id, "size", &jsize, "sha1", &digeststr) < 0) {
+ return -1;
+ }
+
+ if (jsize < 0) return -1;
+ if (l2_sha1_digest_from_hex(&expect_digest, digeststr) < 0) return -1;
+
+ char *pathstr = l2_launcher_sprintf_alloc("%s/assets/indexes/%s.json", l2_state.paths.data, id);
+ if (!pathstr) return -1;
+
+ int res = l2_launcher_download_checksummed(url, pathstr, &expect_digest, (size_t)jsize);
+
+ if (res < 0) {
+ free(pathstr);
+ return res;
+ }
+
+ *path = pathstr;
+ return res;
+}
+
+int l2_assets__load_index(json_t *version, json_t **asset_index)
+{
+ char *path = NULL;
+ int res;
+
+ res = l2_assets__download_index(version, &path);
+
+ if (res < 0) {
+ goto cleanup;
+ }
+
+ json_error_t jerr;
+ json_t *js;
+ if (!(js = json_load_file(path, JSON_REJECT_DUPLICATES, &jerr))) {
+ CMD_ERROR("JSON error parsing asset index: %s", jerr.text);
+ res = -1;
+ goto cleanup;
+ }
+
+ free(path);
+
+ *asset_index = js;
+ return res;
+
+cleanup:
+ free(path);
+ return res;
+}
diff --git a/src/assets.h b/src/assets.h
new file mode 100644
index 0000000..6f8496f
--- /dev/null
+++ b/src/assets.h
@@ -0,0 +1,4 @@
+#ifndef L2SU_ASSETS_H_INCLUDED
+#define L2SU_ASSETS_H_INCLUDED
+
+#endif /* include guard */
diff --git a/src/cmd-version.c b/src/cmd-version.c
index f96d6f3..b11e35c 100644
--- a/src/cmd-version.c
+++ b/src/cmd-version.c
@@ -7,6 +7,7 @@
#include <jansson.h>
#include <stdio.h>
+#include <unistd.h>
unsigned cmd_version_list_remote(struct l2_context_node *ctx, char **args)
{
@@ -40,6 +41,8 @@ bool feat_match_cb(const char *name, json_t *js) {
return false;
}
+int l2_assets__load_index(json_t *version, json_t **asset_index);
+
unsigned cmd_version_install(struct l2_context_node *ctx, char **args)
{
unsigned res = l2_version_load_remote();
@@ -71,6 +74,17 @@ unsigned cmd_version_install(struct l2_context_node *ctx, char **args)
CMD_FATAL("Failed to download client jar: %s", l2_version_strerror(res));
}
+ CMD_INFO0("Downloading asset index...");
+ json_t *assets = NULL;
+ if (l2_assets__load_index(js, &assets) < 0) {
+ CMD_FATAL0("Failed to load asset index.");
+ }
+
+ json_dumpf(assets, stdout, JSON_INDENT(4));
+ putchar('\n');
+
+ json_decref(assets);
+
l2_version_free_libraries(libs);
free(jarpath);
json_decref(js);
diff --git a/src/l2su.h b/src/l2su.h
index 1adfc4c..8c77e14 100644
--- a/src/l2su.h
+++ b/src/l2su.h
@@ -60,6 +60,11 @@ void l2_launcher_download_cleanup(struct l2_dlbuf *buf);
extern const curl_write_callback l2_dlcb;
CURLcode l2_launcher_download(CURL *cd, const char *url, void **odata, size_t *osize);
+
+int l2_launcher_should_download(const char *path, const l2_sha1_digest_t *expectdigest, size_t expectsize);
+int l2_launcher_check_integrity(FILE *fp, const l2_sha1_digest_t *digest, size_t sz);
+int l2_launcher_download_checksummed(const char *url, const char *pathstr, l2_sha1_digest_t *expect_digest, size_t expect_size);
+
int l2_json_merge_objects(json_t *j1, json_t *j2);
/* string substitute utility */
diff --git a/src/launcherutil.c b/src/launcherutil.c
index f7a38fd..2db6238 100644
--- a/src/launcherutil.c
+++ b/src/launcherutil.c
@@ -281,3 +281,179 @@ int l2_json_merge_objects(json_t *j1, json_t *j2)
return 0;
}
+
+int l2_launcher_check_integrity(FILE *fp, const l2_sha1_digest_t *digest, size_t sz)
+{
+ #define VER_READBUF_SZ (1024)
+
+ size_t len = 0, nread;
+ uint8_t buf[VER_READBUF_SZ];
+ l2_sha1_digest_t rdigest;
+ l2_sha1_state_t st;
+
+ if (!digest && sz == 0) return 1;
+
+ l2_sha1_init(&st);
+
+ while ((nread = fread(buf, 1, VER_READBUF_SZ, fp)) > 0) {
+ len += nread;
+ l2_sha1_update(&st, buf, nread);
+ }
+
+ if (ferror(fp)) return -1;
+
+ l2_sha1_finalize(&st, &rdigest);
+
+ if (sz > 0 && sz != len) return 0;
+
+ if (digest) {
+ return !l2_sha1_digest_compare(&rdigest, digest) ? 1 : 0;
+ } else {
+ return 1;
+ }
+}
+
+int l2_launcher_should_download(const char *path, const l2_sha1_digest_t *expectdigest, size_t expectsize)
+{
+ FILE *lfile = fopen(path, "rb");
+
+ if (!lfile) {
+ if (errno == ENOENT) {
+ return 1;
+ } else {
+ CMD_DEBUG("Failed to open %s for reading: %s", path, strerror(errno));
+ return -1;
+ }
+ }
+
+ int res = l2_launcher_check_integrity(lfile, expectdigest, expectsize);
+ fclose(lfile);
+
+ switch (res) {
+ case 0:
+ CMD_DEBUG("SHOULD redownload %s, the SHA1 or size doesn't match.", path);
+ return 1;
+ case 1:
+ CMD_DEBUG("SHOULDN'T redownload %s.", path);
+ return 0;
+ default:
+ return res;
+ }
+}
+
+struct l2_launcher__download_data {
+ l2_sha1_state_t digest_state;
+ size_t recv_size;
+ FILE *fp;
+};
+
+size_t l2_launcher__download_writecb(char *ptr, size_t size, size_t nmemb, void *user)
+{
+ struct l2_launcher__download_data *data = user;
+ size_t realsz = size * nmemb; /* size should be 1 but whatever */
+
+ if (fwrite(ptr, size, nmemb, data->fp) < nmemb) {
+ return CURL_WRITEFUNC_ERROR;
+ }
+
+ l2_sha1_update(&data->digest_state, ptr, realsz);
+ data->recv_size += realsz;
+
+ return realsz;
+}
+
+int l2_launcher_download_checksummed(const char *url, const char *pathstr, l2_sha1_digest_t *expect_digest, size_t expect_size)
+{
+ int res = -1;
+ CURL *pc = NULL;
+
+ /* check if we even need to redownload the thing */
+ int rdres = l2_launcher_should_download(pathstr, expect_digest, expect_size);
+ if (rdres < 0) {
+ return -1;
+ } else if (!rdres) {
+ CMD_DEBUG("Not downloading %s", pathstr);
+ return 0;
+ }
+
+ if (!url) {
+ CMD_WARN("Cannot redownload %s, even though I need to! (no URL specified)", pathstr);
+ return -1;
+ }
+
+ /* redownload the file */
+ struct l2_launcher__download_data dldata;
+ char errbuf[CURL_ERROR_SIZE];
+
+ memset(&dldata, 0, sizeof(struct l2_launcher__download_data));
+ memset(&errbuf, 0, sizeof(errbuf));
+
+ l2_sha1_init(&dldata.digest_state);
+
+ if (l2_launcher_mkdir_parents_ex(pathstr, 1) < 0) {
+ goto cleanup;
+ }
+
+ dldata.fp = fopen(pathstr, "wb");
+ if (!dldata.fp) {
+ CMD_WARN("Failed to open %s for writing: %s", pathstr, strerror(errno));
+ goto cleanup;
+ }
+
+ pc = curl_easy_init();
+ if (!pc) {
+ goto cleanup;
+ }
+
+ curl_easy_setopt(pc, CURLOPT_USERAGENT, L2_USER_AGENT);
+ curl_easy_setopt(pc, CURLOPT_URL, url);
+ curl_easy_setopt(pc, CURLOPT_WRITEDATA, &dldata);
+ curl_easy_setopt(pc, CURLOPT_WRITEFUNCTION, &l2_launcher__download_writecb);
+ curl_easy_setopt(pc, CURLOPT_ERRORBUFFER, errbuf);
+
+ CURLcode cres = curl_easy_perform(pc);
+ if (cres != CURLE_OK) {
+ CMD_WARN("Failed to download %s: %s: %s", pathstr, curl_easy_strerror(cres), errbuf);
+ goto cleanup;
+ }
+
+ fclose(dldata.fp);
+ dldata.fp = NULL;
+
+ curl_easy_cleanup(pc);
+ pc = NULL;
+
+ l2_sha1_digest_t recvdigest;
+ l2_sha1_finalize(&dldata.digest_state, &recvdigest);
+
+ if (expect_digest && l2_sha1_digest_compare(&recvdigest, expect_digest)) {
+ char expstr[L2_SHA1_HEX_STRLEN + 1];
+ char gotstr[L2_SHA1_HEX_STRLEN + 1];
+
+ l2_sha1_digest_to_hex(expect_digest, expstr);
+ l2_sha1_digest_to_hex(&recvdigest, gotstr);
+
+ CMD_WARN("Downloaded %s has wrong digest! (expected: %s, got: %s)", pathstr, expstr, gotstr);
+ if (unlink(pathstr) < 0) {
+ CMD_WARN("Failed to delete %s: %s", pathstr, strerror(errno));
+ }
+ goto cleanup;
+ }
+
+ if (expect_size > 0 && expect_size != dldata.recv_size) {
+ CMD_WARN("Downloaded %s has wrong size! (expected: %zu bytes, got: %zu bytes)", pathstr, expect_size, dldata.recv_size);
+ if (unlink(pathstr) < 0) {
+ CMD_WARN("Failed to delete %s: %s", pathstr, strerror(errno));
+ }
+ goto cleanup;
+ }
+
+ CMD_INFO("Downloaded %s successfully.", pathstr);
+ curl_easy_cleanup(pc);
+ return 1;
+
+cleanup:
+ if (dldata.fp) fclose(dldata.fp);
+ if (pc) curl_easy_cleanup(pc);
+ return res;
+}
diff --git a/src/meson.build b/src/meson.build
index 1f7d40f..86728a6 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -1,4 +1,4 @@
-launcher_srcs = files('l2su.c', 'command.c', 'cmd-instance.c', 'uuid/uuid.c', 'launcherutil.c', 'instance.c', 'cmd-version.c', 'digest/sha1.c', 'version.c', 'subst.c', 'downloadpool.c')
+launcher_srcs = files('l2su.c', 'command.c', 'cmd-instance.c', 'uuid/uuid.c', 'launcherutil.c', 'instance.c', 'cmd-version.c', 'digest/sha1.c', 'version.c', 'subst.c', 'downloadpool.c', 'assets.c')
configure_file(input : 'config.h.in', output : 'config.h', configuration : config_data)
config_include_dir = include_directories('.')
diff --git a/src/version.c b/src/version.c
index 7ca1487..54bdc20 100644
--- a/src/version.c
+++ b/src/version.c
@@ -124,7 +124,7 @@ void l2_version__load_local(const char *id, size_t expectsz, l2_sha1_digest_t *d
FILE *ver = fopen(path, "r");
if (!ver) return;
- int res = l2_version_check_integrity(ver, digest, expectsz);
+ int res = l2_launcher_check_integrity(ver, digest, expectsz);
if (res < 0) {
CMD_WARN("Error checking version file integrity for %s", id);
return;
@@ -564,43 +564,10 @@ cleanup:
return res;
}
-int l2_version_check_integrity(FILE *fp, const l2_sha1_digest_t *digest, size_t sz)
-{
- #define VER_READBUF_SZ (1024)
-
- size_t len = 0, nread;
- uint8_t buf[VER_READBUF_SZ];
- l2_sha1_digest_t rdigest;
- l2_sha1_state_t st;
-
- if (!digest && sz == 0) return 1;
-
- l2_sha1_init(&st);
-
- while ((nread = fread(buf, 1, VER_READBUF_SZ, fp)) > 0) {
- len += nread;
- l2_sha1_update(&st, buf, nread);
- }
-
- if (ferror(fp)) return -1;
-
- l2_sha1_finalize(&st, &rdigest);
-
- if (sz > 0 && sz != len) return 0;
-
- if (digest) {
- return !l2_sha1_digest_compare(&rdigest, digest) ? 1 : 0;
- } else {
- return 1;
- }
-}
-
unsigned l2_version__collect_libraries(json_t *jlibs, l2_subst_t *subst, struct l2_version_library **libs, l2_version_feature_match_proc_t *feature_matcher);
void l2_version_free_libraries(struct l2_version_library *libs);
int l2_version__get_library_artifact_path(json_t *lib, l2_subst_t *subst, const char *classifier, char **path);
-int l2_version__should_download(const char *path, const l2_sha1_digest_t *expectdigest, size_t expectsize);
-
struct l2_version__library_dl_data {
l2_sha1_state_t st;
size_t sz;
@@ -714,7 +681,7 @@ unsigned l2_version_download_libraries(struct l2_version_library *libs)
}
for (struct l2_version_library *cur = libs; cur; cur = cur->next) {
- dlres = l2_version__should_download(cur->fullpath, cur->has_digest ? &cur->digest : NULL, cur->size);
+ dlres = l2_launcher_should_download(cur->fullpath, cur->has_digest ? &cur->digest : NULL, cur->size);
if (dlres < 0) {
res = VERSION_EDOWNLOAD;
goto cleanup;
@@ -791,7 +758,7 @@ int l2_version__should_download(const char *path, const l2_sha1_digest_t *expect
}
}
- int res = l2_version_check_integrity(lfile, expectdigest, expectsize);
+ int res = l2_launcher_check_integrity(lfile, expectdigest, expectsize);
fclose(lfile);
switch (res) {
@@ -1366,41 +1333,17 @@ enum l2_version_check_result l2_version_check_rules(json_t *rules, l2_version_fe
return res;
}
-struct l2_version__download_data {
- l2_sha1_state_t digest_state;
- size_t recv_size;
- FILE *fp;
-};
-
-size_t l2_version__download_writecb(char *ptr, size_t size, size_t nmemb, void *user)
-{
- struct l2_version__download_data *data = user;
- size_t realsz = size * nmemb; /* size should be 1 but whatever */
-
- if (fwrite(ptr, size, nmemb, data->fp) < nmemb) {
- return CURL_WRITEFUNC_ERROR;
- }
-
- l2_sha1_update(&data->digest_state, ptr, realsz);
- data->recv_size += realsz;
-
- return realsz;
-}
-
unsigned l2_version_download_jar(json_t *version, const char *specifier, char **path)
{
const char *id = NULL;
const char *digeststr = NULL;
const char *url = NULL;
- CURL *pc = NULL;
json_int_t jexpectsize = 0;
size_t expect_size;
l2_sha1_digest_t expect_digest;
- unsigned res = VERSION_SUCCESS;
-
if (json_unpack(version, "{s:{s:{s?:s, s?:s, s?:I}}, s:s}", "downloads", specifier, "sha1", &digeststr, "url", &url, "size", &jexpectsize, "id", &id) < 0) {
return VERSION_EJSON;
}
@@ -1414,102 +1357,13 @@ unsigned l2_version_download_jar(json_t *version, const char *specifier, char **
char *pathstr = l2_launcher_sprintf_alloc("%s/versions/%s/%s.jar", l2_state.paths.data, id, id);
if (!pathstr) return VERSION_EALLOC;
- /* check if we even need to redownload the thing */
- int rdres = l2_version__should_download(pathstr, digeststr ? &expect_digest : NULL, expect_size);
- if (rdres < 0) {
- return VERSION_EDOWNLOAD;
- } else if (!rdres) {
- CMD_DEBUG("Not downloading %s jar.", specifier);
- *path = pathstr;
- return VERSION_SUCCESS;
- }
-
- if (!url) {
- CMD_WARN("Cannot redownload %s jar, even though I need to! (no URL specified)", specifier);
- return VERSION_EJSON;
- }
-
- /* redownload the file */
- struct l2_version__download_data dldata;
- char errbuf[CURL_ERROR_SIZE];
-
- memset(&dldata, 0, sizeof(struct l2_version__download_data));
- memset(&errbuf, 0, sizeof(errbuf));
-
- l2_sha1_init(&dldata.digest_state);
-
- if (l2_launcher_mkdir_parents_ex(pathstr, 1) < 0) {
- res = VERSION_EDOWNLOAD;
- goto cleanup;
- }
-
- dldata.fp = fopen(pathstr, "wb");
- if (!dldata.fp) {
- CMD_WARN("Failed to open %s for writing: %s", pathstr, strerror(errno));
- res = VERSION_EDOWNLOAD;
- goto cleanup;
- }
-
- pc = curl_easy_init();
- if (!pc) {
- res = VERSION_EDOWNLOAD;
- goto cleanup;
- }
-
- curl_easy_setopt(pc, CURLOPT_USERAGENT, L2_USER_AGENT);
- curl_easy_setopt(pc, CURLOPT_URL, url);
- curl_easy_setopt(pc, CURLOPT_WRITEDATA, &dldata);
- curl_easy_setopt(pc, CURLOPT_WRITEFUNCTION, &l2_version__download_writecb);
- curl_easy_setopt(pc, CURLOPT_ERRORBUFFER, errbuf);
-
- CURLcode cres = curl_easy_perform(pc);
- if (cres != CURLE_OK) {
- CMD_WARN("Failed to download %s jar: %s: %s", specifier, curl_easy_strerror(cres), errbuf);
- res = VERSION_EDOWNLOAD;
- goto cleanup;
- }
-
- fclose(dldata.fp);
- dldata.fp = NULL;
-
- curl_easy_cleanup(pc);
- pc = NULL;
-
- l2_sha1_digest_t recvdigest;
- l2_sha1_finalize(&dldata.digest_state, &recvdigest);
+ int dlres = l2_launcher_download_checksummed(url, pathstr, digeststr ? &expect_digest : NULL, expect_size);
- if (digeststr && l2_sha1_digest_compare(&recvdigest, &expect_digest)) {
- char expstr[L2_SHA1_HEX_STRLEN + 1];
- char gotstr[L2_SHA1_HEX_STRLEN + 1];
-
- l2_sha1_digest_to_hex(&expect_digest, expstr);
- l2_sha1_digest_to_hex(&recvdigest, gotstr);
-
- CMD_WARN("Downloaded %s jar has wrong digest! (expected: %s, got: %s)", specifier, expstr, gotstr);
- if (unlink(pathstr) < 0) {
- CMD_WARN("Failed to delete %s jar: %s", specifier, strerror(errno));
- }
- res = VERSION_EDOWNLOAD;
- goto cleanup;
+ if (dlres < 0) {
+ free(pathstr);
+ return VERSION_EDOWNLOAD;
}
- if (expect_size > 0 && expect_size != dldata.recv_size) {
- CMD_WARN("Downloaded %s jar has wrong size! (expected: %zu bytes, got: %zu bytes)", specifier, expect_size, dldata.recv_size);
- if (unlink(pathstr) < 0) {
- CMD_WARN("Failed to delete %s jar: %s", specifier, strerror(errno));
- }
- res = VERSION_EDOWNLOAD;
- goto cleanup;
- }
-
- CMD_DEBUG("Downloaded %s jar successfully.", specifier);
- curl_easy_cleanup(pc);
*path = pathstr;
return VERSION_SUCCESS;
-
-cleanup:
- free(pathstr);
- if (dldata.fp) fclose(dldata.fp);
- if (pc) curl_easy_cleanup(pc);
- return res;
}
diff --git a/src/version.h b/src/version.h
index b2f871b..c008481 100644
--- a/src/version.h
+++ b/src/version.h
@@ -88,8 +88,6 @@ unsigned l2_version_load_remote(void);
unsigned l2_version_load_local(const char *name, json_t **ojs);
-int l2_version_check_integrity(FILE *fp, const l2_sha1_digest_t *digest, size_t sz);
-
enum l2_version_check_result {
RULE_CHECK_ERROR = -1,
RULE_CHECK_DEFAULT,