Example #1
0
static int process_response(int wait_for_done, unsigned seq) {
    assert(fd >= 0);
    
    do {
        size_t bytes;
        ssize_t r;
        char replybuf[8*1024];
        char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
        struct msghdr msghdr;
        struct cmsghdr *cmsghdr;
        struct ucred *ucred;
        struct iovec iov; 
        struct nlmsghdr *p = (struct nlmsghdr *) replybuf;
        
        memset(&iov, 0, sizeof(iov));
        iov.iov_base = replybuf; 
 	iov.iov_len = sizeof(replybuf);

        memset(&msghdr, 0, sizeof(msghdr));
        msghdr.msg_name = (void*) NULL;
        msghdr.msg_namelen = 0; 
        msghdr.msg_iov = &iov; 
        msghdr.msg_iovlen = 1; 
        msghdr.msg_control = cred_msg; 
        msghdr.msg_controllen = sizeof(cred_msg); 
 	msghdr.msg_flags = 0;
        
        if ((r = recvmsg(fd, &msghdr, 0)) < 0) {
            daemon_log(LOG_ERR, "recvmsg() failed: %s", strerror(errno));
            return -1;
        }

        if (!(cmsghdr = CMSG_FIRSTHDR(&msghdr)) || cmsghdr->cmsg_type != SCM_CREDENTIALS) {
            daemon_log(LOG_WARNING, "No sender credentials received, ignoring data."); 
            return -1;
        }

        ucred = (struct ucred*) CMSG_DATA(cmsghdr);
        
        if (ucred->uid != 0)
            return -1;

        bytes = (size_t) r;
        
        for (; bytes > 0; p = NLMSG_NEXT(p, bytes)) {

            if (!NLMSG_OK(p, bytes) || bytes < sizeof(struct nlmsghdr) || bytes < p->nlmsg_len) {
                daemon_log(LOG_ERR, "Netlink packet too small.");
                return -1;
            }

            if (p->nlmsg_type == NLMSG_DONE && wait_for_done && p->nlmsg_seq == seq && (pid_t) p->nlmsg_pid == getpid())
                return 0;

            if (p->nlmsg_type == NLMSG_ERROR) {
                struct nlmsgerr *e = (struct nlmsgerr *) NLMSG_DATA (p);

                if (e->error) {
                    daemon_log(LOG_ERR, "Netlink error: %s", strerror(-e->error));
                    return -1;
                }
            }

            if (process_nlmsg(p) < 0)
                return -1;
        }
    } while (wait_for_done);

    return 0;
}
Example #2
0
File: nl.c Project: Naturekid/MSVR
static void routing_packet_read(int fd)
{
    struct in_addr src, dst;
    int i, len, ttl = -1;
    /*AODV_msg *aodv_msg;*/
    struct dev_info *dev;
    struct msghdr msgh;
    struct cmsghdr *cmsg;
    struct iovec iov;
    char ctrlbuf[CMSG_SPACE(sizeof(int)) +
        CMSG_SPACE(sizeof(struct in_pktinfo))];
    struct sockaddr_in src_addr;

    iov.iov_base = recv_buf;
    iov.iov_len = RECV_BUF_SIZE;
    msgh.msg_name = &src_addr;
    msgh.msg_namelen = sizeof(src_addr);
    msgh.msg_iov = &iov;
    msgh.msg_iovlen = 1;
    msgh.msg_control = ctrlbuf;
    msgh.msg_controllen = sizeof(ctrlbuf);

    len = recvmsg(fd, &msgh, 0);

    if (len < 0) {
        fprintf(stderr, "receive ERROR len=%d!", len);
        return;
    }

    src.s_addr = src_addr.sin_addr.s_addr;

    /* Get the ttl and destination address from the control message */
    for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL;
            cmsg = CMSG_NXTHDR_FIX(&msgh, cmsg)) {
        if (cmsg->cmsg_level == SOL_IP) {
            switch (cmsg->cmsg_type) {
                case IP_TTL:
                    ttl = *(CMSG_DATA(cmsg));
                    break;
                case IP_PKTINFO:
                    dst.s_addr =
                        ((struct in_pktinfo *) CMSG_DATA(cmsg))->ipi_addr.s_addr;
            }
        }
    }

    if (ttl < 0) {
        fprintf(stderr, "No TTL, packet ignored!");
        return;
    }

    /* Ignore messages generated locally */
    for (i = 0; i < MAX_NR_INTERFACES; i++)
        if (this_host.devs[i].enabled &&
                memcmp(&src, &this_host.devs[i].ipaddr,
                    sizeof(struct in_addr)) == 0)
            return;

    /*aodv_msg = (AODV_msg *) recv_buf;*/

    /*dev = devfromsock(fd);*/

    callback_set.prot_callback(recv_buf, RECV_BUF_SIZE);

#if 0 
    if (!dev) {
        DEBUG(LOG_ERR, 0, "Could not get device info!\n");
        return;
    }
#endif
}
/*
 * Class:     sun_nio_ch_sctp_SctpChannelImpl
 * Method:    receive0
 * Signature: (ILsun/nio/ch/sctp/ResultContainer;J*Z)I
 */
JNIEXPORT jint JNICALL Java_sun_nio_ch_sctp_SctpChannelImpl_receive0
  (JNIEnv *env, jclass klass, jint fd, jobject resultContainerObj,
   jlong address, jint length, jboolean peek) {
    SOCKADDR sa;
    int sa_len = sizeof(sa);
    ssize_t rv = 0;
    jlong *addr = jlong_to_ptr(address);
    struct iovec iov[1];
    struct msghdr msg[1];
    char cbuf[CMSG_SPACE(sizeof (struct sctp_sndrcvinfo))];
    int flags = peek == JNI_TRUE ? MSG_PEEK : 0;

    /* Set up the msghdr structure for receiving */
    memset(msg, 0, sizeof (*msg));
    msg->msg_name = &sa;
    msg->msg_namelen = sa_len;
    iov->iov_base = addr;
    iov->iov_len = length;
    msg->msg_iov = iov;
    msg->msg_iovlen = 1;
    msg->msg_control = cbuf;
    msg->msg_controllen = sizeof(cbuf);
    msg->msg_flags = 0;

    do {
        if ((rv = recvmsg(fd, msg, flags)) < 0) {
            if (errno == EWOULDBLOCK) {
                return IOS_UNAVAILABLE;
            } else if (errno == EINTR) {
                return IOS_INTERRUPTED;

#ifdef __linux__
            } else if (errno == ENOTCONN) {
                /* ENOTCONN when EOF reached */
                rv = 0;
                /* there will be no control data */
                msg->msg_controllen = 0;
#endif /* __linux__ */

            } else {
                handleSocketError(env, errno);
                return 0;
            }
        }

        if (msg->msg_flags & MSG_NOTIFICATION) {
            char *bufp = (char*)addr;
            union sctp_notification *snp;

            if (!(msg->msg_flags & MSG_EOR) && length < NOTIFICATION_BUFFER_SIZE) {
                char buf[NOTIFICATION_BUFFER_SIZE];
                int rvSAVE = rv;
                memcpy(buf, addr, rv);
                iov->iov_base = buf + rv;
                iov->iov_len = NOTIFICATION_BUFFER_SIZE - rv;
                if ((rv = recvmsg(fd, msg, flags)) < 0) {
                    handleSocketError(env, errno);
                    return 0;
                }
                bufp = buf;
                rv += rvSAVE;
            }
            snp = (union sctp_notification *) bufp;
            if (handleNotification(env, fd, resultContainerObj, snp, rv,
                                   (msg->msg_flags & MSG_EOR),
                                   (struct sockaddr*)&sa ) == JNI_TRUE) {
                /* We have received a notification that is of interest to
                   to the Java API. The appropriate notification will be
                   set in the result container. */
                return 0;
            }

            // set iov back to addr, and reset msg_controllen
            iov->iov_base = addr;
            iov->iov_len = length;
            msg->msg_control = cbuf;
            msg->msg_controllen = sizeof(cbuf);
        }
    } while (msg->msg_flags & MSG_NOTIFICATION);

    handleMessage(env, resultContainerObj, msg, rv,
            (msg->msg_flags & MSG_EOR), (struct sockaddr*)&sa);
    return rv;
}
Example #4
0
int main(int argc, char *argv[])
{
        int sk1, sk2;
        sockaddr_storage_t loop1;
        sockaddr_storage_t loop2;
        struct iovec iov;
        struct msghdr inmessage;
	struct msghdr outmessage;
	char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))];
	char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
	struct cmsghdr *cmsg;
	struct sctp_sndrcvinfo *sinfo;
        struct iovec out_iov;
        int error;
	int pf_class;
	uint32_t ppid;
	uint32_t stream;
	sctp_assoc_t associd1;
	struct sctp_assoc_change *sac;
	struct sctp_event_subscribe subscribe;
	char *big_buffer;
	int offset;
	struct sctp_send_failed *ssf;
	socklen_t len; /* Really becomes 2xlen when set. */
	int orig_len; 
	struct sctp_status gstatus;

        /* Rather than fflush() throughout the code, set stdout to
	 * be unbuffered.
	 */
	setvbuf(stdout, NULL, _IONBF, 0);

	/* Set some basic values which depend on the address family. */
#if TEST_V6
	pf_class = PF_INET6;

        loop1.v6.sin6_family = AF_INET6;
        loop1.v6.sin6_addr = in6addr_loopback;
        loop1.v6.sin6_port = htons(SCTP_TESTPORT_1);

        loop2.v6.sin6_family = AF_INET6;
        loop2.v6.sin6_addr = in6addr_loopback;
        loop2.v6.sin6_port = htons(SCTP_TESTPORT_2);
#else
	pf_class = PF_INET;

        loop1.v4.sin_family = AF_INET;
        loop1.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
        loop1.v4.sin_port = htons(SCTP_TESTPORT_1);

        loop2.v4.sin_family = AF_INET;
        loop2.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
        loop2.v4.sin_port = htons(SCTP_TESTPORT_2);
#endif /* TEST_V6 */

        /* Create the two endpoints which will talk to each other.  */
        sk1 = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
        sk2 = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);

	len = sizeof(int);
	error = getsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &orig_len,
			   &len);
	if (error)
		tst_brkm(TBROK, tst_exit, "can't get rcvbuf size: %s",
			strerror(errno));
	/* Set the MAXSEG to something smallish. */
	{
		int val = SMALL_MAXSEG;
		test_setsockopt(sk1, SCTP_MAXSEG, &val, sizeof(val));
	}

	memset(&subscribe, 0, sizeof(subscribe));
	subscribe.sctp_data_io_event = 1;
	subscribe.sctp_association_event = 1;
	subscribe.sctp_send_failure_event = 1;
	test_setsockopt(sk1, SCTP_EVENTS, &subscribe, sizeof(subscribe));
	test_setsockopt(sk2, SCTP_EVENTS, &subscribe, sizeof(subscribe));

        /* Bind these sockets to the test ports.  */
        test_bind(sk1, &loop1.sa, sizeof(loop1));
        test_bind(sk2, &loop2.sa, sizeof(loop2));

	/*
	 * This code sets the associations RWND very small so we can
	 * fill it.  It does this by manipulating the rcvbuf as follows:
	 * 1) Reduce the rcvbuf size on the socket
	 * 2) create an association so that we advertize rcvbuf/2 as
	 *    our initial rwnd
	 * 3) raise the rcvbuf value so that we don't drop data wile 
	 *    receiving later data
	 */
	len = SMALL_RCVBUF;
	error = setsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &len,
			   sizeof(len));
	if (error)
		tst_brkm(TBROK, tst_exit, "setsockopt(SO_RCVBUF): %s",
			 strerror(errno));

       /* Mark sk2 as being able to accept new associations.  */
	test_listen(sk2, 1);

        /* Send the first message.  This will create the association.  */
        outmessage.msg_name = &loop2;
        outmessage.msg_namelen = sizeof(loop2);
        outmessage.msg_iov = &out_iov;
        outmessage.msg_iovlen = 1;
        outmessage.msg_control = outcmsg;
        outmessage.msg_controllen = sizeof(outcmsg);
        outmessage.msg_flags = 0;
	cmsg = CMSG_FIRSTHDR(&outmessage);
	cmsg->cmsg_level = IPPROTO_SCTP;
	cmsg->cmsg_type = SCTP_SNDRCV;
	cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
	outmessage.msg_controllen = cmsg->cmsg_len;
	sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
	memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
	ppid = rand(); /* Choose an arbitrary value. */
	stream = 1;
	sinfo->sinfo_ppid = ppid;
	sinfo->sinfo_stream = stream;
        outmessage.msg_iov->iov_base = message;
        outmessage.msg_iov->iov_len = strlen(message) + 1;
        test_sendmsg(sk1, &outmessage, 0, strlen(message)+1);

	/* Initialize inmessage for all receives. */
	big_buffer = test_malloc(REALLY_BIG);
        memset(&inmessage, 0, sizeof(inmessage));
        iov.iov_base = big_buffer;
        iov.iov_len = REALLY_BIG;
        inmessage.msg_iov = &iov;
        inmessage.msg_iovlen = 1;
        inmessage.msg_control = incmsg;

        /* Get the communication up message on sk2.  */
        inmessage.msg_controllen = sizeof(incmsg);
        error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
	test_check_msg_notification(&inmessage, error,
				    sizeof(struct sctp_assoc_change),
				    SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
#if 0
	sac = (struct sctp_assoc_change *)iov.iov_base;
	associd2 = sac->sac_assoc_id;
#endif

        /* Get the communication up message on sk1.  */
        inmessage.msg_controllen = sizeof(incmsg);
        error = test_recvmsg(sk1, &inmessage, MSG_WAITALL);
	test_check_msg_notification(&inmessage, error,
				    sizeof(struct sctp_assoc_change),
				    SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
	sac = (struct sctp_assoc_change *)iov.iov_base;
	associd1 = sac->sac_assoc_id;

	/* restore the rcvbuffer size for the receiving socket */
	error = setsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &orig_len,
			   sizeof(orig_len));

	if (error)
		tst_brkm(TBROK, tst_exit, "setsockopt(SO_RCVBUF): %s",
			strerror(errno));

        /* Get the first data message which was sent.  */
        inmessage.msg_controllen = sizeof(incmsg);
        error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
        test_check_msg_data(&inmessage, error, strlen(message) + 1,
			    MSG_EOR, stream, ppid);

	/* Figure out how big to make our fillmsg */
	len = sizeof(struct sctp_status);
	memset(&gstatus,0,sizeof(struct sctp_status));
	gstatus.sstat_assoc_id = associd1;
	error = getsockopt(sk1, IPPROTO_SCTP, SCTP_STATUS, &gstatus, &len);
	
	if (error)
		tst_brkm(TBROK, tst_exit, "can't get rwnd size: %s",
			strerror(errno));
	tst_resm(TINFO, "Creating fillmsg of size %d",
		 gstatus.sstat_rwnd+RWND_SLOP);
	fillmsg = malloc(gstatus.sstat_rwnd+RWND_SLOP);	

	/* Send a fillmsg */
        outmessage.msg_controllen = sizeof(outcmsg);
        outmessage.msg_flags = 0;
	cmsg = CMSG_FIRSTHDR(&outmessage);
	cmsg->cmsg_level = IPPROTO_SCTP;
	cmsg->cmsg_type = SCTP_SNDRCV;
	cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
	outmessage.msg_controllen = cmsg->cmsg_len;
	sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
	memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
	ppid++;
	stream++;
	sinfo->sinfo_ppid = ppid;
	sinfo->sinfo_stream = stream;
	memset(fillmsg, 'X', gstatus.sstat_rwnd+RWND_SLOP);
	fillmsg[gstatus.sstat_rwnd+RWND_SLOP-1] = '\0';
	outmessage.msg_iov->iov_base = fillmsg;
	outmessage.msg_iov->iov_len = gstatus.sstat_rwnd+RWND_SLOP;
	outmessage.msg_name = NULL;
	outmessage.msg_namelen = 0;
	sinfo->sinfo_assoc_id = associd1;
	sinfo->sinfo_timetolive = 0;
	test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL,
			 gstatus.sstat_rwnd+RWND_SLOP);

	/* Now send the message with timeout. */
	sinfo->sinfo_ppid = ppid;
	sinfo->sinfo_stream = stream;
	outmessage.msg_iov->iov_base = ttlmsg;
        outmessage.msg_iov->iov_len = strlen(ttlmsg) + 1;
	outmessage.msg_name = NULL;
	outmessage.msg_namelen = 0;
	sinfo->sinfo_assoc_id = associd1;
	sinfo->sinfo_timetolive = 2000;
	test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, strlen(ttlmsg) + 1);

	tst_resm(TPASS, "Send a message with timeout");

	/* Next send a message with no timeout. */
	sinfo->sinfo_ppid = ppid;
	sinfo->sinfo_stream = stream;
	outmessage.msg_iov->iov_base = nottlmsg;
        outmessage.msg_iov->iov_len = strlen(nottlmsg) + 1;
	outmessage.msg_name = NULL;
	outmessage.msg_namelen = 0;
	sinfo->sinfo_assoc_id = associd1;
	sinfo->sinfo_timetolive = 0;
	test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, strlen(nottlmsg)+1);

	tst_resm(TPASS, "Send a message with no timeout");

	/* And finally a fragmented message that will time out. */
	sinfo->sinfo_ppid = ppid;
	sinfo->sinfo_stream = stream;
	memset(ttlfrag, '0', sizeof(ttlfrag));
	ttlfrag[sizeof(ttlfrag)-1] = '\0';
	outmessage.msg_iov->iov_base = ttlfrag;
        outmessage.msg_iov->iov_len = sizeof(ttlfrag);
	outmessage.msg_name = NULL;
	outmessage.msg_namelen = 0;
	sinfo->sinfo_assoc_id = associd1;
	sinfo->sinfo_timetolive = 2000;
	test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, sizeof(ttlfrag));

	tst_resm(TPASS, "Send a fragmented message with timeout");

	/* Sleep waiting for the message to time out. */
	tst_resm(TINFO, " **  SLEEPING for 3 seconds **");
	sleep(3);

	/* Read the fillmsg snuck in between the ttl'd messages. */
	do {
		inmessage.msg_controllen = sizeof(incmsg);
		error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
	} while (!(inmessage.msg_flags & MSG_EOR));

	/* Now get the message that did NOT time out. */
	inmessage.msg_controllen = sizeof(incmsg);
	error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
	test_check_msg_data(&inmessage, error, strlen(nottlmsg) + 1,
			    MSG_EOR, stream, ppid);
	if (0 != strncmp(iov.iov_base, nottlmsg, strlen(nottlmsg)+1))
		tst_brkm(TBROK, tst_exit, "Received Wrong Message !!!");

	tst_resm(TPASS, "Receive message with no timeout");

	/* Get the SEND_FAILED notification for the message that DID
	 * time out.
	 */
	inmessage.msg_controllen = sizeof(incmsg);
	error = test_recvmsg(sk1, &inmessage, MSG_WAITALL);
	test_check_msg_notification(&inmessage, error,
				    sizeof(struct sctp_send_failed) +
							strlen(ttlmsg) + 1,
				    SCTP_SEND_FAILED, 0);
	ssf = (struct sctp_send_failed *)iov.iov_base;
	if (0 != strncmp(ttlmsg, (char *)ssf->ssf_data, strlen(ttlmsg) + 1))
		tst_brkm(TBROK, tst_exit, "SEND_FAILED data mismatch");

	tst_resm(TPASS, "Receive SEND_FAILED for message with timeout");

	/* Get the SEND_FAILED notification for the fragmented message that
	 * DID time out.
	 */
	offset = 0;
	do {
		inmessage.msg_controllen = sizeof(incmsg);
		error = test_recvmsg(sk1, &inmessage, MSG_WAITALL);
		test_check_msg_notification(&inmessage, error,
					    sizeof(struct sctp_send_failed) +
								  SMALL_MAXSEG,
					    SCTP_SEND_FAILED, 0);
		ssf = (struct sctp_send_failed *)iov.iov_base;
		if (0 != strncmp(&ttlfrag[offset], (char *)ssf->ssf_data,
				 SMALL_MAXSEG))
			tst_brkm(TBROK, tst_exit, "SEND_FAILED data mismatch");
		offset += SMALL_MAXSEG;
	} while (!(ssf->ssf_info.sinfo_flags & 0x01)); /* LAST_FRAG */

	tst_resm(TPASS, "Receive SEND_FAILED for fragmented message with "
		 "timeout");

        /* Shut down the link.  */
        close(sk1);

        /* Get the shutdown complete notification. */
	inmessage.msg_controllen = sizeof(incmsg);
        error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
	test_check_msg_notification(&inmessage, error,
				    sizeof(struct sctp_assoc_change),
				    SCTP_ASSOC_CHANGE, SCTP_SHUTDOWN_COMP);

        close(sk2);

        /* Indicate successful completion.  */
        return 0;
}
Example #5
0
static int
read_cmsgspecs(struct thread *td, int ncmsghdrs, struct cmsgspec **cmsgspecs,
	       payload_size_t *payload_size)
{
	struct cmsgspec *spec, *specs;
	payload_size_t actual_payload_size, level_len, nfds_len, type_len;
	size_t datasize, size;
	int error, i, level, nfds, type;

	size = sizeof(specs[0]) * ncmsghdrs;
	specs = (struct cmsgspec *)fmaster_malloc(td, size);
	if (specs == NULL)
		return (ENOMEM);

	actual_payload_size = 0;
	for (i = 0; i < ncmsghdrs; i++) {
		spec = &specs[i];

		error = fmaster_read_int(td, &level, &level_len);
		if (error != 0)
			return (error);
		actual_payload_size += level_len;
		error = fmaster_read_int(td, &type, &type_len);
		if (error != 0)
			return (error);
		actual_payload_size += type_len;
		spec->cmsgspec_level = level;
		spec->cmsgspec_type = type;

		switch (level) {
		case SOL_SOCKET:
			switch (type) {
			case SCM_CREDS:
				datasize = sizeof(struct cmsgcred);
				break;
			case SCM_RIGHTS:
				error = fmaster_read_int(td, &nfds, &nfds_len);
				if (error != 0)
					return (error);
				actual_payload_size += nfds_len;
				spec->cmsgspec_nfds = nfds;
				datasize = sizeof(int) * nfds;
				break;
			default:
				datasize = 0;
				break;
			}
			break;
		default:
			datasize = 0;
			break;
		}

		spec->cmsgspec_len = CMSG_LEN(datasize);
		spec->cmsgspec_space = CMSG_SPACE(datasize);
	}

	*cmsgspecs = specs;
	*payload_size = actual_payload_size;

	return (0);
}
void
ngx_event_recvmsg(ngx_event_t *ev)
{
    ssize_t            n;
    ngx_log_t         *log;
    ngx_err_t          err;
    ngx_event_t       *rev, *wev;
    struct iovec       iov[1];
    struct msghdr      msg;
    ngx_listening_t   *ls;
    ngx_event_conf_t  *ecf;
    ngx_connection_t  *c, *lc;
    u_char             sa[NGX_SOCKADDRLEN];
    static u_char      buffer[65535];

#if (NGX_HAVE_MSGHDR_MSG_CONTROL)

#if (NGX_HAVE_IP_RECVDSTADDR)
    u_char             msg_control[CMSG_SPACE(sizeof(struct in_addr))];
#elif (NGX_HAVE_IP_PKTINFO)
    u_char             msg_control[CMSG_SPACE(sizeof(struct in_pktinfo))];
#endif

#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)
    u_char             msg_control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
#endif

#endif

    if (ev->timedout) {
        if (ngx_enable_accept_events((ngx_cycle_t *) ngx_cycle) != NGX_OK) {
            return;
        }

        ev->timedout = 0;
    }

    ecf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_core_module);

    if (!(ngx_event_flags & NGX_USE_KQUEUE_EVENT)) {
        ev->available = ecf->multi_accept;
    }

    lc = ev->data;
    ls = lc->listening;
    ev->ready = 0;

    ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
                   "recvmsg on %V, ready: %d", &ls->addr_text, ev->available);

    do {
        ngx_memzero(&msg, sizeof(struct msghdr));

        iov[0].iov_base = (void *) buffer;
        iov[0].iov_len = sizeof(buffer);

        msg.msg_name = &sa;
        msg.msg_namelen = sizeof(sa);
        msg.msg_iov = iov;
        msg.msg_iovlen = 1;

#if (NGX_HAVE_MSGHDR_MSG_CONTROL)

        if (ls->wildcard) {

#if (NGX_HAVE_IP_RECVDSTADDR || NGX_HAVE_IP_PKTINFO)
            if (ls->sockaddr->sa_family == AF_INET) {
                msg.msg_control = &msg_control;
                msg.msg_controllen = sizeof(msg_control);
            }
#endif

#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)
            if (ls->sockaddr->sa_family == AF_INET6) {
                msg.msg_control = &msg_control6;
                msg.msg_controllen = sizeof(msg_control6);
            }
#endif
        }

#endif

        n = recvmsg(lc->fd, &msg, 0);

        if (n == -1) {
            err = ngx_socket_errno;

            if (err == NGX_EAGAIN) {
                ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, err,
                               "recvmsg() not ready");
                return;
            }

            ngx_log_error(NGX_LOG_ALERT, ev->log, err, "recvmsg() failed");

            return;
        }

