void EQStream::WritePacket(int eq_fd, EQProtocolPacket *p) { uint32 length; sockaddr_in address; address.sin_family = AF_INET; address.sin_addr.s_addr=remote_ip; address.sin_port=remote_port; #ifdef NOWAY uint32 ip=address.sin_addr.s_addr; std::cout << "Sending to: " << (int)*(unsigned char *)&ip << "." << (int)*((unsigned char *)&ip+1) << "." << (int)*((unsigned char *)&ip+2) << "." << (int)*((unsigned char *)&ip+3) << "," << (int)ntohs(address.sin_port) << "(" << p->size << ")" << std::endl; p->DumpRaw(); std::cout << "-------------" << std::endl; #endif length=p->serialize(buffer); if (p->opcode!=OP_SessionRequest && p->opcode!=OP_SessionResponse) { if (compressed) { uint32 newlen=EQProtocolPacket::Compress(buffer,length, _tempBuffer, 2048); memcpy(buffer,_tempBuffer,newlen); length=newlen; } if (encoded) { EQProtocolPacket::ChatEncode(buffer,length,Key); } *(uint16 *)(buffer+length)=htons(CRC16(buffer,length,Key)); length+=2; } //dump_message_column(buffer,length,"Writer: "); sendto(eq_fd,(char *)buffer,length,0,(sockaddr *)&address,sizeof(address)); AddBytesSent(length); }
void EQStream::Write(int eq_fd) { queue<EQProtocolPacket *> ReadyToSend; bool SeqEmpty=false,NonSeqEmpty=false; deque<EQProtocolPacket *>::iterator sitr; // Check our rate to make sure we can send more MRate.lock(); int32 threshold=RateThreshold; MRate.unlock(); if (BytesWritten > threshold) { //cout << "Over threshold: " << BytesWritten << " > " << threshold << endl; return; } // If we got more packets to we need to ack, send an ack on the highest one MAcks.lock(); if (CompareSequence(LastAckSent, NextAckToSend) == SeqFuture) SendAck(NextAckToSend); MAcks.unlock(); // Lock the outbound queues while we process MOutboundQueue.lock(); // Place to hold the base packet t combine into EQProtocolPacket *p=NULL; #ifdef RETRANSMITS // if we have a timeout defined and we have not received an ack recently enough, retransmit from beginning of queue if (RuleR(EQStream, RetransmitTimeoutMult) && !SequencedQueue.empty() && NextSequencedSend && (GetState()==ESTABLISHED) && ((retransmittimer+retransmittimeout) < Timer::GetCurrentTime())) { _log(NET__NET_TRACE, _L "Timeout since last ack received, starting retransmit at the start of our unacked buffer (seq %d, was %d)." __L, SequencedBase, SequencedBase+NextSequencedSend); NextSequencedSend = 0; retransmittimer = Timer::GetCurrentTime(); // don't want to endlessly retransmit the first packet } #endif // Find the next sequenced packet to send from the "queue" sitr = SequencedQueue.begin(); if (sitr!=SequencedQueue.end()) sitr += NextSequencedSend; // Loop until both are empty or MaxSends is reached while(!SeqEmpty || !NonSeqEmpty) { // See if there are more non-sequenced packets left if (!NonSequencedQueue.empty()) { if (!p) { // If we don't have a packet to try to combine into, use this one as the base // And remove it form the queue p = NonSequencedQueue.front(); _log(NET__NET_COMBINE, _L "Starting combined packet with non-seq packet of len %d" __L, p->size); NonSequencedQueue.pop(); } else if (!p->combine(NonSequencedQueue.front())) { // Tryint to combine this packet with the base didn't work (too big maybe) // So just send the base packet (we'll try this packet again later) _log(NET__NET_COMBINE, _L "Combined packet full at len %d, next non-seq packet is len %d" __L, p->size, (NonSequencedQueue.front())->size); ReadyToSend.push(p); BytesWritten+=p->size; p=NULL; if (BytesWritten > threshold) { // Sent enough this round, lets stop to be fair _log(NET__RATES, _L "Exceeded write threshold in nonseq (%d > %d)" __L, BytesWritten, threshold); break; } } else { // Combine worked, so just remove this packet and it's spot in the queue _log(NET__NET_COMBINE, _L "Combined non-seq packet of len %d, yeilding %d combined." __L, (NonSequencedQueue.front())->size, p->size); delete NonSequencedQueue.front(); NonSequencedQueue.pop(); } } else { // No more non-sequenced packets NonSeqEmpty=true; } if (sitr!=SequencedQueue.end()) { //_log(NET__NET_COMBINE, _L "Send Seq with %d seq packets starting at seq %d, next send %d, and %d non-seq packets." __L, // SequencedQueue.size(), SequencedBase, NextSequencedSend, NonSequencedQueue.size()); if(uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) { _log(NET__ERROR, _L "Pre-Send Seq NSS=%d Invalid Sequenced queue: BS %d + SQ %d != NOS %d" __L, NextSequencedSend, SequencedBase, SequencedQueue.size(), NextOutSeq); } if(NextSequencedSend > SequencedQueue.size()) { _log(NET__ERROR, _L "Pre-Send Next Send Sequence is beyond the end of the queue NSS %d > SQ %d" __L, NextSequencedSend, SequencedQueue.size()); } uint16 seq_send = SequencedBase + NextSequencedSend; //just for logging... if(SequencedQueue.empty()) { _log(NET__ERROR, _L "Tried to write a packet with an empty queue (%d is past next out %d)" __L, seq_send, NextOutSeq); SeqEmpty=true; continue; } /*if(CompareSequence(NextOutSeq, seq_send) == SeqFuture) { _log(NET__ERROR, _L "Tried to write a packet beyond the end of the queue! (%d is past next out %d)" __L, seq_send, NextOutSeq); sitr=SequencedQueue.end(); continue; }*/ #ifdef RETRANSMITS if (!RuleB(EQStream, RetransmitAckedPackets) && (*sitr)->acked) { _log(NET__NET_TRACE, _L "Not retransmitting seq packet %d because already marked as acked" __L, seq_send); sitr++; NextSequencedSend++; } else if (!p) { #else if (!p) { #endif // If we don't have a packet to try to combine into, use this one as the base // Copy it first as it will still live until it is acked p=(*sitr)->Copy(); _log(NET__NET_COMBINE, _L "Starting combined packet with seq packet %d of len %d" __L, seq_send, p->size); sitr++; NextSequencedSend++; } else if (!p->combine(*sitr)) { // Trying to combine this packet with the base didn't work (too big maybe) // So just send the base packet (we'll try this packet again later) _log(NET__NET_COMBINE, _L "Combined packet full at len %d, next seq packet %d is len %d" __L, p->size, seq_send, (*sitr)->size); ReadyToSend.push(p); BytesWritten+=p->size; p=NULL; if (BytesWritten > threshold) { // Sent enough this round, lets stop to be fair _log(NET__RATES, _L "Exceeded write threshold in seq (%d > %d)" __L, BytesWritten, threshold); break; } } else { // Combine worked _log(NET__NET_COMBINE, _L "Combined seq packet %d of len %d, yeilding %d combined." __L, seq_send, (*sitr)->size, p->size); sitr++; NextSequencedSend++; } if(uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) { _log(NET__ERROR, _L "Post send Invalid Sequenced queue: BS %d + SQ %d != NOS %d" __L, SequencedBase, SequencedQueue.size(), NextOutSeq); } if(NextSequencedSend > SequencedQueue.size()) { _log(NET__ERROR, _L "Post send Next Send Sequence is beyond the end of the queue NSS %d > SQ %d" __L, NextSequencedSend, SequencedQueue.size()); } } else { // No more sequenced packets SeqEmpty=true; } } // Unlock the queue MOutboundQueue.unlock(); // We have a packet still, must have run out of both seq and non-seq, so send it if (p) { _log(NET__NET_COMBINE, _L "Final combined packet not full, len %d" __L, p->size); ReadyToSend.push(p); BytesWritten+=p->size; } // Send all the packets we "made" while(!ReadyToSend.empty()) { p = ReadyToSend.front(); WritePacket(eq_fd,p); delete p; ReadyToSend.pop(); } //see if we need to send our disconnect and finish our close if(SeqEmpty && NonSeqEmpty) { //no more data to send if(CheckState(CLOSING)) { _log(NET__DEBUG, _L "All outgoing data flushed, closing stream." __L ); //we are waiting for the queues to empty, now we can do our disconnect. //this packet will not actually go out until the next call to Write(). _SendDisconnect(); SetState(DISCONNECTING); } } } void EQStream::WritePacket(int eq_fd, EQProtocolPacket *p) { uint32 length; sockaddr_in address; address.sin_family = AF_INET; address.sin_addr.s_addr=remote_ip; address.sin_port=remote_port; #ifdef NOWAY uint32 ip=address.sin_addr.s_addr; cout << "Sending to: " << (int)*(unsigned char *)&ip << "." << (int)*((unsigned char *)&ip+1) << "." << (int)*((unsigned char *)&ip+2) << "." << (int)*((unsigned char *)&ip+3) << "," << (int)ntohs(address.sin_port) << "(" << p->size << ")" << endl; p->DumpRaw(); cout << "-------------" << endl; #endif length=p->serialize(buffer); if (p->opcode!=OP_SessionRequest && p->opcode!=OP_SessionResponse) { if (compressed) { uint32 newlen=EQProtocolPacket::Compress(buffer,length, _tempBuffer, 2048); memcpy(buffer,_tempBuffer,newlen); length=newlen; } if (encoded) { EQProtocolPacket::ChatEncode(buffer,length,Key); } *(uint16 *)(buffer+length)=htons(CRC16(buffer,length,Key)); length+=2; } //dump_message_column(buffer,length,"Writer: "); sendto(eq_fd,(char *)buffer,length,0,(sockaddr *)&address,sizeof(address)); AddBytesSent(length); }