1 /*---------------------------------------------------------------------------*
2   Project:  WiiConnect24
3   File:     Download.c
4 
5   Copyright 2007 Nintendo. All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law. They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Log: Download.c,v $
14   Revision 1.6  2008/08/27 02:51:42  adachi_hiroaki
15   Revised comments.
16 
17   Revision 1.5  2008/07/30 02:09:41  adachi_hiroaki
18   Added support for NANDCheck.
19 
20   Revision 1.4  2008/03/10 00:30:46  adachi_hiroaki
21   Removed notes.
22 
23   Revision 1.3  2008/03/10 00:15:42  adachi_hiroaki
24   Added a note about the overhead of VF archives.
25 
26   Revision 1.2  2007/11/30 08:49:07  adachi_hiroaki
27   Changed the priority that is set.
28 
29   Revision 1.1  2007/06/07 06:06:39  adachi_hiroaki
30   Added a demo of the download feature.
31 
32 
33  *---------------------------------------------------------------------------*/
34 
35 /*---------------------------------------------------------------------------*
36 
37  *---------------------------------------------------------------------------*/
38 
39 #include <string.h>
40 #include <revolution/os.h>
41 #include <revolution/mem.h>
42 #include <revolution/nand.h>
43 #include <revolution/net.h>
44 #include <revolution/vf.h>
45 #include <revolution/nwc24.h>
46 #include <revolution/nwc24/NWC24Dl.h>
47 
48 /*---------------------------------------------------------------------------*
49     Macros
50  *---------------------------------------------------------------------------*/
51 
52 #define VERIFY_NWC24ERR(err, expected)      ASSERTMSG( err == expected, "unexpected error code: %d", err )
53 
54 #define URL             "http://nintendo/file.bin"
55 
56 #define DRIVE           "C"
57 #define SIZE_VF         (500*1024)
58 
59 /* Force simulation of the initial run (it is best to initialize the task list with nwc24init.elf) */
60 #define SIMULATE_FIRSTRUN
61 
62 /* Do not use a signature */
63 #define NOSIGN
64 
65 /* Use the public key prepared by the application */
66 //#define USE_MYPUBLICKEY
67 
68 BOOL DownloadTaskMain( void );
69 
70 /*---------------------------------------------------------------------------*
71     Static Data
72  *---------------------------------------------------------------------------*/
73 
74 /* The application's public key is specified here. It is easiest to use makeo */
75 static u8 publicKey[] =
76 {
77     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
78     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
79     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
80     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
81     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
82     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
83     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
84     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
85     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
86     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
87     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
88     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
89     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
90     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
91     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
92     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
93     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
94     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
95     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
96     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
97     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
98     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
99     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
100     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
101     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
102     0x00, 0x00, 0x00, 0x00, 0x00, 0x00
103 };
104 
105 /*---------------------------------------------------------------------------*
106     Forward references to local functions
107  *---------------------------------------------------------------------------*/
108 static void SetProperty( NWC24DlTask* task );
109 static NWC24Err UpdateTask( NWC24DlTask* task );
110 static BOOL CheckVf( NWC24DlTask* task, NWC24Err* nwc24Err, VFErr* vfErr );
111 static u32 GetFsBlock(s32 sizeByte);
112 
main()113 int main()
114 {
115     OSReport("*******************************************************\n");
116     OSReport("    WiiConnect24 download sample\n");
117     OSReport("*******************************************************\n");
118     VFInit();
119     if (DownloadTaskMain())
120     {
121         OSReport("==== Waiting... ====\n");
122         OSSleepSeconds(60*5);
123 
124         (void) DownloadTaskMain();
125     }
126     else
127     {
128         OSReport("NG\n");
129     }
130     OSHalt("Finished.\n");
131     return 0;
132 }
133 
DownloadTaskMain(void)134 BOOL DownloadTaskMain( void )
135 {
136     static u32  libWorkMem[NWC24_WORK_MEM_SIZE/sizeof(u32)] ATTRIBUTE_ALIGN(32);
137 
138     NWC24Err    err     = NWC24_OK;
139     NWC24Err    err2    = NWC24_OK;
140     VFErr       vfErr   = VF_ERR_SUCCESS;
141     NWC24DlTask dlTask;
142 
143     /*
144        Ease the restrictions on the parameters for the sake of debugging
145        (Incorporating this into products is prohibited)
146      */
147     NWC24EnableDlLaxParameterChecking(TRUE);
148 
149     /*
150        Reduce the scheduler interval to make the downloads happen earlier
151        (Incorporating this into products is prohibited)
152      */
153     (void) NWC24SetScheduleSpan(10, 1);
154 
155     err = NWC24OpenLib(&libWorkMem);
156     if (err < NWC24_OK)
157     {
158         return FALSE;
159     }
160 
161     /* Update the task */
162     err = UpdateTask(&dlTask);
163 
164     if (err < NWC24_OK)
165     {
166         goto close;
167     }
168 
169     /* Display the task's content to the console */
170     (void) NWC24DumpDlTask(&dlTask);
171 
172     /* Check that the content was downloaded */
173     if (CheckVf(&dlTask, &err, &vfErr))
174     {
175         OSReport("a new content was found.\n");
176     }
177 
178 
179 close:
180     err2 = NWC24CloseLib();
181     return err == NWC24_OK;
182 }
183 
UpdateTask(NWC24DlTask * task)184 static NWC24Err UpdateTask( NWC24DlTask* task )
185 {
186     NWC24Err    err;
187     u16         myId    = 0;
188 
189     /*
190        Get the tasks that have already been registered. Register again if it failed
191 
192        Note: This function cannot be used when a single application registers two or more tasks
193 
194           The application must save each task ID and get the tasks using NWC24GetDlTask()
195 
196      */
197 #ifndef SIMULATE_FIRSTRUN
198     err = NWC24GetDlTaskMine( task );
199 #else
200     err = NWC24_ERR_NOT_FOUND;
201 #endif
202     if (err == NWC24_ERR_NOT_FOUND)
203     {
204         /*
205            The task was deleted, either because it had not been registered or had expired, and must be recreated
206 
207          */
208 
209         /* Create a new binary data receiving-type task */
210         err = NWC24InitDlTask(task, NWC24_DLTYPE_OCTETSTREAM);
211         if (err < NWC24_OK)
212         {
213             return err;
214         }
215         /*
216            If the task was newly created, configure the required items
217          */
218         SetProperty( task );
219     }
220     else if (err < NWC24_OK)
221     {
222         return err;
223     }
224 
225     /*
226        Specify the number of remaining downloads
227        Each time a download is done, the number is decreased by one; when it reaches zero, the task is removed
228        For this reason, it is necessary to restore the value each time the application is run in order to prevent the task from being removed
229      */
230     err = NWC24SetDlCount( task, 50 );
231     if (err < NWC24_OK)
232     {
233         return err;
234     }
235 
236     /*
237        Register the task data in the task list
238      */
239     err = NWC24AddDlTask(task);
240     if (err < NWC24_OK)
241     {
242         return err;
243     }
244     return NWC24_OK;
245 }
246 
247 
SetProperty(NWC24DlTask * task)248 static void SetProperty( NWC24DlTask* task )
249 {
250     NWC24Err    err;
251     u32         flags = 0;
252     /* Specify the URL */
253     err = NWC24SetDlUrl( task, URL );
254     VERIFY_NWC24ERR( err, NWC24_OK );
255 
256     /*
257        Specify the priority. Tasks will be run with priority given to those with lower values
258        The values should be set following the guidelines
259      */
260     err = NWC24SetDlPriority( task, 192 );
261     VERIFY_NWC24ERR( err, NWC24_OK );
262 
263     /*
264        Specify the execution interval of the download task
265        Note that task execution will not necessarily be performed in this interval
266      */
267     err = NWC24SetDlInterval( task, 1 );
268     VERIFY_NWC24ERR( err, NWC24_OK );
269 
270     /*
271        Specify the filename when storing in VF
272      */
273     err = NWC24SetDlFilename(task, "file.dat");
274     VERIFY_NWC24ERR( err, NWC24_OK );
275 
276 #ifdef USE_MYPUBLICKEY
277     flags |= NWC24_DL_FLAG_USE_MYPUBLICKEY;
278 #endif
279 
280     /*
281        Specify to download unsigned content without any further processing
282        If parameter checking has been disabled for tasks, this cannot be used for http:// URLs
283      */
284 #ifdef NOSIGN
285     flags |= NWC24_DL_FLAG_RAW_CONTENT;
286 #endif
287 
288     err = NWC24SetDlFlags(task, flags);
289     VERIFY_NWC24ERR( err, NWC24_OK );
290 
291 }
292 
GetFsBlock(s32 sizeByte)293 static u32 GetFsBlock(s32 sizeByte)
294 {
295     ASSERT(sizeByte > 0);
296     if ((sizeByte % NAND_FSBLOCK_SIZE) == 0)
297     {
298         return (u32)(sizeByte / NAND_FSBLOCK_SIZE);
299     }
300     else
301     {
302         return (u32)(sizeByte / NAND_FSBLOCK_SIZE + 1);
303     }
304 }
305 
CheckVf(NWC24DlTask * task,NWC24Err * nwc24Err,VFErr * vfErr)306 static BOOL CheckVf( NWC24DlTask* task, NWC24Err* nwc24Err, VFErr* vfErr )
307 {
308     VFFile*     vfFile = NULL;
309     BOOL        create = TRUE;
310     BOOL        result = FALSE;
311     char        bufVfName[NAND_MAX_PATH];
312     char        bufVfContentName[VF_PATH_BUF_SIZE];
313 
314     /* Load the content that was obtained using the VF library */
315 
316     /* Get the VFF filename */
317     *nwc24Err = NWC24GetDlVfName(task, bufVfName, sizeof(bufVfName));
318     VERIFY_NWC24ERR( *nwc24Err, NWC24_OK );
319 
320     /* Get the filename of the content that was saved within VFF */
321     *nwc24Err = NWC24GetDlFilename(task, bufVfContentName, sizeof(bufVfContentName));
322     VERIFY_NWC24ERR( *nwc24Err, NWC24_OK );
323 
324     OSReport("VF archive = %s\n", bufVfName);
325 
326     /* Mount */
327     *vfErr = VFMountDriveNANDFlash( DRIVE, bufVfName );
328     if (*vfErr == VF_ERR_SUCCESS)
329     {
330         vfFile = VFOpenFile(bufVfContentName, "r", 0);
331         if ( vfFile )
332         {
333             /* Load the content that was downloaded here */
334             {
335                 s32 length = 0;
336                 length = VFGetFileSizeByFd( vfFile );
337                 OSReport("filename = %s, size = %d\n", bufVfContentName, length);
338 
339                /*
340                   To determine if received content is new, it is necessary to embed the sequence number, creation date, and other information in said content and then compare this information with what was previously received
341 
342 
343                 */
344             }
345             (void)VFCloseFile( vfFile );
346 
347             /* If subsequent files are not required, delete them */
348             *vfErr = VFDeleteFile(bufVfContentName);
349             result = TRUE;
350             create = FALSE;
351         }
352         else
353         {
354             result = FALSE;
355             /* Find out the reason that the file failed to open */
356             *vfErr = VFGetLastError();
357             if (*vfErr == VF_ERR_ENOENT)
358             {
359                 /* The file simply does not exist. Recreating VFF is not necessary */
360                 create = FALSE;
361             }
362             else
363             {
364                 /* There is a chance that the VFF file is corrupted. Recreate it just in case */
365                 create = TRUE;
366             }
367         }
368         (void)VFUnmountDrive( DRIVE );
369     }
370     else
371     {
372         result = FALSE;
373         create = TRUE;
374     }
375 
376     /*
377        If the VFF file needs to be recreated, do so together with files under the home directory
378 
379      */
380     if (create)
381     {
382         s32 checkResult = 0;
383         u32 answer = 0;
384 
385         /* Prepare by deleting all files below the home directory */
386         (void)NANDDelete(bufVfName);
387         (void)NWC24ClearDlKeys();
388 
389         /*
390            Before creating the files, do a check with NANDCheck()
391            If you will use NWC24SetDlKeys(), the key file must also be checked
392            (The key file uses 1 FS block and consumes 1 inode)
393          */
394         checkResult = NANDCheck(GetFsBlock(SIZE_VF) + 1, 2, &answer);
395         if (checkResult != NAND_RESULT_OK
396             || answer != 0)
397         {
398             /* Follow the NANDCheck processing sequence */
399             return FALSE;
400         }
401 
402         /*
403            Prepare a 500 KB VF archive as the destination for storing the download file
404            The FAT region is included in the 500 KB, so the actual downloadable size is approximately 490 KB
405         */
406         *nwc24Err = NWC24CreateDlVf(task, SIZE_VF);
407         if (*nwc24Err < NWC24_OK)
408         {
409             /* If creation failed, handle it in the same way as you would if save data creation failed */
410             return FALSE;
411         }
412 
413         *nwc24Err = NWC24SetDlKeys(publicKey, NULL);
414         if (*nwc24Err < NWC24_OK)
415         {
416             /* If configuration failed, handle it in the same way as you would if save data creation failed */
417             return FALSE;
418         }
419     }
420     return result;
421 }
422 
423 #if 0
424 static void CheckErrors( NWC24DlTask* task )
425 {
426     NWC24Err    err;
427     int         globalErr = 0, count = 0;
428 
429     /* Get the error that occurred when the task was running */
430     err = NWC24GetDlError( task, &globalErr, &count );
431     VERIFY_NWC24ERR( err, NWC24_OK );
432 
433     if (count > 0 && globalErr != 0)
434     {
435         /* Handle errors */
436         OSReport("error %d\n", globalErr);
437 
438         /* Clear error information stored in the task */
439         (void) NWC24ClearDlError( task );
440     }
441 }
442 #endif
443 
444 /*---------------------------------------------------------------------------*/
445 
446 /*---------------------------------------------------------------------------*/
447