#if (NGX_STAT_STUB)
        (void) ngx_atomic_fetch_add(ngx_stat_accepted, 1);
#endif

#if (NGX_HAVE_MSGHDR_MSG_CONTROL)
        if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) {
            ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
                          "recvmsg() truncated data");
            continue;
        }
#endif

        ngx_accept_disabled = ngx_cycle->connection_n / 8
                              - ngx_cycle->free_connection_n;

        c = ngx_get_connection(lc->fd, ev->log);
        if (c == NULL) {
            return;
        }

        c->shared = 1;
        c->type = SOCK_DGRAM;
        c->socklen = msg.msg_namelen;

#if (NGX_STAT_STUB)
        (void) ngx_atomic_fetch_add(ngx_stat_active, 1);
#endif

        c->pool = ngx_create_pool(ls->pool_size, ev->log);
        if (c->pool == NULL) {
            ngx_close_accepted_connection(c);
            return;
        }

        c->sockaddr = ngx_palloc(c->pool, c->socklen);
        if (c->sockaddr == NULL) {
            ngx_close_accepted_connection(c);
            return;
        }

        ngx_memcpy(c->sockaddr, msg.msg_name, c->socklen);

        log = ngx_palloc(c->pool, sizeof(ngx_log_t));
        if (log == NULL) {
            ngx_close_accepted_connection(c);
            return;
        }

        *log = ls->log;

        c->send = ngx_udp_send;

        c->log = log;
        c->pool->log = log;

        c->listening = ls;
        c->local_sockaddr = ls->sockaddr;
        c->local_socklen = ls->socklen;

#if (NGX_HAVE_MSGHDR_MSG_CONTROL)

        if (ls->wildcard) {
            struct cmsghdr   *cmsg;
            struct sockaddr  *sockaddr;

            sockaddr = ngx_palloc(c->pool, c->local_socklen);
            if (sockaddr == NULL) {
                ngx_close_accepted_connection(c);
                return;
            }

            ngx_memcpy(sockaddr, c->local_sockaddr, c->local_socklen);
            c->local_sockaddr = sockaddr;

            for (cmsg = CMSG_FIRSTHDR(&msg);
                 cmsg != NULL;
                 cmsg = CMSG_NXTHDR(&msg, cmsg))
            {

#if (NGX_HAVE_IP_RECVDSTADDR)

                if (cmsg->cmsg_level == IPPROTO_IP
                    && cmsg->cmsg_type == IP_RECVDSTADDR
                    && sockaddr->sa_family == AF_INET)
                {
                    struct in_addr      *addr;
                    struct sockaddr_in  *sin;

                    addr = (struct in_addr *) CMSG_DATA(cmsg);
                    sin = (struct sockaddr_in *) sockaddr;
                    sin->sin_addr = *addr;

                    break;
                }

#elif (NGX_HAVE_IP_PKTINFO)

                if (cmsg->cmsg_level == IPPROTO_IP
                    && cmsg->cmsg_type == IP_PKTINFO
                    && sockaddr->sa_family == AF_INET)
                {
                    struct in_pktinfo   *pkt;
                    struct sockaddr_in  *sin;

                    pkt = (struct in_pktinfo *) CMSG_DATA(cmsg);
                    sin = (struct sockaddr_in *) sockaddr;
                    sin->sin_addr = pkt->ipi_addr;

                    break;
                }

#endif

#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)

                if (cmsg->cmsg_level == IPPROTO_IPV6
                    && cmsg->cmsg_type == IPV6_PKTINFO
                    && sockaddr->sa_family == AF_INET6)
                {
                    struct in6_pktinfo   *pkt6;
                    struct sockaddr_in6  *sin6;

                    pkt6 = (struct in6_pktinfo *) CMSG_DATA(cmsg);
                    sin6 = (struct sockaddr_in6 *) sockaddr;
                    sin6->sin6_addr = pkt6->ipi6_addr;

                    break;
                }

#endif

            }
        }

#endif

        c->buffer = ngx_create_temp_buf(c->pool, n);
        if (c->buffer == NULL) {
            ngx_close_accepted_connection(c);
            return;
        }

        c->buffer->last = ngx_cpymem(c->buffer->last, buffer, n);

        rev = c->read;
        wev = c->write;

        wev->ready = 1;

        rev->log = log;
        wev->log = log;

        /*
         * TODO: MT: - ngx_atomic_fetch_add()
         *             or protection by critical section or light mutex
         *
         * TODO: MP: - allocated in a shared memory
         *           - ngx_atomic_fetch_add()
         *             or protection by critical section or light mutex
         */

        c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);

#if (NGX_STAT_STUB)
        (void) ngx_atomic_fetch_add(ngx_stat_handled, 1);
#endif

        if (ls->addr_ntop) {
            c->addr_text.data = ngx_pnalloc(c->pool, ls->addr_text_max_len);
            if (c->addr_text.data == NULL) {
                ngx_close_accepted_connection(c);
                return;
            }

            c->addr_text.len = ngx_sock_ntop(c->sockaddr, c->socklen,
                                             c->addr_text.data,
                                             ls->addr_text_max_len, 0);
            if (c->addr_text.len == 0) {
                ngx_close_accepted_connection(c);
                return;
            }
        }

#if (NGX_DEBUG)
        {
        ngx_str_t  addr;
        u_char     text[NGX_SOCKADDR_STRLEN];

        ngx_debug_accepted_connection(ecf, c);

        if (log->log_level & NGX_LOG_DEBUG_EVENT) {
            addr.data = text;
            addr.len = ngx_sock_ntop(c->sockaddr, c->socklen, text,
                                     NGX_SOCKADDR_STRLEN, 1);

            ngx_log_debug4(NGX_LOG_DEBUG_EVENT, log, 0,
                           "*%uA recvmsg: %V fd:%d n:%z",
                           c->number, &addr, c->fd, n);
        }

        }
#endif

        log->data = NULL;
        log->handler = NULL;

        ls->handler(c);

        if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
            ev->available -= n;
        }

    } while (ev->available);
}
Example #7
0
  Object* IO::recv_fd(STATE) {
#ifdef _WIN32
    return Primitives::failure();
#else
    struct msghdr msg;
    struct iovec vec[1];
    char buf[1];

    struct cmsghdr *cmsg;
    char cmsg_buf[cmsg_space];

    msg.msg_name = NULL;
    msg.msg_namelen = 0;

    /* Linux and Solaris doesn't work if msg_iov is NULL. */
    buf[0] = '\0';
    vec[0].iov_base = buf;
    vec[0].iov_len = 1;
    msg.msg_iov = vec;
    msg.msg_iovlen = 1;

    msg.msg_control = (caddr_t)cmsg_buf;
    msg.msg_controllen = sizeof(cmsg_buf);
    msg.msg_flags = 0;
    cmsg = CMSG_FIRSTHDR(&msg);
    memset(cmsg_buf, 0, sizeof(cmsg_buf));
    cmsg->cmsg_len = CMSG_LEN(sizeof(int));
    cmsg->cmsg_level = SOL_SOCKET;
    cmsg->cmsg_type = SCM_RIGHTS;

    // Workaround for GCC's broken strict-aliasing checks.
    int* fd_data = (int *)CMSG_DATA(cmsg);
    *fd_data = -1;

    int read_fd = descriptor(state);

    int code = -1;

  retry:
    state->vm()->interrupt_with_signal();
    state->vm()->thread()->sleep(state, cTrue);

    {
      UnmanagedPhase unmanaged(state);
      code = recvmsg(read_fd, &msg, 0);
    }

    state->vm()->thread()->sleep(state, cFalse);
    state->vm()->clear_waiter();

    if(code == -1) {
      if(errno == EAGAIN || errno == EINTR) {
        if(state->vm()->thread_interrupted_p(state)) return NULL;
        ensure_open(state);
        goto retry;
      }

      return Primitives::failure();
    }

    if(msg.msg_controllen != CMSG_SPACE(sizeof(int))
        || cmsg->cmsg_len != CMSG_LEN(sizeof(int))
        || cmsg->cmsg_level != SOL_SOCKET
        || cmsg->cmsg_type != SCM_RIGHTS) {
      return Primitives::failure();
    }

    // Workaround for GCC's broken strict-aliasing checks.
    fd_data = (int *)CMSG_DATA(cmsg);
    return Fixnum::from(*fd_data);
#endif
  }
