You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

downloader.c 7.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. /*
  2. * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License as
  6. * published by the Free Software Foundation; either version 2 of the
  7. * License, or any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. */
  18. FILE_LICENCE ( GPL2_OR_LATER );
  19. #include <stdlib.h>
  20. #include <stdarg.h>
  21. #include <errno.h>
  22. #include <gpxe/xfer.h>
  23. #include <gpxe/open.h>
  24. #include <gpxe/job.h>
  25. #include <gpxe/uaccess.h>
  26. #include <gpxe/umalloc.h>
  27. #include <gpxe/image.h>
  28. #include <gpxe/downloader.h>
  29. /** @file
  30. *
  31. * Image downloader
  32. *
  33. */
  34. /** A downloader */
  35. struct downloader {
  36. /** Reference count for this object */
  37. struct refcnt refcnt;
  38. /** Job control interface */
  39. struct job_interface job;
  40. /** Data transfer interface */
  41. struct xfer_interface xfer;
  42. /** Image to contain downloaded file */
  43. struct image *image;
  44. /** Current position within image buffer */
  45. size_t pos;
  46. /** Image registration routine */
  47. int ( * register_image ) ( struct image *image );
  48. };
  49. /**
  50. * Free downloader object
  51. *
  52. * @v refcnt Downloader reference counter
  53. */
  54. static void downloader_free ( struct refcnt *refcnt ) {
  55. struct downloader *downloader =
  56. container_of ( refcnt, struct downloader, refcnt );
  57. image_put ( downloader->image );
  58. free ( downloader );
  59. }
  60. /**
  61. * Terminate download
  62. *
  63. * @v downloader Downloader
  64. * @v rc Reason for termination
  65. */
  66. static void downloader_finished ( struct downloader *downloader, int rc ) {
  67. /* Block further incoming messages */
  68. job_nullify ( &downloader->job );
  69. xfer_nullify ( &downloader->xfer );
  70. /* Free resources and close interfaces */
  71. xfer_close ( &downloader->xfer, rc );
  72. job_done ( &downloader->job, rc );
  73. }
  74. /**
  75. * Ensure that download buffer is large enough for the specified size
  76. *
  77. * @v downloader Downloader
  78. * @v len Required minimum size
  79. * @ret rc Return status code
  80. */
  81. static int downloader_ensure_size ( struct downloader *downloader,
  82. size_t len ) {
  83. userptr_t new_buffer;
  84. /* If buffer is already large enough, do nothing */
  85. if ( len <= downloader->image->len )
  86. return 0;
  87. DBGC ( downloader, "Downloader %p extending to %zd bytes\n",
  88. downloader, len );
  89. /* Extend buffer */
  90. new_buffer = urealloc ( downloader->image->data, len );
  91. if ( ! new_buffer ) {
  92. DBGC ( downloader, "Downloader %p could not extend buffer to "
  93. "%zd bytes\n", downloader, len );
  94. return -ENOBUFS;
  95. }
  96. downloader->image->data = new_buffer;
  97. downloader->image->len = len;
  98. return 0;
  99. }
  100. /****************************************************************************
  101. *
  102. * Job control interface
  103. *
  104. */
  105. /**
  106. * Handle kill() event received via job control interface
  107. *
  108. * @v job Downloader job control interface
  109. */
  110. static void downloader_job_kill ( struct job_interface *job ) {
  111. struct downloader *downloader =
  112. container_of ( job, struct downloader, job );
  113. /* Terminate download */
  114. downloader_finished ( downloader, -ECANCELED );
  115. }
  116. /** Downloader job control interface operations */
  117. static struct job_interface_operations downloader_job_operations = {
  118. .done = ignore_job_done,
  119. .kill = downloader_job_kill,
  120. .progress = ignore_job_progress,
  121. };
  122. /****************************************************************************
  123. *
  124. * Data transfer interface
  125. *
  126. */
  127. /**
  128. * Handle deliver_raw() event received via data transfer interface
  129. *
  130. * @v xfer Downloader data transfer interface
  131. * @v iobuf Datagram I/O buffer
  132. * @v meta Data transfer metadata
  133. * @ret rc Return status code
  134. */
  135. static int downloader_xfer_deliver_iob ( struct xfer_interface *xfer,
  136. struct io_buffer *iobuf,
  137. struct xfer_metadata *meta ) {
  138. struct downloader *downloader =
  139. container_of ( xfer, struct downloader, xfer );
  140. size_t len;
  141. size_t max;
  142. int rc;
  143. /* Calculate new buffer position */
  144. if ( meta->whence != SEEK_CUR )
  145. downloader->pos = 0;
  146. downloader->pos += meta->offset;
  147. /* Ensure that we have enough buffer space for this data */
  148. len = iob_len ( iobuf );
  149. max = ( downloader->pos + len );
  150. if ( ( rc = downloader_ensure_size ( downloader, max ) ) != 0 )
  151. goto done;
  152. /* Copy data to buffer */
  153. copy_to_user ( downloader->image->data, downloader->pos,
  154. iobuf->data, len );
  155. /* Update current buffer position */
  156. downloader->pos += len;
  157. done:
  158. free_iob ( iobuf );
  159. return rc;
  160. }
  161. /**
  162. * Handle close() event received via data transfer interface
  163. *
  164. * @v xfer Downloader data transfer interface
  165. * @v rc Reason for close
  166. */
  167. static void downloader_xfer_close ( struct xfer_interface *xfer, int rc ) {
  168. struct downloader *downloader =
  169. container_of ( xfer, struct downloader, xfer );
  170. /* Register image if download was successful */
  171. if ( rc == 0 )
  172. rc = downloader->register_image ( downloader->image );
  173. /* Terminate download */
  174. downloader_finished ( downloader, rc );
  175. }
  176. /** Downloader data transfer interface operations */
  177. static struct xfer_interface_operations downloader_xfer_operations = {
  178. .close = downloader_xfer_close,
  179. .vredirect = xfer_vreopen,
  180. .window = unlimited_xfer_window,
  181. .alloc_iob = default_xfer_alloc_iob,
  182. .deliver_iob = downloader_xfer_deliver_iob,
  183. .deliver_raw = xfer_deliver_as_iob,
  184. };
  185. /****************************************************************************
  186. *
  187. * Instantiator
  188. *
  189. */
  190. /**
  191. * Instantiate a downloader
  192. *
  193. * @v job Job control interface
  194. * @v image Image to fill with downloaded file
  195. * @v register_image Image registration routine
  196. * @v type Location type to pass to xfer_open()
  197. * @v ... Remaining arguments to pass to xfer_open()
  198. * @ret rc Return status code
  199. *
  200. * Instantiates a downloader object to download the specified URI into
  201. * the specified image object. If the download is successful, the
  202. * image registration routine @c register_image() will be called.
  203. */
  204. int create_downloader ( struct job_interface *job, struct image *image,
  205. int ( * register_image ) ( struct image *image ),
  206. int type, ... ) {
  207. struct downloader *downloader;
  208. va_list args;
  209. int rc;
  210. /* Allocate and initialise structure */
  211. downloader = zalloc ( sizeof ( *downloader ) );
  212. if ( ! downloader )
  213. return -ENOMEM;
  214. downloader->refcnt.free = downloader_free;
  215. job_init ( &downloader->job, &downloader_job_operations,
  216. &downloader->refcnt );
  217. xfer_init ( &downloader->xfer, &downloader_xfer_operations,
  218. &downloader->refcnt );
  219. downloader->image = image_get ( image );
  220. downloader->register_image = register_image;
  221. va_start ( args, type );
  222. /* Instantiate child objects and attach to our interfaces */
  223. if ( ( rc = xfer_vopen ( &downloader->xfer, type, args ) ) != 0 )
  224. goto err;
  225. /* Attach parent interface, mortalise self, and return */
  226. job_plug_plug ( &downloader->job, job );
  227. ref_put ( &downloader->refcnt );
  228. va_end ( args );
  229. return 0;
  230. err:
  231. downloader_finished ( downloader, rc );
  232. ref_put ( &downloader->refcnt );
  233. va_end ( args );
  234. return rc;
  235. }