501 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			501 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include <map>
 | |
| #include <string.h>
 | |
| #include <stdlib.h>
 | |
| #include <sys/time.h>
 | |
| #include <arpa/inet.h>
 | |
| 
 | |
| unsigned int getNowMS(){
 | |
|   timeval t;
 | |
|   gettimeofday(&t, 0);
 | |
|   return t.tv_sec + t.tv_usec/1000;
 | |
| }
 | |
| 
 | |
| 
 | |
| unsigned int chunk_rec_max = 128;
 | |
| unsigned int chunk_snd_max = 128;
 | |
| unsigned int rec_window_size = 0xFA00;
 | |
| unsigned int snd_window_size = 1024*500;
 | |
| unsigned int rec_window_at = 0;
 | |
| unsigned int snd_window_at = 0;
 | |
| unsigned int rec_cnt = 0;
 | |
| unsigned int snd_cnt = 0;
 | |
| 
 | |
| unsigned int firsttime;
 | |
| 
 | |
| struct chunkinfo {
 | |
|   unsigned int cs_id;
 | |
|   unsigned int timestamp;
 | |
|   unsigned int len;
 | |
|   unsigned int real_len;
 | |
|   unsigned int len_left;
 | |
|   unsigned char msg_type_id;
 | |
|   unsigned int msg_stream_id;
 | |
| };//chunkinfo
 | |
| 
 | |
| struct chunkpack {
 | |
|   unsigned char chunktype;
 | |
|   unsigned int cs_id;
 | |
|   unsigned int timestamp;
 | |
|   unsigned int len;
 | |
|   unsigned int real_len;
 | |
|   unsigned int len_left;
 | |
|   unsigned char msg_type_id;
 | |
|   unsigned int msg_stream_id;
 | |
|   unsigned char * data;
 | |
| };//chunkpack
 | |
| 
 | |
| //clean a chunk so that it may be re-used without memory leaks
 | |
| void scrubChunk(struct chunkpack c){
 | |
|   if (c.data){free(c.data);}
 | |
|   c.data = 0;
 | |
|   c.real_len = 0;
 | |
| }//scrubChunk
 | |
| 
 | |
| 
 | |
| //ugly global, but who cares...
 | |
| std::map<unsigned int, chunkinfo> prevmap;
 | |
| //return previous packet of this cs_id
 | |
| chunkinfo GetPrev(unsigned int cs_id){
 | |
|   return prevmap[cs_id];
 | |
| }//GetPrev
 | |
| //store packet information of last packet of this cs_id
 | |
| void PutPrev(chunkpack prev){
 | |
|   prevmap[prev.cs_id].timestamp = prev.timestamp;
 | |
|   prevmap[prev.cs_id].len = prev.len;
 | |
|   prevmap[prev.cs_id].real_len = prev.real_len;
 | |
|   prevmap[prev.cs_id].len_left = prev.len_left;
 | |
|   prevmap[prev.cs_id].msg_type_id = prev.msg_type_id;
 | |
|   prevmap[prev.cs_id].msg_stream_id = prev.msg_stream_id;
 | |
| }//PutPrev
 | |
| 
 | |
| //ugly global, but who cares...
 | |
| std::map<unsigned int, chunkinfo> sndprevmap;
 | |
| //return previous packet of this cs_id
 | |
| chunkinfo GetSndPrev(unsigned int cs_id){
 | |
|   return sndprevmap[cs_id];
 | |
| }//GetPrev
 | |
| //store packet information of last packet of this cs_id
 | |
| void PutSndPrev(chunkpack prev){
 | |
|   sndprevmap[prev.cs_id].cs_id = prev.cs_id;
 | |
|   sndprevmap[prev.cs_id].timestamp = prev.timestamp;
 | |
|   sndprevmap[prev.cs_id].len = prev.len;
 | |
|   sndprevmap[prev.cs_id].real_len = prev.real_len;
 | |
|   sndprevmap[prev.cs_id].len_left = prev.len_left;
 | |
|   sndprevmap[prev.cs_id].msg_type_id = prev.msg_type_id;
 | |
|   sndprevmap[prev.cs_id].msg_stream_id = prev.msg_stream_id;
 | |
| }//PutPrev
 | |
| 
 | |
| 
 | |
| 
 | |
| //sends the chunk over the network
 | |