Example #8
0
int J1939SocketRead (int Socket, struct J1939FrameBag *Bags, unsigned int BagsCount, int TimeoutMs)
{
    struct mmsghdr msgs[BagsCount];
    struct iovec iovs[BagsCount];
    struct sockaddr_can addr[BagsCount];
    char ctrlmsgs[BagsCount][
            CMSG_SPACE(sizeof(struct timeval))
          + CMSG_SPACE(sizeof(__u8)) /* dest addr */
          + CMSG_SPACE(sizeof(__u64)) /* dest name */
          + CMSG_SPACE(sizeof(__u8)) /* priority */
          ];

    unsigned int i;
    for (i = 0; i < BagsCount; i++)
    {
        memset(&msgs[i], 0, sizeof(msgs[0]));
        memset(&iovs[i], 0, sizeof(iovs[0]));
        memset(&addr[i], 0, sizeof(addr[0]));

        msgs[i].msg_hdr.msg_name = &addr[i];
        msgs[i].msg_hdr.msg_namelen = sizeof(struct sockaddr_can);

        iovs[i].iov_base = (void *) &(Bags[i].Frame.data);
        iovs[i].iov_len = sizeof(Bags[i].Frame.data);
        msgs[i].msg_hdr.msg_iov = &iovs[i];
        msgs[i].msg_hdr.msg_iovlen = 1;

        msgs[i].msg_hdr.msg_control = &ctrlmsgs[i];
        msgs[i].msg_hdr.msg_controllen = sizeof(ctrlmsgs[0]);
        msgs[i].msg_hdr.msg_flags = 0;
    }

    struct timeval tNow, tEnd;
    for ( initTimers(&tNow, &tEnd, TimeoutMs); timercmp(&tNow, &tEnd, <=); gettimeofday (&tNow, NULL) )
    {
        int rcount;
        rcount = recvmmsg(Socket, msgs, BagsCount, MSG_DONTWAIT, NULL);
        if (rcount >= 0)
        {
            int i;
            for (i = 0; i < rcount; i ++)
            {
                struct timeval tv;
                struct cmsghdr *cmsg;

                for (cmsg = CMSG_FIRSTHDR(&msgs[i].msg_hdr);
                    cmsg;
                    cmsg = CMSG_NXTHDR(&msgs[i].msg_hdr,cmsg))
                {
                    switch (cmsg->cmsg_level) {
                    case SOL_SOCKET:
                        if (cmsg->cmsg_type == SO_TIMESTAMP)
                        {
                            tv = *(struct timeval *)CMSG_DATA(cmsg);
                            Bags[i].TimeStamp.seconds = tv.tv_sec;
                            Bags[i].TimeStamp.microseconds = tv.tv_usec;
                        }
                        else if (cmsg->cmsg_type == SO_RXQ_OVFL)
                            Bags[i].DroppedMessagesCount = *(__u32 *)CMSG_DATA(cmsg);
                        break;
                    case SOL_CAN_J1939:

                        break;
                    }
                }

                Bags[i].Frame.pgn = addr[i].can_addr.j1939.pgn;
                Bags[i].Frame.length = msgs[i].msg_len;

                if (msgs[i].msg_hdr.msg_flags & MSG_CONFIRM)
                    Bags[i].Flags |= (1 << 0);
            }
            return rcount;
        }
        else
        {
            int errsv = errno;
            if (errsv == EAGAIN)
            {
              usleep (100);
              continue;
            }
            else
              return errsv;
        }
    }
    return 0;
}
Example #9
0
static PyObject *sendmsg_sendmsg(PyObject *self, PyObject *args, PyObject *keywds) {

    int fd;
    int flags = 0;
    Py_ssize_t sendmsg_result, iovec_length;
    struct msghdr message_header;
    struct iovec iov[1];
    PyObject *ancillary = NULL;
    PyObject *iterator = NULL;
    PyObject *item = NULL;
    PyObject *result_object = NULL;

    static char *kwlist[] = {"fd", "data", "flags", "ancillary", NULL};

    if (!PyArg_ParseTupleAndKeywords(
            args, keywds, "it#|iO:sendmsg", kwlist,
            &fd,
            &iov[0].iov_base,
            &iovec_length,
            &flags,
            &ancillary)) {
        return NULL;
    }

    iov[0].iov_len = iovec_length;

    message_header.msg_name = NULL;
    message_header.msg_namelen = 0;

    message_header.msg_iov = iov;
    message_header.msg_iovlen = 1;

    message_header.msg_control = NULL;
    message_header.msg_controllen = 0;

    message_header.msg_flags = 0;

    if (ancillary) {

        if (!PyList_Check(ancillary)) {
            PyErr_Format(PyExc_TypeError,
                         "send1msg argument 3 expected list, got %s",
                         ancillary->ob_type->tp_name);
            goto finished;
        }

        iterator = PyObject_GetIter(ancillary);

        if (iterator == NULL) {
            goto finished;
        }

        size_t all_data_len = 0;

        /* First we need to know how big the buffer needs to be in order to
           have enough space for all of the messages. */
        while ( (item = PyIter_Next(iterator)) ) {
            int type, level;
            Py_ssize_t data_len;
            size_t prev_all_data_len;
            char *data;

            if (!PyTuple_Check(item)) {
                PyErr_Format(PyExc_TypeError,
                             "send1msg argument 3 expected list of tuple, "
                             "got list containing %s",
                             item->ob_type->tp_name);
                goto finished;
            }

            if (!PyArg_ParseTuple(
                        item, "iit#:sendmsg ancillary data (level, type, data)",
                        &level, &type, &data, &data_len)) {
                goto finished;
            }

            prev_all_data_len = all_data_len;
            all_data_len += CMSG_SPACE(data_len);

            Py_DECREF(item);
            item = NULL;

            if (all_data_len < prev_all_data_len) {
                PyErr_Format(PyExc_OverflowError,
                             "Too much msg_control to fit in a size_t: %zu",
                             prev_all_data_len);
                goto finished;
            }
        }

        Py_DECREF(iterator);
        iterator = NULL;

        /* Allocate the buffer for all of the ancillary elements, if we have
         * any.  */
        if (all_data_len) {
            if (all_data_len > SOCKLEN_MAX) {
                PyErr_Format(PyExc_OverflowError,
                             "Too much msg_control to fit in a socklen_t: %zu",
                             all_data_len);
                goto finished;
            }
            message_header.msg_control = PyMem_Malloc(all_data_len);
            if (!message_header.msg_control) {
                PyErr_NoMemory();
                goto finished;
            }
            /* From Python 3.5.2 socketmodule.c:3891:
               Need to zero out the buffer as a workaround for glibc's
               CMSG_NXTHDR() implementation.  After getting the pointer to
               the next header, it checks its (uninitialized) cmsg_len
               member to see if the "message" fits in the buffer, and
               returns NULL if it doesn't.  Zero-filling the buffer
               ensures that this doesn't happen. */
            memset(message_header.msg_control, 0, all_data_len);
        } else {
            message_header.msg_control = NULL;
        }
        message_header.msg_controllen = (socklen_t) all_data_len;

        iterator = PyObject_GetIter(ancillary); /* again */

        if (!iterator) {
            goto finished;
        }

        /* Unpack the tuples into the control message. */
        struct cmsghdr *control_message = CMSG_FIRSTHDR(&message_header);
        while ( (item = PyIter_Next(iterator)) && control_message!=NULL ) {
            int type, level;
            Py_ssize_t data_len;
            size_t data_size;
            unsigned char *data, *cmsg_data;

            /* We explicitly allocated enough space for all ancillary data
               above; if there isn't enough room, all bets are off. */
            assert(control_message);

            if (!PyArg_ParseTuple(item,
                                  "iit#:sendmsg ancillary data (level, type, data)",
                                  &level,
                                  &type,
                                  &data,
                                  &data_len)) {
                goto finished;
            }

            control_message->cmsg_level = level;
            control_message->cmsg_type = type;
            data_size = CMSG_LEN(data_len);

            if (data_size > SOCKLEN_MAX) {
                PyErr_Format(PyExc_OverflowError,
                             "CMSG_LEN(%zd) > SOCKLEN_MAX", data_len);
                goto finished;
            }

            control_message->cmsg_len = (socklen_t) data_size;

            cmsg_data = CMSG_DATA(control_message);
            memcpy(cmsg_data, data, data_len);

            Py_DECREF(item);
            item = NULL;

            control_message = CMSG_NXTHDR(&message_header, control_message);
        }
        Py_DECREF(iterator);
        iterator = NULL;

        if (PyErr_Occurred()) {
            goto finished;
        }
    }

    sendmsg_result = sendmsg(fd, &message_header, flags);

    if (sendmsg_result < 0) {
        PyErr_SetFromErrno(sendmsg_socket_error);
        goto finished;
    }

    result_object = Py_BuildValue("n", sendmsg_result);

 finished:

    if (item) {
        Py_DECREF(item);
        item = NULL;
    }
    if (iterator) {
        Py_DECREF(iterator);
        iterator = NULL;
    }
    if (message_header.msg_control) {
        PyMem_Free(message_header.msg_control);
        message_header.msg_control = NULL;
    }
    return result_object;
}
static int dgram_sctp_write(BIO *b, const char *in, int inl)
	{
	int ret;
	bio_dgram_sctp_data *data = (bio_dgram_sctp_data *)b->ptr;
	struct bio_dgram_sctp_sndinfo *sinfo = &(data->sndinfo);
	struct bio_dgram_sctp_prinfo *pinfo = &(data->prinfo);
	struct bio_dgram_sctp_sndinfo handshake_sinfo;
	struct iovec iov[1];
	struct msghdr msg;
	struct cmsghdr *cmsg;
#if defined(SCTP_SNDINFO) && defined(SCTP_PRINFO)
	char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndinfo)) + CMSG_SPACE(sizeof(struct sctp_prinfo))];
	struct sctp_sndinfo *sndinfo;
	struct sctp_prinfo *prinfo;
#else
	char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
	struct sctp_sndrcvinfo *sndrcvinfo;
#endif

	clear_socket_error();

	/* If we're send anything else than application data,
	 * disable all user parameters and flags.
	 */
	if (in[0] != 23) {
		memset(&handshake_sinfo, 0x00, sizeof(struct bio_dgram_sctp_sndinfo));
#ifdef SCTP_SACK_IMMEDIATELY
		handshake_sinfo.snd_flags = SCTP_SACK_IMMEDIATELY;
#endif
		sinfo = &handshake_sinfo;
	}

	/* If we have to send a shutdown alert message and the
	 * socket is not dry yet, we have to save it and send it
	 * as soon as the socket gets dry.
	 */
	if (data->save_shutdown && !BIO_dgram_sctp_wait_for_dry(b))
	{
		data->saved_message.bio = b;
		data->saved_message.length = inl;
		data->saved_message.data = OPENSSL_malloc(inl);
		memcpy(data->saved_message.data, in, inl);
		return inl;
	}

	iov[0].iov_base = (char *)in;
	iov[0].iov_len = inl;
	msg.msg_name = NULL;
	msg.msg_namelen = 0;
	msg.msg_iov = iov;
	msg.msg_iovlen = 1;
	msg.msg_control = (caddr_t)cmsgbuf;
	msg.msg_controllen = 0;
	msg.msg_flags = 0;
#if defined(SCTP_SNDINFO) && defined(SCTP_PRINFO)
	cmsg = (struct cmsghdr *)cmsgbuf;
	cmsg->cmsg_level = IPPROTO_SCTP;
	cmsg->cmsg_type = SCTP_SNDINFO;
	cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo));
	sndinfo = (struct sctp_sndinfo *)CMSG_DATA(cmsg);
	memset(sndinfo, 0, sizeof(struct sctp_sndinfo));
	sndinfo->snd_sid = sinfo->snd_sid;
	sndinfo->snd_flags = sinfo->snd_flags;
	sndinfo->snd_ppid = sinfo->snd_ppid;
	sndinfo->snd_context = sinfo->snd_context;
	msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo));

	cmsg = (struct cmsghdr *)&cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndinfo))];
	cmsg->cmsg_level = IPPROTO_SCTP;
	cmsg->cmsg_type = SCTP_PRINFO;
	cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo));
	prinfo = (struct sctp_prinfo *)CMSG_DATA(cmsg);
	memset(prinfo, 0, sizeof(struct sctp_prinfo));
	prinfo->pr_policy = pinfo->pr_policy;
	prinfo->pr_value = pinfo->pr_value;
	msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo));
#else
	cmsg = (struct cmsghdr *)cmsgbuf;
	cmsg->cmsg_level = IPPROTO_SCTP;
	cmsg->cmsg_type = SCTP_SNDRCV;
	cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
	sndrcvinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
	memset(sndrcvinfo, 0, sizeof(struct sctp_sndrcvinfo));
	sndrcvinfo->sinfo_stream = sinfo->snd_sid;
	sndrcvinfo->sinfo_flags = sinfo->snd_flags;
#ifdef __FreeBSD__
	sndrcvinfo->sinfo_flags |= pinfo->pr_policy;
#endif
	sndrcvinfo->sinfo_ppid = sinfo->snd_ppid;
	sndrcvinfo->sinfo_context = sinfo->snd_context;
	sndrcvinfo->sinfo_timetolive = pinfo->pr_value;
	msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndrcvinfo));
#endif

	ret = sendmsg(b->num, &msg, 0);

	BIO_clear_retry_flags(b);
	if (ret <= 0)
		{
		if (BIO_dgram_should_retry(ret))
			{
			BIO_set_retry_write(b);  
			data->_errno = get_last_socket_error();
			}
		}
	return(ret);
	}
Example #11
0
static void aodv_socket_read(int fd)
{
    u_int32_t src, dst;
    int i, len, ttl = 0;
    AODV_msg *aodv_msg;

#ifdef USE_IW_SPY
    char ifname[IFNAMSIZ];
#endif				/* USE_IW_SPY */

#ifdef RAW_SOCKET
    int iph_len;
    struct iphdr *iph;
    struct udphdr *udph;

    len = recvfrom(fd, recv_buf, RECV_BUF_SIZE, 0, NULL, NULL);

    if (len < 0 || len < IPHDR_SIZE) {
	log(LOG_WARNING, 0, __FUNCTION__, "receive ERROR!");
	return;
    }
    /* Parse the IP header */
    iph = (struct iphdr *) recv_buf;

    src = ntohl(iph->saddr);
    dst = ntohl(iph->daddr);
    ttl = iph->ttl;
    iph_len = iph->ihl << 2;

    udph = (struct udphdr *) (recv_buf + iph_len);

    if (ntohs(udph->dest) != AODV_PORT && ntohs(udph->source) != AODV_PORT)
	return;

    /* Ignore messages generated locally */
    for (i = 0; i < MAX_NR_INTERFACES; i++)
	if (this_host.devs[i].enabled &&
	    memcmp(&src, &this_host.devs[i].ipaddr, sizeof(u_int32_t)) == 0)
	    return;

    aodv_msg = (AODV_msg *) (recv_buf + iph_len + sizeof(struct udphdr));
    len = ntohs(udph->len) - sizeof(struct udphdr);

#else
    struct sockaddr_in src_addr;
    struct msghdr msg;
    union {
	struct cmsghdr cm;
	char control[CMSG_SPACE(sizeof(int)) +
		     CMSG_SPACE(sizeof(struct in_pktinfo))];
    } control_union;
    struct cmsghdr *cmsg;
    struct in_pktinfo pktinfo;
    int sockaddr_len = sizeof(struct sockaddr_in);

    msg.msg_name = NULL;
    msg.msg_namelen = 0;
    msg.msg_iov = NULL;
    msg.msg_iovlen = 0;
    msg.msg_control = control_union.control;
    msg.msg_controllen = sizeof(control_union.control);

    /* Get the information control message first */
    if ((len = recvmsg(fd, &msg, MSG_PEEK)) < 0) {
	log(LOG_WARNING, 0, __FUNCTION__, "recvmsg ERROR!");
	return;
    }
    /* Read the data payload (i.e. AODV msg) */
    len = recvfrom(fd, recv_buf, RECV_BUF_SIZE, 0,
		   (struct sockaddr *) &src_addr, &sockaddr_len);

    if (len < 0) {
	log(LOG_WARNING, 0, __FUNCTION__, "receive ERROR!");
	return;
    }
    aodv_msg = (AODV_msg *) (recv_buf);
    src = ntohl(src_addr.sin_addr.s_addr);

    /* Ignore messages generated locally */
    for (i = 0; i < MAX_NR_INTERFACES; i++)
	if (this_host.devs[i].enabled &&
	    memcmp(&src, &this_host.devs[i].ipaddr, sizeof(u_int32_t)) == 0)
	    return;

    /* Get the TTL and pktinfo struct (destination address) from the
       control messages... For some reason the correct use of the
       CMSG(3) macros using CMSG_NXTHDR does not work across different
       Red Hat versions (6.2 vs 7.2), but this code seem to work: */
    cmsg = CMSG_FIRSTHDR(&msg);
    for (i = 0; i < 2; i++) {
	if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_TTL) {
	    memcpy(&ttl, CMSG_DATA(cmsg), sizeof(int));
	    cmsg = (void *) cmsg + CMSG_SPACE(sizeof(int));
	} else if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_PKTINFO) {
	    memcpy(&pktinfo, CMSG_DATA(cmsg), sizeof(struct in_pktinfo));
	    cmsg = (void *) cmsg + CMSG_SPACE(sizeof(struct in_pktinfo));
	}
    }

    dst = ntohl(pktinfo.ipi_addr.s_addr);
#endif				/* RAW_SOCKET */

#ifdef USE_IW_SPY
    if (spy_addrs &&
	link_qual_get_from_ip(src, if_indextoname(pktinfo.ipi_ifindex,
						  ifname)) <
	hello_qual_threshold)
	return;
#endif				/* USE_IW_SPY */

    aodv_socket_process_packet(aodv_msg, len, src, dst, ttl,
			       pktinfo.ipi_ifindex);
}
Example #12
0
void pass_fd(int sfd, int fd_to_send)
{
	struct msghdr msg;
	
	/*allocate memory to 'msg_control' field in msghdr struct */
	char buf[CMSG_SPACE(sizeof(int))];
	/*the memory to be allocated should include data + header..
	this is calculated by the above macro...(it merely adds some
	no. of bytes and returs that number..*/
	
	struct cmsghdr *cmsg;
	
	struct iovec ve;	
	/*must send/receive atleast one byte...
	main purpose is to have some error 
	checking.. but this is completely 
	irrelevant in the current context..*/
	
	char *st ="I";
	/*jst let us allocate 1 byte for formality 
	and leave it that way...*/
	ve.iov_base = st;
	ve.iov_len =1;
	
	/*attach this memory to our main msghdr struct...*/
	msg.msg_iov = &ve;
	msg.msg_iovlen = 1;
	
	/*these are optional fields ..
	leave these fields with zeros..
	to prevent unnecessary SIGSEGVs..*/
	msg.msg_name = NULL;
	msg.msg_namelen = 0;
	
	
	/*here starts the main part..*/
	/*attach the 'buf' to msg_control..
	and fill in the size field correspondingly..
	*/
	
	msg.msg_control = buf;
	msg.msg_controllen = sizeof(buf);
	
	/*actually msg_control field must 
	point to a struct of type 'cmsghdr'
	we just allocated the memory, yet we need to 
	set all the corresponding fields..
	It is done as follows:
	*/
	cmsg = CMSG_FIRSTHDR(&msg);
	/* this macro returns the address in the buffer..
	from where the first header starts..
	*/
	
	/*set all the fields appropriately..*/
  	cmsg->cmsg_level = SOL_SOCKET;
  	cmsg->cmsg_type = SCM_RIGHTS;
  	cmsg->cmsg_len = CMSG_LEN(sizeof(fd_to_send));
	/*in the above field we need to store
	the size of header + data(in this case 4 bytes(int) for our fd..
	this is returned by the 'CMSG_LEN' macro..*/
	
	*(int*)CMSG_DATA(cmsg) = fd_to_send;
	/*after the above three fields we keep the actual data..
	the macro 'CMSG_DATA' returns pointer to this location
	and we set it to the file descriptor to be sent..
	*/
	
	msg.msg_controllen = cmsg->cmsg_len;
	/*now that we have filled the 'cmsg' struct 
	we store the size of this struct..*/
	/*this one isn't required when you
	pass a single fd..
	but useful when u pass multiple fds.*/
	
	msg.msg_flags = 0;
	/*leave the flags field zeroed..*/
	
	if(sendmsg( sfd, &msg, 0)==-1){ perror("snd:\n"); exit(1); }
	/*send this over the UNIX deomain socoket..*/ 
	printf("sent fd:%d\n", fd_to_send);
	close(fd_to_send);
	/*close the fd which was sent..*/
}
Example #13
0
/**
 * Send netlink message.
 * @arg sk		Netlink socket.
 * @arg msg		Netlink message to be sent.
 * @arg iov		iovec to be sent.
 * @arg iovlen		number of struct iovec to be sent.
 * @see nl_sendmsg()
 * @return Number of characters sent on success or a negative error code.
 */
int nl_send_iovec(struct nl_sock *sk, struct nl_msg *msg, struct iovec *iov, unsigned iovlen)
{
	struct sockaddr_nl *dst;
	struct ucred *creds;
	struct msghdr hdr = {
		.msg_name = (void *) &sk->s_peer,
		.msg_namelen = sizeof(struct sockaddr_nl),
		.msg_iov = iov,
		.msg_iovlen = iovlen,
	};

	/* Overwrite destination if specified in the message itself, defaults
	 * to the peer address of the socket.
	 */
	dst = nlmsg_get_dst(msg);
	if (dst->nl_family == AF_NETLINK)
		hdr.msg_name = dst;

	/* Add credentials if present. */
	creds = nlmsg_get_creds(msg);
	if (creds != NULL) {
		char buf[CMSG_SPACE(sizeof(struct ucred))];
		struct cmsghdr *cmsg;

		hdr.msg_control = buf;
		hdr.msg_controllen = sizeof(buf);

		cmsg = CMSG_FIRSTHDR(&hdr);
		cmsg->cmsg_level = SOL_SOCKET;
		cmsg->cmsg_type = SCM_CREDENTIALS;
		cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
		memcpy(CMSG_DATA(cmsg), creds, sizeof(struct ucred));
	}

	return nl_sendmsg(sk, msg, &hdr);
}



