c - recvmsg linux receive wrong data -
i using recvmsg , sendmsg send data on asynchronous stream socket . amount of data transfer rather big, between 15 mb , 30 mb.
i cannot understand why data arrives corrupted. sending messages , reciving function gets interrupted errno eintr adn eagain.
the functions ma using :
int receive_result_with_extra(int fd, struct syscall_result * result, int extra_size, char * buf) { struct iovec io[2]; struct msghdr msg; int transfered=0, temp=0; const int total = size_result + extra_size; clean_msg(&msg); memset(io, 0, sizeof(io)); // result header io[1].iov_len=size_result; io[1].iov_base=result; // result buffer io[0].iov_len = extra_size; io[0].iov_base = buf; // iov struct msg.msg_iov=io; msg.msg_iovlen=2; { temp = recvmsg(fd,&msg, 0); if ( temp < 0 && (errno==eagain || errno == eintr || errno == ewouldblock)) continue; else if ( temp < 0 ) die("error receiveing data recvmsg (receive_result_with_extra)"); transfered += temp; } while(transfered < total); if ( transfered < 0) die("recvmsg (receive_result_with_extra)"); assert(transfered == total); return transfered; } int send_result_with_extra(int fd, struct syscall_result * result, int extra_size, char * buf) { struct iovec io[2]; struct msghdr msg; int transfered=0, temp=0; const int total = size_result + extra_size; clean_msg(&msg); memset(io, 0, sizeof(io)); // result header io[1].iov_len=size_result; io[1].iov_base=result; // result buffer io[0].iov_len = extra_size; io[0].iov_base = buf; // iov struct msg.msg_iov=io; msg.msg_iovlen=2; { temp=sendmsg(fd,&msg, 0); if ( temp < 0 && (errno == eintr || errno == eagain || errno == ewouldblock)) continue; else if ( temp < 0) die("failed sending data ( send_result_with_extra)"); transfered += temp; } while( transfered < total); if ( transfered < 0) die("recvmsg (fstat handler)"); assert(transfered == total); return transfered; }
you don't update iovecs in send/recv loops, repeatedly send same prefix / recv beginning of data buffer if data large transfer in single network packet.
i use common function both send , receive update iovec:
/** * shrinks iovec associated msg given number of bytes. * * @msg message iovec needs updating. * @bytes number of bytes remove beginning of iovec. * * @return returns 0 iff updated iovec empty. */ int update_buffer(struct msghdr* msg, size_t bytes) { while (msg->msg_iovlen > 0) { if (bytes < msg->msg_iov[0].iov_len) { msg->msg_iov[0].iov_len -= bytes; msg->msg_iov[0].iov_base += bytes; return 1; } bytes -= msg->msg_iov[0].iov_len; ++msg->msg_iov; --msg->msg_iovlen; } return 0; } you can use return value of update function in condition of send/recv loops. e.g.:
do { { temp = sendmsg(fd, &msg, 0); } while (temp < 0 && (errno == eintr || errno == eagain || errno == ewouldblock)); if (temp < 0) die("failed sending data (send_result_with_extra)"); } while (update_buffer(&msg, temp));
Comments
Post a Comment