| void SendChunk(chunkpack ch){
 | |
|   unsigned char tmp;
 | |
|   unsigned int tmpi;
 | |
|   unsigned char chtype = 0x00;
 | |
|   chunkinfo prev = GetSndPrev(ch.cs_id);
 | |
|   ch.timestamp -= firsttime;
 | |
|   if (prev.cs_id == ch.cs_id){
 | |
|     if (ch.msg_stream_id == prev.msg_stream_id){
 | |
|       chtype = 0x40;//do not send msg_stream_id
 | |
|       if (ch.len == prev.len){
 | |
|         if (ch.msg_type_id == prev.msg_type_id){
 | |
|           chtype = 0x80;//do not send len and msg_type_id
 | |
|           if (ch.timestamp == prev.timestamp){
 | |
|             chtype = 0xC0;//do not send timestamp
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   if (ch.cs_id <= 63){
 | |
|     tmp = chtype | ch.cs_id; DDV_write(&tmp, 1, 1, CONN_fd);
 | |
|     snd_cnt+=1;
 | |
|   }else{
 | |
|     if (ch.cs_id <= 255+64){
 | |
|       tmp = chtype | 0; DDV_write(&tmp, 1, 1, CONN_fd);
 | |
|       tmp = ch.cs_id - 64; DDV_write(&tmp, 1, 1, CONN_fd);
 | |
|       snd_cnt+=2;
 | |
|     }else{
 | |
|       tmp = chtype | 1; DDV_write(&tmp, 1, 1, CONN_fd);
 | |
|       tmpi = ch.cs_id - 64;
 | |
|       tmp = tmpi % 256; DDV_write(&tmp, 1, 1, CONN_fd);
 | |
|       tmp = tmpi / 256; DDV_write(&tmp, 1, 1, CONN_fd);
 | |
|       snd_cnt+=3;
 | |
|     }
 | |
|   }
 | |
|   unsigned int ntime = 0;
 | |
|   if (chtype != 0xC0){
 | |
|     //timestamp or timestamp diff
 | |
|     if (chtype == 0x00){
 | |
|       tmpi = ch.timestamp;
 | |
|       if (tmpi >= 0x00ffffff){ntime = tmpi; tmpi = 0x00ffffff;}
 | |
|       tmp = tmpi / (256*256); DDV_write(&tmp, 1, 1, CONN_fd);
 | |
|       tmp = tmpi / 256; DDV_write(&tmp, 1, 1, CONN_fd);
 | |
|       tmp = tmpi % 256; DDV_write(&tmp, 1, 1, CONN_fd);
 | |
|       snd_cnt+=3;
 | |
|     }else{
 | |
|       tmpi = ch.timestamp - prev.timestamp;
 | |
|       if (tmpi >= 0x00ffffff){ntime = tmpi; tmpi = 0x00ffffff;}
 | |
|       tmp = tmpi / (256*256); DDV_write(&tmp, 1, 1, CONN_fd);
 | |
|       tmp = tmpi / 256; DDV_write(&tmp, 1, 1, CONN_fd);
 | |
|       tmp = tmpi % 256; DDV_write(&tmp, 1, 1, CONN_fd);
 | |
|       snd_cnt+=3;
 | |
|     }
 | |
|     if (chtype != 0x80){
 | |
|       //len
 | |
|       tmpi = ch.len;
 | |
|       tmp = tmpi / (256*256); DDV_write(&tmp, 1, 1, CONN_fd);
 | |
|       tmp = tmpi / 256; DDV_write(&tmp, 1, 1, CONN_fd);
 | |
|       tmp = tmpi % 256; DDV_write(&tmp, 1, 1, CONN_fd);
 | |
|       snd_cnt+=3;
 | |
|       //msg type id
 | |
|       tmp = ch.msg_type_id; DDV_write(&tmp, 1, 1, CONN_fd);
 | |
|       snd_cnt+=1;
 | |
|       if (chtype != 0x40){
 | |
|         //msg stream id
 | |
|         tmp = ch.msg_stream_id % 256; DDV_write(&tmp, 1, 1, CONN_fd);
 | |
|         tmp = ch.msg_stream_id / 256; DDV_write(&tmp, 1, 1, CONN_fd);
 | |
|         tmp = ch.msg_stream_id / (256*256); DDV_write(&tmp, 1, 1, CONN_fd);
 | |
|         tmp = ch.msg_stream_id / (256*256*256); DDV_write(&tmp, 1, 1, CONN_fd);
 | |
|         snd_cnt+=4;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   //support for 0x00ffffff timestamps
 | |
|   if (ntime){
 | |
|     tmp = ntime / (256*256*256); DDV_write(&tmp, 1, 1, CONN_fd);
 | |
|     tmp = ntime / (256*256); DDV_write(&tmp, 1, 1, CONN_fd);
 | |
|     tmp = ntime / 256; DDV_write(&tmp, 1, 1, CONN_fd);
 | |
|     tmp = ntime % 256; DDV_write(&tmp, 1, 1, CONN_fd);
 | |
|     snd_cnt+=4;
 | |
|   }
 | |
|   ch.len_left = 0;
 | |
|   while (ch.len_left < ch.len){
 | |
|     tmpi = ch.len - ch.len_left;
 | |
|     if (tmpi > chunk_snd_max){tmpi = chunk_snd_max;}
 | |
|     DDV_write((ch.data + ch.len_left), 1, tmpi, CONN_fd);
 | |
|     snd_cnt+=tmpi;
 | |
|     ch.len_left += tmpi;
 | |
|     if (ch.len_left < ch.len){
 | |
|       if (ch.cs_id <= 63){
 | |
|         tmp = 0xC0 + ch.cs_id; DDV_write(&tmp, 1, 1, CONN_fd);
 | |
|         snd_cnt+=1;
 | |
|       }else{
 | |
|         if (ch.cs_id <= 255+64){
 | |
|           tmp = 0xC0; DDV_write(&tmp, 1, 1, CONN_fd);
 | |
|           tmp = ch.cs_id - 64; DDV_write(&tmp, 1, 1, CONN_fd);
 | |
|           snd_cnt+=2;
 | |
|         }else{
 | |
|           tmp = 0xC1; DDV_write(&tmp, 1, 1, CONN_fd);
 | |
|           tmpi = ch.cs_id - 64;
 | |
|           tmp = tmpi % 256; DDV_write(&tmp, 1, 1, CONN_fd);
 | |
|           tmp = tmpi / 256; DDV_write(&tmp, 1, 1, CONN_fd);
 | |
|           snd_cnt+=4;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   PutSndPrev(ch);
 | |
| }//SendChunk
 | |
| 
 | |
| //sends a chunk
 | |
| void SendChunk(unsigned int cs_id, unsigned char msg_type_id, unsigned int msg_stream_id, std::string data){
 | |
|   chunkpack ch;
 | |
|   ch.cs_id = cs_id;
 | |
|   ch.timestamp = getNowMS();
 | |
|   ch.len = data.size();
 | |
|   ch.real_len = data.size();
 | |
|   ch.len_left = 0;
 | |
|   ch.msg_type_id = msg_type_id;
 | |
|   ch.msg_stream_id = msg_stream_id;
 | |
|   ch.data = (unsigned char*)malloc(data.size());
 | |
|   memcpy(ch.data, data.c_str(), data.size());
 | |
|   SendChunk(ch);
 | |
|   free(ch.data);
 | |
| }//SendChunk
 | |
| 
 | |
| //sends a media chunk
 | |
| void SendMedia(unsigned char msg_type_id, unsigned char * data, int len, unsigned int ts){
 | |
|   chunkpack ch;
 | |
|   ch.cs_id = msg_type_id;
 | |
|   ch.timestamp = ts;
 | |
|   ch.len = len;
 | |
|   ch.real_len = len;
 | |
|   ch.len_left = 0;
 | |
|   ch.msg_type_id = msg_type_id;
 | |
|   ch.msg_stream_id = 1;
 | |
|   ch.data = (unsigned char*)malloc(len);
 | |
|   memcpy(ch.data, data, len);
 | |
|   SendChunk(ch);
 | |
|   free(ch.data);
 | |
| }//SendMedia
 | |
| 
 | |
| //sends a control message
 | |
| void SendCTL(unsigned char type, unsigned int data){
 | |
|   chunkpack ch;
 | |
|   ch.cs_id = 2;
 | |
|   ch.timestamp = getNowMS();
 | |
|   ch.len = 4;
 | |
|   ch.real_len = 4;
 | |
|   ch.len_left = 0;
 | |
|   ch.msg_type_id = type;
 | |
|   ch.msg_stream_id = 0;
 | |
|   ch.data = (unsigned char*)malloc(4);
 | |
|   data = htonl(data);
 | |
|   memcpy(ch.data, &data, 4);
 | |
|   SendChunk(ch);
 | |
|   free(ch.data);
 | |
| }//SendCTL
 | |
| 
 | |
| //sends a control message
 | |
| void SendCTL(unsigned char type, unsigned int data, unsigned char data2){
 | |
|   chunkpack ch;
 | |
|   ch.cs_id = 2;
 | |
|   ch.timestamp = getNowMS();
 | |
|   ch.len = 5;
 | |
|   ch.real_len = 5;
 | |
|   ch.len_left = 0;
 | |
|   ch.msg_type_id = type;
 | |
|   ch.msg_stream_id = 0;
 | |
|   ch.data = (unsigned char*)malloc(5);
 | |
|   data = htonl(data);
 | |
|   memcpy(ch.data, &data, 4);
 | |
|   ch.data[4] = data2;
 | |
|   SendChunk(ch);
 | |
|   free(ch.data);
 | |
| }//SendCTL
 | |
| 
 | |
| //sends a usr control message
 | |
| void SendUSR(unsigned char type, unsigned int data){
 | |
|   chunkpack ch;
 | |
|   ch.cs_id = 2;
 | |
|   ch.timestamp = getNowMS();
 | |
|   ch.len = 6;
 | |
|   ch.real_len = 6;
 | |
|   ch.len_left = 0;
 | |
|   ch.msg_type_id = 4;
 | |
|   ch.msg_stream_id = 0;
 | |
|   ch.data = (unsigned char*)malloc(6);
 | |
|   data = htonl(data);
 | |
|   memcpy(ch.data+2, &data, 4);
 | |
|   ch.data[0] = 0;
 | |
|   ch.data[1] = type;
 | |
|   SendChunk(ch);
 | |
|   free(ch.data);
 | |
| }//SendUSR
 | |
| 
 | |
| //sends a usr control message
 | |
| void SendUSR(unsigned char type, unsigned int data, unsigned int data2){
 | |
|   chunkpack ch;
 | |
|   ch.cs_id = 2;
 | |
|   ch.timestamp = getNowMS();
 | |
|   ch.len = 10;
 | |
|   ch.real_len = 10;
 | |
|   ch.len_left = 0;
 | |
|   ch.msg_type_id = 4;
 | |
|   ch.msg_stream_id = 0;
 | |
|   ch.data = (unsigned char*)malloc(10);
 | |
|   data = htonl(data);
 | |
|   data2 = htonl(data2);
 | |
|   memcpy(ch.data+2, &data, 4);
 | |
|   memcpy(ch.data+6, &data2, 4);
 | |
|   ch.data[0] = 0;
 | |
|   ch.data[1] = type;
 | |
|   SendChunk(ch);
 | |
|   free(ch.data);
 | |
| }//SendUSR
 | |
| 
 | |
| //get a chunk from standard input
 | |
| struct chunkpack getChunk(){
 | |
|   gettimeofday(&lastrec, 0);
 | |
|   struct chunkpack ret;
 | |
|   unsigned char temp;
 | |
|   DDV_read(&(ret.chunktype), 1, 1, CONN_fd);
 | |
|   rec_cnt++;
 | |
|   //read the chunkstream ID properly
 | |
|   switch (ret.chunktype & 0x3F){
 | |
|     case 0:
 | |
|       DDV_read(&temp, 1, 1, CONN_fd);
 | |
|       rec_cnt++;
 | |
|       ret.cs_id = temp + 64;
 | |
|       break;
 | |
|     case 1:
 | |
|       DDV_read(&temp, 1, 1, CONN_fd);
 | |
|       ret.cs_id = temp + 64;
 | |
|       DDV_read(&temp, 1, 1, CONN_fd);
 | |
|       ret.cs_id += temp * 256;
 | |
|       rec_cnt+=2;
 | |
|       break;
 | |
|     default:
 | |
|       ret.cs_id = ret.chunktype & 0x3F;
 | |
|       break;
 | |
|   }
 | |
|   chunkinfo prev = GetPrev(ret.cs_id);
 | |
|   //process the rest of the header, for each chunk type
 | |
|   switch (ret.chunktype & 0xC0){
 | |
|     case 0x00:
 | |
|       DDV_read(&temp, 1, 1, CONN_fd);
 | |
|       ret.timestamp = temp*256*256;
 | |
|       DDV_read(&temp, 1, 1, CONN_fd);
 | |
|       ret.timestamp += temp*256;
 | |
|       DDV_read(&temp, 1, 1, CONN_fd);
 | |
|       ret.timestamp += temp;
 | |
|       DDV_read(&temp, 1, 1, CONN_fd);
 | |
|       ret.len = temp*256*256;
 | |
|       DDV_read(&temp, 1, 1, CONN_fd);
 | |
|       ret.len += temp*256;
 | |
|       DDV_read(&temp, 1, 1, CONN_fd);
 | |
|       ret.len += temp;
 | |
|       ret.len_left = 0;
 | |
|       DDV_read(&temp, 1, 1, CONN_fd);
 | |
|       ret.msg_type_id = temp;
 | |
|       DDV_read(&temp, 1, 1, CONN_fd);
 | |
|       ret.msg_stream_id = temp;
 | |
|       DDV_read(&temp, 1, 1, CONN_fd);
 | |
|       ret.msg_stream_id += temp*256;
 | |
|       DDV_read(&temp, 1, 1, CONN_fd);
 | |
|       ret.msg_stream_id += temp*256*256;
 | |
|       DDV_read(&temp, 1, 1, CONN_fd);
 | |
|       ret.msg_stream_id += temp*256*256*256;
 | |
|       rec_cnt+=11;
 | |
|       break;
 | |
|     case 0x40:
 | |
|       DDV_read(&temp, 1, 1, CONN_fd);
 | |
|       ret.timestamp = temp*256*256;
 | |
|       DDV_read(&temp, 1, 1, CONN_fd);
 | |
|       ret.timestamp += temp*256;
 | |
|       DDV_read(&temp, 1, 1, CONN_fd);
 | |
|       ret.timestamp += temp;
 | |
|       ret.timestamp += prev.timestamp;
 | |
|       DDV_read(&temp, 1, 1, CONN_fd);
 | |
|       ret.len = temp*256*256;
 | |
|       DDV_read(&temp, 1, 1, CONN_fd);
 | |
|       ret.len += temp*256;
 | |
|       DDV_read(&temp, 1, 1, CONN_fd);
 | |
|       ret.len += temp;
 | |
|       ret.len_left = 0;
 | |
|       DDV_read(&temp, 1, 1, CONN_fd);
 | |
|       ret.msg_type_id = temp;
 | |
|       ret.msg_stream_id = prev.msg_stream_id;
 | |
|       rec_cnt+=7;
 | |
|       break;
 | |
|     case 0x80:
 | |
|       DDV_read(&temp, 1, 1, CONN_fd);
 | |
|       ret.timestamp = temp*256*256;
 | |
|       DDV_read(&temp, 1, 1, CONN_fd);
 | |
|       ret.timestamp += temp*256;
 | |
|       DDV_read(&temp, 1, 1, CONN_fd);
 | |
|       ret.timestamp += temp;
 | |
|       ret.timestamp += prev.timestamp;
 | |
|       ret.len = prev.len;
 | |
|       ret.len_left = prev.len_left;
 | |
|       ret.msg_type_id = prev.msg_type_id;
 | |
|       ret.msg_stream_id = prev.msg_stream_id;
 | |
|       rec_cnt+=3;
 | |
|       break;
 | |
|     case 0xC0:
 | |
|       ret.timestamp = prev.timestamp;
 | |
|       ret.len = prev.len;
 | |
|       ret.len_left = prev.len_left;
 | |
|       ret.msg_type_id = prev.msg_type_id;
 | |
|       ret.msg_stream_id = prev.msg_stream_id;
 | |
|       break;
 | |
|   }
 | |
|   //calculate chunk length, real length, and length left till complete
 | |
|   if (ret.len_left > 0){
 | |
|     ret.real_len = ret.len_left;
 | |
|     ret.len_left -= ret.real_len;
 | |
|   }else{
 | |
|     ret.real_len = ret.len;
 | |
|   }
 | |
|   if (ret.real_len > chunk_rec_max){
 | |
|     ret.len_left += ret.real_len - chunk_rec_max;
 | |
|     ret.real_len = chunk_rec_max;
 | |
|   }
 | |
|   //read extended timestamp, if neccesary
 | |
|   if (ret.timestamp == 0x00ffffff){
 | |
|     DDV_read(&temp, 1, 1, CONN_fd);
 | |
|     ret.timestamp = temp*256*256*256;
 | |
|     DDV_read(&temp, 1, 1, CONN_fd);
 | |
|     ret.timestamp += temp*256*256;
 | |
|     DDV_read(&temp, 1, 1, CONN_fd);
 | |
|     ret.timestamp += temp*256;
 | |
|     DDV_read(&temp, 1, 1, CONN_fd);
 | |
|     ret.timestamp += temp;
 | |
|     rec_cnt+=4;
 | |
|   }
 | |
|   //read data if length > 0, and allocate it
 | |
|   if (ret.real_len > 0){
 | |
|     ret.data = (unsigned char*)malloc(ret.real_len);
 | |
|     DDV_read(ret.data, 1, ret.real_len, CONN_fd);
 | |
|     rec_cnt+=ret.real_len;
 | |
|   }else{
 | |
|     ret.data = 0;
 | |
|   }
 | |
|   PutPrev(ret);
 | |
|   return ret;
 | |
| }//getChunk
 | |
| 
 | |
| //adds newchunk to global list of unfinished chunks, re-assembling them complete
 | |
| //returns pointer to chunk when a chunk is finished, 0 otherwise
 | |
| //removes pointed to chunk from internal list if returned, without cleanup
 | |
| // (cleanup performed in getWholeChunk function)
 | |
| chunkpack * AddChunkPart(chunkpack newchunk){
 | |
|   chunkpack * p;
 | |
|   unsigned char * tmpdata = 0;
 | |
|   static std::map<unsigned int, chunkpack *> ch_lst;
 | |
|   std::map<unsigned int, chunkpack *>::iterator it;
 | |
|   it = ch_lst.find(newchunk.cs_id);
 | |
|   if (it == ch_lst.end()){
 | |
|     p = (chunkpack*)malloc(sizeof(chunkpack));
 | |
|     *p = newchunk;
 | |
|     p->data = (unsigned char*)malloc(p->real_len);
 | |
|     memcpy(p->data, newchunk.data, p->real_len);
 | |
|     if (p->len_left == 0){return p;}
 | |
|     ch_lst[newchunk.cs_id] = p;
 | |
|   }else{
 | |
|     p = it->second;
 | |
|     tmpdata = (unsigned char*)realloc(p->data, p->real_len + newchunk.real_len);
 | |
|     if (tmpdata == 0){
 | |
|       #ifdef DEBUG
 | |
|       fprintf(stderr, "Error allocating memory!\n");
 | |
|       #endif
 | |
|       return 0;
 | |
|     }
 | |
|     p->data = tmpdata;
 | |
|     memcpy(p->data+p->real_len, newchunk.data, newchunk.real_len);
 | |
|     p->real_len += newchunk.real_len;
 | |
|     p->len_left -= newchunk.real_len;
 | |
|     if (p->len_left <= 0){
 | |
|       ch_lst.erase(it);
 | |
|       return p;
 | |
|     }else{
 | |
|       ch_lst[newchunk.cs_id] = p;//pointer may have changed
 | |
|     }
 | |
|   }
 | |
|   return 0;
 | |
| }//AddChunkPart
 | |
| 
 | |
| //grabs chunks until a whole one comes in, then returns that
 | |
| chunkpack getWholeChunk(){
 | |
|   static chunkpack gwc_next, gwc_complete;
 | |
|   static bool clean = false;
 | |
|   int counter = 0;
 | |
|   if (!clean){gwc_complete.data = 0; clean = true;}//prevent brain damage
 | |
|   chunkpack * ret = 0;
 | |
|   scrubChunk(gwc_complete);
 | |
|   while (counter < 10000){
 | |
|     gwc_next = getChunk();
 | |
|     ret = AddChunkPart(gwc_next);
 | |
|     scrubChunk(gwc_next);
 | |
|     if (ret){
 | |
|       gwc_complete = *ret;
 | |
|       free(ret);//cleanup returned chunk
 | |
|       return gwc_complete;
 | |
|     }
 | |
|     if (socketError){break;}
 | |
|     counter++;
 | |
|   }
 | |
|   gwc_complete.msg_type_id = 0;
 | |
|   return gwc_complete;
 | |
| }//getWholeChunk
 | 