/**
* Send netlink message.
* @arg sk		Netlink socket.
* @arg msg		Netlink message to be sent.
* @see nl_sendmsg()
* @return Number of characters sent on success or a negative error code.
*/
int nl_send(struct nl_sock *sk, struct nl_msg *msg)
{
	struct iovec iov = {
		.iov_base = (void *) nlmsg_hdr(msg),
		.iov_len = nlmsg_hdr(msg)->nlmsg_len,
	};

	return nl_send_iovec(sk, msg, &iov, 1);
}

void nl_auto_complete(struct nl_sock *sk, struct nl_msg *msg)
{
	struct nlmsghdr *nlh;

	nlh = nlmsg_hdr(msg);
	if (nlh->nlmsg_pid == 0)
		nlh->nlmsg_pid = sk->s_local.nl_pid;

	if (nlh->nlmsg_seq == 0)
		nlh->nlmsg_seq = sk->s_seq_next++;

	if (msg->nm_protocol == -1)
		msg->nm_protocol = sk->s_proto;

	nlh->nlmsg_flags |= NLM_F_REQUEST;

	if (!(sk->s_flags & NL_NO_AUTO_ACK))
		nlh->nlmsg_flags |= NLM_F_ACK;
}

/**
 * Send netlink message and check & extend header values as needed.
 * @arg sk		Netlink socket.
 * @arg msg		Netlink message to be sent.
 *
 * Checks the netlink message \c nlh for completness and extends it
 * as required before sending it out. Checked fields include pid,
 * sequence nr, and flags.
 *
 * @see nl_send()
 * @return Number of characters sent or a negative error code.
 */
int nl_send_auto_complete(struct nl_sock *sk, struct nl_msg *msg)
{
	struct nl_cb *cb = sk->s_cb;

	nl_auto_complete(sk, msg);

	if (cb->cb_send_ow)
		return cb->cb_send_ow(sk, msg);
	else
		return nl_send(sk, msg);
}

/**
 * Send simple netlink message using nl_send_auto_complete()
 * @arg sk		Netlink socket.
 * @arg type		Netlink message type.
 * @arg flags		Netlink message flags.
 * @arg buf		Data buffer.
 * @arg size		Size of data buffer.
 *
 * Builds a netlink message with the specified type and flags and
 * appends the specified data as payload to the message.
 *
 * @see nl_send_auto_complete()
 * @return Number of characters sent on success or a negative error code.
 */
int nl_send_simple(struct nl_sock *sk, int type, int flags, void *buf,
		   size_t size)
{
	int err;
	struct nl_msg *msg;

	msg = nlmsg_alloc_simple(type, flags);
	if (!msg)
		return -NLE_NOMEM;

	if (buf && size) {
		err = nlmsg_append(msg, buf, size, NLMSG_ALIGNTO);
		if (err < 0)
			goto errout;
	}
	

	err = nl_send_auto_complete(sk, msg);
errout:
	nlmsg_free(msg);

	return err;
}

/** @} */

/**
 * @name Receive
 * @{
 */

/**
 * Receive data from netlink socket
 * @arg sk		Netlink socket.
 * @arg nla		Destination pointer for peer's netlink address.
 * @arg buf		Destination pointer for message content.
 * @arg creds		Destination pointer for credentials.
 *
 * Receives a netlink message, allocates a buffer in \c *buf and
 * stores the message content. The peer's netlink address is stored
 * in \c *nla. The caller is responsible for freeing the buffer allocated
 * in \c *buf if a positive value is returned.  Interruped system calls
 * are handled by repeating the read. The input buffer size is determined
 * by peeking before the actual read is done.
 *
 * A non-blocking sockets causes the function to return immediately with
 * a return value of 0 if no data is available.
 *
 * @return Number of octets read, 0 on EOF or a negative error code.
 */
int nl_recv(struct nl_sock *sk, struct sockaddr_nl *nla,
	    unsigned char **buf, struct ucred **creds)
{
	int n;
	int flags = 0;
	static int page_size = 0;
	struct iovec iov;
	struct msghdr msg = {
		.msg_name = (void *) nla,
		.msg_namelen = sizeof(struct sockaddr_nl),
		.msg_iov = &iov,
		.msg_iovlen = 1,
		.msg_control = NULL,
		.msg_controllen = 0,
		.msg_flags = 0,
	};
	struct cmsghdr *cmsg;

	if (sk->s_flags & NL_MSG_PEEK)
		flags |= MSG_PEEK;

	if (page_size == 0)
		page_size = getpagesize();

	iov.iov_len = page_size;
	iov.iov_base = *buf = malloc(iov.iov_len);

	if (sk->s_flags & NL_SOCK_PASSCRED) {
		msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred));
		msg.msg_control = calloc(1, msg.msg_controllen);
	}
retry:

	n = recvmsg(sk->s_fd, &msg, flags);
	if (!n)
		goto abort;
	else if (n < 0) {
		if (errno == EINTR) {
			NL_DBG(3, "recvmsg() returned EINTR, retrying\n");
			goto retry;
		} else if (errno == EAGAIN) {
			NL_DBG(3, "recvmsg() returned EAGAIN, aborting\n");
			goto abort;
		} else {
			free(msg.msg_control);
			free(*buf);
			return -nl_syserr2nlerr(errno);
		}
	}

	if (iov.iov_len < n ||
	    msg.msg_flags & MSG_TRUNC) {
		/* Provided buffer is not long enough, enlarge it
		 * and try again. */
		iov.iov_len *= 2;
		iov.iov_base = *buf = realloc(*buf, iov.iov_len);
		goto retry;
	} else if (msg.msg_flags & MSG_CTRUNC) {
		msg.msg_controllen *= 2;
		msg.msg_control = realloc(msg.msg_control, msg.msg_controllen);
		goto retry;
	} else if (flags != 0) {
		/* Buffer is big enough, do the actual reading */
		flags = 0;
		goto retry;
	}

	if (msg.msg_namelen != sizeof(struct sockaddr_nl)) {
		free(msg.msg_control);
		free(*buf);
		return -NLE_NOADDR;
	}

	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
		if (cmsg->cmsg_level == SOL_SOCKET &&
		    cmsg->cmsg_type == SCM_CREDENTIALS) {
			*creds = calloc(1, sizeof(struct ucred));
			memcpy(*creds, CMSG_DATA(cmsg), sizeof(struct ucred));
			break;
		}
	}

	free(msg.msg_control);
	return n;

abort:
	free(msg.msg_control);
	free(*buf);
	return 0;
}

#define NL_CB_CALL(cb, type, msg) \
do { \
	err = nl_cb_call(cb, type, msg); \
	switch (err) { \
	case NL_OK: \
		err = 0; \
		break; \
	case NL_SKIP: \
		goto skip; \
	case NL_STOP: \
		goto stop; \
	default: \
		goto out; \
	} \
} while (0)

static int recvmsgs(struct nl_sock *sk, struct nl_cb *cb)
{
	int n, err = 0, multipart = 0;
	unsigned char *buf = NULL;
	struct nlmsghdr *hdr;
	struct sockaddr_nl nla = {0};
	struct nl_msg *msg = NULL;
	struct ucred *creds = NULL;

continue_reading:
	NL_DBG(3, "Attempting to read from %p\n", sk);
	if (cb->cb_recv_ow)
		n = cb->cb_recv_ow(sk, &nla, &buf, &creds);
	else
		n = nl_recv(sk, &nla, &buf, &creds);

	if (n <= 0)
		return n;

	NL_DBG(3, "recvmsgs(%p): Read %d bytes\n", sk, n);

	hdr = (struct nlmsghdr *) buf;
	while (nlmsg_ok(hdr, n)) {
		NL_DBG(3, "recgmsgs(%p): Processing valid message...\n", sk);

		nlmsg_free(msg);
		msg = nlmsg_convert(hdr);
		if (!msg) {
			err = -NLE_NOMEM;
			goto out;
		}

		nlmsg_set_proto(msg, sk->s_proto);
		nlmsg_set_src(msg, &nla);
		if (creds)
			nlmsg_set_creds(msg, creds);

		/* Raw callback is the first, it gives the most control
		 * to the user and he can do his very own parsing. */
		if (cb->cb_set[NL_CB_MSG_IN])
			NL_CB_CALL(cb, NL_CB_MSG_IN, msg);

		/* Sequence number checking. The check may be done by
		 * the user, otherwise a very simple check is applied
		 * enforcing strict ordering */
		if (cb->cb_set[NL_CB_SEQ_CHECK])
			NL_CB_CALL(cb, NL_CB_SEQ_CHECK, msg);
		else if (hdr->nlmsg_seq != sk->s_seq_expect) {
			if (cb->cb_set[NL_CB_INVALID])
				NL_CB_CALL(cb, NL_CB_INVALID, msg);
			else {
				err = -NLE_SEQ_MISMATCH;
				goto out;
			}
		}

		if (hdr->nlmsg_type == NLMSG_DONE ||
		    hdr->nlmsg_type == NLMSG_ERROR ||
		    hdr->nlmsg_type == NLMSG_NOOP ||
		    hdr->nlmsg_type == NLMSG_OVERRUN) {
			/* We can't check for !NLM_F_MULTI since some netlink
			 * users in the kernel are broken. */
			sk->s_seq_expect++;
			NL_DBG(3, "recvmsgs(%p): Increased expected " \
			       "sequence number to %d\n",
			       sk, sk->s_seq_expect);
		}

		if (hdr->nlmsg_flags & NLM_F_MULTI)
			multipart = 1;
	
		/* Other side wishes to see an ack for this message */
		if (hdr->nlmsg_flags & NLM_F_ACK) {
			if (cb->cb_set[NL_CB_SEND_ACK])
				NL_CB_CALL(cb, NL_CB_SEND_ACK, msg);
			else {
				/* FIXME: implement */
			}
		}

		/* messages terminates a multpart message, this is
		 * usually the end of a message and therefore we slip
		 * out of the loop by default. the user may overrule
		 * this action by skipping this packet. */
		if (hdr->nlmsg_type == NLMSG_DONE) {
			multipart = 0;
			if (cb->cb_set[NL_CB_FINISH])
				NL_CB_CALL(cb, NL_CB_FINISH, msg);
		}

		/* Message to be ignored, the default action is to
		 * skip this message if no callback is specified. The
		 * user may overrule this action by returning
		 * NL_PROCEED. */
		else if (hdr->nlmsg_type == NLMSG_NOOP) {
			if (cb->cb_set[NL_CB_SKIPPED])
				NL_CB_CALL(cb, NL_CB_SKIPPED, msg);
			else
				goto skip;
		}

		/* Data got lost, report back to user. The default action is to
		 * quit parsing. The user may overrule this action by retuning
		 * NL_SKIP or NL_PROCEED (dangerous) */
		else if (hdr->nlmsg_type == NLMSG_OVERRUN) {
			if (cb->cb_set[NL_CB_OVERRUN])
				NL_CB_CALL(cb, NL_CB_OVERRUN, msg);
			else {
				err = -NLE_MSG_OVERFLOW;
				goto out;
			}
		}

		/* Message carries a nlmsgerr */
		else if (hdr->nlmsg_type == NLMSG_ERROR) {
			struct nlmsgerr *e = nlmsg_data(hdr);

			if (hdr->nlmsg_len < nlmsg_msg_size(sizeof(*e))) {
				/* Truncated error message, the default action
				 * is to stop parsing. The user may overrule
				 * this action by returning NL_SKIP or
				 * NL_PROCEED (dangerous) */
				if (cb->cb_set[NL_CB_INVALID])
					NL_CB_CALL(cb, NL_CB_INVALID, msg);
				else {
					err = -NLE_MSG_TRUNC;
					goto out;
				}
			} else if (e->error) {
				/* Error message reported back from kernel. */
				if (cb->cb_err) {
					err = cb->cb_err(&nla, e,
							   cb->cb_err_arg);
					if (err < 0)
						goto out;
					else if (err == NL_SKIP)
						goto skip;
					else if (err == NL_STOP) {
						err = -nl_syserr2nlerr(e->error);
						goto out;
					}
				} else {
					err = -nl_syserr2nlerr(e->error);
					goto out;
				}
			} else if (cb->cb_set[NL_CB_ACK])
				NL_CB_CALL(cb, NL_CB_ACK, msg);
		} else {
			/* Valid message (not checking for MULTIPART bit to
			 * get along with broken kernels. NL_SKIP has no
			 * effect on this.  */
			if (cb->cb_set[NL_CB_VALID])
				NL_CB_CALL(cb, NL_CB_VALID, msg);
		}
skip:
		err = 0;
		hdr = nlmsg_next(hdr, &n);
	}
	
	nlmsg_free(msg);
	free(buf);
	free(creds);
	buf = NULL;
	msg = NULL;
	creds = NULL;

	if (multipart) {
		/* Multipart message not yet complete, continue reading */
		goto continue_reading;
	}
stop:
	err = 0;
out:
	nlmsg_free(msg);
	free(buf);
	free(creds);

	return err;
}
Example #14
0
bool Connection::sendOutgoingMessage(std::unique_ptr<MessageEncoder> encoder)
{
    COMPILE_ASSERT(sizeof(MessageInfo) + attachmentMaxAmount * sizeof(size_t) <= messageMaxSize, AttachmentsFitToMessageInline);

    Vector<Attachment> attachments = encoder->releaseAttachments();
    AttachmentResourceGuard<Vector<Attachment>, Vector<Attachment>::iterator> attachementDisposer(attachments);

    if (attachments.size() > (attachmentMaxAmount - 1)) {
        ASSERT_NOT_REACHED();
        return false;
    }

    MessageInfo messageInfo(encoder->bufferSize(), attachments.size());
    size_t messageSizeWithBodyInline = sizeof(messageInfo) + (attachments.size() * sizeof(AttachmentInfo)) + encoder->bufferSize();
    if (messageSizeWithBodyInline > messageMaxSize && encoder->bufferSize()) {
        RefPtr<WebKit::SharedMemory> oolMessageBody = WebKit::SharedMemory::create(encoder->bufferSize());
        if (!oolMessageBody)
            return false;

        WebKit::SharedMemory::Handle handle;
        if (!oolMessageBody->createHandle(handle, WebKit::SharedMemory::ReadOnly))
            return false;

        messageInfo.setMessageBodyIsOutOfLine();

        memcpy(oolMessageBody->data(), encoder->buffer(), encoder->bufferSize());

        attachments.append(handle.releaseToAttachment());
    }

    struct msghdr message;
    memset(&message, 0, sizeof(message));

    struct iovec iov[3];
    memset(&iov, 0, sizeof(iov));

    message.msg_iov = iov;
    int iovLength = 1;

    iov[0].iov_base = reinterpret_cast<void*>(&messageInfo);
    iov[0].iov_len = sizeof(messageInfo);

    auto attachmentInfo = std::make_unique<AttachmentInfo[]>(attachments.size());

    size_t attachmentFDBufferLength = 0;
    if (!attachments.isEmpty()) {
        for (size_t i = 0; i < attachments.size(); ++i) {
            if (attachments[i].fileDescriptor() != -1)
                attachmentFDBufferLength++;
        }
    }
    auto attachmentFDBuffer = std::make_unique<char[]>(CMSG_SPACE(sizeof(int) * attachmentFDBufferLength));

    if (!attachments.isEmpty()) {
        int* fdPtr = 0;

        if (attachmentFDBufferLength) {
            message.msg_control = attachmentFDBuffer.get();
            message.msg_controllen = CMSG_SPACE(sizeof(int) * attachmentFDBufferLength);
            memset(message.msg_control, 0, message.msg_controllen);

            struct cmsghdr* cmsg = CMSG_FIRSTHDR(&message);
            cmsg->cmsg_level = SOL_SOCKET;
            cmsg->cmsg_type = SCM_RIGHTS;
            cmsg->cmsg_len = CMSG_LEN(sizeof(int) * attachmentFDBufferLength);

            fdPtr = reinterpret_cast<int*>(CMSG_DATA(cmsg));
        }

        int fdIndex = 0;
        for (size_t i = 0; i < attachments.size(); ++i) {
            attachmentInfo[i].setType(attachments[i].type());

            switch (attachments[i].type()) {
            case Attachment::MappedMemoryType:
                attachmentInfo[i].setSize(attachments[i].size());
                // Fall trhough, set file descriptor or null.
            case Attachment::SocketType:
                if (attachments[i].fileDescriptor() != -1) {
                    ASSERT(fdPtr);
                    fdPtr[fdIndex++] = attachments[i].fileDescriptor();
                } else
                    attachmentInfo[i].setNull();
                break;
            case Attachment::Uninitialized:
            default:
                break;
            }
        }

        iov[iovLength].iov_base = attachmentInfo.get();
        iov[iovLength].iov_len = sizeof(AttachmentInfo) * attachments.size();
        ++iovLength;
    }

    if (!messageInfo.isMessageBodyIsOutOfLine() && encoder->bufferSize()) {
        iov[iovLength].iov_base = reinterpret_cast<void*>(encoder->buffer());
        iov[iovLength].iov_len = encoder->bufferSize();
        ++iovLength;
    }

    message.msg_iovlen = iovLength;

    int bytesSent = 0;
    while ((bytesSent = sendmsg(m_socketDescriptor, &message, 0)) == -1) {
        if (errno != EINTR)
            return false;
    }
    return true;
}
Example #15
0
File: preload.c Project: passimm/rr
/**
 * Install the seccomp-bpf that generates trace traps for all syscalls
 * other than those made through _untraced_syscall_entry_point().
 */
static void install_syscall_filter(void)
{
	void* untraced_syscall_start = get_untraced_syscall_entry_point();
	struct sock_filter filter[] = {
		/* Allow all system calls from our protected_call
		 * callsite */
		ALLOW_SYSCALLS_FROM_CALLSITE((uintptr_t)untraced_syscall_start),
		/* All the rest are handled in rr */
		TRACE_PROCESS,
	};
	struct sock_fprog prog = {
		.len = (unsigned short)(sizeof(filter)/sizeof(filter[0])),
		.filter = filter,
	};

	debug("Initializing syscall buffer: protected_call_start = %p",
	      untraced_syscall_start);

	if (traced_prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
		fatal("prctl(NO_NEW_PRIVS) failed, SECCOMP_FILTER is not available: your kernel is too old.  Use `record -n` to disable the filter.");
	}

	/* Note: the filter is installed only for record. This call
	 * will be emulated in the replay */
	if (traced_prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER,
			 (uintptr_t)&prog, 0, 0)) {
		fatal("prctl(SECCOMP) failed, SECCOMP_FILTER is not available: your kernel is too old.  Use `record -n` to disable the filter.");
	}
	/* anything that happens from this point on gets filtered! */
}

