profile
viewpoint

Ask questionsAdd TCP FastOpen support for macOS

The connectx system call

This function is commonly used for inititiating a TCP Fast Open connection.

Available since iOS 9 and OS X 10.11

// Original definition in /usr/include/sys

__API_AVAILABLE(macosx(10.11), ios(9.0), tvos(9.0), watchos(2.0))
int connectx(int, const sa_endpoints_t *, sae_associd_t, unsigned int,
    const struct iovec *, unsigned int, size_t *, sae_connid_t *);

__API_AVAILABLE(macosx(10.11), ios(9.0), tvos(9.0), watchos(2.0))
int disconnectx(int, sae_associd_t, sae_connid_t);

Definition:

int connectx(int socket,
             const sa_endpoints_t *endpoints,
             sae_associd_t associd /* Reserved, always be SAE_ASSOCID_ANY */,
             unsigned int flags,
             const struct iovec *iov,
             unsigned int iovcnt,
             size_t *len,
             sae_connid_t *connid /* Reserved, always be NULL */);

Example usage:

struct sockaddr_in sa;
memcpy(&sa, /* TARGET ADDR */, sizeof(struct sockaddr_in));
sa.sin_len = sizeof(struct sockaddr_in);
sa_endpoints_t endpoints;
memset((char *)&endpoints, 0, sizeof(endpoints));
endpoints.sae_dstaddr    = (struct sockaddr *)&sa;
endpoints.sae_dstaddrlen = /* TARGET ADDR LEN */;

s = connectx(sockfd,
             &endpoints,
             SAE_ASSOCID_ANY,
             CONNECT_DATA_IDEMPOTENT | CONNECT_RESUME_ON_READ_WRITE,
             NULL,
             0,
             NULL,
             NULL);

Variable definitions

  • SAE_ASSOCID_ANY

    // Defined in /usr/include/sys/socket.h (MacOSX.sdk)
    #define SAE_ASSOCID_ANY 0
    
  • CONNECT_DATA_IDEMPOTENT and CONNECT_RESUME_ON_READ_WRITE

    // Defined in /usr/include/sys/socket.h (MacOSX.sdk)
    #define CONNECT_RESUME_ON_READ_WRITE    0x1 /* resume connect() on read/write */
    #define CONNECT_DATA_IDEMPOTENT         0x2 /* data is idempotent */
    

sa_endpoints_t

// Defined in /usr/include/sys/socket.h (MacOSX.sdk)

/* sockaddr endpoints */
typedef struct sa_endpoints {
	unsigned int            sae_srcif;      /* optional source interface */
	const struct sockaddr   *sae_srcaddr;   /* optional source address */
	socklen_t               sae_srcaddrlen; /* size of source address */
	const struct sockaddr   *sae_dstaddr;   /* destination address */
	socklen_t               sae_dstaddrlen; /* size of destination address */
} sa_endpoints_t;

sae_associd_t

// Defined in /usr/include/sys/socket.h (MacOSX.sdk)

typedef __uint32_t sae_associd_t;
rust-lang/libc

Answer questions zonyitoo

Client

use std::mem;
use std::ptr;

use libc;

extern "C" {
    fn inet_pton(af: libc::c_int, src: *const libc::c_char, dst: *mut libc::c_void) -> libc::c_int;
    fn htons(hostshort: u16) -> u16;
}

fn main() {
    unsafe {
        let socket = libc::socket(libc::PF_INET, libc::SOCK_STREAM, libc::IPPROTO_TCP);
        assert!(socket > 0);

        println!("Socket {}", socket);

        let mut saddr: libc::sockaddr_in = mem::zeroed();
        saddr.sin_family = libc::AF_INET as libc::sa_family_t;
        saddr.sin_port = htons(8000);
        inet_pton(
            libc::AF_INET,
            "127.0.0.1".as_ptr() as *const _,
            &mut saddr.sin_addr as *mut _ as *mut libc::c_void,
        );

        let mut endpoints: libc::sa_endpoints_t = mem::zeroed();
        endpoints.sae_dstaddr = &mut saddr as *mut _ as *mut libc::sockaddr;
        endpoints.sae_dstaddrlen = mem::size_of_val(&saddr) as libc::socklen_t;

        let ret = libc::connectx(
            socket,
            &mut endpoints as *mut _,
            libc::SAE_ASSOCID_ANY,
            libc::CONNECT_DATA_IDEMPOTENT,
            ptr::null(),
            0,
            ptr::null_mut(),
            ptr::null_mut(),
        );
        assert!(ret == 0);

        let ret = libc::disconnectx(socket, libc::SAE_ASSOCID_ANY, libc::SAE_CONNID_ANY);
        assert!(ret == 0);
    }
}

Server

use std::mem;

use libc;

extern "C" {
    fn inet_pton(af: libc::c_int, src: *const libc::c_char, dst: *mut libc::c_void) -> libc::c_int;
    fn htons(hostshort: u16) -> u16;
}

fn main() {
    unsafe {
        let socket = libc::socket(libc::PF_INET, libc::SOCK_STREAM, 0);
        assert!(socket > 0);

        println!("Socket {}", socket);

        let mut saddr: libc::sockaddr_in = mem::zeroed();
        saddr.sin_family = libc::AF_INET as libc::sa_family_t;
        saddr.sin_port = htons(8000);
        inet_pton(
            libc::AF_INET,
            "127.0.0.1".as_ptr() as *const _,
            &mut saddr.sin_addr as *mut _ as *mut libc::c_void,
        );

        let ret = libc::bind(
            socket,
            &saddr as *const _ as *const libc::sockaddr,
            mem::size_of_val(&saddr) as libc::socklen_t,
        );
        assert!(ret == 0);

        let queue_len: libc::c_int = 5;

        let ret = libc::listen(socket, queue_len);
        assert!(ret == 0);

        let enable: libc::c_int = 1;

        let ret = libc::setsockopt(
            socket,
            libc::IPPROTO_TCP,
            libc::TCP_FASTOPEN,
            &enable as *const _ as *const libc::c_void,
            mem::size_of_val(&enable) as libc::socklen_t,
        );
        assert!(ret == 0);

        loop {
            let mut saddr: libc::sockaddr = mem::zeroed();
            let mut slen: libc::socklen_t = 0;
            let csocket = libc::accept(socket, &mut saddr, &mut slen);
            assert!(csocket > 0);

            println!("Accepted csocket {}", csocket);

            libc::close(csocket);
        }
    }
}
useful!

Related questions

No questions were found.
source:https://uonfu.com/
Github User Rank List