/** ****************************************************************************** @file /net/comm.cpp @brief Spolecny predek k tridam klienta a serveru @author Vta @version 1.0 ******************************************************************************/ #include #include "net/comm.h" #include "net/compress.h" #include "common/compatibility.h" namespace net { TComm::TComm() { if ( (this->mutex=SDL_CreateMutex()) == NULL ) { GLOBALLOGID(PRIORITY_FATAL,"Can not create a mutext"); THROW(E_8K_NET,"Can not create a mutext"); } this->fd=0; this->xml_in_da=new DA(100); this->queue=new(TMessageQueue); this->port=DEFAULT_PORT; this->compressbuff=new DA(1000); this->status=STATUS_RUNNING; this->msg=(char*)KMemAlloc(sizeof(char)*MAX_SIZE_OF_MESSAGE); this->ping_time=PING_TIME; this->max_timeout=MAX_TIMEOUT; } TComm::~TComm() { delete(this->compressbuff); delete(this->queue); delete(this->xml_in_da); KMemFree(this->msg); SDL_DestroyMutex(mutex); } int sendInThread(void * data) { // size_t len2; TComm * that=(TComm *) data; char head[25]; try { SDL_SemPost(that->sem); GLOBALLOGID(PRIORITY_THREAD, "Comm - sendInThread is running"); TMessageQueue * q = that->queue; TMessageBody * message; int res; while (1) { while ((message=q->messageToSend())==NULL) // dokud ve fronte nic neni { SDL_Delay(COMM_WAIT_FOR_MESSAGE); if (q->isEnding()==QUEUE_ENDING) // fronta(tj. cely server/klient) se rusi { // printf("Ending send thread"); GLOBALLOGID(PRIORITY_THREAD, "Comm - sendInThread is ending"); return 0; } } // len=strlen(message->data)+1; GLOBALLOGID(PRIORITY_SENDING_DATA, "Sending data: %i Bytes",message->len); // printf("\nSending data\n"); // KOMENTAR!!! // that->lock(); if (/* (that->localGame==0) && */ (message->to!=0)) { if ((message->len>999999999) || (message->len<8)) { // printf(">>>> ALERT %i \n%s\n <<<<\n",len,message->data); THROW(E_8K_NET,"Damaged message to be sent"); } if (message->part_sent==0) // pouze prvni cast ma hlavicku { sprintf(head,"%09i",message->len); head[22]=0; // jen tak formalne res=that->sendTo(message->to,head,22); } // if (res!=22) // printf(">>>> ALERT spatna hlavicka\n%s\n <<<<\n",head); if ((message->len-message->part_sent)>MAX_SIZE_OF_MESSAGE) { res=that->sendTo(message->to,message->data+message->part_sent,MAX_SIZE_OF_MESSAGE); message->part_sent=message->part_sent+MAX_SIZE_OF_MESSAGE; } else { res=that->sendTo(message->to,message->data+message->part_sent,(message->len-message->part_sent)); message->part_sent=message->part_sent+(message->len-message->part_sent); } // if (res!=len) // printf(">>>> ALERT spatna zprava\n%s\n <<<<\n",message->data); } else { message->part_sent=message->len; // odeslano cele TXMLdata * receive = new (TXMLdata); // musi se vytvorit nova, jinak by se zabily data v TPackage if (receive->readChar(message->data)!=XML_ERROR_OK) { GLOBALLOGID(PRIORITY_FATAL,"SendInThread: Bad data to be sent"); // toto by doopravdy nemelo nastat delete (receive); } else { int structid=receive->getDataInt("_id_struct",0,NULL); if (structid==XML_ERROR_NO_SUCH_A_PATH) { GLOBALLOGID(PRIORITY_FATAL,"SendInThread: Bad data to be sent"); // toto by doopravdy nemelo nastat delete (receive); } else { TPackage * ret = new TPackage(structid); ret->setXML(receive); if (that->status!=STATUS_ENDING) KSendMessage(RQUEUE,MSG_MESSAGE_RECEIVED,MOD_NET,MOD_NET,(void*)ret); // vse jde na MESSAGE_RECEIVED tam pak az se to posle bud Worldu nebo posle zas pres sit } } // receive se nemaze, smaze ho prijemce spolu s ret } // printf("%i",res); q->messageWasSend(); // that->unlock(); SDL_Delay(COMM_WAIT_AFTER_MESSAGE); } } catch (E_8K &e) { GLOBALLOGID(PRIORITY_EXCETION_IN_THREAD, "Exception in sendInThread"); char err[1000]; snprintf(err,999,"%s:%i:%s",e.getFileName(),e.getLineNumber(),e.getDescription()); err[999]=0; GLOBALLOGID(PRIORITY_EXCETION_IN_THREAD, err); if (that->status!=STATUS_ENDING) KSendMessage(RQUEUE,MSG_EXCEPTION_IN_THREAD,MOD_NET,BROADCAST,&e); } return 0; } int TComm::createMySocket() { if ((this->fd = MySocket()) == MY_INVALID_SOCKET ) { GLOBALLOGID(PRIORITY_FATAL, "Comm - MySocket() error"); THROW(E_8K_NET,"Comm - MySocket() error"); // return MY_INVALID_SOCKET; } else { GLOBALLOGID(PRIORITY_NEW_SOCKET, "Sockcet this->fd = %i has been created",this->fd); // printf("fd: %i",this->fd); return 0; } } int TComm::sendTo(mysocket sock,const char * msg,size_t count) { return MySend(sock,msg,count); } int TComm::amILocal() { return this->localGame; } int TComm::recvFrom(mysocket sock,DA * recvbuff,DA *decompressbuff,int clientid,int &sizeofmessage) { char * old=this->msg; // schovani puvodniho naalokovaneho pole na prijem zprav this->lock(); // LOCK int i; if (sizeofmessage==0) // jeste nevim jak bude pristi zprava velka { int head=22; while (head!=0) { i=MyRecv(sock,this->msg+22-head,head); // nactu jen hlavicku if (i<=0) break; head=head-i; if (head!=0) { // printf(">>>> Alert <<<<"); } } this->msg[22]=0; if (i<22) { // printf(">>>> Alert <<<<"); } // printf("Nacitam hlavicku delka %i %s\n",i,this->msg); sizeofmessage=atoi(this->msg+6); this->unlock(); // UNLOCK return i; } else { if (sizeofmessage>(MAX_SIZE_OF_MESSAGE-1)) { i=MyRecv(sock,this->msg,MAX_SIZE_OF_MESSAGE-1); // zacnu nacitat zpravu if (i!=(MAX_SIZE_OF_MESSAGE-1)) { // printf(">>>> Alert <<<<"); // printf("Nacitam jen cast tela delka %i mela byt %i (celkem %i) %s\n",i,MAX_SIZE_OF_MESSAGE-1,sizeofmessage,this->msg); } } else { i=MyRecv(sock,this->msg,sizeofmessage); // zacnu nacitat zpravu if (i!=sizeofmessage) { // printf(">>>> Alert <<<<"); // printf("Nacitam jen cast tela delka %i mela byt %i %s\n",i,sizeofmessage,this->msg); } } if (i<=0) // nejaka chyba { sizeofmessage=0; this->unlock(); // UNLOCK return i; } else { sizeofmessage=sizeofmessage-i; } } this->msg[i]=0; if (i>0) { if (recvbuff->getActiveMembers()>0) recvbuff->push(NULL); // odeberu posledni nulu addtoda(recvbuff,this->msg,1); } if (sizeofmessage==0) // cela zpraav { int ret; TXMLdata * receive = new(TXMLdata); // printf(msg); #if COMPRESS_ACTIVE == 1 { MyDecompress(this->msg,i,decompressbuff); this->msg=decompressbuff->getData(); // docasne presmerovani ret=receive->readChar(this->msg); } #else { ret=receive->readChar(recvbuff->getData()); } #endif // printf("Zprava prijata\n"); // printf("%s\n\n",this->msg); /////////////////////////// /* DA temp; addtoda(&temp,this->msg,1); if (temp.getActiveMembers()>0) temp.push(NULL); // GLOBALLOGID(PRIORITY_SENDING_DATA, temp.getData()); */ /////////////////////////// // printf(this->msg); this->unlock(); // UNLOCK V DRUHE VETVI if (ret!=XML_ERROR_WRONG_INPUT) // pokud je to OK - je to uz cele { GLOBALLOGID(PRIORITY_SENDING_DATA, "Receiving data: %i Bytes",recvbuff->getMaxId()); int structid=receive->getDataInt("_id_struct",0,NULL); if (clientid!=0) // pouze server provadi tuto kontrolu { int from=receive->getDataInt("from_",0,NULL); if (from!=clientid) { GLOBALLOGID(PRIORITY_SENDING_DATA,"Bad Sender ID - the message at port %i has sender %i",clientid,from); } else // proslo to kontrolou u serveru { TPackage * ret = new TPackage(structid); ret->setXML(receive); KSendMessage(RQUEUE,MSG_MESSAGE_RECEIVED,MOD_NET,MOD_NET,(void*)ret); // vse jde na MESSAGE_RECEIVED tam pak az se to posle bud Worldu nebo posle zas pres sit recvbuff->reset(); } } else // klient to prijme vzdy { TPackage * ret = new TPackage(structid); ret->setXML(receive); KSendMessage(RQUEUE,MSG_MESSAGE_RECEIVED,MOD_NET,MOD_NET,(void*)ret); // vse jde na MESSAGE_RECEIVED tam pak az se to posle bud Worldu nebo posle zas pres sit recvbuff->reset(); } } else { GLOBALLOGID(PRIORITY_SENDING_DATA, "Receiving damaged message: %i Bytes",recvbuff->getMaxId()); // printf("\n%s\n\n",recvbuff->getData()); recvbuff->reset(); delete(receive); THROW(E_8K_NET,"Received damaged message"); } /* if (i<(MAX_SIZE_OF_MESSAGE-1)) // prisel jiste konec zpravy, pokud by nahodou jeste neco v this->recvbuff bylo, lze to odstranit, pristi recv uz bude pro nove xml { // recvbuff->reset(); } */ } else this->unlock(); // UNLOCK V JEDNE VETVI this->msg=old; // vraceni puvodniho bufferu return i; } int TComm::getStatus() { return this->status; } void TComm::lock(void) { if ( SDL_mutexP(this->mutex) < 0 ) { GLOBALLOGID(PRIORITY_FATAL, "Can not lock the mutext"); THROW(E_8K_NET,"Can not lock the mutext"); } GLOBALLOGID(PRIORITY_MUTEX,"Lock %i\n",SDL_ThreadID()); // printf("<"); } void TComm::unlock(void) { if ( SDL_mutexV(this->mutex) < 0 ) { GLOBALLOGID(PRIORITY_FATAL, "Can not unlock the mutext"); THROW(E_8K_NET,"Can not unlock the mutext"); } GLOBALLOGID(PRIORITY_MUTEX,"Unlock %i\n",SDL_ThreadID()); // printf(">"); } }