2 * Copyright (C) 2008 dhewg, #wiidev efnet
4 * this file is part of geckoloader
5 * http://wiibrew.org/index.php?title=Geckoloader
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
44 #define WIILOAD_VERSION_MAYOR 0
45 #define WIILOAD_VERSION_MINOR 5
47 #define LD_TCP_PORT 4299
49 #define MAX_ARGS_LEN 1024
55 typedef unsigned char u8
;
56 typedef unsigned short u16
;
57 typedef unsigned int u32
;
58 typedef unsigned long long u64
;
59 typedef signed char s8
;
60 typedef signed short s16
;
61 typedef signed int s32
;
62 typedef signed long long s64
;
64 typedef enum { false, true } bool;
67 static const char *desc_export
= "export";
69 static const char *desc_gecko
= "/dev/ttyUSB0";
71 static const char *desc_gecko
= "/dev/tty.usbserial-GECKUSB0";
74 static const char *desc_export
= "set";
75 static const char *desc_gecko
= "COM4";
78 static const char *envvar
= "WIILOAD";
80 static bool send_gecko (const char *dev
, const u8
*buf
, u32 len
, u32 len_un
,
81 const char *args
, u16 args_len
) {
86 if (gecko_open (dev
)) {
87 fprintf (stderr
, "unable to open the device '%s'\n", dev
);
91 printf ("sending upload request\n");
98 if (gecko_write (b
, 4)) {
100 fprintf (stderr
, "error sending data\n");
104 b
[0] = WIILOAD_VERSION_MAYOR
;
105 b
[1] = WIILOAD_VERSION_MINOR
;
106 b
[2] = (args_len
>> 8) & 0xff;
107 b
[3] = args_len
& 0xff;
109 if (gecko_write (b
, 4)) {
111 fprintf (stderr
, "error sending data\n");
115 printf ("sending file size (%u bytes)\n", len
);
117 b
[0] = (len
>> 24) & 0xff;
118 b
[1] = (len
>> 16) & 0xff;
119 b
[2] = (len
>> 8) & 0xff;
122 if (gecko_write (b
, 4)) {
124 fprintf (stderr
, "error sending data\n");
128 b
[0] = (len_un
>> 24) & 0xff;
129 b
[1] = (len_un
>> 16) & 0xff;
130 b
[2] = (len_un
>> 8) & 0xff;
131 b
[3] = len_un
& 0xff;
133 if (gecko_write (b
, 4)) {
135 fprintf (stderr
, "error sending data\n");
139 printf ("sending data");
150 if (gecko_write (p
, block
)) {
151 fprintf (stderr
, "error sending block\n");
163 printf ("sending arguments (%u bytes)\n", args_len
);
165 if (gecko_write ((u8
*) args
, args_len
)) {
176 static bool tcp_write (int s
, const u8
*buf
, u32 len
) {
183 block
= send (s
, p
, left
, 0);
186 perror ("send failed");
197 static bool send_tcp (const char *host
, const u8
*buf
, u32 len
, u32 len_un
,
198 const char *args
, u16 args_len
) {
199 struct sockaddr_in sa
;
208 if (WSAStartup (MAKEWORD(2,2), &wsa_data
)) {
209 printf ("WSAStartup failed\n");
214 memset (&sa
, 0, sizeof (sa
));
216 sa
.sin_addr
.s_addr
= inet_addr (host
);
218 if (sa
.sin_addr
.s_addr
== INADDR_NONE
) {
219 printf ("resolving %s\n", host
);
221 he
= gethostbyname (host
);
225 herror ("error resolving hostname");
227 fprintf (stderr
, "error resolving hostname\n");
232 if (he
->h_addrtype
!= AF_INET
) {
233 fprintf (stderr
, "unsupported address");
237 sa
.sin_addr
.s_addr
= *((u32
*) he
->h_addr
);
240 s
= socket (PF_INET
, SOCK_STREAM
, 0);
243 perror ("error creating socket");
247 sa
.sin_port
= htons (LD_TCP_PORT
);
248 sa
.sin_family
= AF_INET
;
250 printf ("connecting to %s:%d\n", inet_ntoa (sa
.sin_addr
), LD_TCP_PORT
);
252 if (connect (s
, (struct sockaddr
*) &sa
, sizeof (sa
)) == -1) {
253 perror ("error connecting");
258 printf ("sending upload request\n");
265 if (!tcp_write (s
, b
, 4)) {
270 b
[0] = WIILOAD_VERSION_MAYOR
;
271 b
[1] = WIILOAD_VERSION_MINOR
;
272 b
[2] = (args_len
>> 8) & 0xff;
273 b
[3] = args_len
& 0xff;
275 if (!tcp_write (s
, b
, 4)) {
280 printf ("sending file size (%u bytes)\n", len
);
282 b
[0] = (len
>> 24) & 0xff;
283 b
[1] = (len
>> 16) & 0xff;
284 b
[2] = (len
>> 8) & 0xff;
287 if (!tcp_write (s
, b
, 4)) {
292 b
[0] = (len_un
>> 24) & 0xff;
293 b
[1] = (len_un
>> 16) & 0xff;
294 b
[2] = (len_un
>> 8) & 0xff;
295 b
[3] = len_un
& 0xff;
297 if (!tcp_write (s
, b
, 4)) {
302 printf ("sending data");
310 if (block
> 4 * 1024)
314 if (!tcp_write (s
, p
, block
)) {
331 printf ("sending arguments (%u bytes)\n", args_len
);
333 if (!tcp_write (s
, (u8
*) args
, args_len
)) {
342 shutdown (s
, SD_SEND
);
350 static void usage (const char *argv0
) {
351 fprintf (stderr
, "set the environment variable %s to a valid "
357 "\t\t%s %s=tcp:wii\n"
358 "\t\t%s %s=tcp:192.168.0.30\n\n"
360 "\t%s <filename> <application arguments>\n\n",
362 desc_export
, envvar
, desc_gecko
,
369 int main (int argc
, char **argv
) {
373 bool compress
= true;
380 char args
[MAX_ARGS_LEN
];
382 u16 args_len
, args_left
;
386 printf ("wiiload v%u.%u\n"
387 "coded by dhewg, #wiidev efnet\n\n",
388 WIILOAD_VERSION_MAYOR
, WIILOAD_VERSION_MINOR
);
393 ev
= getenv (envvar
);
397 fd
= open (argv
[1], O_RDONLY
| O_BINARY
);
399 perror ("error opening the file");
403 if (fstat (fd
, &st
)) {
405 perror ("error stat'ing the file");
411 if (fsize
< 512 || fsize
> 20 * 1024 * 1024) {
413 fprintf (stderr
, "error: invalid file size\n");
417 buf
= malloc (fsize
);
420 fprintf (stderr
, "out of memory\n");
424 if (read (fd
, buf
, fsize
) != fsize
) {
427 perror ("error reading the file");
435 if (!memcmp(buf
, "PK\x03\x04", 4))
439 bufzlen
= (uLongf
) ((float) fsize
* 1.02);
441 bufz
= malloc (bufzlen
);
443 fprintf (stderr
, "out of memory\n");
447 printf("compressing %u bytes...", (u32
) fsize
);
450 res
= compress2 (bufz
, &bufzlen
, buf
, fsize
, 6);
454 fprintf (stderr
, "error compressing data: %d\n", res
);
458 if (bufzlen
< (u32
) fsize
) {
459 printf(" %.2f%%\n", 100.0f
* (float) bufzlen
/ (float) fsize
);
466 printf(" compressed size gained size, discarding\n");
474 args_left
= MAX_ARGS_LEN
;
476 c
= snprintf (arg_pos
, args_left
, "%s", basename (argv
[1]));
481 for (i
= 2; i
< argc
; ++i
) {
482 c
= snprintf (arg_pos
, args_left
, "%s", argv
[i
]);
484 if (c
>= args_left
) {
486 fprintf (stderr
, "argument string too long\n");
496 fprintf (stderr
, "argument string too long\n");
502 args_len
= MAX_ARGS_LEN
- args_left
+ 1;
504 if (strncmp (ev
, "tcp:", 4)) {
508 res
= send_gecko (ev
, buf
, len
, len_un
, args
, args_len
);
513 res
= send_tcp (&ev
[4], buf
, len
, len_un
, args
, args_len
);
519 printf ("transfer failed.\n");