Scarica il sorgente pastebin/http_download_v0.01.04.cpp
  1. #include "http_download.h"
  2.  
  3. http_download::http_download(){
  4.  
  5. file_size = 0;
  6. buffer_size = 0;
  7. multidownload = 0;
  8. status = HD_STATUS_UNINITIALIZED;
  9.  
  10. is_range_accepted = 0;
  11. is_size_comunicated = 0;
  12.  
  13. //variabili di comunicazione interna
  14. luncher_ready_to_pause = 0;
  15. luncher_ready_to_stop = 0;
  16. vanilla_ready_to_stop = 0;
  17.  
  18. }
  19.  
  20. http_download::~http_download(){
  21.  
  22. }
  23.  
  24. int http_download::initialize(char *_url, char *_file, int _multidownload){
  25.  
  26. int x;
  27.  
  28. if(status != HD_STATUS_UNINITIALIZED)
  29. return 0;
  30. if(_multidownload<0)
  31. return 0;
  32.  
  33. //url
  34. strncpy(url, _url, strlen(_url)+1);
  35.  
  36. //file
  37. strncpy(file, _file, strlen(_file)+1);
  38.  
  39. //host
  40. for(x=7; x<(int)strlen(_url) ;x++)
  41. if(_url[x] == '/'){
  42. break;
  43. }
  44. strncpy(host, &url[7], x-7);
  45. host[x-7] = '\0';
  46.  
  47. //host_url
  48. strncpy(host_url, &url[x], strlen(_url)-x+1);
  49. host_url[strlen(_url)-x+1] = '\0';
  50.  
  51. //multidownload
  52. multidownload = _multidownload;
  53.  
  54. //porta http
  55. porta = HD_HTTP_DEFAULT_PORT;
  56.  
  57. //download buffer size
  58. buffer_size = HD_DOWNLOAD_BUFFER_DEFAULT_SIZE;
  59.  
  60. //aggiornamento status
  61. status = HD_STATUS_INITIALIZED;
  62.  
  63. return 1;
  64. }
  65.  
  66. int http_download::settings(long _buffer_size, int _porta_http){
  67.  
  68. if(status == HD_STATUS_INITIALIZED){
  69.  
  70. if(_buffer_size != 0)
  71. buffer_size = _buffer_size;
  72.  
  73. if(_porta_http != 0)
  74. porta = _porta_http;
  75.  
  76. return 1;
  77.  
  78. }
  79. else{
  80. #ifdef DEBUG_MODE
  81. printf("ERROR settings(): l'oggetto non è nello status HD_STATUS_INITIALIZED\n");
  82. #endif
  83.  
  84. return 0;
  85. }
  86.  
  87. }
  88.  
  89. int http_download::start(){
  90.  
  91. long x;
  92. DWORD thread_id;
  93.  
  94. //controllo dello status (che deve essere HD_STATUS_INITIALIZED) prima di procedere
  95. if(status != HD_STATUS_INITIALIZED){
  96. #ifdef DEBUG_MODE
  97. printf("ERROR start(): You are not in the right status.\n");
  98. #endif
  99. return 0;
  100. }
  101.  
  102. /*ci connettiamo al server con la funzione hd_connessione_asincrona_header per ricevere
  103. info sul file e controllare che effettivamente esista, il ciclo serve per seguire le
  104. redirezioni (302 found) fino a quando non si trova il vero indirizzo*/
  105. while(status == HD_STATUS_FILE_REDIRECTED || status == HD_STATUS_INITIALIZED){
  106.  
  107. hd_connessione_header(this);
  108.  
  109. //controlliamo i possibili errori
  110. if(status == HD_STATUS_PROTOCOL_NOT_HTTP11){
  111. #ifdef DEBUG_MODE
  112. printf("ERROR: HD_STATUS_PROTOCOL_NOT_HTTP11\n");
  113. #endif
  114. return 0;
  115. }
  116. if(status == HD_STATUS_FILE_NOT_FOUND){
  117. #ifdef DEBUG_MODE
  118. printf("HTTP PROTOCOL 404: HD_STATUS_FILE_NOT_FOUND\n");
  119. #endif
  120. return 0;
  121. }
  122. if(status == HD_STATUS_HTTP_CODE_NOT_RECOGNIZED){
  123. #ifdef DEBUG_MODE
  124. printf("ERROR: HD_STATUS_HTTP_CODE_NOT_RECOGNIZED\n");
  125. #endif
  126. return 0;
  127. }
  128.  
  129. }
  130.  
  131. /*se il server ci ha comuncato la grandezza del file da scaricare allora controlliamo
  132. se il server accetta il range, se lo accetta procediamo al multidownload e possibilità
  133. di pausa, se non lo accetta allora dobbiamo fare un download normale*/
  134. if(is_size_comunicated){
  135. #ifdef DEBUG_MODE
  136. printf("start(): File size: %d bytes\n",file_size);
  137. #endif
  138.  
  139. /*il server non ci ha comunicato di accettare i range, ma non tutte le speranze sono perdute
  140. perche il server non è obbligato a comunicarci la disponibilità del servizio: possiamo
  141. inviare al server una richiesta con range per vedere se il servizio effettivamente esiste*/
  142. if(!is_range_accepted){
  143.  
  144. //inviamo una richiesta con range sperando di rivere un 206 PARTIAL CONTENT
  145. hd_connessione_header_partial_content(this);
  146.  
  147. }
  148.  
  149. /*se il server accetta il range-bytes allora possiamo spezzare il download in piu segmenti*/
  150. if(is_range_accepted){ //range accettato
  151. #ifdef DEBUG_MODE
  152. printf("start(): Accept-Ranges: bytes\n");
  153. #endif
  154.  
  155. //prepariamo matrice dati per il multidownload
  156. multidownload_points.create_with_value(multidownload+1, 3, 0);
  157. for(x=0; x<multidownload; x++){
  158. multidownload_points[x][0] = (file_size/multidownload)*x; //impostiamo punto di partenza segmento
  159. multidownload_points[x][1] = multidownload_points[x][0]; //impostiamo punto attuale del segmento
  160. }
  161. multidownload_points[multidownload][0] = file_size;
  162.  
  163. #ifdef DEBUG_MODE
  164. printf("start(): multidownload possibile, segmenti %d\n", multidownload);
  165. #endif
  166.  
  167. if(multidownload == 0)
  168. //se è preteso, avviamo un download normale, senza multidownload ne pausa
  169. CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) hd_connessione_download_vanilla, this, 0, &thread_id);
  170. else
  171. //avviamo in modo asincrono la funzione che si occuperà di avviare il multidownload
  172. CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) hd_multidownload_luncher, this, 0, &thread_id);
  173.  
  174. }
  175. else{ //range non accettato
  176.  
  177. //senza range, avviamo un download normale, senza multidownload ne pausa
  178. CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) hd_connessione_download_vanilla, this, 0, &thread_id);
  179.  
  180. }
  181. }
  182. else{ //file size non comunicato
  183. #ifdef DEBUG_MODE
  184. printf("start(): File size not comunicated :(\n",file_size);
  185. #endif
  186.  
  187. //senza grandezza file, avviamo un download normale, senza multidownload ne pausa
  188. CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) hd_connessione_download_vanilla, this, 0, &thread_id);
  189.  
  190. }
  191.  
  192. return 1;
  193. }
  194.  
  195. int http_download::stop(){
  196. long x,y;
  197.  
  198. if(status == HD_STATUS_DOWNLOADING){
  199. status = HD_STATUS_STOPPED;
  200.  
  201. while(!vanilla_ready_to_stop)
  202. Sleep(10);
  203. vanilla_ready_to_stop = 0;
  204.  
  205. //qui devo cancellare il file dove sono stati scaricati i dati
  206.  
  207. status = HD_STATUS_UNINITIALIZED;
  208.  
  209. return 1;
  210. }
  211. else if(status == HD_STATUS_MULTIDOWNLOADING || status == HD_STATUS_PAUSED
  212. || status == HD_STATUS_SAVED){
  213. status = HD_STATUS_STOPPED;
  214.  
  215. //controlliamo ed eventualmente aspettiamo che i download parziali siano tutti terminati
  216. while(1){
  217. y=0;
  218. for(x=0;x<multidownload;x++)
  219. if(multidownload_points[x][2] == 0)
  220. y++;
  221. if(y==multidownload)
  222. break;
  223. Sleep(10);
  224. }
  225.  
  226. //aspettiamo che luncher abbia ricevuto il segnale
  227. while(1){
  228. if(luncher_ready_to_stop == 1)
  229. break;
  230. Sleep(10);
  231. } luncher_ready_to_stop = 0;
  232.  
  233. //togliamo le cose che vanno tolte e resettiamo alcune variabili
  234. multidownload_points.~matrice();
  235. file_size = 0;
  236. is_range_accepted = 0;
  237. is_size_comunicated = 0;
  238.  
  239. luncher_ready_to_pause = 0;
  240. luncher_ready_to_stop = 0;
  241. vanilla_ready_to_stop = 0;
  242.  
  243. /*qui si dovranno cancellare i file temporanei, ma se si è in stato
  244. HD_STATUS_SAVED vanno lasciati ;)*/
  245.  
  246. status = HD_STATUS_INITIALIZED;
  247.  
  248. return 1;
  249. }
  250. else{
  251. #ifdef DEBUG_MODE
  252. printf("stop(): non puo essere usato se non si sta scaricando\n",file_size);
  253. #endif
  254. return 0;
  255. }
  256. }
  257.  
  258. int http_download::pause(){
  259.  
  260. if(status != HD_STATUS_MULTIDOWNLOADING){
  261. #ifdef DEBUG_MODE
  262. printf("pause(): puo essere usata solo in stato HD_STATUS_MULTIDOWNLOADING\n",file_size);
  263. #endif
  264. return 0;
  265. }
  266.  
  267. status = HD_STATUS_PAUSED;
  268.  
  269. while(!luncher_ready_to_pause)
  270. Sleep(50);
  271.  
  272. #ifdef DEBUG_MODE
  273. printf("pause(): pausa bloccante avvenuta con successo.\n");
  274. #endif
  275.  
  276. return 1;
  277. }
  278.  
  279. int http_download::resume(){
  280.  
  281. if(status != HD_STATUS_PAUSED){
  282. #ifdef DEBUG_MODE
  283. printf("resume(): puo essere usata solo in stato HD_STATUS_PAUSED\n",file_size);
  284. #endif
  285. return 0;
  286. }
  287.  
  288. status = HD_STATUS_RESUME;
  289.  
  290. return 1;
  291. }
  292.  
  293. int http_download::save(){
  294. long x,y;
  295.  
  296. char *_file_matrice;
  297. char *_main_content;
  298. FILE *main;
  299.  
  300. /*la funzione save() è possibile solo nello stato HD_STATUS_PAUSED*/
  301. if(status != HD_STATUS_PAUSED){
  302. #ifdef DEBUG_MODE
  303. printf("save(): puo essere usata solo in stato HD_STATUS_PAUSED\n",file_size);
  304. #endif
  305. return 0;
  306. }
  307. //controlliamo ed eventualmente aspettiamo che i download parziali siano tutti terminati
  308. while(1){
  309. y=0;
  310. for(x=0;x<multidownload;x++)
  311. if(multidownload_points[x][2] == 0)
  312. y++;
  313. if(y==multidownload)
  314. break;
  315. Sleep(10);
  316. }
  317.  
  318. //salviamo la matrice multidownload_points
  319. _file_matrice = new char[10000];
  320. sprintf(_file_matrice,"%s.points",file);
  321. multidownload_points.save_in_file(_file_matrice);
  322.  
  323. //salviamo i dati principali
  324. _main_content = new char[100000];
  325.  
  326. main = fopen(file, "wb");
  327.  
  328. //scriviamo magic number
  329. fwrite("HD_FILE\0", 1, 8, main);
  330. //scriviamo url
  331. fwrite(url, 1, strlen(url)+1, main);
  332. //scriviamo porta
  333. itoa(porta, _file_matrice, 10); //utilizziamo _file_matrice come buffer visto che non ci serve piu ;)
  334. fwrite(_file_matrice, 1, strlen(_file_matrice)+1, main);
  335.  
  336. fclose(main);
  337.  
  338. delete [] _file_matrice;
  339. delete [] _main_content;
  340.  
  341. status = HD_STATUS_SAVED;
  342.  
  343. //alla fine del salvataggio stoppiamo il download
  344. stop();
  345.  
  346. return 1;
  347. }
  348.  
  349. int http_download::load(char *_load_file){
  350. long x,y;
  351.  
  352. char *_load_file_matrice;
  353. char *_url;
  354. char *_porta;
  355.  
  356. FILE *load_file_stream;
  357. char *buffer;
  358. long lbuffer;
  359.  
  360. if(status != HD_STATUS_UNINITIALIZED){
  361. #ifdef DEBUG_MODE
  362. printf("load(): puo essere usata solo in stato HD_STATUS_UNINITIALIZED\n");
  363. #endif
  364. return 0;
  365. }
  366.  
  367. if(hd_is_file(_load_file) == 0){ //controllo esistenza file
  368. #ifdef DEBUG_MODE
  369. printf("load(): file non esite :(\n");
  370. #endif
  371. return 0;
  372. }
  373.  
  374. _load_file_matrice = new char[10000];
  375. sprintf(_load_file_matrice,"%s.points",_load_file);
  376.  
  377. if(hd_is_file(_load_file_matrice) == 0){ //controllo esistenza file matrice
  378. #ifdef DEBUG_MODE
  379. printf("load(): file matrice non esite :(\n");
  380. #endif
  381. delete [] _load_file_matrice;
  382. return 0;
  383. }
  384.  
  385. load_file_stream = fopen(_load_file, "rb");
  386. fseek(load_file_stream, 0, SEEK_END);
  387. lbuffer = ftell(load_file_stream);
  388. rewind(load_file_stream);
  389. buffer = new char[lbuffer];
  390. fread(buffer, 1, lbuffer, load_file_stream);
  391. fclose(load_file_stream);
  392.  
  393. if(strncmp(buffer, "HD_FILE", 7) != 0){ //controllo il magic number
  394. #ifdef DEBUG_MODE
  395. printf("load(): magic number non corrisponde, non posso aprirlo :(\n");
  396. #endif
  397. delete [] _load_file_matrice;
  398. delete [] buffer;
  399. return 0;
  400. }
  401.  
  402. y=0;
  403. for(x=0;x<lbuffer;x++){
  404. if(buffer[x] == '\0')
  405. y++;
  406. if(y==2)
  407. break;
  408. }
  409. y=x;
  410.  
  411. _url = &buffer[8];
  412. _porta = &buffer[x+1];
  413.  
  414. //carico multidownload_points
  415. multidownload_points.load_from_file(_load_file_matrice);
  416. //carico multidownload
  417. multidownload = multidownload_points.rows()-1;
  418. //carico file
  419. sprintf(file,"%s",_load_file);
  420. //carico url
  421. strncpy(url, _url, strlen(_url)+1);
  422. //carico host
  423. for(x=7; x<(int)strlen(_url) ;x++)
  424. if(_url[x] == '/'){
  425. break;
  426. }
  427. strncpy(host, &_url[7], x-7);
  428. host[x-7] = '\0';
  429. //carico host_url
  430. strncpy(host_url, &url[x], strlen(_url)-x+1);
  431. host_url[strlen(_url)-x+1] = '\0';
  432. //carico porta
  433. porta = atoi(_porta);
  434. //download buffer size
  435. buffer_size = HD_DOWNLOAD_BUFFER_DEFAULT_SIZE;
  436. //aggiornamento status
  437. status = HD_STATUS_INITIALIZED;
  438.  
  439. delete [] buffer;
  440. delete [] _load_file_matrice;
  441.  
  442. return 1;
  443. }
  444.  
  445. int http_download::backup(char *_save_file){
  446.  
  447. //long x;
  448. //partial_download_data *_dati_multidownload;
  449.  
  450. ////creiamo la struttura partial_download_data
  451. //_dati_multidownload = new partial_download_data[multidownload];
  452.  
  453. //for(x=0;x<multidownload;x++){ //carichiamo i dati che ci servono nella struttura
  454. // _dati_multidownload[x].id_segmento = x;
  455. // _dati_multidownload[x].file_parziale = new char[strlen(file)+5];
  456. // sprintf(_dati_multidownload[x].file_parziale,"%s.%03d",file,x);
  457. //}
  458.  
  459. return 1;
  460. }
  461.  
  462. int http_download::get_status(){
  463. return status;
  464. }
  465.  
  466. int http_download::print(){
  467.  
  468. if(status == HD_STATUS_UNINITIALIZED){
  469. #ifdef DEBUG_MODE
  470. printf("ERROR print(): non puoi eseguire a HD_STATUS_UNINITIALIZED.\n");
  471. #endif
  472. return 0;
  473. }
  474.  
  475. printf("file: %s\n", file);
  476. printf("url: %s\n", url);
  477. printf("host: %s\n", host);
  478. printf("host_url: %s\n", host_url);
  479. printf("porta: %d\n", porta);
  480. printf("download: %d\n", multidownload);
  481. multidownload_points.print();
  482.  
  483. return 1;
  484. }
  485.  
  486. int hd_connessione_download_vanilla(http_download *download){
  487.  
  488. long x=0;
  489.  
  490. struct sockaddr_in indirizzo;
  491. struct hostent *ip;
  492. WORD socket_version;
  493. WSADATA socket_data;
  494. SOCKET sock;
  495. int sock_err;
  496.  
  497. char *richiesta_http;
  498. char *risposta_http;
  499. char header_buffer;
  500.  
  501. FILE *file_stream;
  502. long downloaded_bytes, written_bytes, total_written_bytes=0, total_downloaded_bytes=0;
  503. char *download_buffer;
  504. long _buffer_size = download->buffer_size;
  505.  
  506. //verifichiamo che l'oggetto download sia pronto
  507. if(download->status != HD_STATUS_FILE_OK){
  508. #ifdef DEBUG_MODE
  509. printf("ERROR hd_connessione_download_vanilla(): not the right status.\n");
  510. #endif
  511. return 0;
  512. }
  513.  
  514. //avviamo socket
  515. socket_version = MAKEWORD(2, 2);
  516. WSAStartup(socket_version, &socket_data); //attiva la lib winsock 2.2
  517.  
  518. //dati per la connessione
  519. ip = gethostbyname(download->host);
  520. indirizzo.sin_family = AF_INET; //tipo di indirizzo
  521. indirizzo.sin_port = htons(download->porta); //porta in cui è in ascolto server HTTP
  522. memcpy(&indirizzo.sin_addr, ip->h_addr, ip->h_length); //copia l'indirizzo nella struttura indirizzo
  523.  
  524. //richiesta HTTP
  525. richiesta_http = new char[10000];
  526. sprintf(richiesta_http,"GET %s HTTP/1.1\n"\
  527. "host: %s\n"\
  528. "Keep-Alive: 300\n"\
  529. "Connection: keep-alive\n"\
  530. "\n\0"\
  531. , download->host_url, download->host);
  532.  
  533. #ifdef DEBUG_MODE
  534. printf("%s\n",richiesta_http);
  535. #endif
  536.  
  537. //ci connettiamo
  538. sock = socket(AF_INET, SOCK_STREAM, 0);
  539. sock_err = connect(sock, (struct sockaddr *)&indirizzo, sizeof(indirizzo));
  540. if(!sock || sock_err != 0){
  541. #ifdef DEBUG_MODE
  542. printf("ERROR hd_connessione_download_vanilla(): socket: %d connect: %d\n", sock, sock_err);
  543. #endif
  544. return 0;
  545. }
  546.  
  547. //mandiamo richiesta HTTP
  548. send(sock, richiesta_http, strlen(richiesta_http)+1, 0);
  549.  
  550. //riceviamo risposta: header HTTP
  551. risposta_http = new char[10000];
  552. while(
  553. recv(sock, &header_buffer, 1, 0) != 0
  554. ){
  555. risposta_http[x] = header_buffer;
  556. x++;
  557.  
  558. if(risposta_http[x-1] == '\x0a' && risposta_http[x-3] == '\x0a')//controllo per vedere se l'header è finito
  559. break;
  560. }
  561. risposta_http[x] = '\0';
  562.  
  563. #ifdef DEBUG_MODE
  564. printf("%s\n",risposta_http);
  565. #endif
  566.  
  567. //controlliamo header HTTP ricevuto in risposta
  568. if( strncmp("HTTP/1.1", risposta_http, 8) != 0 ){ //controlliamo che il protocollo sia HTTP/1.1
  569. download->status = HD_STATUS_PROTOCOL_NOT_HTTP11;
  570.  
  571. delete [] richiesta_http;
  572. delete [] risposta_http;
  573.  
  574. shutdown(sock, 2);
  575. closesocket(sock);
  576. WSACleanup();
  577.  
  578. return 0;
  579. }
  580.  
  581. if( strncmp("200", &risposta_http[9], 3) == 0 ){ //verifichiamo se tutto ok e iniziamo a scaricare
  582.  
  583. download->status = HD_STATUS_DOWNLOADING;
  584.  
  585. download_buffer = new char[_buffer_size]; //alloco la memoria per il buffer
  586. file_stream = fopen(download->file, "wb"); //apro il file in cui salvare i dati
  587.  
  588. //riceviamo risposta: file
  589. while (1){ //prendiamo il file un po alla volta
  590. downloaded_bytes = recv(sock, download_buffer, _buffer_size, 0);
  591.  
  592. if(!(downloaded_bytes > 0))
  593. break;
  594.  
  595. written_bytes = fwrite(download_buffer, 1, downloaded_bytes, file_stream); //scrivo i dati
  596. total_written_bytes += written_bytes;
  597. total_downloaded_bytes += downloaded_bytes;
  598.  
  599. #ifdef DEBUG_MODE
  600. printf("d:%d w:%d\n",total_downloaded_bytes,total_written_bytes);
  601. #endif
  602.  
  603. if(download->status == HD_STATUS_STOPPED){ //controlliamo di non aver ricevuto l'ordine di fermarci
  604. download->vanilla_ready_to_stop = 1;
  605. break;
  606. }
  607. }
  608.  
  609. fclose(file_stream); //chiudiamo file
  610. delete [] download_buffer; //disallochiamo buffer
  611.  
  612. }
  613. else{
  614. download->status = HD_STATUS_HTTP_CODE_NOT_RECOGNIZED;
  615.  
  616. delete [] richiesta_http;
  617. delete [] risposta_http;
  618.  
  619. shutdown(sock, 2);
  620. closesocket(sock);
  621. WSACleanup();
  622.  
  623. return 0;
  624. }
  625.  
  626. delete [] richiesta_http;
  627. delete [] risposta_http;
  628.  
  629. shutdown(sock, 2);
  630. closesocket(sock);
  631. WSACleanup();
  632.  
  633. /*questo controllo serve per fare in modo di non segnare come HD_STATUS_DOWNLOAD_COMPLETED
  634. un oggetto che invece è stato stoppato ed è in status HD_STATUS_STOPPED*/
  635. if(download->status == HD_STATUS_DOWNLOADING)
  636. download->status = HD_STATUS_DOWNLOAD_COMPLETED;
  637.  
  638. return 1;
  639. }
  640.  
  641. int hd_connessione_header_partial_content(http_download *download){
  642. long x=0;
  643.  
  644. struct sockaddr_in indirizzo;
  645. struct hostent *ip;
  646. WORD socket_version;
  647. WSADATA socket_data;
  648. SOCKET sock;
  649. int sock_err;
  650.  
  651. char *richiesta_http;
  652. char *risposta_http;
  653. char header_buffer;
  654.  
  655. //verifichiamo che la richiesta partial content sia inviata con status HD_STATUS_FILE_OK
  656. if(download->status != HD_STATUS_FILE_OK){
  657. #ifdef DEBUG_MODE
  658. printf("ERROR hd_connessione_header_partial_content(): not the right status.\n");
  659. #endif
  660. return 0;
  661. }
  662.  
  663. //avviamo socket
  664. socket_version = MAKEWORD(2, 2);
  665. WSAStartup(socket_version, &socket_data); //attiva la lib winsock 2.2
  666.  
  667. //dati per la connessione
  668. ip = gethostbyname(download->host);
  669. indirizzo.sin_family = AF_INET; //tipo di indirizzo
  670. indirizzo.sin_port = htons(download->porta); //porta in cui è in ascolto server HTTP
  671. memcpy(&indirizzo.sin_addr, ip->h_addr, ip->h_length); //copia l'indirizzo nella struttura indirizzo
  672.  
  673. //richiesta HTTP partial download
  674. richiesta_http = new char[10000];
  675. sprintf(richiesta_http,"GET %s HTTP/1.1\n"\
  676. "host: %s\n"\
  677. "Keep-Alive: 300\n"\
  678. "Connection: keep-alive\n"\
  679. "Range: bytes=1-\n"\
  680. "\n\0"\
  681. , download->host_url, download->host);
  682.  
  683. #ifdef DEBUG_MODE
  684. printf("%s\n",richiesta_http);
  685. #endif
  686.  
  687. //ci connettiamo
  688. sock = socket(AF_INET, SOCK_STREAM, 0);
  689. sock_err = connect(sock, (struct sockaddr *)&indirizzo, sizeof(indirizzo));
  690. if(!sock || sock_err != 0){
  691. #ifdef DEBUG_MODE
  692. printf("ERROR hd_connessione_header_partial_content(): socket: %d connect: %d\n", sock, sock_err);
  693. #endif
  694. return 0;
  695. }
  696.  
  697. //mandiamo richiesta HTTP
  698. send(sock, richiesta_http, strlen(richiesta_http)+1, 0);
  699.  
  700. //riceviamo risposta: header HTTP
  701. risposta_http = new char[10000];
  702. while(
  703. recv(sock, &header_buffer, 1, 0) != 0
  704. ){
  705. risposta_http[x] = header_buffer;
  706. x++;
  707.  
  708. if(risposta_http[x-1] == '\x0a' && risposta_http[x-3] == '\x0a')//controllo per vedere se l'header è finito
  709. break;
  710. }
  711. risposta_http[x] = '\0';
  712.  
  713. #ifdef DEBUG_MODE
  714. printf("%s\n",risposta_http);
  715. #endif
  716.  
  717. shutdown(sock, 2);
  718. closesocket(sock);
  719. WSACleanup();
  720.  
  721. //controlliamo header HTTP ricevuto in risposta
  722. if( strncmp("HTTP/1.1", risposta_http, 8) != 0 ){ //controlliamo che il protocollo sia HTTP/1.1
  723. download->status = HD_STATUS_PROTOCOL_NOT_HTTP11;
  724.  
  725. delete [] richiesta_http;
  726. delete [] risposta_http;
  727. return 0;
  728. }
  729.  
  730. if( strncmp("206", &risposta_http[9], 3) == 0 ){ //verifichiamo se il download parziale è stato accettato
  731. download->is_range_accepted = 1;
  732. return 1;
  733. }
  734.  
  735. return 1;
  736. }
  737.  
  738. int hd_connessione_header(http_download *download){
  739.  
  740. long x=0,y;
  741.  
  742. struct sockaddr_in indirizzo;
  743. struct hostent *ip;
  744. WORD socket_version;
  745. WSADATA socket_data;
  746. SOCKET sock;
  747. int sock_err;
  748.  
  749. char *richiesta_http;
  750. char *risposta_http;
  751. char header_buffer;
  752.  
  753. //verifichiamo che l'oggetto download sia pronto
  754. if(download->status != HD_STATUS_INITIALIZED
  755. && download->status != HD_STATUS_FILE_REDIRECTED){
  756. #ifdef DEBUG_MODE
  757. printf("ERROR hd_connessione_header(): not the right status.\n");
  758. #endif
  759. return 0;
  760. }
  761.  
  762. //avviamo socket
  763. socket_version = MAKEWORD(2, 2);
  764. WSAStartup(socket_version, &socket_data); //attiva la lib winsock 2.2
  765.  
  766. //dati per la connessione
  767. ip = gethostbyname(download->host);
  768. indirizzo.sin_family = AF_INET; //tipo di indirizzo
  769. indirizzo.sin_port = htons(download->porta); //porta in cui è in ascolto server HTTP
  770. memcpy(&indirizzo.sin_addr, ip->h_addr, ip->h_length); //copia l'indirizzo nella struttura indirizzo
  771.  
  772. //richiesta HTTP
  773. richiesta_http = new char[10000];
  774. sprintf(richiesta_http,"GET %s HTTP/1.1\n"\
  775. "host: %s\n"\
  776. "Keep-Alive: 300\n"\
  777. "Connection: keep-alive\n"\
  778. "\n\0"\
  779. , download->host_url, download->host);
  780.  
  781. #ifdef DEBUG_MODE
  782. printf("%s\n",richiesta_http);
  783. #endif
  784.  
  785. //ci connettiamo
  786. sock = socket(AF_INET, SOCK_STREAM, 0);
  787. sock_err = connect(sock, (struct sockaddr *)&indirizzo, sizeof(indirizzo));
  788. if(!sock || sock_err != 0){
  789. #ifdef DEBUG_MODE
  790. printf("ERROR hd_connessione_header(): socket: %d connect: %d\n", sock, sock_err);
  791. #endif
  792. return 0;
  793. }
  794.  
  795. //mandiamo richiesta HTTP
  796. send(sock, richiesta_http, strlen(richiesta_http)+1, 0);
  797.  
  798. //riceviamo risposta: header HTTP
  799. risposta_http = new char[10000];
  800. while(
  801. recv(sock, &header_buffer, 1, 0) != 0
  802. ){
  803. risposta_http[x] = header_buffer;
  804. x++;
  805.  
  806. if(risposta_http[x-1] == '\x0a' && risposta_http[x-3] == '\x0a')//controllo per vedere se l'header è finito
  807. break;
  808. }
  809. risposta_http[x] = '\0';
  810.  
  811. #ifdef DEBUG_MODE
  812. printf("%s\n",risposta_http);
  813. #endif
  814.  
  815. shutdown(sock, 2);
  816. closesocket(sock);
  817. WSACleanup();
  818.  
  819. //controlliamo header HTTP ricevuto in risposta
  820. if( strncmp("HTTP/1.1", risposta_http, 8) != 0 ){ //controlliamo che il protocollo sia HTTP/1.1
  821. download->status = HD_STATUS_PROTOCOL_NOT_HTTP11;
  822.  
  823. delete [] richiesta_http;
  824. delete [] risposta_http;
  825. return 0;
  826. }
  827.  
  828. if( strncmp("404", &risposta_http[9], 3) == 0 ){ //verifichiamo se si è verificato l'errore 404 not found
  829. download->status = HD_STATUS_FILE_NOT_FOUND;
  830. }
  831. else if( strncmp("302", &risposta_http[9], 3) == 0 ){ //verifichiamo se c'è un redirect con 302 found
  832. download->status = HD_STATUS_FILE_REDIRECTED;
  833.  
  834. //cerchiamo il nuovo indirizzo dentro l'header della risposta
  835. for(x=0; x<(int)strlen(risposta_http) ;x++){ //iniziamo ricerca indirizzo
  836. if(strncmp("\x0aLocation: ", &risposta_http[x], 11)==0){ //se incontriamo la sequenza "\x0aLocation: "
  837. for(y=x+11;;y++){ //leggiamo l'indirizzo
  838. if(risposta_http[y] == '\x0d'){ //fine dell'indirizzo
  839. risposta_http[y] = '\0'; //terminiamo la stringa
  840. break;
  841. }
  842. }
  843. y = x+11; //&risposta_http[y] è diventata la stringa contenente il nuovo indirizzo
  844. break; //abbiamo trovato il nuovo indirizzo, abbandoniamo la ricerca
  845. }
  846. }
  847.  
  848. //modifichiamo l'oggetto in modo da poter scaricare dal nuovo indirizzo
  849. //url
  850. strncpy(download->url, &risposta_http[y], strlen(&risposta_http[y])+1);
  851. //host
  852. for(x=7; x<(int)strlen(&risposta_http[y]) ;x++)
  853. if(risposta_http[y+x] == '/'){
  854. break;
  855. }
  856. strncpy(download->host, &risposta_http[y+7], x-7);
  857. download->host[x-7] = '\0';
  858. //host_url
  859. strncpy(download->host_url, &risposta_http[y+x], strlen(&risposta_http[y])-x+1);
  860. download->host_url[strlen(&risposta_http[y])-x+1] = '\0';
  861.  
  862. }
  863. else if( strncmp("200", &risposta_http[9], 3) == 0 ){ //verifichiamo se siamo pronti al download
  864. download->status = HD_STATUS_FILE_OK;
  865.  
  866. //controlliamo se il server ci ha comunicato la possiblità di usare range bytes
  867. for(x=0; x<(int)strlen(risposta_http) ;x++){ //cerchiamo il messaggio "Accept-Ranges: bytes"
  868. if(strncmp("Accept-Ranges: bytes", &risposta_http[x], strlen("Accept-Ranges: bytes\0"))==0){
  869. download->is_range_accepted = 1;
  870. break;
  871. }
  872. }
  873.  
  874. //controlliamo se il server ci ha detto quanto è grande il file e in tal caso prendiamo il dato
  875. for(x=0; x<(int)strlen(risposta_http) ;x++){ //cerchiamo il messaggio "Content-Lenght: "
  876. if(strncmp("Content-Length: ", &risposta_http[x], strlen("Content-Length: \0"))==0){
  877. download->is_size_comunicated = 1;
  878. for(y=x+strlen("Content-Length: \0");;y++){ //leggiamo il numero
  879. if(risposta_http[y] == '\x0d'){ //fine del numero
  880. risposta_http[y] = '\0'; //terminiamo la stringa
  881. download->file_size = atoi(&risposta_http[x+strlen("Content-Length: \0")]); //preleviamo numero
  882. risposta_http[y] = '\x0d'; //ripristiniamo la stringa
  883. break;
  884. }
  885. }
  886. break;
  887. }
  888. }
  889.  
  890. }
  891. else{ //se riceviamo un codice http che non è previsto dagli if precedenti
  892. download->status = HD_STATUS_HTTP_CODE_NOT_RECOGNIZED;
  893. }
  894.  
  895. delete [] richiesta_http;
  896. delete [] risposta_http;
  897.  
  898. return 1;
  899. }
  900.  
  901. int hd_multidownload_luncher(http_download *download){
  902.  
  903. DWORD thread_id;
  904. long x,stato1,stato2;
  905. partial_download_data *dati_multidownload;
  906.  
  907. dati_multidownload = new partial_download_data[download->multidownload];
  908.  
  909. for(x=0;x<download->multidownload;x++){ //carichiamo i dati che ci servono nella struttura
  910. dati_multidownload[x].id_segmento = x;
  911. dati_multidownload[x].oggetto = (void *) download;
  912. dati_multidownload[x].file_parziale = new char[strlen(download->file)+5];
  913. sprintf(dati_multidownload[x].file_parziale,"%s.%03d",download->file,x);
  914. }
  915.  
  916. for(x=0;x<download->multidownload;x++){ //avviamo i thread asincroni
  917. download->multidownload_points[x][2] = 1;
  918. CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) hd_connessione_multidownload_segmento,
  919. &dati_multidownload[x], 0, &thread_id);
  920. }
  921.  
  922. //segnaliamo che la procedura di multidownload sta iniziando
  923. download->status = HD_STATUS_MULTIDOWNLOADING;
  924.  
  925. while(1){ //ciclo per la gestione dei download parziali
  926. stato1=0;stato2=0;
  927. for(x=0;x<download->multidownload;x++){ //controlliamo i thread uno ad uno
  928.  
  929. //se il thread si è chiuso e lo status lo consente
  930. if(download->multidownload_points[x][2] == 0 && download->status == HD_STATUS_MULTIDOWNLOADING){
  931. download->multidownload_points[x][2] = 1;
  932. CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) hd_connessione_multidownload_segmento,
  933. &dati_multidownload[x], 0, &thread_id); //lo riavviamo
  934. }
  935. else if (download->multidownload_points[x][2] == 2)
  936. stato2++; //contiamo il numero di segmenti terminati
  937. else if (download->multidownload_points[x][2] == 1)
  938. stato1++; //e il numero di segmenti in download
  939.  
  940. }
  941.  
  942. if(stato2 == download->multidownload){ //se tutti i segmenti hanno finito di scaricare
  943. download->status = HD_STATUS_MULTIDOWNLOADING_ASSEMBLING; //segnaliamo che il download è completato
  944. break; //e chiudiamo questo ciclo di controllo
  945. }
  946.  
  947. if(download->status == HD_STATUS_PAUSED){ //controlliamo se siamo in pausa
  948. while(1){
  949. if(download->status == HD_STATUS_RESUME){
  950. download->status = HD_STATUS_MULTIDOWNLOADING;
  951. download->luncher_ready_to_pause = 0;
  952. break;
  953. }
  954.  
  955. //prima di stoppare luncher ci assicuriamo che tutti i parziali si siano fermati
  956. if(download->status == HD_STATUS_STOPPED){
  957. download->luncher_ready_to_pause = 0;
  958. break;
  959. }
  960.  
  961. if(stato1 == 0){ //comunichiamo che la pausa è avvenuta
  962. download->luncher_ready_to_pause = 1;
  963. }
  964.  
  965. stato1=0; //essendo in loop necessitiamo di ciclo alternativo per controllo stato1
  966. for(x=0;x<download->multidownload;x++)
  967. if(download->multidownload_points[x][2] == 1)
  968. stato1++;
  969.  
  970. Sleep(50);
  971. }
  972.  
  973. }
  974.  
  975. if(download->status == HD_STATUS_STOPPED){ //controlliamo se abbiamo ricevuto l'ordine di fermarci
  976. while(1){
  977. //prima di stoppare luncher ci assicuriamo che tutti i parziali si siano fermati
  978. if(download->status == HD_STATUS_STOPPED && stato1 == 0){
  979. download->luncher_ready_to_stop = 1;
  980. break;
  981. }
  982.  
  983. stato1=0; //essendo in loop necessitiamo di ciclo alternativo per controllo stato1
  984. for(x=0;x<download->multidownload;x++)
  985. if(download->multidownload_points[x][2] == 1)
  986. stato1++;
  987.  
  988. Sleep(50);
  989. }
  990. break;
  991. }
  992.  
  993. Sleep(100);
  994. }
  995.  
  996. //se il download è completato assembliamo i file parziali
  997. if(download->status == HD_STATUS_MULTIDOWNLOADING_ASSEMBLING){
  998. if(hd_multidownload_files_assembler(download,dati_multidownload) == 1)
  999. download->status = HD_STATUS_DOWNLOAD_COMPLETED;
  1000. else
  1001. download->status = HD_STATUS_MULTIDOWNLOADING_ASSEMBLING_ERROR;
  1002. }
  1003.  
  1004. delete [] dati_multidownload;
  1005.  
  1006. #ifdef DEBUG_MODE
  1007. printf("hd_multidownload_luncher(): chiusura...\n");
  1008. #endif
  1009.  
  1010. return 1;
  1011. }
  1012.  
  1013. int hd_connessione_multidownload_segmento(partial_download_data *dati){
  1014. long x;
  1015.  
  1016. http_download *download;
  1017. int id = dati->id_segmento; //id del segmento
  1018.  
  1019. download = (http_download *) dati->oggetto; //puntatore all'istanza della nostra classe per il download
  1020. download->multidownload_points[id][2] = 1; //segnaliamo che il processo parziale sta tentando il download
  1021.  
  1022. struct sockaddr_in indirizzo;
  1023. struct hostent *ip;
  1024. WORD socket_version;
  1025. WSADATA socket_data;
  1026. SOCKET sock;
  1027. int sock_err;
  1028.  
  1029. char *richiesta_http;
  1030. char *risposta_http;
  1031. char header_buffer;
  1032.  
  1033. FILE *file_stream;
  1034. long downloaded_bytes, written_bytes, total_downloaded_bytes=0, total_written_bytes=0;
  1035. char *download_buffer;
  1036. long _buffer_size = download->buffer_size;
  1037.  
  1038. //avviamo socket
  1039. socket_version = MAKEWORD(2, 2);
  1040. WSAStartup(socket_version, &socket_data); //attiva la lib winsock 2.2
  1041.  
  1042. //dati per la connessione
  1043. ip = gethostbyname(download->host);
  1044. indirizzo.sin_family = AF_INET; //tipo di indirizzo
  1045. indirizzo.sin_port = htons(download->porta); //porta in cui è in ascolto server HTTP
  1046. memcpy(&indirizzo.sin_addr, ip->h_addr, ip->h_length); //copia l'indirizzo nella struttura indirizzo
  1047.  
  1048. //richiesta HTTP partial download
  1049. //qui impostiamo il punto del file da cui vogliamo i dati e fino a dove li vogliamo
  1050. richiesta_http = new char[10000];
  1051. sprintf(richiesta_http,"GET %s HTTP/1.1\n"\
  1052. "host: %s\n"\
  1053. "Keep-Alive: 300\n"\
  1054. "Connection: keep-alive\n"\
  1055. "Range: bytes=%d-%d\n"\
  1056. "\n\0"\
  1057. , download->host_url, download->host, (long)download->multidownload_points[id][1],
  1058. (long)download->multidownload_points[id+1][0]-1);
  1059.  
  1060. //ci connettiamo
  1061. sock = socket(AF_INET, SOCK_STREAM, 0);
  1062. sock_err = connect(sock, (struct sockaddr *)&indirizzo, sizeof(indirizzo));
  1063. if(!sock || sock_err != 0){
  1064. #ifdef DEBUG_MODE
  1065. printf("ERROR hd_connessione_multidownload_segmento() id %d: socket: %d connect: %d\n", id, sock, sock_err);
  1066. #endif
  1067.  
  1068. download->multidownload_points[id][2] = 0; //segnaliamo che il processo si sta chiudendo
  1069. return 0;
  1070. }
  1071.  
  1072. //mandiamo richiesta HTTP
  1073. send(sock, richiesta_http, strlen(richiesta_http)+1, 0);
  1074.  
  1075. //riceviamo risposta: header HTTP
  1076. risposta_http = new char[10000];
  1077. x=0;
  1078. while(
  1079. recv(sock, &header_buffer, 1, 0) != 0
  1080. ){
  1081. risposta_http[x] = header_buffer;
  1082. x++;
  1083.  
  1084. if(risposta_http[x-1] == '\x0a' && risposta_http[x-3] == '\x0a')//controllo per vedere se l'header è finito
  1085. break;
  1086. }
  1087. risposta_http[x] = '\0';
  1088.  
  1089. #ifdef DEBUG_MODE
  1090. printf("id: %d\n%s\n%s\n",id,richiesta_http,risposta_http);
  1091. #endif
  1092.  
  1093. //verifichiamo se tutto ok e iniziamo a scaricare
  1094. if( strncmp("206", &risposta_http[9], 3) == 0 ){
  1095.  
  1096. download_buffer = new char[_buffer_size]; //alloco la memoria per il buffer
  1097. if(download->multidownload_points[id][1] == download->multidownload_points[id][0])
  1098. file_stream = fopen(dati->file_parziale, "wb"); //apro il file in cui salvare i dati
  1099. else
  1100. file_stream = fopen(dati->file_parziale, "ab"); //apro il file in cui salvare i dati
  1101.  
  1102. //riceviamo risposta: file
  1103. while (1){ //prendiamo il file un po alla volta
  1104. downloaded_bytes = recv(sock, download_buffer, _buffer_size, 0);
  1105.  
  1106. if(downloaded_bytes <= 0)
  1107. break;
  1108.  
  1109. written_bytes = fwrite(download_buffer, 1, downloaded_bytes, file_stream); //scrivo i dati
  1110. total_downloaded_bytes += downloaded_bytes;
  1111. total_written_bytes += written_bytes;
  1112.  
  1113. //aggiorno la situazione nella matrice download_points
  1114. download->multidownload_points[id][1] += downloaded_bytes;
  1115.  
  1116. #ifdef DEBUG_MODE
  1117. printf("hd_connessione_multidownload_segmento() id %d: d:%d p:%d\n",
  1118. id, total_downloaded_bytes, (long)download->multidownload_points[id][1]);
  1119. #endif
  1120.  
  1121.  
  1122.  
  1123. if(download->status == HD_STATUS_STOPPED) //chiudiamo il processo se c'è l'ordine di stop
  1124. break;
  1125.  
  1126. if(download->status == HD_STATUS_PAUSED || download->status == HD_STATUS_SAVED) //chiudiamo il processo se siamo in pausa
  1127. break;
  1128. }
  1129.  
  1130. fclose(file_stream); //chiudiamo file
  1131. delete [] download_buffer; //disallochiamo buffer
  1132.  
  1133. }
  1134. else if( strncmp("503", &risposta_http[9], 3) == 0 ){
  1135.  
  1136. #ifdef DEBUG_MODE
  1137. printf("hd_connessione_multidownload_segmento() id %d: ricevuta risposta 503, aspettiamo 10 secondi\n", id);
  1138. #endif
  1139.  
  1140. Sleep(10000);
  1141.  
  1142. delete [] richiesta_http;
  1143. delete [] risposta_http;
  1144.  
  1145. shutdown(sock, 2);
  1146. closesocket(sock);
  1147. WSACleanup();
  1148.  
  1149. download->multidownload_points[id][2] = 0; //segnaliamo che il processo si sta chiudendo
  1150. return 0;
  1151. }
  1152. else if( strncmp("416", &risposta_http[9], 3) == 0 ){
  1153.  
  1154. #ifdef DEBUG_MODE
  1155. printf("ERROR hd_connessione_multidownload_segmento() id %d: ricevuta risposta 416, assumiamo di aver finito\n", id);
  1156. #endif
  1157.  
  1158. delete [] richiesta_http;
  1159. delete [] risposta_http;
  1160.  
  1161. shutdown(sock, 2);
  1162. closesocket(sock);
  1163. WSACleanup();
  1164.  
  1165. download->multidownload_points[id][2] = 2; //segnaliamo che il processo si sta chiudendo
  1166. return 0;
  1167. }
  1168. else{
  1169.  
  1170. #ifdef DEBUG_MODE
  1171. printf("ERROR hd_connessione_multidownload_segmento() id %d: il serve ci ha negato il download parziale 206 :(\n", id);
  1172. #endif
  1173.  
  1174. delete [] richiesta_http;
  1175. delete [] risposta_http;
  1176.  
  1177. shutdown(sock, 2);
  1178. closesocket(sock);
  1179. WSACleanup();
  1180.  
  1181. download->multidownload_points[id][2] = 0; //segnaliamo che il processo si sta chiudendo
  1182. return 0;
  1183. }
  1184.  
  1185. delete [] richiesta_http;
  1186. delete [] risposta_http;
  1187.  
  1188. shutdown(sock, 2);
  1189. closesocket(sock);
  1190. WSACleanup();
  1191.  
  1192. if(download->multidownload_points[id][1] >= download->multidownload_points[id+1][0]-1){
  1193. download->multidownload_points[id][2] = 2; //segnaliamo che il processo ha scaricato tutto
  1194. }
  1195. else
  1196. download->multidownload_points[id][2] = 0; //segnaliamo che il processo si sta chiudendo
  1197. return 1;
  1198. }
  1199.  
  1200. int hd_multidownload_files_assembler(http_download *download, partial_download_data *dati){
  1201. long x;
  1202.  
  1203. FILE *f_stream;
  1204. FILE *pf_stream;
  1205. char *pf_name;
  1206. char *copy_buffer;
  1207. long bytes_copied, total_bytes_copied=0, ps_size;
  1208.  
  1209. pf_name = new char[10000];
  1210. copy_buffer = new char[download->buffer_size];
  1211.  
  1212. f_stream = fopen(download->file,"wb"); //apriamo file generale
  1213.  
  1214. //apriamo i file parziali uno ad uno e li copiamo nel file generale
  1215. for(x=0; x<download->multidownload ;x++){
  1216. pf_stream = fopen(dati[x].file_parziale, "rb");
  1217. if(pf_stream == NULL)
  1218. return 0;
  1219.  
  1220. ps_size = (long)(download->multidownload_points[x+1][0]-download->multidownload_points[x][0]); //grandezza segmento
  1221.  
  1222. total_bytes_copied=0;
  1223. while(1){
  1224. bytes_copied = fread(copy_buffer,1,download->buffer_size,pf_stream);
  1225. if(bytes_copied<=0)
  1226. break;
  1227.  
  1228. if(total_bytes_copied+bytes_copied > ps_size)
  1229. fwrite(copy_buffer, 1, ps_size-total_bytes_copied, f_stream);
  1230. else
  1231. fwrite(copy_buffer, 1, bytes_copied, f_stream);
  1232.  
  1233. total_bytes_copied += bytes_copied;
  1234. }
  1235.  
  1236. fclose(pf_stream);
  1237. }
  1238.  
  1239. fclose(f_stream);
  1240.  
  1241. delete [] pf_name;
  1242. delete [] copy_buffer;
  1243.  
  1244. return 1;
  1245. }
  1246.  
  1247. int hd_is_file(char *pathname){
  1248. FILE *file;
  1249. file = fopen(pathname, "rb");
  1250. if(file == NULL)
  1251. return 0;
  1252. fclose(file);
  1253. return 1;
  1254. }