/**
 * Return a counter that generates a signal targeted at this task
 * every time the task is descheduled |nr_descheds| times.
 */
static int open_desched_event_counter(size_t nr_descheds, pid_t tid)
{
	struct perf_event_attr attr;
	int fd;
	struct f_owner_ex own;

	memset(&attr, 0, sizeof(attr));
	attr.size = sizeof(attr);
	attr.type = PERF_TYPE_SOFTWARE;
	attr.config = PERF_COUNT_SW_CONTEXT_SWITCHES;
	attr.disabled = 1;
	attr.sample_period = nr_descheds;

	fd = traced_perf_event_open(&attr, 0/*self*/, -1/*any cpu*/, -1, 0);
	if (0 > fd) {
		fatal("Failed to perf_event_open(cs, period=%u)", nr_descheds);
	}
	if (traced_fcntl(fd, F_SETFL, O_ASYNC)) {
		fatal("Failed to fcntl(O_ASYNC) the desched counter");
	}
	own.type = F_OWNER_TID;
	own.pid = tid;
	if (traced_fcntl(fd, F_SETOWN_EX, &own)) {
		fatal("Failed to fcntl(SETOWN_EX) the desched counter to this");
	}
	if (traced_fcntl(fd, F_SETSIG, SYSCALLBUF_DESCHED_SIGNAL)) {
		fatal("Failed to fcntl(SETSIG, %d) the desched counter",
		      SYSCALLBUF_DESCHED_SIGNAL);
	}

	return fd;
}

static void set_up_buffer(void)
{
	struct sockaddr_un addr;
	struct msghdr msg;
	struct iovec data;
	int msgbuf;
	struct cmsghdr* cmsg;
	int* msg_fdptr;
	int* cmsg_fdptr;
	char cmsgbuf[CMSG_SPACE(sizeof(*cmsg_fdptr))];
	struct socketcall_args args_vec;
	struct rrcall_init_buffers_params args;
	pid_t tid = traced_gettid();

	assert(!buffer);

	/* NB: we want this setup emulated during replay. */
	if (buffer_enabled) {
		desched_counter_fd = open_desched_event_counter(1, tid);
	}

	/* Prepare arguments for rrcall.  We do this in the tracee
	 * just to avoid some hairy IPC to set up the arguments
	 * remotely from the tracer; this isn't strictly
	 * necessary. */
	prepare_syscallbuf_socket_addr(&addr, tid);

	memset(&msg, 0, sizeof(msg));
	msg_fdptr = &msgbuf;
	data.iov_base = msg_fdptr;
	data.iov_len = sizeof(msgbuf);
	msg.msg_iov = &data;
	msg.msg_iovlen = 1;
	msg.msg_control = cmsgbuf;
	msg.msg_controllen = sizeof(cmsgbuf);
	cmsg = CMSG_FIRSTHDR(&msg);
	cmsg->cmsg_len = CMSG_LEN(sizeof(*cmsg_fdptr));
	cmsg->cmsg_level = SOL_SOCKET;
	cmsg->cmsg_type = SCM_RIGHTS;
	cmsg_fdptr = (int*)CMSG_DATA(cmsg);

	/* Set the "fd parameter" in the message buffer, which we send
	 * to let the other side know the local fd number we shared to
	 * it. */
	*msg_fdptr = desched_counter_fd;
	/* Set the "fd parameter" in the cmsg buffer, which is the one
	 * the kernel parses, dups, then sets to the fd number
	 * allocated in the other process. */
	*cmsg_fdptr = desched_counter_fd;

	args.syscallbuf_enabled = buffer_enabled;
	args.traced_syscall_ip = get_traced_syscall_entry_point();
	args.untraced_syscall_ip = get_untraced_syscall_entry_point();
	args.sockaddr = &addr;
	args.msg = &msg;
	args.fdptr = cmsg_fdptr;
	args.args_vec = &args_vec;

	/* Trap to rr: let the magic begin!  We've prepared the buffer
	 * so that it's immediately ready to be sendmsg()'d to rr to
	 * share the desched counter to it (under rr's control).  rr
	 * can further use the buffer to share more fd's to us.
	 *
	 * If the desched signal is currently blocked, then the tracer
	 * will clear our TCB guard and we won't be able to buffer
	 * syscalls.  But the tracee will set the guard when (or if)
	 * the signal is unblocked. */
	rrcall_init_buffers(&args);

	/* rr initializes the buffer header. */
	buffer = args.syscallbuf_ptr;
}

/**
 * Initialize thread-local buffering state, if enabled.
 */
static void init_thread(void)
{
	assert(process_inited);
	assert(!thread_inited);

	if (!buffer_enabled) {
		thread_inited = 1;
		return;
	}

	set_up_buffer();
	thread_inited = 1;
}
Example #16
0
static PyObject *sendmsg_recvmsg(PyObject *self, PyObject *args, PyObject *keywds) {
    int fd = -1;
    int flags = 0;
    int maxsize = 8192;
    int cmsg_size = 4096;
    size_t cmsg_space;
    size_t cmsg_overhead;
    Py_ssize_t recvmsg_result;

    struct msghdr message_header;
    struct cmsghdr *control_message;
    struct iovec iov[1];
    char *cmsgbuf;
    PyObject *ancillary;
    PyObject *final_result = NULL;

    static char *kwlist[] = {"fd", "flags", "maxsize", "cmsg_size", NULL};

    if (!PyArg_ParseTupleAndKeywords(args, keywds, "i|iii:recvmsg", kwlist,
                                     &fd, &flags, &maxsize, &cmsg_size)) {
        return NULL;
    }

    cmsg_space = CMSG_SPACE(cmsg_size);

    /* overflow check */
    if (cmsg_space > SOCKLEN_MAX) {
        PyErr_Format(PyExc_OverflowError,
                     "CMSG_SPACE(cmsg_size) greater than SOCKLEN_MAX: %d",
                     cmsg_size);
        return NULL;
    }

    message_header.msg_name = NULL;
    message_header.msg_namelen = 0;

    iov[0].iov_len = maxsize;
    iov[0].iov_base = PyMem_Malloc(maxsize);

    if (!iov[0].iov_base) {
        PyErr_NoMemory();
        return NULL;
    }

    message_header.msg_iov = iov;
    message_header.msg_iovlen = 1;

    cmsgbuf = PyMem_Malloc(cmsg_space);

    if (!cmsgbuf) {
        PyMem_Free(iov[0].iov_base);
        PyErr_NoMemory();
        return NULL;
    }

    memset(cmsgbuf, 0, cmsg_space);
    message_header.msg_control = cmsgbuf;
    /* see above for overflow check */
    message_header.msg_controllen = (socklen_t) cmsg_space;

    recvmsg_result = recvmsg(fd, &message_header, flags);
    if (recvmsg_result < 0) {
        PyErr_SetFromErrno(sendmsg_socket_error);
        goto finished;
    }

    ancillary = PyList_New(0);
    if (!ancillary) {
        goto finished;
    }

    for (control_message = CMSG_FIRSTHDR(&message_header);
         control_message;
         control_message = CMSG_NXTHDR(&message_header,
                                       control_message)) {
        PyObject *entry;

        /* Some platforms apparently always fill out the ancillary data
           structure with a single bogus value if none is provided; ignore it,
           if that is the case. */

        if ((!(control_message->cmsg_level)) &&
            (!(control_message->cmsg_type))) {
            continue;
        }

        /*
         * Figure out how much of the cmsg size is cmsg structure overhead - in
         * other words, how much is not part of the application data.  This lets
         * us compute the right application data size below.  There should
         * really be a CMSG_ macro for this.
         */
        cmsg_overhead = (char*)CMSG_DATA(control_message) - (char*)control_message;

        entry = Py_BuildValue(
            "(iis#)",
            control_message->cmsg_level,
            control_message->cmsg_type,
            CMSG_DATA(control_message),
            (Py_ssize_t) (control_message->cmsg_len - cmsg_overhead));

        if (!entry) {
            Py_DECREF(ancillary);
            goto finished;
        }

        if (PyList_Append(ancillary, entry) < 0) {
            Py_DECREF(ancillary);
            Py_DECREF(entry);
            goto finished;
        } else {
            Py_DECREF(entry);
        }
    }

    final_result = Py_BuildValue(
        "s#iO",
        iov[0].iov_base,
        recvmsg_result,
        message_header.msg_flags,
        ancillary);

    Py_DECREF(ancillary);

  finished:
    PyMem_Free(iov[0].iov_base);
    PyMem_Free(cmsgbuf);
    return final_result;
}
Example #17
0
struct command *read_command( int cmd_fd ) {
	struct command *cmd = malloc(sizeof(struct command));
	if (! cmd) {
		fprintf(stderr, "Unable to allocate memory for command!\n");
		return NULL;
	}

	int fd[1] = {-1};
	char buffer[CMSG_SPACE(sizeof fd)];

	struct iovec v = {
		.iov_base = cmd,
		.iov_len  = sizeof(*cmd)
	};
	struct msghdr msg = {
		.msg_iov        = &v,
		.msg_iovlen     = 1,
		.msg_control    = buffer,
		.msg_controllen = sizeof(buffer)
	};

	int done = recvmsg( cmd_fd, &msg, 0 );

	if (done == -1) {
		fprintf(stderr, "Error reading command.");
		free(cmd);
		return NULL;
	}
	struct cmsghdr *cmessage = CMSG_FIRSTHDR(&msg);
	if (cmessage) {
		memcpy(fd, CMSG_DATA(cmessage), sizeof fd);
		/* place FD back in the command message */
		cmd->fd = (int) fd[0];
	}
	return cmd;
}

int send_command( int cmd_fd, enum command_type type, char *param, int passfd, int exclusive, char *tag ) {
	if (type == CMD_ADD && passfd == 1) {
		type = CMD_PASSFD;
	}
	struct command cmd = {
		.fd    = -1,
		.exclusive = exclusive,
		.type  = type,
		.param = {0},
		.tag = {0}
	};
	if (param != NULL) {
		strncpy(cmd.param, param, TH_COMMAND_PARAM_LENGTH);
		cmd.param[TH_COMMAND_PARAM_LENGTH-1] = '\0';
	}
	if (tag != NULL) {
		strncpy(cmd.tag, tag, TH_DEVICE_TAG_LENGTH);
		cmd.tag[TH_DEVICE_TAG_LENGTH-1] = '\0';
	}

	struct iovec v = {
		.iov_base = &cmd,
		.iov_len = sizeof(cmd)
	};
	struct msghdr m = {
		.msg_iov    = &v,
		.msg_iovlen = 1
	};

	/* add FD */
	int dev_fd[1] = { -1 };
	char buffer[CMSG_SPACE(sizeof(dev_fd))];
	if (passfd) {
		int fd = open( param, O_RDONLY );
		if (fd < 0) {
			perror("open");
			return 1;
		}
		dev_fd[0] = fd ;
		m.msg_control = buffer;
		m.msg_controllen = sizeof(buffer);

		struct cmsghdr *cmessage = CMSG_FIRSTHDR(&m);
		cmessage->cmsg_level = SOL_SOCKET;
		cmessage->cmsg_type = SCM_RIGHTS;
		cmessage->cmsg_len = CMSG_LEN(sizeof(dev_fd));

		m.msg_controllen = cmessage->cmsg_len;
		memcpy(CMSG_DATA(cmessage), dev_fd, sizeof dev_fd);
	}
	int done = sendmsg( cmd_fd, &m, 0 );
	return (done == -1);
}
int sendfromto(int s, void *buf, size_t len, int flags,
	       struct sockaddr *from, socklen_t fromlen,
	       struct sockaddr *to, socklen_t tolen)
{
	struct msghdr msgh;
	struct cmsghdr *cmsg;
	struct iovec iov;
	char cbuf[256];

#ifdef __FreeBSD__
	/*
	 *	FreeBSD is extra pedantic about the use of IP_SENDSRCADDR,
	 *	and sendmsg will fail with EINVAL if IP_SENDSRCADDR is used
	 *	with a socket which is bound to something other than
	 *	INADDR_ANY
	 */
	struct sockaddr bound;
	socklen_t bound_len = sizeof(bound);

	if (getsockname(s, &bound, &bound_len) < 0) {
		return -1;
	}

	switch (bound.sa_family) {
	case AF_INET:
		if (((struct sockaddr_in *) &bound)->sin_addr.s_addr != INADDR_ANY) {
			from = NULL;
		}
		break;

	case AF_INET6:
		if (!IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *) &bound)->sin6_addr)) {
			from = NULL;
		}
		break;
	}
#else
#  if !defined(IP_PKTINFO) && !defined(IP_SENDSRCADDR) && !defined(IPV6_PKTINFO)
	/*
	 *	If the sendmsg() flags aren't defined, fall back to
	 *	using sendto().
	 */
	from = NULL;
#  endif
#endif

	/*
	 *	Catch the case where the caller passes invalid arguments.
	 */
	if (!from || (fromlen == 0) || (from->sa_family == AF_UNSPEC)) {
		return sendto(s, buf, len, flags, to, tolen);
	}

	/* Set up control buffer iov and msgh structures. */
	memset(&cbuf, 0, sizeof(cbuf));
	memset(&msgh, 0, sizeof(msgh));
	memset(&iov, 0, sizeof(iov));
	iov.iov_base = buf;
	iov.iov_len = len;
	msgh.msg_iov = &iov;
	msgh.msg_iovlen = 1;
	msgh.msg_name = to;
	msgh.msg_namelen = tolen;

	if (from->sa_family == AF_INET) {
#if !defined(IP_PKTINFO) && !defined(IP_SENDSRCADDR)
		return sendto(s, buf, len, flags, to, tolen);
#else
		struct sockaddr_in *s4 = (struct sockaddr_in *) from;

#  ifdef IP_PKTINFO
		struct in_pktinfo *pkt;

		msgh.msg_control = cbuf;
		msgh.msg_controllen = CMSG_SPACE(sizeof(*pkt));

		cmsg = CMSG_FIRSTHDR(&msgh);
		cmsg->cmsg_level = SOL_IP;
		cmsg->cmsg_type = IP_PKTINFO;
		cmsg->cmsg_len = CMSG_LEN(sizeof(*pkt));

		pkt = (struct in_pktinfo *) CMSG_DATA(cmsg);
		memset(pkt, 0, sizeof(*pkt));
		pkt->ipi_spec_dst = s4->sin_addr;
#  endif

#  ifdef IP_SENDSRCADDR
		struct in_addr *in;

		msgh.msg_control = cbuf;
		msgh.msg_controllen = CMSG_SPACE(sizeof(*in));

		cmsg = CMSG_FIRSTHDR(&msgh);
		cmsg->cmsg_level = IPPROTO_IP;
		cmsg->cmsg_type = IP_SENDSRCADDR;
		cmsg->cmsg_len = CMSG_LEN(sizeof(*in));

		in = (struct in_addr *) CMSG_DATA(cmsg);
		*in = s4->sin_addr;
#  endif
#endif	/* IP_PKTINFO or IP_SENDSRCADDR */
	}

#ifdef AF_INET6
	else if (from->sa_family == AF_INET6) {
#  if !defined(IPV6_PKTINFO)
		return sendto(s, buf, len, flags, to, tolen);
#  else
		struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) from;

		struct in6_pktinfo *pkt;

		msgh.msg_control = cbuf;
		msgh.msg_controllen = CMSG_SPACE(sizeof(*pkt));

		cmsg = CMSG_FIRSTHDR(&msgh);
		cmsg->cmsg_level = IPPROTO_IPV6;
		cmsg->cmsg_type = IPV6_PKTINFO;
		cmsg->cmsg_len = CMSG_LEN(sizeof(*pkt));

		pkt = (struct in6_pktinfo *) CMSG_DATA(cmsg);
		memset(pkt, 0, sizeof(*pkt));
		pkt->ipi6_addr = s6->sin6_addr;
#  endif	/* IPV6_PKTINFO */
	}
#endif

	/*
	 *	Unknown address family.
	 */
	else {
		errno = EINVAL;
		return -1;
	}

	return sendmsg(s, &msgh, flags);
}
Example #19
0
/*
 * Receive a file descriptor from a Unix socket.
 * Contributed by @mkasick
 *
 * Returns the file descriptor on success, or -1 if a file
 * descriptor was not actually included in the message
 *
 * On error the function terminates by calling exit(-1)
 */
static int recv_fd(int sockfd) {
    // Need to receive data from the message, otherwise don't care about it.
    char iovbuf;

    struct iovec iov = {
        .iov_base = &iovbuf,
        .iov_len  = 1,
    };

    char cmsgbuf[CMSG_SPACE(sizeof(int))];

    struct msghdr msg = {
        .msg_iov        = &iov,
        .msg_iovlen     = 1,
        .msg_control    = cmsgbuf,
        .msg_controllen = sizeof(cmsgbuf),
    };

    if (recvmsg(sockfd, &msg, MSG_WAITALL) != 1) {
        goto error;
    }

    // Was a control message actually sent?
    switch (msg.msg_controllen) {
    case 0:
        // No, so the file descriptor was closed and won't be used.
        return -1;
    case sizeof(cmsgbuf):
        // Yes, grab the file descriptor from it.
        break;
    default:
        goto error;
    }

    struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);

    if (cmsg             == NULL                  ||
        cmsg->cmsg_len   != CMSG_LEN(sizeof(int)) ||
        cmsg->cmsg_level != SOL_SOCKET            ||
        cmsg->cmsg_type  != SCM_RIGHTS) {
error:
        LOGE("unable to read fd");
        exit(-1);
    }

    return *(int *)CMSG_DATA(cmsg);
}

/*
 * Send a file descriptor through a Unix socket.
 * Contributed by @mkasick
 *
 * On error the function terminates by calling exit(-1)
 *
 * fd may be -1, in which case the dummy data is sent,
 * but no control message with the FD is sent.
 */
static void send_fd(int sockfd, int fd) {
    // Need to send some data in the message, this will do.
    struct iovec iov = {
        .iov_base = "",
        .iov_len  = 1,
    };

    struct msghdr msg = {
        .msg_iov        = &iov,
        .msg_iovlen     = 1,
    };

    char cmsgbuf[CMSG_SPACE(sizeof(int))];

    if (fd != -1) {
        // Is the file descriptor actually open?
        if (fcntl(fd, F_GETFD) == -1) {
            if (errno != EBADF) {
                goto error;
            }
            // It's closed, don't send a control message or sendmsg will EBADF.
        } else {
            // It's open, send the file descriptor in a control message.
            msg.msg_control    = cmsgbuf;
            msg.msg_controllen = sizeof(cmsgbuf);

            struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);

            cmsg->cmsg_len   = CMSG_LEN(sizeof(int));
            cmsg->cmsg_level = SOL_SOCKET;
            cmsg->cmsg_type  = SCM_RIGHTS;

            *(int *)CMSG_DATA(cmsg) = fd;
        }
    }

    if (sendmsg(sockfd, &msg, 0) != 1) {
error:
        PLOGE("unable to send fd");
        exit(-1);
    }
}

