Ho due processi che comunicano su una coppia di socket creati con socketpair() e SOCK_SEQPACKET. Come questo:Perché non vedo MSG_EOR per SOCK_SEQPACKET su linux?
int ipc_sockets[2];
socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, ipc_sockets);
A quanto ho capito, mi dovrebbe vedere MSG_EOR negli Stati msg_flags di "struct msghdr" quando si riceve un record SOCK_SEQPACKET. Sto impostando MSG_EOR in sendmsg() per essere certo che il record sia segnato MSG_EOR, ma non lo vedo quando lo ricevo in recvmsg(). Ho persino provato a impostare MSG_EOR nel campo msg_flags prima di inviare il record, ma ciò non ha fatto alcuna differenza.
Penso che dovrei vedere MSG_EOR a meno che il record non sia stato interrotto, ad es. un segnale, ma io no. Perché?
Ho incollato il mio codice di invio e ricezione in basso.
Grazie, Jules
int
send_fd(int fd,
void *data,
const uint32_t len,
int fd_to_send,
uint32_t * const bytes_sent)
{
ssize_t n;
struct msghdr msg;
struct iovec iov;
memset(&msg, 0, sizeof(struct msghdr));
memset(&iov, 0, sizeof(struct iovec));
#ifdef HAVE_MSGHDR_MSG_CONTROL
union {
struct cmsghdr cm;
char control[CMSG_SPACE_SIZEOF_INT];
} control_un;
struct cmsghdr *cmptr;
msg.msg_control = control_un.control;
msg.msg_controllen = sizeof(control_un.control);
memset(msg.msg_control, 0, sizeof(control_un.control));
cmptr = CMSG_FIRSTHDR(&msg);
cmptr->cmsg_len = CMSG_LEN(sizeof(int));
cmptr->cmsg_level = SOL_SOCKET;
cmptr->cmsg_type = SCM_RIGHTS;
*((int *) CMSG_DATA(cmptr)) = fd_to_send;
#else
msg.msg_accrights = (caddr_t) &fd_to_send;
msg.msg_accrightslen = sizeof(int);
#endif
msg.msg_name = NULL;
msg.msg_namelen = 0;
iov.iov_base = data;
iov.iov_len = len;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
#ifdef __linux__
msg.msg_flags = MSG_EOR;
n = sendmsg(fd, &msg, MSG_EOR);
#elif defined __APPLE__
n = sendmsg(fd, &msg, 0); /* MSG_EOR is not supported on Mac
* OS X due to lack of
* SOCK_SEQPACKET support on
* socketpair() */
#endif
switch (n) {
case EMSGSIZE:
return EMSGSIZE;
case -1:
return 1;
default:
*bytes_sent = n;
}
return 0;
}
int
recv_fd(int fd,
void *buf,
const uint32_t len,
int *recvfd,
uint32_t * const bytes_recv)
{
struct msghdr msg;
struct iovec iov;
ssize_t n = 0;
#ifndef HAVE_MSGHDR_MSG_CONTROL
int newfd;
#endif
memset(&msg, 0, sizeof(struct msghdr));
memset(&iov, 0, sizeof(struct iovec));
#ifdef HAVE_MSGHDR_MSG_CONTROL
union {
struct cmsghdr cm;
char control[CMSG_SPACE_SIZEOF_INT];
} control_un;
struct cmsghdr *cmptr;
msg.msg_control = control_un.control;
msg.msg_controllen = sizeof(control_un.control);
memset(msg.msg_control, 0, sizeof(control_un.control));
#else
msg.msg_accrights = (caddr_t) &newfd;
msg.msg_accrightslen = sizeof(int);
#endif
msg.msg_name = NULL;
msg.msg_namelen = 0;
iov.iov_base = buf;
iov.iov_len = len;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
if (recvfd)
*recvfd = -1;
n = recvmsg(fd, &msg, 0);
if (msg.msg_flags) { // <== I should see MSG_EOR here if the entire record was received
return 1;
}
if (bytes_recv)
*bytes_recv = n;
switch (n) {
case 0:
*bytes_recv = 0;
return 0;
case -1:
return 1;
default:
break;
}
#ifdef HAVE_MSGHDR_MSG_CONTROL
if ((NULL != (cmptr = CMSG_FIRSTHDR(&msg)))
&& cmptr->cmsg_len == CMSG_LEN(sizeof(int))) {
if (SOL_SOCKET != cmptr->cmsg_level) {
return 0;
}
if (SCM_RIGHTS != cmptr->cmsg_type) {
return 0;
}
if (recvfd)
*recvfd = *((int *) CMSG_DATA(cmptr));
}
#else
if (recvfd && (sizeof(int) == msg.msg_accrightslen))
*recvfd = newfd;
#endif
return 0;
}
Non letto tutto troppo, come si può vedere da me confondendo su quale metodo stavo leggendo, inviando e ricevendo condivido un sacco di codice che potrebbe essere scomposto. Stai cercando di inviare dati fuori banda. Le prese e le pipe IP non possono inviare dati fuori banda (tranne EOF quando la connessione è chiusa), presumo che le prese unix siano le stesse. –