Home > Archive > Unix Programming > July 2004 > porting recvmsg()
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
|
|
| Wim Deprez 2004-07-22, 8:56 am |
| Hi Group,
for porting issues, I need to translate a recvmsg() to a
recvfrom()-function. Is this possible?
I have no experience with recvmsg() or msghdr and still writing some
test-code. Where does msghdr store the received data?
if the original code is
bytes_read=recvmsg(sd, &msg, 0);
I think it should be the following:
bytes_read=recvmsg(sd, &msg.msg_control->cmsg_data,
&msg.msg_control->cmsg_len, 0, (sockaddr
*)&msg.msn_name,&msg.msg_namelen);
but I am not sure. Can somebody guide me in the right direction?
Many kind greetings and thanks in advance,
--wim
| |
| Lev Walkin 2004-07-22, 8:56 am |
| Wim Deprez wrote:
> Hi Group,
>
> for porting issues, I need to translate a recvmsg() to a
> recvfrom()-function. Is this possible?
>
> I have no experience with recvmsg() or msghdr and still writing some
> test-code. Where does msghdr store the received data?
>
> if the original code is
>
> bytes_read=recvmsg(sd, &msg, 0);
>
> I think it should be the following:
>
> bytes_read=recvmsg(sd, &msg.msg_control->cmsg_data,
> &msg.msg_control->cmsg_len, 0, (sockaddr
> *)&msg.msn_name,&msg.msg_namelen);
>
> but I am not sure. Can somebody guide me in the right direction?
start from this one:
ssize_t
fake_recvmsg(int sd, struct msghdr *msg, int flags) {
ssize_t bytes_read;
assert(msg->msg_iov);
assert(msg->msg_iovlen == 1);
bytes_read = recvfrom(sd,
msg->msg_iov->iov_base,
msg->msg_iov->iov_len,
flags,
(struct sockaddr *)msg->msg_name,
msg->msg_namelen
);
return bytes_read;
}
--
Lev Walkin
vlm@lionet.info
| |
| Wim Deprez 2004-07-22, 3:58 pm |
| Lev Walkin wrote:
[...]
>
>
> start from this one:
>
>
>
> ssize_t
> fake_recvmsg(int sd, struct msghdr *msg, int flags) {
> ssize_t bytes_read;
>
> assert(msg->msg_iov);
> assert(msg->msg_iovlen == 1);
>
> bytes_read = recvfrom(sd,
> msg->msg_iov->iov_base,
> msg->msg_iov->iov_len,
> flags,
> (struct sockaddr *)msg->msg_name,
> msg->msg_namelen
> );
>
> return bytes_read;
> }
>
>
Ah, so that is how it works, thanks a lot :-)
Then I guess fake_sendmsg() should be something like this?
ssize_t
fake_sendmsg(int sd, struct msghdr *msg, int flags) {
ssize_t bytes_read;
assert(msg->msg_iov);
assert(msg->msg_iovlen == 1);
bytes_read = sendto(sd,
msg->msg_iov->iov_base,
msg->msg_iov->iov_len,
flags,
(struct sockaddr *)msg->msg_name,
msg->msg_namelen
);
return bytes_read;
}
and I guess the assert(msg->msg_iov) does something similar to
if(msg->msg_iov == NULL)
return -1;
?
Oh, does somebody has some example code so I can test this, please? The
framework is to big and complex to try it out.
Many kind greetings and thanks for the fast reply,
--wim
| |
| Casper H.S. Dik 2004-07-22, 3:58 pm |
| wim.deprez+google@student.luc.ac.be (Wim Deprez) writes:
>Hi Group,
>for porting issues, I need to translate a recvmsg() to a
>recvfrom()-function. Is this possible?
>I have no experience with recvmsg() or msghdr and still writing some
>test-code. Where does msghdr store the received data?
>if the original code is
> bytes_read=recvmsg(sd, &msg, 0);
>I think it should be the following:
> bytes_read=recvmsg(sd, &msg.msg_control->cmsg_data,
>&msg.msg_control->cmsg_len, 0, (sockaddr
>*)&msg.msn_name,&msg.msg_namelen);
>but I am not sure. Can somebody guide me in the right direction?
>Many kind greetings and thanks in advance,
No; the msg data goes into the msg_iov arguments; does you system
not have recvmsg?
Casper
--
Expressed in this posting are my opinions. They are in no way related
to opinions held by my employer, Sun Microsystems.
Statements on Sun products included here are not gospel and may
be fiction rather than truth.
| |
| Wim Deprez 2004-07-22, 3:58 pm |
|
"Casper H.S. Dik" <Casper.Dik@Sun.COM> escribió en el mensaje
news:40ffc2b3$0$36860$e4fe514c@news.xs4all.nl...
[...]
>
> No; the msg data goes into the msg_iov arguments; does you system
> not have recvmsg?
>
> Casper
the target system is win32 (yeah, they make me use it :-S) and as far as i
know, there is no recvmsg() there, so the porting is not that easy imho.
the original code goes like this:
<originalcode>
static struct msghdr msg;
static struct sockaddr msg_name;
static struct iovec msg_iov[2];
static int bytes_read;
/* Message Header */
msg.msg_name=(caddr_t) &msg_name;
msg.msg_namelen=sizeof(struct sockaddr_in);
msg_iov[0].iov_base=(caddr_t) SOMEHEADER;
msg_iov[0].iov_len=sizeof(SOMEHEADER); /* da letzten 2 nur dummys */
msg_iov[1].iov_base=((caddr_t) SOMEDATA);
msg_iov[1].iov_len=SOMEDATA_LENGTH;
msg.msg_iov=msg_iov;
msg.msg_iovlen=2;
bytes_read=recvmsg(sd, &msg, 0);
</originalcode>
I don't get the meaning of msg.msg_iovlen . Why is it two? So it contains 2
packets then?
Greetings,
--wim
| |
| Wim Deprez 2004-07-22, 3:58 pm |
|
"Lev Walkin" <vlm@lionet.info> escribió en el mensaje
news:2m9qegFki87rU1@uni-berlin.de...
[...]
> start from this one:
>
>
>
> ssize_t fake_recvmsg(int sd, struct msghdr *msg, int flags) {
> ssize_t bytes_read;
>
> assert(msg->msg_iov);
> assert(msg->msg_iovlen == 1);
>
> bytes_read = recvfrom(sd,
> msg->msg_iov->iov_base,
> msg->msg_iov->iov_len,
> flags,
> (struct sockaddr *)msg->msg_name,
> msg->msg_namelen
> );
>
> return bytes_read;
> }
>
>
the original code goes like this:
<originalcode>
static struct msghdr msg;
static struct sockaddr msg_name;
static struct iovec msg_iov[2];
static int bytes_read;
/* Message Header */
msg.msg_name=(caddr_t) &msg_name;
msg.msg_namelen=sizeof(struct sockaddr_in);
msg_iov[0].iov_base=(caddr_t) SOMEHEADER;
msg_iov[0].iov_len=sizeof(SOMEHEADER); /* da letzten 2 nur dummys */
msg_iov[1].iov_base=((caddr_t) SOMEDATA);
msg_iov[1].iov_len=SOMEDATA_LENGTH;
msg.msg_iov=msg_iov;
msg.msg_iovlen=2;
bytes_read=recvmsg(sd, &msg, 0);
</originalcode>
I don't get the meaning of msg.msg_iovlen . Why is it two? So it contains 2
packets then?
do I have to run recvfrom() twice then?
Greetings,
--wim
| |
| Lev Walkin 2004-07-22, 3:58 pm |
| Wim Deprez wrote:
> Lev Walkin wrote:
>
> [...]
>
>
>
>
> Ah, so that is how it works, thanks a lot :-)
>
> Then I guess fake_sendmsg() should be something like this?
>
> ssize_t
> fake_sendmsg(int sd, struct msghdr *msg, int flags) {
> ssize_t bytes_read;
>
> assert(msg->msg_iov);
> assert(msg->msg_iovlen == 1);
>
> bytes_read = sendto(sd,
> msg->msg_iov->iov_base,
> msg->msg_iov->iov_len,
> flags,
> (struct sockaddr *)msg->msg_name,
> msg->msg_namelen
> );
>
> return bytes_read;
> }
Almost. When sending, you should really try to avoid making
assumptions on msg_iovlen range. It is better to reconstruct the
message in one large buffer in case msg->msg_iovlen > 1, then
allow this to fail. Generally, you cannot be sure if caller would
use exactly one msg_iov structure, so make it a little more
flexible.
> and I guess the assert(msg->msg_iov) does something similar to
No. It just calls abort() if msg->msg_iov is NULL.
> if(msg->msg_iov == NULL)
> return -1;
Make a habit of setting errno. The correct code is
if(msg->msg_iov == NULL) {
errno = EFAULT; /* Or EINVAL */
return -1;
}
or you may just return 0 because it does not make sense
to send nothing.
--
Lev Walkin
vlm@lionet.info
| |
| Lev Walkin 2004-07-22, 3:58 pm |
| Wim Deprez wrote:
> "Lev Walkin" <vlm@lionet.info> escribi=F3 en el mensaje
> news:2m9qegFki87rU1@uni-berlin.de...
>=20
> [...]
>=20
>=20
>=20
>=20
> the original code goes like this:
>=20
> <originalcode>
> static struct msghdr msg;
> static struct sockaddr msg_name;
> static struct iovec msg_iov[2];
> static int bytes_read;
>=20
> /* Message Header */
> msg.msg_name=3D(caddr_t) &msg_name;
> msg.msg_namelen=3Dsizeof(struct sockaddr_in);
> msg_iov[0].iov_base=3D(caddr_t) SOMEHEADER;
> msg_iov[0].iov_len=3Dsizeof(SOMEHEADER); /* da letzten 2 nur dummys *=
/
> msg_iov[1].iov_base=3D((caddr_t) SOMEDATA);
> msg_iov[1].iov_len=3DSOMEDATA_LENGTH;
> msg.msg_iov=3Dmsg_iov;
> msg.msg_iovlen=3D2;
>=20
> bytes_read=3Drecvmsg(sd, &msg, 0);
> </originalcode>
>=20
> I don't get the meaning of msg.msg_iovlen . Why is it two? So it contai=
ns 2
> packets then?
> do I have to run recvfrom() twice then?
No. You have to reconstruct a big buffer out of two small ones. Like that=
:
ssize_t
fake_recvmsg(int sd, struct msghdr *msg, int flags) {
ssize_t bytes_read;
size_t expected_recv_size;
ssize_t left2move;
char *tmp_buf;
char *tmp;
int i;
assert(msg->msg_iov);
expected_recv_size =3D 0;
for(i =3D 0; i < msg->msg_iovlen; i++)
expected_recv_size +=3D msg->msg_iov[i].iov_len;
tmp_buf =3D malloc(expected_recv_size);
if(!tmp_buf)
return -1;
left2move =3D bytes_read =3D recvfrom(sd,
tmp_buf, expected_recv_size,
flags,
(struct sockaddr *)msg->msg_name,
msg->msg_namelen
);
for(tmp =3D tmp_buf, i =3D 0; i < msg->msg_iovlen; i++) {
if(left2move <=3D 0) break;
assert(msg->msg_iov[i].iov_base);
memcpy(msg->msg_iov[i].iov_base, tmp,
MIN(msg->msg_iov[i].iov_len, left2move);
left2move -=3D msg->msg_iov[i].iov_len;
tmp +=3D msg->msg_iov[i].iov_len;
}
free(tmp_buf);
return bytes_read;
}
--=20
Lev Walkin
vlm@lionet.info
| |
| Wim Deprez 2004-07-22, 3:58 pm |
| Lev Walkin wrote:
> Wim Deprez wrote:
>
[...]
[color=darkred]
>
> No. You have to reconstruct a big buffer out of two small ones. Like that:
>
> ssize_t
> fake_recvmsg(int sd, struct msghdr *msg, int flags) {
> ssize_t bytes_read;
> size_t expected_recv_size;
> ssize_t left2move;
> char *tmp_buf;
> char *tmp;
> int i;
>
> assert(msg->msg_iov);
>
> expected_recv_size = 0;
> for(i = 0; i < msg->msg_iovlen; i++)
> expected_recv_size += msg->msg_iov[i].iov_len;
> tmp_buf = malloc(expected_recv_size);
> if(!tmp_buf)
> return -1;
>
> left2move = bytes_read = recvfrom(sd,
> tmp_buf, expected_recv_size,
> flags,
> (struct sockaddr *)msg->msg_name,
> msg->msg_namelen
> );
>
> for(tmp = tmp_buf, i = 0; i < msg->msg_iovlen; i++) {
> if(left2move <= 0) break;
> assert(msg->msg_iov[i].iov_base);
> memcpy(msg->msg_iov[i].iov_base, tmp,
> MIN(msg->msg_iov[i].iov_len, left2move);
"MIN" ? never seen that before, sorry :-S what does it do?
> left2move -= msg->msg_iov[i].iov_len;
> tmp += msg->msg_iov[i].iov_len;
> }
>
> free(tmp_buf);
>
> return bytes_read;
> }
>
>
ok great, to be honest, until know i really did not get the concept of
'iovec', but i think i'm getting there now, thanks a lot!
now i try to make a simple example program to test the translations, but i
really don't get the recvmsg working:
<code>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
// <recvmsg>
#include <sys/uio.h>
#include <fcntl.h>
// </recvmsg>
#define MYPORT 4950 // the port users will be connecting to
#define MAXBUFLEN 100
int main(void)
{
int sockfd;
struct sockaddr_in my_addr; // my address information
int addr_len;
char buf[MAXBUFLEN];
static struct msghdr msg;
static struct sockaddr msg_name;
static struct iovec msg_iov;
static int bytes_read;
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("socket");
exit(1);
}
my_addr.sin_family = AF_INET; // host byte order
my_addr.sin_port = htons(MYPORT); // short, network byte order
my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP
memset(&(my_addr.sin_zero), '\0', 8); // zero the rest of the struct
if (bind(sockfd, (struct sockaddr *)&my_addr,
sizeof(struct sockaddr)) == -1) {
perror("bind");
exit(1);
}
msg.msg_name=(caddr_t) &msg_name;
msg.msg_namelen=sizeof(struct sockaddr_in);
msg_iov.iov_base="xxxxxxxx";
msg_iov.iov_len=MAXBUFLEN-1;
msg.msg_iov=&msg_iov;
msg.msg_iovlen=1;
if (-1==fcntl(sockfd, F_SETFL, O_NONBLOCK)) {
perror("vogelarij");
exit(1);
}
if((bytes_read=recvmsg(sockfd, &msg, 0)) == -1)
{
perror("recvmsg");
exit(1);
}
printf("packet is %d bytes long\n",bytes_read);
buf[bytes_read] = '\0';
printf("packet contains \"%s\"\n",buf);
close(sockfd);
return 0;
}
</code>
did i forget something??
Greetings and thanks,
--wim
| |
| Lev Walkin 2004-07-22, 3:58 pm |
| Wim Deprez wrote:
> ok great, to be honest, until know i really did not get the concept of
> 'iovec', but i think i'm getting there now, thanks a lot!
>
> now i try to make a simple example program to test the translations, but i
> really don't get the recvmsg working:
>
[skip]
> msg.msg_name=(caddr_t) &msg_name;
> msg.msg_namelen=sizeof(struct sockaddr_in);
> msg_iov.iov_base="xxxxxxxx";
> msg_iov.iov_len=MAXBUFLEN-1;
> did i forget something??
Very funny. This code will work only after
strcpy("abc", "def");
will start working on your unix platform.
You are supposed to allocate a _writable_ memory segment before
reading data into.
msg.msg_name=(caddr_t) &msg_name;
msg.msg_namelen=sizeof(msg_name); /* Note this too! */
msg_iov.iov_len=MAXBUFLEN;
msg_iov.iov_base=malloc(MAXBUFLEN);
--
Lev Walkin
vlm@lionet.info
| |
| Wim Deprez 2004-07-22, 3:58 pm |
|
"Lev Walkin" <vlm@lionet.info> :
[...]
>
> Very funny. This code will work only after
>
> strcpy("abc", "def");
>
> will start working on your unix platform.
>
> You are supposed to allocate a _writable_ memory segment before
> reading data into.
oh my God, i cannot believe i did that, the embarrassment... well, it works
now, receiving is ok now, thanks a lot!!
let's take a look at the sending now
many kind greetings,
--wim
| |
| Wim Deprez 2004-07-28, 9:05 pm |
| Lev Walkin <vlm@lionet.info> wrote:
[...]
> No. You have to reconstruct a big buffer out of two small ones. Like that
> :
>
> ssize t
> fake recvmsg(int sd, struct msghdr *msg, int flags) {
> ssize t bytes read;
> size t expected recv size;
> ssize t left2move;
> char *tmp buf;
> char *tmp;
> int i;
>
> assert(msg->msg iov);
>
> expected recv size = 0;
> for(i = 0; i < msg->msg iovlen; i++)
> expected recv size += msg->msg iov[i].iov len;
> tmp buf = malloc(expected recv size);
> if(!tmp buf)
> return -1;
>
> left2move = bytes read = recvfrom(sd,
> tmp buf, expected recv size,
> flags,
> (struct sockaddr *)msg->msg name,
> msg->msg namelen
> );
>
> for(tmp = tmp buf, i = 0; i < msg->msg iovlen; i++) {
> if(left2move <= 0) break;
> assert(msg->msg iov[i].iov base);
> memcpy(msg->msg iov[i].iov base, tmp,
> MIN(msg->msg iov[i].iov len, left2move);
> left2move -= msg->msg iov[i].iov len;
> tmp += msg->msg iov[i].iov len;
> }
>
> free(tmp buf);
>
> return bytes read;
> }
ok great, just for the threads-sake, i'll post my version of sendmsg()
then:
ssize_t fake_sendmsg(int sd, struct msghdr *msg, int flags)
{
ssize_t bytes_send;
size_t expected_send_size;
size_t left2move;
char *tmp_buf;
char *tmp;
int i;
assert(msg->msg_iov);
expected_send_size = 0;
for(i = 0; i < msg->msg_iovlen; i++)
expected_send_size += msg->msg_iov[i].iov_len;
tmp_buf = malloc(expected_send_size);
if(!tmp_buf)
return -1;
for(tmp = tmp_buf, left2move = expected_send_size, i = 0; i <
msg->msg_iovlen; i++)
{
if(left2move <= 0) break;
assert(msg->msg_iov[i].iov_base);
memcpy(
tmp,
msg->msg_iov[i].iov_base,
MIN(msg->msg_iov[i].iov_len,left2move));
left2move -= msg->msg_iov[i].iov_len;
tmp += msg->msg_iov[i].iov_len;
}
bytes_send = sendto(sd,
tmp_buf,
expected_send_size,
flags,
(struct sockaddr *)msg->msg_name,
msg->msg_namelen
);
free(tmp_buf);
return bytes_send;
}
guess that's quite ok... any comments are welcome of course :-)
Thanks a lot Lev, you really guided me in the right direction :-)
Many kind greetings,
--wim
| |
|
| Wim Deprez wrote:
[snip]
> ok great, just for the threads-sake, i'll post my version of sendmsg()
> then:
>
> ssize_t fake_sendmsg(int sd, struct msghdr *msg, int flags)
> {
> ssize_t bytes_send;
> size_t expected_send_size;
> size_t left2move;
> char *tmp_buf;
> char *tmp;
> int i;
>
> assert(msg->msg_iov);
>
> expected_send_size = 0;
> for(i = 0; i < msg->msg_iovlen; i++)
> expected_send_size += msg->msg_iov[i].iov_len;
> tmp_buf = malloc(expected_send_size);
> if(!tmp_buf)
> return -1;
>
> for(tmp = tmp_buf, left2move = expected_send_size, i = 0; i <
> msg->msg_iovlen; i++)
> {
> if(left2move <= 0) break;
> assert(msg->msg_iov[i].iov_base);
> memcpy(
> tmp,
> msg->msg_iov[i].iov_base,
> MIN(msg->msg_iov[i].iov_len,left2move));
> left2move -= msg->msg_iov[i].iov_len;
> tmp += msg->msg_iov[i].iov_len;
> }
>
> bytes_send = sendto(sd,
> tmp_buf,
> expected_send_size,
> flags,
> (struct sockaddr *)msg->msg_name,
> msg->msg_namelen
> );
>
> free(tmp_buf);
>
> return bytes_send;
> }
>
> guess that's quite ok... any comments are welcome of course :-)
OK.
a) If the variable expected_send_size turns out to be zero, malloc()
will return NULL on some platforms. Your function will then return -1,
indicating an error. Maybe it is better just to return 0 if
expected_send_size is 0?
b) Do you need the left2move variable?
boa@home
[snip]
| |
| Wim Deprez 2004-07-28, 9:05 pm |
| boa <root@localhost.com> wrote in message news:<ucRMc.911$Cc.208791@juliett.dax.net>...
> Wim Deprez wrote:
>
> [snip]
>
>
> OK.
> a) If the variable expected_send_size turns out to be zero, malloc()
> will return NULL on some platforms. Your function will then return -1,
> indicating an error. Maybe it is better just to return 0 if
> expected_send_size is 0?
ok, thanks for the tip
>
> b) Do you need the left2move variable?
don't see any harm in it, thought it to be more "readable", no?
>
> boa@home
>
> [snip]
thanks for the comments, greetings,
--wim
|
|
|
|
|