Atrinik Client  4.0
resources.c
Go to the documentation of this file.
1 /*************************************************************************
2  * Atrinik, a Multiplayer Online Role Playing Game *
3  * *
4  * Copyright (C) 2009-2014 Alex Tokar and Atrinik Development Team *
5  * *
6  * Fork from Crossfire (Multiplayer game for X-windows). *
7  * *
8  * This program is free software; you can redistribute it and/or modify *
9  * it under the terms of the GNU General Public License as published by *
10  * the Free Software Foundation; either version 2 of the License, or *
11  * (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License *
19  * along with this program; if not, write to the Free Software *
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
21  * *
22  * The author can be reached at admin@atrinik.org *
23  ************************************************************************/
24 
32 #include <global.h>
33 #include <resources.h>
34 #include <toolkit/string.h>
35 #include <toolkit/path.h>
36 #include <toolkit/packet.h>
37 
41 static resource_t *resources = NULL;
42 
46 void
48 {
49 }
50 
51 static void
52 resources_free (void)
53 {
54  resource_t *resource, *tmp;
55 
56  HASH_ITER(hh, resources, resource, tmp) {
57  HASH_DEL(resources, resource);
58 
59  if (resource->request != NULL) {
60  curl_request_free(resource->request);
61  }
62 
63  efree(resource->name);
64  efree(resource);
65  }
66 
67  resources = NULL;
68 }
69 
73 void
75 {
76  resources_free();
77 }
78 
84 void
86 {
87  resources_free();
88 }
89 
90 resource_t *
91 resources_find (const char *name)
92 {
93  resource_t *resource;
94  HASH_FIND(hh, resources, name, strlen(name), resource);
95  return resource;
96 }
97 
99 void
100 socket_command_resource (uint8_t *data, size_t len, size_t pos)
101 {
102  char resource_name[HUGE_BUF];
103  packet_to_string(data, len, &pos, VS(resource_name));
104  if (string_isempty(resource_name)) {
105  LOG(PACKET, "Received empty resource name");
106  return;
107  }
108 
109  if (resources_find(resource_name) != NULL) {
110  return;
111  }
112 
113  const unsigned char *md = data + pos;
114  if (len - pos != sizeof(((resource_t *) NULL)->md)) {
115  LOG(PACKET, "Invalid remaining packet size");
116  return;
117  }
118 
119  char digest[sizeof(((resource_t *) NULL)->digest)];
120  SOFT_ASSERT(string_tohex(md,
121  len - pos,
122  VS(digest),
123  false) == sizeof(digest) - 1,
124  "string_tohex failed");
125  string_tolower(digest);
126 
127  resource_t *resource = ecalloc(1, sizeof(*resource));
128  resource->name = estrdup(resource_name);
129  memcpy(resource->md, md, sizeof(resource->md));
130  memcpy(resource->digest, digest, sizeof(resource->digest));
131  HASH_ADD_KEYPTR(hh,
132  resources,
133  resource->name,
134  strlen(resource->name),
135  resource);
136 
137  char path[HUGE_BUF];
138  snprintf(VS(path), "resources/%s", resource->digest);
139  FILE *fp = path_fopen(path, "r");
140  if (fp != NULL) {
141  fclose(fp);
142  resource->loaded = true;
143  return;
144  }
145 
146  char url[HUGE_BUF];
147  snprintf(VS(url), "%s/resources/%s", cpl.http_url, resource_name);
148  resource->request = curl_request_create(url, CURL_PKEY_TRUST_APPLICATION);
149  curl_request_start_get(resource->request);
150 }
151 
160 bool
162 {
163  if (resource->loaded) {
164  return true;
165  }
166 
167  if (curl_request_get_state(resource->request) == CURL_STATE_INPROGRESS) {
168  return false;
169  }
170 
171  if (curl_request_get_http_code(resource->request) != 200) {
172  LOG(ERROR, "Failed to download painting %s",
173  curl_request_get_url(resource->request));
174  goto error;
175  }
176 
177  size_t body_size;
178  char *body = curl_request_get_body(resource->request, &body_size);
179  if (body == NULL) {
180  LOG(ERROR, "Failed to download painting %s",
181  curl_request_get_url(resource->request));
182  goto error;
183  }
184 
185  unsigned char md[SHA512_DIGEST_LENGTH];
186  if (SHA512((unsigned char *) body, body_size, md) == NULL) {
187  LOG(ERROR, "SHA512() failed");
188  goto error;
189  }
190 
191  if (memcmp(md, resource->md, sizeof(md)) != 0) {
192  LOG(ERROR, "!!! SHA512 digests do not match for resource %s !!!",
193  resource->name);
194  goto error;
195  }
196 
197  char path[HUGE_BUF];
198  snprintf(VS(path), "resources/%s", resource->digest);
199  FILE *fp = path_fopen(path, "wb");
200  if (fp == NULL) {
201  LOG(ERROR, "Failed to open %s: %s (%d)",
202  path,
203  strerror(errno),
204  errno);
205  goto error;
206  }
207 
208  if (fwrite(body, 1, body_size, fp) != body_size) {
209  LOG(ERROR, "Failed to write enough bytes to %s: %s (%d)",
210  path,
211  strerror(errno),
212  errno);
213  fclose(fp);
214  goto error;
215  }
216 
217  fclose(fp);
218  resource->loaded = true;
219 
220  bool ret = true;
221  goto out;
222 
223 error:
224  ret = false;
225  curl_request_free(resource->request);
226  resource->request = NULL;
227 
228 out:
229  return ret;
230 }
void resources_deinit(void)
Definition: resources.c:74
Client_Player cpl
Definition: client.c:50
char http_url[MAX_BUF]
Definition: player.h:252
static resource_t * resources
Definition: resources.c:41
bool resources_is_ready(resource_t *resource)
Definition: resources.c:161
void resources_reload(void)
Definition: resources.c:85
void socket_command_resource(uint8_t *data, size_t len, size_t pos)
Definition: resources.c:100
void resources_init(void)
Definition: resources.c:47