int Peer_Handler::recv (ACE_Message_Block *&mb) { if (this->msg_frag_ == 0) // No existing fragment... ACE_NEW_RETURN (this->msg_frag_, ACE_Message_Block (sizeof (Event)), -1); Event *event = (Event *) this->msg_frag_->rd_ptr (); ssize_t header_received = 0; const size_t HEADER_SIZE = sizeof (Event_Header); ssize_t header_bytes_left_to_read = HEADER_SIZE - this->msg_frag_->length (); if (header_bytes_left_to_read > 0) { header_received = this->peer ().recv (this->msg_frag_->wr_ptr (), header_bytes_left_to_read); if (header_received == -1 /* error */ || header_received == 0 /* EOF */) { ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("Recv error during header read"))); ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("attempted to read %d bytes\n"), header_bytes_left_to_read)); this->msg_frag_ = this->msg_frag_->release (); return header_received; } // Bump the write pointer by the amount read. this->msg_frag_->wr_ptr (header_received); // At this point we may or may not have the ENTIRE header. if (this->msg_frag_->length () < HEADER_SIZE) { ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Partial header received: only %d bytes\n"), this->msg_frag_->length ())); // Notify the caller that we didn't get an entire event. errno = EWOULDBLOCK; return -1; } // Convert the header into host byte order so that we can access // it directly without having to repeatedly muck with it... event->header_.decode (); if (event->header_.len_ > ACE_INT32 (sizeof event->data_)) { // This data_ payload is too big! errno = EINVAL; ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Data payload is too big (%d bytes)\n"), event->header_.len_)); return -1; } } // At this point there is a complete, valid header in Event. Now we // need to get the event payload. Due to incomplete reads this may // not be the first time we've read in a fragment for this message. // We account for this here. Note that the first time in here // <msg_frag_->wr_ptr> will point to <event->data_>. Every time we // do a successful fragment read, we advance <wr_ptr>. Therefore, // by subtracting how much we've already read from the // <event->header_.len_> we complete the // <data_bytes_left_to_read>... ssize_t data_bytes_left_to_read = ssize_t (event->header_.len_ - (msg_frag_->wr_ptr () - event->data_)); // peer().recv() should not be called when data_bytes_left_to_read is 0. ssize_t data_received = !data_bytes_left_to_read ? 0 : this->peer ().recv (this->msg_frag_->wr_ptr (), data_bytes_left_to_read); // Try to receive the remainder of the event. switch (data_received) { case -1: if (errno == EWOULDBLOCK) // This might happen if only the header came through. return -1; /* FALLTHROUGH */; case 0: // Premature EOF. if (data_bytes_left_to_read) { this->msg_frag_ = this->msg_frag_->release (); return 0; } /* FALLTHROUGH */; default: // Set the write pointer at 1 past the end of the event. this->msg_frag_->wr_ptr (data_received); if (data_received != data_bytes_left_to_read) { errno = EWOULDBLOCK; // Inform caller that we didn't get the whole event. return -1; } else { // Set the read pointer to the beginning of the event. this->msg_frag_->rd_ptr (this->msg_frag_->base ()); mb = this->msg_frag_; // Reset the pointer to indicate we've got an entire event. this->msg_frag_ = 0; } ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) connection id = %d, cur len = %d, total bytes read = %d\n"), event->header_.connection_id_, event->header_.len_, data_received + header_received)); if (Options::instance ()->enabled (Options::VERBOSE)) ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("data_ = %*s\n"), event->header_.len_ - 2, event->data_)); return data_received + header_received; } }
int Supplier_Handler::recv (ACE_Message_Block *&forward_addr) { if (this->msg_frag_ == 0) // No existing fragment... ACE_NEW_RETURN (this->msg_frag_, ACE_Message_Block (sizeof (Event), ACE_Message_Block::MB_DATA, 0, 0, 0, Options::instance ()->locking_strategy ()), -1); Event *event = (Event *) this->msg_frag_->rd_ptr (); ssize_t header_received = 0; const size_t HEADER_SIZE = sizeof (Event_Header); ssize_t header_bytes_left_to_read = HEADER_SIZE - this->msg_frag_->length (); if (header_bytes_left_to_read > 0) { header_received = this->peer ().recv (this->msg_frag_->wr_ptr (), header_bytes_left_to_read); if (header_received == -1 /* error */ || header_received == 0 /* EOF */) { ACE_ERROR ((LM_ERROR, "%p\n", "Recv error during header read ")); ACE_DEBUG ((LM_DEBUG, "attempted to read %d\n", header_bytes_left_to_read)); this->msg_frag_ = this->msg_frag_->release (); return header_received; } // Bump the write pointer by the amount read. this->msg_frag_->wr_ptr (header_received); // At this point we may or may not have the ENTIRE header. if (this->msg_frag_->length () < HEADER_SIZE) { ACE_DEBUG ((LM_DEBUG, "Partial header received: only %d bytes\n", this->msg_frag_->length ())); // Notify the caller that we didn't get an entire event. errno = EWOULDBLOCK; return -1; } // Convert the header into host byte order so that we can access // it directly without having to repeatedly muck with it... event->header_.decode (); if (event->header_.len_ > ACE_INT32 (sizeof event->data_)) { // This data_ payload is too big! errno = EINVAL; ACE_DEBUG ((LM_DEBUG, "Data payload is too big (%d bytes)\n", event->header_.len_)); return -1; } } // At this point there is a complete, valid header in Event. Now we // need to get the event payload. Due to incomplete reads this may // not be the first time we've read in a fragment for this message. // We account for this here. Note that the first time in here // msg_frag_->wr_ptr() will point to event->data_. Every time we do // a successful fragment read, we advance wr_ptr(). Therefore, by // subtracting how much we've already read from the // event->header_.len_ we complete the data_bytes_left_to_read... ssize_t data_bytes_left_to_read = ssize_t (event->header_.len_ - (msg_frag_->wr_ptr () - event->data_)); ssize_t data_received = !data_bytes_left_to_read ? 0 // peer().recv() should not be called when data_bytes_left_to_read is 0. : this->peer ().recv (this->msg_frag_->wr_ptr (), data_bytes_left_to_read); // Try to receive the remainder of the event. switch (data_received) { case -1: if (errno == EWOULDBLOCK) // This might happen if only the header came through. return -1; else /* FALLTHROUGH */; case 0: // Premature EOF. if (data_bytes_left_to_read) { this->msg_frag_ = this->msg_frag_->release (); return 0; } /* FALLTHROUGH */; default: // Set the write pointer at 1 past the end of the event. this->msg_frag_->wr_ptr (data_received); if (data_received != data_bytes_left_to_read) { errno = EWOULDBLOCK; // Inform caller that we didn't get the whole event. return -1; } else { // Set the read pointer to the beginning of the event. this->msg_frag_->rd_ptr (this->msg_frag_->base ()); // Allocate an event forwarding header and chain the data // portion onto its continuation field. forward_addr = new ACE_Message_Block (sizeof (Event_Key), ACE_Message_Block::MB_PROTO, this->msg_frag_, 0, 0, Options::instance ()->locking_strategy ()); if (forward_addr == 0) { this->msg_frag_ = this->msg_frag_->release (); errno = ENOMEM; return -1; } Event_Key event_addr (this->connection_id (), event->header_.type_); // Copy the forwarding address from the Event_Key into // forward_addr. forward_addr->copy ((char *) &event_addr, sizeof (Event_Key)); // Reset the pointer to indicate we've got an entire event. this->msg_frag_ = 0; } this->total_bytes (data_received + header_received); ACE_DEBUG ((LM_DEBUG, "(%t) connection id = %d, cur len = %d, total bytes read = %d\n", event->header_.connection_id_, event->header_.len_, data_received + header_received)); if (Options::instance ()->enabled (Options::VERBOSE)) ACE_DEBUG ((LM_DEBUG, "data_ = %*s\n", event->header_.len_ - 2, event->data_)); // Encode before returning so that we can set things out in // network byte order. event->header_.encode (); return data_received + header_received; } }