static int read_int(int fd) {
    int val;
    int len = read(fd, &val, sizeof(int));
    if (len != sizeof(int)) {
        LOGE("unable to read int: %d", len);
        exit(-1);
    }
    return val;
}

static void write_int(int fd, int val) {
    int written = write(fd, &val, sizeof(int));
    if (written != sizeof(int)) {
        PLOGE("unable to write int");
        exit(-1);
    }
}

static char* read_string(int fd) {
    int len = read_int(fd);
    if (len > PATH_MAX || len < 0) {
        LOGE("invalid string length %d", len);
        exit(-1);
    }
    char* val = malloc(sizeof(char) * (len + 1));
    if (val == NULL) {
        LOGE("unable to malloc string");
        exit(-1);
    }
    val[len] = '\0';
    int amount = read(fd, val, len);
    if (amount != len) {
        LOGE("unable to read string");
        exit(-1);
    }
    return val;
}

static void write_string(int fd, char* val) {
    int len = strlen(val);
    write_int(fd, len);
    int written = write(fd, val, len);
    if (written != len) {
        PLOGE("unable to write string");
        exit(-1);
    }
}
Example #20
0
ssize_t
imsg_read(struct imsgbuf *ibuf)
{
	struct msghdr		 msg;
	struct cmsghdr		*cmsg;
	union {
		struct cmsghdr hdr;
		char	buf[CMSG_SPACE(sizeof(int) * 1)];
	} cmsgbuf;
	struct iovec		 iov;
	ssize_t			 n = -1;
	int			 fd;
	struct imsg_fd		*ifd;

	memset(&msg, 0, sizeof(msg));
	memset(&cmsgbuf, 0, sizeof(cmsgbuf));

	iov.iov_base = ibuf->r.buf + ibuf->r.wpos;
	iov.iov_len = sizeof(ibuf->r.buf) - ibuf->r.wpos;
	msg.msg_iov = &iov;
	msg.msg_iovlen = 1;
	msg.msg_control = &cmsgbuf.buf;
	msg.msg_controllen = CMSG_SPACE(sizeof(int) * 16);

	if ((ifd = calloc(1, sizeof(struct imsg_fd))) == NULL)
		return (-1);

again:
	if (getdtablecount() + imsg_fd_overhead +
	    (int)((CMSG_SPACE(sizeof(int))-CMSG_SPACE(0))/sizeof(int))
	    >= getdtablesize()) {
		errno = EAGAIN;
		free(ifd);
		return (-1);
	}

	if ((n = recvmsg(ibuf->fd, &msg, 0)) == -1) {
		if (errno == EINTR)
			goto again;
		goto fail;
	}

	ibuf->r.wpos += n;

	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
	    cmsg = CMSG_NXTHDR(&msg, cmsg)) {
		if (cmsg->cmsg_level == SOL_SOCKET &&
		    cmsg->cmsg_type == SCM_RIGHTS) {
			int i;
			int j;

			/*
			 * We only accept one file descriptor.  Due to C
			 * padding rules, our control buffer might contain
			 * more than one fd, and we must close them.
			 */
			j = ((char *)cmsg + cmsg->cmsg_len -
			    (char *)CMSG_DATA(cmsg)) / sizeof(int);
			for (i = 0; i < j; i++) {
				fd = ((int *)CMSG_DATA(cmsg))[i];
				if (ifd != NULL) {
					ifd->fd = fd;
					TAILQ_INSERT_TAIL(&ibuf->fds, ifd,
					    entry);
					ifd = NULL;
				} else
					close(fd);
			}
		}
		/* we do not handle other ctl data level */
	}

fail:
	free(ifd);
	return (n);
}
Example #21
0
namespace rubinius {

  void IO::bootstrap(STATE) {
    GO(io).set(state->memory()->new_class<Class, IO>(state, G(object), "IO"));
    G(io)->set_object_type(state, IOType);
  }

  IO* IO::create(STATE, int fd) {
    IO* io = state->memory()->new_object<IO>(state, G(io));

    return io;
  }

  native_int IO::open_with_cloexec(STATE, const char* path, int mode, int permissions) {
    if(Class* fd_class = try_as<Class>(G(io)->get_const(state, "FileDescriptor"))) {
      Tuple* args = Tuple::from(state, 3,
          String::create(state, path),
          Fixnum::from(mode),
          Fixnum::from(permissions));

      if(Fixnum* fd = try_as<Fixnum>(fd_class->send(state,
              state->symbol("open_with_cloexec"),
              Array::from_tuple(state, args))))
      {
        return fd->to_native();
      } else {
        Exception::raise_runtime_error(state, "unable to open IO with cloexec");
      }
    } else {
      Exception::raise_runtime_error(state, "unable to access IO::FileDescriptor class");
    }
  }

  native_int IO::descriptor(STATE) {
    if(Fixnum* fd = try_as<Fixnum>(send(state, state->symbol("descriptor")))) {
      return fd->to_native();
    }

    Exception::raise_runtime_error(state, "IO descriptor is not a Fixnum");
  }

  void IO::ensure_open(STATE) {
    // Will raise an exception if the file descriptor is not open
    send(state, state->symbol("ensure_open"));
  }

  Array* ipaddr(STATE, struct sockaddr* addr, socklen_t len) {
    String* family;
    char buf[NI_MAXHOST];
    char pbuf[NI_MAXSERV];

    switch(addr->sa_family) {
    case AF_UNSPEC:
      family = String::create(state, "AF_UNSPEC");
      break;
    case AF_INET:
      family = String::create(state, "AF_INET");
      break;
#ifdef INET6
    case AF_INET6:
      family = String::create(state, "AF_INET6");
      break;
#endif
#ifdef AF_LOCAL
    case AF_LOCAL:
      family = String::create(state, "AF_LOCAL");
      break;
#elif  AF_UNIX
    case AF_UNIX:
      family = String::create(state, "AF_UNIX");
      break;
#endif
    default:
      snprintf(pbuf, NI_MAXSERV, "unknown:%d", addr->sa_family);
      family = String::create(state, pbuf);
      break;
    }

    int e = getnameinfo(addr, len, buf, NI_MAXHOST, pbuf, NI_MAXSERV,
                        NI_NUMERICHOST | NI_NUMERICSERV);

    // TODO this doesn't support doing the DNS bound lookup at all.
    //      Not doing it better than doing it badly, thats why it's
    //      not here.
    //
    String* host;
    if(e) {
      host = String::create(state, (char*)addr, len);
    } else {
      host = String::create(state, buf);
    }

    Array* ary = Array::create(state, 4);
    ary->set(state, 0, family);
    ary->set(state, 1, Fixnum::from(atoi(pbuf)));
    ary->set(state, 2, host);
    ary->set(state, 3, host);

    return ary;
  }

#ifndef RBX_WINDOWS
  static const char* unixpath(struct sockaddr_un *sockaddr, socklen_t len) {
    if(sockaddr->sun_path < (char*)sockaddr + len) {
      return sockaddr->sun_path;
    }
    return "";
  }

  Array* unixaddr(STATE, struct sockaddr_un* addr, socklen_t len) {
    Array* ary = Array::create(state, 2);
    ary->set(state, 0, String::create(state, "AF_UNIX"));
    ary->set(state, 1, String::create(state, unixpath(addr, len)));
    return ary;
  }
#endif

  Object* IO::socket_read(STATE, Fixnum* bytes, Fixnum* flags, Fixnum* type) {
    char buf[1024];
    socklen_t alen = sizeof(buf);
    size_t size = (size_t)bytes->to_native();

    String* buffer = String::create_pinned(state, bytes);

    OnStack<1> variables(state, buffer);

    ssize_t bytes_read;
    native_int t = type->to_native();

  retry:
    state->vm()->interrupt_with_signal();
    state->vm()->thread()->sleep(state, cTrue);

    {
      UnmanagedPhase unmanaged(state);

      bytes_read = recvfrom(descriptor(state),
                            (char*)buffer->byte_address(), size,
                            flags->to_native(),
                            (struct sockaddr*)buf, &alen);
    }

    state->vm()->thread()->sleep(state, cFalse);
    state->vm()->clear_waiter();

    buffer->unpin();

    if(bytes_read == -1) {
      if(errno == EINTR) {
        if(state->vm()->thread_interrupted_p(state)) return NULL;
        ensure_open(state);
        goto retry;
      } else {
        Exception::raise_errno_error(state, "read(2) failed");
      }

      return NULL;
    }

    buffer->num_bytes(state, Fixnum::from(bytes_read));

    if(t == 0) return buffer; // none

    Array* ary = Array::create(state, 2);
    ary->set(state, 0, buffer);

    switch(type->to_native()) {
    case 1: // ip
      // Hack from MRI:
      // OSX doesn't return a 'from' result from recvfrom for connection-oriented sockets
      if(alen && alen != sizeof(buf)) {
        ary->set(state, 1, ipaddr(state, (struct sockaddr*)buf, alen));
      } else {
        ary->set(state, 1, cNil);
      }
      break;
#ifndef RBX_WINDOWS
    case 2: // unix
      ary->set(state, 1, unixaddr(state, (struct sockaddr_un*)buf, alen));
      break;
#endif
    default:
      ary->set(state, 1, String::create(state, buf, alen));
    }

    return ary;
  }

  // Stole/ported from 1.8.7. The system fnmatch doesn't support
  // a bunch of things this does (and must).

#ifndef CASEFOLD_FILESYSTEM
# if defined DOSISH || defined __VMS
#   define CASEFOLD_FILESYSTEM 1
# else
#   define CASEFOLD_FILESYSTEM 0
# endif
#endif

#define FNM_NOESCAPE	0x01
#define FNM_PATHNAME	0x02
#define FNM_DOTMATCH	0x04
#define FNM_CASEFOLD	0x08
#define FNM_EXTGLOB 	0x10
#if CASEFOLD_FILESYSTEM
#define FNM_SYSCASE	FNM_CASEFOLD
#else
#define FNM_SYSCASE	0
#endif

#define FNM_NOMATCH	1
#define FNM_ERROR	2

#define downcase(c) (nocase && ISUPPER(c) ? tolower(c) : (c))
#define compare(c1, c2) (((unsigned char)(c1)) - ((unsigned char)(c2)))
#define Next(p) ((p) + 1)
#define Inc(p) (++(p))
#define Compare(p1, p2) (compare(downcase(*(p1)), downcase(*(p2))))

  namespace {

    static char *bracket(const char* p, const char* s, int flags) {
      const int nocase = flags & FNM_CASEFOLD;
      const int escape = !(flags & FNM_NOESCAPE);

      int ok = 0, nope = 0;

      if(*p == '!' || *p == '^') {
        nope = 1;
        p++;
      }

      while(*p != ']') {
        const char *t1 = p;
        if(escape && *t1 == '\\') t1++;
        if(!*t1) return NULL;

        p = Next(t1);
        if(p[0] == '-' && p[1] != ']') {
          const char *t2 = p + 1;
          if(escape && *t2 == '\\') t2++;
          if(!*t2) return NULL;

          p = Next(t2);
          if(!ok && Compare(t1, s) <= 0 && Compare(s, t2) <= 0) ok = 1;
        } else {
          if(!ok && Compare(t1, s) == 0) ok = 1;
        }
      }

      return ok == nope ? NULL : (char *)p + 1;
    }
    /* If FNM_PATHNAME is set, only path element will be matched. (upto '/' or '\0')
       Otherwise, entire string will be matched.
       End marker itself won't be compared.
       And if function succeeds, *pcur reaches end marker.
       */
#define UNESCAPE(p) (escape && *(p) == '\\' ? (p) + 1 : (p))
#define ISEND(p) (!*(p) || (pathname && *(p) == '/'))
#define RETURN(val) return *pcur = p, *scur = s, (val);

    bool mri_fnmatch_helper(const char** pcur, const char** scur, int flags) {
      const int period = !(flags & FNM_DOTMATCH);
      const int pathname = flags & FNM_PATHNAME;
      const int escape = !(flags & FNM_NOESCAPE);
      const int nocase = flags & FNM_CASEFOLD;

      const char *ptmp = 0;
      const char *stmp = 0;

      const char *p = *pcur;
      const char *s = *scur;

      if(period && *s == '.' && *UNESCAPE(p) != '.') /* leading period */
        RETURN(false);

      while(1) {
        switch(*p) {
        case '*':
          do { p++; } while (*p == '*');
          if(ISEND(UNESCAPE(p))) {
            p = UNESCAPE(p);
            RETURN(true);
          }
          if(ISEND(s)) RETURN(false);

          ptmp = p;
          stmp = s;
          continue;

        case '?':
          if(ISEND(s)) RETURN(false);
          p++;
          Inc(s);
          continue;

        case '[': {
          const char *t;
          if(ISEND(s)) RETURN(false);
          if((t = bracket(p + 1, s, flags)) != 0) {
            p = t;
            Inc(s);
            continue;
          }
          goto failed;
        }
        }

        /* ordinary */
        p = UNESCAPE(p);
        if(ISEND(s)) RETURN(ISEND(p) ? true : false);
        if(ISEND(p)) goto failed;
        if(Compare(p, s) != 0) goto failed;

        Inc(p);
        Inc(s);
        continue;

failed: /* try next '*' position */
        if(ptmp && stmp) {
          p = ptmp;
          Inc(stmp); /* !ISEND(*stmp) */
          s = stmp;
          continue;
        }
        RETURN(false);
      }
    }

    int mri_fnmatch(const char* p, const char* s, int flags) {
      const int period = !(flags & FNM_DOTMATCH);
      const int pathname = flags & FNM_PATHNAME;

      const char *ptmp = 0;
      const char *stmp = 0;

      if(pathname) {
        while(1) {
          if(p[0] == '*' && p[1] == '*' && p[2] == '/') {
            do { p += 3; } while (p[0] == '*' && p[1] == '*' && p[2] == '/');
            ptmp = p;
            stmp = s;
          }
          if(mri_fnmatch_helper(&p, &s, flags)) {
            while(*s && *s != '/') Inc(s);
            if(*p && *s) {
              p++;
              s++;
              continue;
            }
            if(!*p && !*s)
              return true;
          }
          /* failed : try next recursion */
          if(ptmp && stmp && !(period && *stmp == '.')) {
            while(*stmp && *stmp != '/') Inc(stmp);
            if(*stmp) {
              p = ptmp;
              stmp++;
              s = stmp;
              continue;
            }
          }
          return false;
        }
      } else {
        return mri_fnmatch_helper(&p, &s, flags);
      }
    }
  }

  Object* IO::fnmatch(STATE, String* pattern, String* path, Fixnum* flags) {
    return RBOOL(mri_fnmatch(pattern->c_str(state), path->c_str(state), flags->to_native()));
  }


  /** Socket methods */
  static const int cmsg_space = CMSG_SPACE(sizeof(int));

  Object* IO::send_io(STATE, IO* io) {
#ifdef _WIN32
    return Primitives::failure();
#else
    int fd;
    struct msghdr msg;
    struct iovec vec[1];
    char buf[1];

    struct cmsghdr *cmsg;
    char cmsg_buf[cmsg_space];

    fd = io->descriptor(state);

    msg.msg_name = NULL;
    msg.msg_namelen = 0;

    /* Linux and Solaris doesn't work if msg_iov is NULL. */
    buf[0] = '\0';
    vec[0].iov_base = buf;
    vec[0].iov_len = 1;
    msg.msg_iov = vec;
    msg.msg_iovlen = 1;

    msg.msg_control = (caddr_t)cmsg_buf;
    msg.msg_controllen = sizeof(cmsg_buf);
    msg.msg_flags = 0;
    cmsg = CMSG_FIRSTHDR(&msg);
    memset(cmsg_buf, 0, sizeof(cmsg_buf));
    cmsg->cmsg_len = CMSG_LEN(sizeof(int));
    cmsg->cmsg_level = SOL_SOCKET;
    cmsg->cmsg_type = SCM_RIGHTS;

    // Workaround for GCC's broken strict-aliasing checks.
    int* fd_data = (int*)CMSG_DATA(cmsg);
    *fd_data = fd;

    if(sendmsg(descriptor(state), &msg, 0) == -1) {
      return Primitives::failure();
    }

    return cNil;
#endif
  }

  Object* IO::recv_fd(STATE) {
#ifdef _WIN32
    return Primitives::failure();
#else
    struct msghdr msg;
    struct iovec vec[1];
    char buf[1];

    struct cmsghdr *cmsg;
    char cmsg_buf[cmsg_space];

    msg.msg_name = NULL;
    msg.msg_namelen = 0;

    /* Linux and Solaris doesn't work if msg_iov is NULL. */
    buf[0] = '\0';
    vec[0].iov_base = buf;
    vec[0].iov_len = 1;
    msg.msg_iov = vec;
    msg.msg_iovlen = 1;

    msg.msg_control = (caddr_t)cmsg_buf;
    msg.msg_controllen = sizeof(cmsg_buf);
    msg.msg_flags = 0;
    cmsg = CMSG_FIRSTHDR(&msg);
    memset(cmsg_buf, 0, sizeof(cmsg_buf));
    cmsg->cmsg_len = CMSG_LEN(sizeof(int));
    cmsg->cmsg_level = SOL_SOCKET;
    cmsg->cmsg_type = SCM_RIGHTS;

    // Workaround for GCC's broken strict-aliasing checks.
    int* fd_data = (int *)CMSG_DATA(cmsg);
    *fd_data = -1;

    int read_fd = descriptor(state);

    int code = -1;

  retry:
    state->vm()->interrupt_with_signal();
    state->vm()->thread()->sleep(state, cTrue);

    {
      UnmanagedPhase unmanaged(state);
      code = recvmsg(read_fd, &msg, 0);
    }

    state->vm()->thread()->sleep(state, cFalse);
    state->vm()->clear_waiter();

    if(code == -1) {
      if(errno == EAGAIN || errno == EINTR) {
        if(state->vm()->thread_interrupted_p(state)) return NULL;
        ensure_open(state);
        goto retry;
      }

      return Primitives::failure();
    }

    if(msg.msg_controllen != CMSG_SPACE(sizeof(int))
        || cmsg->cmsg_len != CMSG_LEN(sizeof(int))
        || cmsg->cmsg_level != SOL_SOCKET
        || cmsg->cmsg_type != SCM_RIGHTS) {
      return Primitives::failure();
    }

    // Workaround for GCC's broken strict-aliasing checks.
    fd_data = (int *)CMSG_DATA(cmsg);
    return Fixnum::from(*fd_data);
#endif
  }

