about summary refs log tree commit diff stats
path: root/source/http.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/http.c')
-rw-r--r--source/http.c359
1 files changed, 359 insertions, 0 deletions
diff --git a/source/http.c b/source/http.c new file mode 100644 index 0000000..1979e22 --- /dev/null +++ b/source/http.c
@@ -0,0 +1,359 @@
1/*
2 * Copyright (C) 2008 Tantric
3 * Copyright (C) 2012 Pedro Aguiar
4 * Copyright (C) 2017 hatkirby
5 *
6 * Originally part of the WiiTweet project, which was distributed under the
7 * GPL.
8 */
9#include "http.h"
10#include <gccore.h>
11#include <network.h>
12#include <unistd.h>
13#include <fcntl.h>
14#include <ogcsys.h>
15#include <ogc/lwp_watchdog.h>
16#include <sys/errno.h>
17#include <string.h>
18#include <stdio.h>
19
20#define TCP_CONNECT_TIMEOUT 4000
21#define TCP_SEND_SIZE (32 * 1024)
22#define TCP_RECV_SIZE (32 * 1024)
23#define TCP_BLOCK_RECV_TIMEOUT 4000
24#define TCP_BLOCK_SEND_TIMEOUT 4000
25#define TCP_BLOCK_SIZE 1024
26#define HTTP_TIMEOUT 10000
27#define IOS_O_NONBLOCK 0x04
28
29static int tcpWrite(
30 bool secure,
31 void* firstParam,
32 const u8* buffer,
33 u32 length)
34{
35 int left = length;
36 int sent = 0;
37 int step = 0;
38
39 u64 t = gettime();
40 while (left)
41 {
42 if (ticks_to_millisecs(diff_ticks(t, gettime())) > TCP_BLOCK_SEND_TIMEOUT)
43 {
44 return HTTPR_ERR_TIMEOUT;
45 }
46
47 int block = left;
48 if (block > TCP_SEND_SIZE)
49 {
50 block = TCP_SEND_SIZE;
51 }
52
53 int result;
54 if (secure)
55 {
56 result = wolfSSL_write(*(WOLFSSL**)firstParam, buffer, block);
57 } else {
58 result = net_write(*(s32*)firstParam, buffer, block);
59 }
60
61 if ((result == 0) || (result == -56))
62 {
63 usleep(20 * 1000);
64
65 continue;
66 }
67
68 if (result < 0)
69 {
70 break;
71 }
72
73 sent += result;
74 left -= result;
75 buffer += result;
76 usleep(100);
77
78 if ((sent / TCP_BLOCK_SIZE) > step)
79 {
80 t = gettime();
81 step++;
82 }
83 }
84
85 if (left == 0)
86 {
87 return HTTPR_OK;
88 } else {
89 return HTTPR_ERR_WRITE;
90 }
91}
92
93static int tcpRead(
94 bool secure,
95 void* firstParam,
96 char* buffer,
97 u16 maxLength)
98{
99 u64 startTime = gettime();
100 u16 cur = 0;
101
102 while (cur < maxLength)
103 {
104 if (ticks_to_millisecs(diff_ticks(startTime, gettime())) > HTTP_TIMEOUT)
105 {
106 return HTTPR_ERR_TIMEOUT;
107 }
108
109 u32 result;
110 if (secure)
111 {
112 result = wolfSSL_read(*(WOLFSSL**)firstParam, &buffer[cur], 1);
113 } else {
114 result = net_read(*(s32*)firstParam, &buffer[cur], 1);
115 }
116
117 if (result == -EAGAIN)
118 {
119 usleep(20 * 1000);
120
121 continue;
122 }
123
124 if (result <= 0)
125 {
126 break;
127 }
128
129 if ((cur > 0) && (buffer[cur-1] == '\r') && (buffer[cur] == '\n'))
130 {
131 buffer[cur-1] = 0;
132
133 return HTTPR_OK;
134 }
135
136 cur++;
137 startTime = gettime();
138 usleep(100);
139 }
140
141 return HTTPR_ERR_RECEIVE;
142}
143
144int submitToApi(
145 const char* endpoint,
146 WOLFSSL_CTX* sslContext,
147 cJSON* data,
148 const char* username,
149 const char* password)
150{
151 // Form request body.
152 cJSON* jRequestBody = cJSON_CreateObject();
153
154 cJSON_AddItemToObject(jRequestBody, "game", data);
155
156 cJSON_AddItemToObject(
157 jRequestBody,
158 "username",
159 cJSON_CreateString(username));
160
161 cJSON_AddItemToObject(
162 jRequestBody,
163 "password",
164 cJSON_CreateString(password));
165
166 const char* requestBody = cJSON_PrintUnformatted(jRequestBody);
167
168 // Gather data from endpoint URL.
169 char httpHost[64];
170 char httpPath[256];
171 int httpPort = 80;
172 bool secure = false;
173
174 if (!strncasecmp(endpoint, "https://", 8))
175 {
176 endpoint += 8;
177 secure = true;
178 httpPort = 443;
179 } else if (!strncasecmp(endpoint, "http://", 7))
180 {
181 endpoint += 7;
182 } else {
183 return 10;
184 }
185
186 char* solidus = strchr(endpoint, '/');
187 if ((solidus == NULL) || (solidus[0] == 0))
188 {
189 return 11;
190 }
191
192 char* colon = strchr(endpoint, ':');
193 if (colon != NULL)
194 {
195 snprintf(httpHost, colon - endpoint + 1, "%s", endpoint);
196 sscanf(colon + 1, "%d", &httpPort);
197 } else {
198 snprintf(httpHost, solidus - endpoint + 1, "%s", endpoint);
199 }
200
201 strcpy(httpPath, solidus);
202
203 // Connect to endpoint.
204 printf("Connecting...\n");
205
206 s32 socket = net_socket(PF_INET, SOCK_STREAM, IPPROTO_IP);
207 if (socket < 0)
208 {
209 return HTTPR_ERR_CONNECT;
210 }
211
212 if (!secure)
213 {
214 int result = net_fcntl(socket, F_GETFL, 0);
215 if (result < 0)
216 {
217 net_close(socket);
218
219 return HTTPR_ERR_CONNECT;
220 }
221
222 if (net_fcntl(socket, F_SETFL, result | IOS_O_NONBLOCK))
223 {
224 net_close(socket);
225
226 return HTTPR_ERR_CONNECT;
227 }
228 }
229
230 struct sockaddr_in sa;
231 memset(&sa, 0, sizeof(struct sockaddr_in));
232 sa.sin_family = PF_INET;
233 sa.sin_len = sizeof(struct sockaddr_in);
234 sa.sin_port = htons(httpPort);
235
236 struct in_addr inAddr;
237 if ((strlen(httpHost) < 16) && (inet_aton(httpHost, &inAddr)))
238 {
239 sa.sin_addr.s_addr = inAddr.s_addr;
240 } else {
241 struct hostent* hp = net_gethostbyname(httpHost);
242 if (!hp || (hp->h_addrtype != PF_INET))
243 {
244 return HTTPR_ERR_CONNECT;
245 }
246
247 memcpy(
248 (char*) &sa.sin_addr,
249 hp->h_addr_list[0],
250 hp->h_length);
251 }
252
253 u64 time1 = ticks_to_secs(gettime());
254 s32 connectResult;
255 do
256 {
257 connectResult = net_connect(
258 socket,
259 (struct sockaddr*) &sa,
260 sizeof(sa));
261
262 if (ticks_to_secs(gettime()) - time1 > TCP_CONNECT_TIMEOUT*1000)
263 {
264 break;
265 }
266 } while (connectResult != -EISCONN);
267
268 if (connectResult != -EISCONN)
269 {
270 net_close(socket);
271
272 return HTTPR_ERR_CONNECT;
273 }
274
275 // Initialize SSL, if necessary.
276 WOLFSSL* sslHandle = 0;
277 if (secure)
278 {
279 sslHandle = wolfSSL_new(sslContext);
280 if (sslHandle == NULL)
281 {
282 net_close(socket);
283
284 return HTTPR_ERR_SSL;
285 }
286
287 wolfSSL_set_fd(sslHandle, socket);
288 }
289
290 // Send request.
291 printf("Sending...\n");
292
293 void* firstParam = 0;
294
295 if (secure)
296 {
297 firstParam = &sslHandle;
298 } else {
299 firstParam = &socket;
300 }
301
302 char requestHeader[1024];
303 char* r = requestHeader;
304 r += sprintf(r, "POST %s HTTP/1.1\r\n", httpPath);
305 r += sprintf(r, "Host: %s\r\n", httpHost);
306 r += sprintf(r, "Content-Type: application/json\r\n");
307 r += sprintf(r, "Content-Length: %d\r\n\r\n", strlen(requestBody));
308
309 int result = tcpWrite(
310 secure,
311 firstParam,
312 (u8*) requestHeader,
313 strlen(requestHeader));
314 if (result != HTTPR_OK)
315 {
316 return result;
317 }
318
319 result = tcpWrite(
320 secure,
321 firstParam,
322 (u8*) requestBody,
323 strlen(requestBody));
324
325 if (result != HTTPR_OK)
326 {
327 return result;
328 }
329
330 // Read response.
331 char line[1024];
332 int httpStatus = 404;
333 while (!tcpRead(secure, firstParam, line, 1024))
334 {
335 if (!line[0])
336 {
337 break;
338 }
339
340 sscanf(line, "HTTP/1.%*u %u", &httpStatus);
341 }
342
343 if (httpStatus != 200)
344 {
345 return HTTPR_ERR_STATUS;
346 }
347
348 // Clean up.
349 if (secure)
350 {
351 wolfSSL_free(sslHandle);
352 }
353
354 net_close(socket);
355
356 cJSON_Delete(jRequestBody);
357
358 return HTTPR_OK;
359}