  void FDSet::bootstrap(STATE) {
    // Create a constant for FDSet under the IO::Select namespace, i.e. IO::Select::FDSet
    GO(select).set(state->memory()->new_class<Class>(state, G(io), "Select"));
    GO(fdset).set(state->memory()->new_class<Class, FDSet>(state, G(select), "FDSet"));
  }

  FDSet* FDSet::allocate(STATE, Object* self) {
    FDSet* fdset = create(state);
    fdset->klass(state, as<Class>(self));
    return fdset;
  }

  FDSet* FDSet::create(STATE) {
    FDSet* fdset = state->memory()->new_object<FDSet>(state, G(fdset));
    return fdset;
  }

  Object* FDSet::zero(STATE) {
    FD_ZERO((fd_set*)descriptor_set);
    return cTrue;
  }

  Object* FDSet::set(STATE, Fixnum* descriptor) {
    native_int fd = descriptor->to_native();

    FD_SET((int_fd_t)fd, (fd_set*)descriptor_set);

    return cTrue;
  }

  Object* FDSet::is_set(STATE, Fixnum* descriptor) {
    native_int fd = descriptor->to_native();

    if (FD_ISSET(fd, (fd_set*)descriptor_set)) {
      return cTrue;
    }
    else {
      return cFalse;
    }
  }

  Object* FDSet::to_set(STATE) {
    void *ptr = (void*)&descriptor_set;

    return Pointer::create(state, ptr);
  }

  void RIOStream::bootstrap(STATE) {
    GO(rio_stream).set(state->memory()->new_class<Class, RIOStream>(
          state, G(rubinius), "RIOStream"));
  }

  Object* RIOStream::close(STATE, Object* io, Object* allow_exception) {
    // If there is a handle for this IO, and it's been promoted into
    // a lowlevel RIO struct using fdopen, then we MUST use fclose
    // to close it.

    if(capi::Handle* hdl = io->handle(state)) {
      if(hdl->is_rio()) {
        if(!hdl->rio_close() && CBOOL(allow_exception)) {
          Exception::raise_errno_error(state, "failed to close RIOStream");
        }
        return cTrue;
      }
    }
    return cFalse;
  }
}
Example #22
0
File: scm.c Project: AllenDou/linux
void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
{
	struct cmsghdr __user *cm
		= (__force struct cmsghdr __user*)msg->msg_control;

	int fdmax = 0;
	int fdnum = scm->fp->count;
	struct file **fp = scm->fp->fp;
	int __user *cmfptr;
	int err = 0, i;

	if (MSG_CMSG_COMPAT & msg->msg_flags) {
		scm_detach_fds_compat(msg, scm);
		return;
	}

	if (msg->msg_controllen > sizeof(struct cmsghdr))
		fdmax = ((msg->msg_controllen - sizeof(struct cmsghdr))
			 / sizeof(int));

	if (fdnum < fdmax)
		fdmax = fdnum;

	for (i=0, cmfptr=(__force int __user *)CMSG_DATA(cm); i<fdmax;
	     i++, cmfptr++)
	{
		struct socket *sock;
		int new_fd;
		err = security_file_receive(fp[i]);
		if (err)
			break;
		err = get_unused_fd_flags(MSG_CMSG_CLOEXEC & msg->msg_flags
					  ? O_CLOEXEC : 0);
		if (err < 0)
			break;
		new_fd = err;
		err = put_user(new_fd, cmfptr);
		if (err) {
			put_unused_fd(new_fd);
			break;
		}
		/* Bump the usage count and install the file. */
		sock = sock_from_file(fp[i], &err);
		if (sock)
			sock_update_netprioidx(sock->sk, current);
		fd_install(new_fd, get_file(fp[i]));
	}

	if (i > 0)
	{
		int cmlen = CMSG_LEN(i*sizeof(int));
		err = put_user(SOL_SOCKET, &cm->cmsg_level);
		if (!err)
			err = put_user(SCM_RIGHTS, &cm->cmsg_type);
		if (!err)
			err = put_user(cmlen, &cm->cmsg_len);
		if (!err) {
			cmlen = CMSG_SPACE(i*sizeof(int));
			msg->msg_control += cmlen;
			msg->msg_controllen -= cmlen;
		}
	}
	if (i < fdnum || (fdnum && fdmax <= 0))
		msg->msg_flags |= MSG_CTRUNC;

	/*
	 * All of the files that fit in the message have had their
	 * usage counts incremented, so we just free the list.
	 */
	__scm_destroy(scm);
}
Example #23
0
uint8_t negotiate(struct np_map *npm, uint8_t no_maps, const struct in6_addr *saddr, const struct in6_addr *daddr, int iif, int sock_fd)
{
//    uint8_t all_hosts_addr[] = {0xff,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
    struct sockaddr_in6 addr;
    struct nd_neighbor_advert *na;
    struct iovec iov;
    struct cmsghdr *cmsg;
    char chdr[CMSG_SPACE(sizeof(struct in6_pktinfo))];
    struct in6_pktinfo *pkt_info;
    struct msghdr mhdr;
    int i,j = 0;
	float cur_best_prio = -1;
//	struct np_finalise npf;
	struct np_fin_nd_opt npf;
	char *proc_cat_s = malloc(MAX_PROC_STR_SIZE + 1);

    unsigned char buff[MSG_SIZE];
    int len = 0;
    int err;
	struct ifreq ifr;

	uint8_t *ucp;
	unsigned int slla_len;

    memset((void *)&addr, 0, sizeof(addr));
    addr.sin6_family = AF_INET6;
    addr.sin6_port = htons(IPPROTO_ICMPV6);
    memcpy(&addr.sin6_addr, saddr, sizeof(struct in6_addr));

    memset(&buff, 0, sizeof(buff));

    na = (struct nd_neighbor_advert *) buff;

    na->nd_na_type = ND_NEIGHBOR_ADVERT;
    na->nd_na_code  = 0;
    na->nd_na_cksum = 0;
    na->nd_na_target = *daddr;

    len = sizeof(struct nd_neighbor_advert);

	/*
	* Add the Source LL Address ICMPv6 Option
	*/

	ifr.ifr_addr.sa_family = AF_INET6;
	strncpy(ifr.ifr_name, conf.interface, IF_NAMESIZE-1);

	ioctl(sock_fd, SIOCGIFHWADDR, &ifr);

	printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
			(unsigned char)ifr.ifr_hwaddr.sa_data[0],
			(unsigned char)ifr.ifr_hwaddr.sa_data[1],
			(unsigned char)ifr.ifr_hwaddr.sa_data[2],
			(unsigned char)ifr.ifr_hwaddr.sa_data[3],
			(unsigned char)ifr.ifr_hwaddr.sa_data[4],
			(unsigned char)ifr.ifr_hwaddr.sa_data[5]);

	ucp = (uint8_t *) (buff + len);

	*ucp++  = ND_OPT_SOURCE_LINKADDR;
	*ucp++  = 1; /* XXX : HACK : This will only work for MAC */

	len += 2 * sizeof(uint8_t);

	slla_len = 6; /* XXX : HACK : This will only work for MAC */
	memcpy(buff + len, &ifr.ifr_hwaddr.sa_data, slla_len);
	len+= slla_len;

	/*
	* Add NP++ Finalisation Option
	*/
	npf.type = 63;
	npf.length = 1;

	for(i = 0; i < NP_FIN_PAD_SIZE; i++)
	{
		npf.pad[i] = 0;
	}

	/*
	* Perform comparison of mapping tables to determine best mapping to use
	*/
	for(i = 0; i < no_maps; i++)
	{
		for(j = 0; j < no_my_maps; j++)
		{
			// Check mapping exists in both lists
			if(my_npm[j].mapping == npm[i].mapping)
			{
				float av_prio = 0;
				av_prio = (float)(((float)my_npm[j].prio + (float)npm[i].prio) / 2);
				if(av_prio > cur_best_prio)
				{
					cur_best_prio = av_prio;
					npf.mapping = my_npm[j].mapping;
				}
			}
		}
	}
	printf("New Mapping ID == %d\n", npf.mapping);

	/*
	* NP++ : Copy the ICMPv6 option type, length and no_maps field into the send buffer
	*/
    memcpy(buff + len, &npf, sizeof(npf));
    len += (sizeof(npf));


	iov.iov_len  = len;
    iov.iov_base = (caddr_t) buff;

    memset(chdr, 0, sizeof(chdr));
    cmsg = (struct cmsghdr *) chdr;

    cmsg->cmsg_len   = CMSG_LEN(sizeof(struct in6_pktinfo));
    cmsg->cmsg_level = IPPROTO_IPV6;
    cmsg->cmsg_type  = IPV6_PKTINFO;

    pkt_info = (struct in6_pktinfo *)CMSG_DATA(cmsg);
    pkt_info->ipi6_ifindex = conf.ifindex;
    memcpy(&pkt_info->ipi6_addr, &conf.lladdr, sizeof(struct in6_addr));

    addr.sin6_scope_id = conf.ifindex;

    memset(&mhdr, 0, sizeof(mhdr));
    mhdr.msg_name = (caddr_t)&addr;
    mhdr.msg_namelen = sizeof(struct sockaddr_in6);
    mhdr.msg_iov = &iov;
    mhdr.msg_iovlen = 1;
    mhdr.msg_control = (void *) cmsg;
    mhdr.msg_controllen = sizeof(chdr);

    err = sendmsg(sock_fd, &mhdr, 0);

//	printf("NA Received Finalising The Mapping %d - Setting the /proc/ entry\n", mapping);
#ifdef __linux__
	snprintf(proc_cat_s, MAX_PROC_STR_SIZE + 1, "echo %d > /proc/net/np++/ifcurmappings/%s", npf.mapping, conf.interface);
	system(proc_cat_s);
#endif
	free(proc_cat_s);

    if (err < 0)
    {
        perror("sendmsg() : ");
    }



	return 0;
}
Example #24
0
/*
 * If sendStdio is non-zero, the current process's stdio file descriptors
 * will be sent and inherited by the spawned process.
 */
static int send_request(int fd, int sendStdio, int argc, const char **argv)
{
#ifndef HAVE_ANDROID_OS
    // not supported on simulator targets
    //ALOGE("zygote_* not supported on simulator targets");
    return -1;
#else /* HAVE_ANDROID_OS */
    uint32_t pid;
    int i;
    struct iovec ivs[2];
    struct msghdr msg;
    char argc_buffer[12];
    const char *newline_string = "\n";
    struct cmsghdr *cmsg;
    char msgbuf[CMSG_SPACE(sizeof(int) * 3)];
    int *cmsg_payload;
    ssize_t ret;

    memset(&msg, 0, sizeof(msg));
    memset(&ivs, 0, sizeof(ivs));

    // First line is arg count 
    snprintf(argc_buffer, sizeof(argc_buffer), "%d\n", argc);

    ivs[0].iov_base = argc_buffer;
    ivs[0].iov_len = strlen(argc_buffer);

    msg.msg_iov = ivs;
    msg.msg_iovlen = 1;

    if (sendStdio != 0) {
        // Pass the file descriptors with the first write
        msg.msg_control = msgbuf;
        msg.msg_controllen = sizeof msgbuf;

        cmsg = CMSG_FIRSTHDR(&msg);

        cmsg->cmsg_len = CMSG_LEN(3 * sizeof(int));
        cmsg->cmsg_level = SOL_SOCKET;
        cmsg->cmsg_type = SCM_RIGHTS;

        cmsg_payload = (int *)CMSG_DATA(cmsg);
        cmsg_payload[0] = STDIN_FILENO;
        cmsg_payload[1] = STDOUT_FILENO;
        cmsg_payload[2] = STDERR_FILENO;
    }

    do {
        ret = sendmsg(fd, &msg, MSG_NOSIGNAL);
    } while (ret < 0 && errno == EINTR);

    if (ret < 0) {
        return -1;
    }

    // Only send the fd's once
    msg.msg_control = NULL;
    msg.msg_controllen = 0;

    // replace any newlines with spaces and send the args
    for (i = 0; i < argc; i++) {
        char *tofree = NULL;
        const char *toprint;

        toprint = argv[i];

        if (strchr(toprint, '\n') != NULL) {
            tofree = strdup(toprint);
            toprint = tofree;
            replace_nl(tofree);
        }

        ivs[0].iov_base = (char *)toprint;
        ivs[0].iov_len = strlen(toprint);
        ivs[1].iov_base = (char *)newline_string;
        ivs[1].iov_len = 1;

        msg.msg_iovlen = 2;

        do {
            ret = sendmsg(fd, &msg, MSG_NOSIGNAL);
        } while (ret < 0 && errno == EINTR);

        if (tofree != NULL) {
            free(tofree);
        }

        if (ret < 0) {
            return -1;
        }
    }

    // Read the pid, as a 4-byte network-order integer

    ivs[0].iov_base = &pid;
    ivs[0].iov_len = sizeof(pid);
    msg.msg_iovlen = 1;

    do {
        do {
            ret = recvmsg(fd, &msg, MSG_NOSIGNAL | MSG_WAITALL);
        } while (ret < 0 && errno == EINTR);

        if (ret < 0) {
            return -1;
        }

        ivs[0].iov_len -= ret;
        ivs[0].iov_base += ret;
    } while (ivs[0].iov_len > 0);

    pid = ntohl(pid);

    return pid;
#endif /* HAVE_ANDROID_OS */
}
Example #25
0
static int afalg_start_cipher_sk(afalg_ctx *actx, const unsigned char *in,
                                 size_t inl, const unsigned char *iv,
                                 unsigned int enc)
{
    struct msghdr msg = { 0 };
    struct cmsghdr *cmsg;
    struct iovec iov;
    ssize_t sbytes;
# ifdef ALG_ZERO_COPY
    int ret;
# endif
    char cbuf[CMSG_SPACE(ALG_IV_LEN(ALG_AES_IV_LEN)) + CMSG_SPACE(ALG_OP_LEN)];

    memset(cbuf, 0, sizeof(cbuf));
    msg.msg_control = cbuf;
    msg.msg_controllen = sizeof(cbuf);

    /*
     * cipher direction (i.e. encrypt or decrypt) and iv are sent to the
     * kernel as part of sendmsg()'s ancillary data
     */
    cmsg = CMSG_FIRSTHDR(&msg);
    afalg_set_op_sk(cmsg, enc);
    cmsg = CMSG_NXTHDR(&msg, cmsg);
    afalg_set_iv_sk(cmsg, iv, ALG_AES_IV_LEN);

    /* iov that describes input data */
    iov.iov_base = (unsigned char *)in;
    iov.iov_len = inl;

    msg.msg_flags = MSG_MORE;

# ifdef ALG_ZERO_COPY
    /*
     * ZERO_COPY mode
     * Works best when buffer is 4k aligned
     * OPENS: out of place processing (i.e. out != in)
     */

    /* Input data is not sent as part of call to sendmsg() */
    msg.msg_iovlen = 0;
    msg.msg_iov = NULL;

    /* Sendmsg() sends iv and cipher direction to the kernel */
    sbytes = sendmsg(actx->sfd, &msg, 0);
    if (sbytes < 0) {
        ALG_PERR("%s: sendmsg failed for zero copy cipher operation : ",
                 __func__);
        return 0;
    }

    /*
     * vmsplice and splice are used to pin the user space input buffer for
     * kernel space processing avoiding copys from user to kernel space
     */
    ret = vmsplice(actx->zc_pipe[1], &iov, 1, SPLICE_F_GIFT);
    if (ret < 0) {
        ALG_PERR("%s: vmsplice failed : ", __func__);
        return 0;
    }

    ret = splice(actx->zc_pipe[0], NULL, actx->sfd, NULL, inl, 0);
    if (ret < 0) {
        ALG_PERR("%s: splice failed : ", __func__);
        return 0;
    }
# else
    msg.msg_iovlen = 1;
    msg.msg_iov = &iov;

    /* Sendmsg() sends iv, cipher direction and input data to the kernel */
    sbytes = sendmsg(actx->sfd, &msg, 0);
    if (sbytes < 0) {
        ALG_PERR("%s: sendmsg failed for cipher operation : ", __func__);
        return 0;
    }

    if (sbytes != (ssize_t) inl) {
        ALG_WARN("Cipher operation send bytes %zd != inlen %zd\n", sbytes,
                inl);
        return 0;
    }
# endif

    return 1;
}
void linux_event_loop<handler>::run()
{
    int ready_cnt;
    int buf_size;
    struct epoll_event evlist[MAX_EVENTS];
    char buffer[MAX_BUFFER];
 
    struct msghdr msg;
    struct iovec iov;
    char ctrl[CMSG_SPACE(sizeof(struct timeval))];
    struct cmsghdr *cmsg = (struct cmsghdr *) & ctrl;    
    struct timeval kernel_time; 
    
    iov.iov_base = buffer;
    iov.iov_len = MAX_BUFFER;
    msg.msg_name = NULL;
    msg.msg_namelen = 0;
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;
    msg.msg_control = (char *)ctrl;
    msg.msg_controllen = sizeof(ctrl);
   
    struct timeval tcp_time; 

    _is_running =  true;
    while( _is_running )
    {
        ready_cnt = epoll_wait( _fd_epoll, evlist, MAX_EVENTS, -1 );

        if( ready_cnt < 0 ) 
        {
            char m[1000];
            perror(m);
            std::cerr  << "Error in epoll_wait " << m <<  std::endl;
            continue;
        }

        if( ready_cnt == 0 )
            continue;

        for( int i = 0; i < ready_cnt; ++i)
        {
            if (evlist[i].events & (EPOLLHUP | EPOLLERR | EPOLLRDHUP))
            {
                std::string what_exactly;

                if( evlist[i].events & EPOLLHUP ) what_exactly = "EPOLLHUP";
                else if ( evlist[i].events & EPOLLERR ) what_exactly = "EPOLLERR";
                else if ( evlist[i].events & EPOLLRDHUP ) what_exactly = "EPOLLRDHUP";	

                std::cerr << "Error " << what_exactly << " on fd =" << evlist[i].data.fd << std::endl;
                disable(evlist[i].data.fd);
                remove(evlist[i].data.fd);
                _handler->on_disconnect(evlist[i].data.fd);
                continue;
            }

            con_type type = _cons[ evlist[i].data.fd ].type;
            if(type == UDP)
            {
                if(evlist[i].events & EPOLLIN) 
                {
                    iov.iov_len = MAX_BUFFER;
                    while( (buf_size = recvmsg(evlist[i].data.fd, &msg, MSG_DONTWAIT)) > 0 ) 
                    {
                        if(cmsg->cmsg_level != SOL_SOCKET ||  
                            cmsg->cmsg_type != SCM_TIMESTAMP || 
                            cmsg->cmsg_len != CMSG_LEN(sizeof(kernel_time)))
                        {
                            std::cerr << "cannot obtain kernel timestamp ignoring UDP packet" << std::endl;
                        } 
                        else 
                        {
                            _handler->on_udp_packet(evlist[i].data.fd, buffer, buf_size, 
                                from_timeval(*(struct timeval *)CMSG_DATA(cmsg)));
                        }
                        iov.iov_len = MAX_BUFFER;
                    }	    
                }
            }
            else if(type == TCP) 
            {
                if(evlist[i].events & EPOLLIN) 
                {
                    while( ( buf_size = recv(evlist[i].data.fd, buffer, MAX_BUFFER, MSG_DONTWAIT)) > 0) 
                    {
                        gettimeofday((struct timeval *)&tcp_time, NULL);
                        _handler->on_tcp_packet(evlist[i].data.fd, buffer, buf_size, from_timeval(tcp_time));
                    }
                }
            }
            else if(type == TIMER) 
            {
                if(evlist[i].events & EPOLLIN) 
                {
                    if ( (buf_size = read(evlist[i].data.fd, buffer, MAX_BUFFER)) > 0) 
                    {
                        gettimeofday((struct timeval *)&tcp_time, NULL);
                        _handler->on_timer(evlist[i].data.fd, buffer, buf_size, from_timeval(tcp_time));
                    }
                }	
            }
        }
    }
}
Example #27
0
int
main(int argc, char *argv[])
{
        int error;
	socklen_t len;
	int sk,lstn_sk,clnt_sk,acpt_sk,pf_class,sk1;
	struct msghdr outmessage;
        struct msghdr inmessage;
        char *message = "hello, world!\n";
        struct iovec iov;
        struct iovec iov_rcv;
        struct sctp_sndrcvinfo *sinfo;
        int msg_count;
        char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
        struct cmsghdr *cmsg;
        struct iovec out_iov;
        char * buffer_snd;
        char * buffer_rcv;
	char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))];
	struct sockaddr *laddrs, *paddrs;

        struct sockaddr_in conn_addr,lstn_addr,acpt_addr;
	struct sockaddr_in *addr;

	/* Rather than fflush() throughout the code, set stdout to
         * be unbuffered.
         */
        setvbuf(stdout, NULL, _IONBF, 0);
        setvbuf(stderr, NULL, _IONBF, 0);

        pf_class = PF_INET;

        sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);

	/*Creating a regular socket*/
	clnt_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);

	/*Creating a listen socket*/
        lstn_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);

	conn_addr.sin_family = AF_INET;
        conn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK;
        conn_addr.sin_port = htons(SCTP_TESTPORT_1);

	lstn_addr.sin_family = AF_INET;
        lstn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK;
        lstn_addr.sin_port = htons(SCTP_TESTPORT_1);

	/*Binding the listen socket*/
	test_bind(lstn_sk, (struct sockaddr *) &lstn_addr, sizeof(lstn_addr));

	/*Listening many sockets as we are calling too many connect here*/
	test_listen(lstn_sk, 1);

	len = sizeof(struct sockaddr_in);

	test_connect(clnt_sk, (struct sockaddr *) &conn_addr, len);

	acpt_sk = test_accept(lstn_sk, (struct sockaddr *) &acpt_addr, &len);

	memset(&inmessage, 0, sizeof(inmessage));
        buffer_rcv = malloc(REALLY_BIG);

        iov_rcv.iov_base = buffer_rcv;
        iov_rcv.iov_len = REALLY_BIG;
        inmessage.msg_iov = &iov_rcv;
        inmessage.msg_iovlen = 1;
        inmessage.msg_control = incmsg;
        inmessage.msg_controllen = sizeof(incmsg);

        msg_count = strlen(message) + 1;

	memset(&outmessage, 0, sizeof(outmessage));
        buffer_snd = malloc(REALLY_BIG);

        outmessage.msg_name = &lstn_addr;
        outmessage.msg_namelen = sizeof(lstn_addr);
        outmessage.msg_iov = &out_iov;
        outmessage.msg_iovlen = 1;
        outmessage.msg_control = outcmsg;
        outmessage.msg_controllen = sizeof(outcmsg);
        outmessage.msg_flags = 0;

        cmsg = CMSG_FIRSTHDR(&outmessage);
        cmsg->cmsg_level = IPPROTO_SCTP;
        cmsg->cmsg_type = SCTP_SNDRCV;
        cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
        outmessage.msg_controllen = cmsg->cmsg_len;
        sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
        memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));

        iov.iov_base = buffer_snd;
	iov.iov_len = REALLY_BIG;
        outmessage.msg_iov->iov_base = message;

        outmessage.msg_iov->iov_len = msg_count;
	test_sendmsg(clnt_sk, &outmessage, MSG_NOSIGNAL, msg_count);

	test_recvmsg(acpt_sk, &inmessage, MSG_NOSIGNAL);

	/*sctp_getladdrs() TEST1: Bad socket descriptor, EBADF Expected error*/
	error = sctp_getladdrs(-1, 0, &laddrs);
	if (error != -1 || errno != EBADF)
		tst_brkm(TBROK, NULL, "sctp_getladdrs with a bad socket "
			 "descriptor error:%d, errno:%d", error, errno);

	tst_resm(TPASS, "sctp_getladdrs() with a bad socket descriptor - "
		 "EBADF");

	/*sctp_getladdrs() TEST2: Invalid socket, ENOTSOCK Expected error*/
	error = sctp_getladdrs(0, 0, &laddrs);
	if (error != -1 || errno != ENOTSOCK)
		tst_brkm(TBROK, NULL, "sctp_getladdrs with invalid socket "
			 "error:%d, errno:%d", error, errno);

	tst_resm(TPASS, "sctp_getladdrs() with invalid socket - ENOTSOCK");

	/*sctp_getladdrs() TEST3: socket of different protocol
	EOPNOTSUPP Expected error*/
        sk1 = socket(pf_class, SOCK_STREAM, IPPROTO_IP);
	error = sctp_getladdrs(sk1, 0, &laddrs);
	if (error != -1 || errno != EOPNOTSUPP)
		tst_brkm(TBROK, NULL, "sctp_getladdrs with socket of "
			 "different protocol error:%d, errno:%d", error, errno);

	tst_resm(TPASS, "sctp_getladdrs() with socket of different protocol - "
		 "EOPNOTSUPP");

	/*sctp_getladdrs() TEST4: Getting the local addresses*/
	error = sctp_getladdrs(lstn_sk, 0, &laddrs);
	if (error < 0)
		tst_brkm(TBROK, NULL, "sctp_getladdrs with valid socket "
			 "error:%d, errno:%d", error, errno);

	addr = (struct sockaddr_in *)laddrs;
	if (addr->sin_port != lstn_addr.sin_port ||
	    addr->sin_family != lstn_addr.sin_family ||
	    addr->sin_addr.s_addr != lstn_addr.sin_addr.s_addr)
		tst_brkm(TBROK, NULL, "sctp_getladdrs comparision failed");

	tst_resm(TPASS, "sctp_getladdrs() - SUCCESS");

	/*sctp_freealddrs() TEST5: freeing the local address*/
	if ((sctp_freeladdrs(laddrs)) < 0)
		tst_brkm(TBROK, NULL, "sctp_freeladdrs "
			 "error:%d, errno:%d", error, errno);

	tst_resm(TPASS, "sctp_freeladdrs() - SUCCESS");

	/*sctp_getpaddrs() TEST6: Bad socket descriptor, EBADF Expected error*/
	error = sctp_getpaddrs(-1, 0, &paddrs);
	if (error != -1 || errno != EBADF)
		tst_brkm(TBROK, NULL, "sctp_getpaddrs with a bad socket "
			 "descriptor error:%d, errno:%d", error, errno);

	tst_resm(TPASS, "sctp_getpaddrs() with a bad socket descriptor - "
		 "EBADF");

	/*sctp_getpaddrs() TEST7: Invalid socket, ENOTSOCK Expected error*/
	error = sctp_getpaddrs(0, 0, &paddrs);
	if (error != -1 || errno != ENOTSOCK)
		tst_brkm(TBROK, NULL, "sctp_getpaddrs with invalid socket "
			 "error:%d, errno:%d", error, errno);

	tst_resm(TPASS, "sctp_getpaddrs() with invalid socket - ENOTSOCK");

	/*sctp_getpaddrs() TEST8: socket of different protocol
	EOPNOTSUPP Expected error*/
	error = sctp_getpaddrs(sk1, 0, &laddrs);
	if (error != -1 || errno != EOPNOTSUPP)
		tst_brkm(TBROK, NULL, "sctp_getpaddrs with socket of "
			 "different protocol error:%d, errno:%d", error, errno);

	tst_resm(TPASS, "sctp_getpaddrs() with socket of different protocol - "
		 "EOPNOTSUPP");

	/*sctp_getpaddrs() TEST9: Getting the peer addresses*/
	error = sctp_getpaddrs(acpt_sk, 0, &paddrs);
	if (error < 0)
		tst_brkm(TBROK, NULL, "sctp_getpaddrs with valid socket "
			 "error:%d, errno:%d", error, errno);

	addr = (struct sockaddr_in *)paddrs;
	if (addr->sin_port != acpt_addr.sin_port ||
            addr->sin_family != acpt_addr.sin_family ||
            addr->sin_addr.s_addr != acpt_addr.sin_addr.s_addr)
		tst_brkm(TBROK, NULL, "sctp_getpaddrs comparision failed");

	tst_resm(TPASS, "sctp_getpaddrs() - SUCCESS");

	/*sctp_freeapddrs() TEST10: freeing the peer address*/
	if ((sctp_freepaddrs(paddrs)) < 0)
		tst_brkm(TBROK, NULL, "sctp_freepaddrs "
			 "error:%d, errno:%d", error, errno);

	tst_resm(TPASS, "sctp_freepaddrs() - SUCCESS");

	close(clnt_sk);

	tst_exit();
}
Example #28
0
File: ndisc.c Project: jlanza/umip
static int ndisc_send_unspec(int oif, const struct in6_addr *dest,
			     uint8_t *hdr, int hdrlen, struct iovec *optv,
			     size_t optvlen)
{
	struct {
		struct ip6_hdr ip;
		struct icmp6_hdr icmp;
		uint8_t data[1500];
	} frame;

	struct msghdr msgh;
	struct cmsghdr *cmsg;
	struct in6_pktinfo *pinfo;
	struct sockaddr_in6 dst;
	char cbuf[CMSG_SPACE(sizeof(*pinfo))];
	struct iovec iov;
	uint8_t *data = (uint8_t *)(&frame.icmp);
	int type, fd, ret, remlen, datalen = 0, written = 0, v = 1;

	if (hdr == NULL || hdrlen < 0 ||
	    (size_t)hdrlen < sizeof(struct icmp6_hdr) ||
	    (size_t)hdrlen > (sizeof(frame) - sizeof(struct ip6_hdr)))
		return -EINVAL;

	if ((fd = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW)) < 0)
		return -1;

	if (setsockopt(fd, IPPROTO_IPV6, IP_HDRINCL, &v, sizeof(v)) < 0) {
		dbg("cannot set IP_HDRINCL: %s\n", strerror(errno));
		close(fd);
		return -errno;
	}

	memset(&frame, 0, sizeof(frame));
	memset(&dst, 0, sizeof(dst));

	dst.sin6_addr = *dest;

	/* Copy ICMPv6 header and update various length values */
	memcpy(data, hdr, hdrlen);
	data += hdrlen;
	datalen += hdrlen;
	remlen = sizeof(frame) - sizeof(struct ip6_hdr) - hdrlen;

	/* Prepare for csum: write trailing options by linearizing iov */
	if ((iov_linearize(data, remlen, optv, optvlen, &written) != 0) ||
	    (written & 0x1)) /* Ensure length is even for csum() */
		return -1;
	datalen += written;

	/* Fill in the IPv6 header */
	frame.ip.ip6_vfc = 0x60;
	frame.ip.ip6_plen = htons(datalen);
	frame.ip.ip6_nxt = IPPROTO_ICMPV6;
	frame.ip.ip6_hlim = 255;
	frame.ip.ip6_dst = *dest;
	/* all other fields are already set to zero */

	frame.icmp.icmp6_cksum = in6_cksum(&in6addr_any, dest, &frame.icmp,
					   datalen, IPPROTO_ICMPV6);

	iov.iov_base = &frame;
	iov.iov_len = sizeof(frame.ip) + datalen;

	dst.sin6_family = AF_INET6;
	msgh.msg_name = &dst;
	msgh.msg_namelen = sizeof(dst);
	msgh.msg_iov = &iov;
	msgh.msg_iovlen = 1;
	msgh.msg_flags = 0;

	memset(cbuf, 0, CMSG_SPACE(sizeof(*pinfo)));
	cmsg = (struct cmsghdr *)cbuf;
	pinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
	pinfo->ipi6_ifindex = oif;

	cmsg->cmsg_len = CMSG_LEN(sizeof(*pinfo));
	cmsg->cmsg_level = IPPROTO_IPV6;
	cmsg->cmsg_type = IPV6_PKTINFO;
	msgh.msg_control = cmsg;
	msgh.msg_controllen = cmsg->cmsg_len;

	ret = sendmsg(fd, &msgh, 0);
	if (ret < 0)
		dbg("sendmsg: %s\n", strerror(errno));

	close(fd);
	type = hdr[0];
	if (type == ND_NEIGHBOR_SOLICIT) {
		statistics_inc(&mipl_stat, MIPL_STATISTICS_OUT_NS_UNSPEC);
	} else if (type == ND_ROUTER_SOLICIT) {
		statistics_inc(&mipl_stat, MIPL_STATISTICS_OUT_RS_UNSPEC);
	}
	return ret;
}
/*
 * Class:     sun_nio_ch_sctp_SctpChannelImpl
 * Method:    send0
 * Signature: (IJILjava/net/InetAddress;IIIZI)I
 */
JNIEXPORT jint JNICALL Java_sun_nio_ch_sctp_SctpChannelImpl_send0
  (JNIEnv *env, jclass klass, jint fd, jlong address, jint length,
   jobject targetAddress, jint targetPort, jint assocId, jint streamNumber,
   jboolean unordered, jint ppid) {
    SOCKADDR sa;
    int sa_len = sizeof(sa);
    ssize_t rv = 0;
    jlong *addr = jlong_to_ptr(address);
    struct iovec iov[1];
    struct msghdr msg[1];
    int cbuf_size = CMSG_SPACE(sizeof (struct sctp_sndrcvinfo));
    char cbuf[CMSG_SPACE(sizeof (struct sctp_sndrcvinfo))];
    struct controlData cdata[1];

    /* SctpChannel:
     *    targetAddress may contain the preferred address or NULL to use primary,
     *    assocId will always be -1
     * SctpMultiChannell:
     *    Setup new association, targetAddress will contain address, assocId = -1
     *    Association already existing, assocId != -1, targetAddress = preferred addr
     */
    if (targetAddress != NULL /*&& assocId <= 0*/) {
        if (NET_InetAddressToSockaddr(env, targetAddress, targetPort,
                                      (struct sockaddr *)&sa,
                                      &sa_len, JNI_TRUE) != 0) {
            return IOS_THROWN;
        }
    } else {
        memset(&sa, '\x0', sa_len);
        sa_len = 0;
    }

    /* Set up the msghdr structure for sending */
    memset(msg, 0, sizeof (*msg));
    memset(cbuf, 0, cbuf_size);
    msg->msg_name = &sa;
    msg->msg_namelen = sa_len;
    iov->iov_base = addr;
    iov->iov_len = length;
    msg->msg_iov = iov;
    msg->msg_iovlen = 1;
    msg->msg_control = cbuf;
    msg->msg_controllen = cbuf_size;
    msg->msg_flags = 0;

    cdata->streamNumber = streamNumber;
    cdata->assocId = assocId;
    cdata->unordered = unordered;
    cdata->ppid = ppid;
    setControlData(msg, cdata);

    if ((rv = sendmsg(fd, msg, 0)) < 0) {
        if (errno == EWOULDBLOCK) {
            return IOS_UNAVAILABLE;
        } else if (errno == EINTR) {
            return IOS_INTERRUPTED;
        } else if (errno == EPIPE) {
            JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
                            "Socket is shutdown for writing");
        } else {
            handleSocketError(env, errno);
            return 0;
        }
    }

    return rv;
}
bool LogListener::onDataAvailable(SocketClient *cli) {
    static bool name_set;
    if (!name_set) {
        prctl(PR_SET_NAME, "logd.writer");
        name_set = true;
    }

    char buffer[sizeof_log_id_t + sizeof(uint16_t) + sizeof(log_time)
        + LOGGER_ENTRY_MAX_PAYLOAD];
    struct iovec iov = { buffer, sizeof(buffer) };
    memset(buffer, 0, sizeof(buffer));

    char control[CMSG_SPACE(sizeof(struct ucred))];
    struct msghdr hdr = {
        NULL,
        0,
        &iov,
        1,
        control,
        sizeof(control),
        0,
    };

    int socket = cli->getSocket();

    ssize_t n = recvmsg(socket, &hdr, 0);
    if (n <= (ssize_t)(sizeof(android_log_header_t))) {
        return false;
    }

    struct ucred *cred = NULL;

    struct cmsghdr *cmsg = CMSG_FIRSTHDR(&hdr);
    while (cmsg != NULL) {
        if (cmsg->cmsg_level == SOL_SOCKET
                && cmsg->cmsg_type  == SCM_CREDENTIALS) {
            cred = (struct ucred *)CMSG_DATA(cmsg);
            break;
        }
        cmsg = CMSG_NXTHDR(&hdr, cmsg);
    }

    if (cred == NULL) {
        return false;
    }

    if (cred->uid == AID_LOGD) {
        // ignore log messages we send to ourself.
        // Such log messages are often generated by libraries we depend on
        // which use standard Android logging.
        return false;
    }

    android_log_header_t *header = reinterpret_cast<android_log_header_t *>(buffer);
    if (/* header->id < LOG_ID_MIN || */ header->id >= LOG_ID_MAX) {
        return false;
    }

    char *msg = ((char *)buffer) + sizeof(android_log_header_t);
    n -= sizeof(android_log_header_t);

    // NB: hdr.msg_flags & MSG_TRUNC is not tested, silently passing a
    // truncated message to the logs.

    if (logbuf->log((log_id_t)header->id, header->realtime,
            cred->uid, cred->pid, header->tid, msg,
            ((size_t) n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX) >= 0) {
        reader->notifyNewLog();
    }

    return true;
}