// File: KinderRiven[P]rdma_demo/server.cc
// Function: connect_qpair(rdma_context_t*)
static void connect_qpair(rdma_context_t* context)
{
    printf("----------- Connect QPair -----------\n");
    //////////////// BUILD TCP/IP CONNECT /////////////////////////
    // bind
    struct addrinfo hints;
    struct addrinfo *result, *rp;
    int sock_fd = -1, ret = 0;

    memset(&hints, 0, sizeof(struct addrinfo));
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_family = AF_UNSPEC;
    hints.ai_flags = AI_PASSIVE;

    ret = getaddrinfo(NULL, "4396", &hints, &result);
    if (!ret) {
        printf("|--getaddrinfo ok.\n");
    } else {
        printf("|--getaddrinfo failed.\n");
        exit(1);
    }

    for (rp = result; rp != NULL; rp = rp->ai_next) {
        sock_fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
        if (sock_fd < 0) {
            continue;
        }
        ret = bind(sock_fd, rp->ai_addr, rp->ai_addrlen);
        if (ret == 0) {
            printf("|--create socket ok[%d].\n", sock_fd);
            break;
        }
        close(sock_fd);
        sock_fd = -1;
    }
    freeaddrinfo(result);

    // listen
    ret = listen(sock_fd, 5);
    if (!ret) {
        printf("|--listen ok.\n");
    } else {
        printf("|--listen failed.\n");
        exit(1);
    }

    // accept
    int peer_sockfd;
    struct sockaddr_in peer_addr;
    socklen_t peer_addr_len = sizeof(struct sockaddr_in);
    peer_sockfd = accept(sock_fd, (struct sockaddr*)&peer_addr, &peer_addr_len);
    printf("|--accept ok.[%d]\n", peer_sockfd);
    context->sockfd = peer_sockfd;

    //////////////////// SWAP QP INFO ////////////////////////
    // recv
    qp_info_t* remote_qp_info = (qp_info_t*)malloc(sizeof(qp_info_t));
    context->remote_qp = remote_qp_info;
    size_t sz = sock_read(peer_sockfd, remote_qp_info, sizeof(qp_info_t));
    printf("|--sock_read[%zu/%zu]\n", sz, sizeof(qp_info_t));
    printf("|----[addr:%llx][rkey:%d]\n", remote_qp_info->addr, remote_qp_info->rkey);
    printf("|----[lid:%d][qp_num:%d]\n", remote_qp_info->lid, remote_qp_info->qp_num);
    printf("|----[gid:");
    uint8_t* _rm_gids = (uint8_t*)(&remote_qp_info->gid);
    for (int i = 0; i < 16; i++) {
        printf("%02x", _rm_gids[i]);
        if (i & 1) {
            printf(":");
        }
    }
    printf("]\n");

    // send
    qp_info_t* local_qp_info = (qp_info_t*)malloc(sizeof(qp_info_t));
    context->local_qp = local_qp_info;
    local_qp_info->addr = (uint64_t)context->ib_buf;
    local_qp_info->rkey = context->mr->rkey;
    local_qp_info->qp_num = context->qp[0]->qp_num; // qp number
    local_qp_info->lid = context->port_attr.lid;
    memcpy((void*)(&local_qp_info->gid), (void*)(&context->gid), sizeof(context->gid));
    sz = sock_write(peer_sockfd, local_qp_info, sizeof(qp_info_t));
    printf("|--sock_write[%zu/%zu]\n", sz, sizeof(qp_info_t));
    printf("|----[addr:%llx][rkey:%d]\n", local_qp_info->addr, local_qp_info->rkey);
    printf("|----[lid:%d][qp_num:%d]\n", local_qp_info->lid, local_qp_info->qp_num);
    printf("|----[gid:");
    uint8_t* _lo_gids = (uint8_t*)(&local_qp_info->gid);
    for (int i = 0; i < 16; i++) {
        printf("%02x", _lo_gids[i]);
        if (i & 1) {
            printf(":");
        }
    }
    printf("]\n");

    /////////////////
    ret = modify_qp_to_init(context->qp[0]);
    printf("|--modify_qp_to_init = %d. %s.\n", ret, strerror(ret));

    // modify the QP to RTR
    ret = modify_qp_to_rtr(context->qp[0], remote_qp_info->qp_num, remote_qp_info->lid, (uint8_t*)(&remote_qp_info->gid));
    printf("|--modify_qp_to_rtr = %d. %s.\n", ret, strerror(ret));

    // modify QP state to RTS
    ret = modify_qp_to_rts(context->qp[0]);
    printf("|--modify_qp_to_rts = %d. %s.\n", ret, strerror(ret));
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xb0, %rsp
movq %rdi, -0x8(%rbp)
leaq 0x1e3e(%rip), %rdi      # 0x33a4
movb $0x0, %al
callq 0x1050
movl $0xffffffff, -0x4c(%rbp) # imm = 0xFFFFFFFF
movl $0x0, -0x50(%rbp)
leaq -0x38(%rbp), %rdi
xorl %esi, %esi
movl $0x30, %edx
callq 0x10c0
movl $0x1, -0x30(%rbp)
movl $0x0, -0x34(%rbp)
movl $0x1, -0x38(%rbp)
xorl %eax, %eax
movl %eax, %edi
leaq 0x1e20(%rip), %rsi      # 0x33cb
leaq -0x38(%rbp), %rdx
leaq -0x40(%rbp), %rcx
callq 0x1160
movl %eax, -0x50(%rbp)
cmpl $0x0, -0x50(%rbp)
jne 0x15d1
leaq 0x1e08(%rip), %rdi      # 0x33d0
movb $0x0, %al
callq 0x1050
jmp 0x15e9
leaq 0x1e0c(%rip), %rdi      # 0x33e4
movb $0x0, %al
callq 0x1050
movl $0x1, %edi
callq 0x1150
movq -0x40(%rbp), %rax
movq %rax, -0x48(%rbp)
cmpq $0x0, -0x48(%rbp)
je 0x166d
movq -0x48(%rbp), %rax
movl 0x4(%rax), %edi
movq -0x48(%rbp), %rax
movl 0x8(%rax), %esi
movq -0x48(%rbp), %rax
movl 0xc(%rax), %edx
callq 0x1080
movl %eax, -0x4c(%rbp)
cmpl $0x0, -0x4c(%rbp)
jge 0x161d
jmp 0x165f
movl -0x4c(%rbp), %edi
movq -0x48(%rbp), %rax
movq 0x18(%rax), %rsi
movq -0x48(%rbp), %rax
movl 0x10(%rax), %edx
callq 0x1060
movl %eax, -0x50(%rbp)
cmpl $0x0, -0x50(%rbp)
jne 0x1650
movl -0x4c(%rbp), %esi
leaq 0x1db5(%rip), %rdi      # 0x33fc
movb $0x0, %al
callq 0x1050
jmp 0x166d
movl -0x4c(%rbp), %edi
callq 0x1200
movl $0xffffffff, -0x4c(%rbp) # imm = 0xFFFFFFFF
movq -0x48(%rbp), %rax
movq 0x28(%rax), %rax
movq %rax, -0x48(%rbp)
jmp 0x15f1
movq -0x40(%rbp), %rdi
callq 0x1170
movl -0x4c(%rbp), %edi
movl $0x5, %esi
callq 0x1120
movl %eax, -0x50(%rbp)
cmpl $0x0, -0x50(%rbp)
jne 0x169c
leaq 0x1d83(%rip), %rdi      # 0x3416
movb $0x0, %al
callq 0x1050
jmp 0x16b4
leaq 0x1d82(%rip), %rdi      # 0x3425
movb $0x0, %al
callq 0x1050
movl $0x1, %edi
callq 0x1150
movl $0x10, -0x68(%rbp)
movl -0x4c(%rbp), %edi
leaq -0x64(%rbp), %rsi
leaq -0x68(%rbp), %rdx
callq 0x1090
movl %eax, -0x54(%rbp)
movl -0x54(%rbp), %esi
leaq 0x1d60(%rip), %rdi      # 0x3438
movb $0x0, %al
callq 0x1050
movl -0x54(%rbp), %ecx
movq -0x8(%rbp), %rax
movl %ecx, 0x580(%rax)
movl $0x22, %edi
callq 0x1180
movq %rax, -0x70(%rbp)
movq -0x70(%rbp), %rcx
movq -0x8(%rbp), %rax
movq %rcx, 0x558(%rax)
movl -0x54(%rbp), %edi
movq -0x70(%rbp), %rsi
movl $0x22, %edx
callq 0x1310
movq %rax, -0x78(%rbp)
movq -0x78(%rbp), %rsi
leaq 0x1d22(%rip), %rdi      # 0x344b
movl $0x22, %edx
movb $0x0, %al
callq 0x1050
movq -0x70(%rbp), %rax
movq (%rax), %rsi
movq -0x70(%rbp), %rax
movl 0x8(%rax), %edx
leaq 0x1d18(%rip), %rdi      # 0x3462
movb $0x0, %al
callq 0x1050
movq -0x70(%rbp), %rax
movzwl 0x10(%rax), %esi
movq -0x70(%rbp), %rax
movl 0xc(%rax), %edx
leaq 0x1d16(%rip), %rdi      # 0x347d
movb $0x0, %al
callq 0x1050
leaq 0x1d22(%rip), %rdi      # 0x3497
movb $0x0, %al
callq 0x1050
movq -0x70(%rbp), %rax
addq $0x12, %rax
movq %rax, -0x80(%rbp)
movl $0x0, -0x84(%rbp)
cmpl $0x10, -0x84(%rbp)
jge 0x17e7
movq -0x80(%rbp), %rax
movslq -0x84(%rbp), %rcx
movzbl (%rax,%rcx), %esi
leaq 0x19bf(%rip), %rdi      # 0x3170
movb $0x0, %al
callq 0x1050
movl -0x84(%rbp), %eax
andl $0x1, %eax
cmpl $0x0, %eax
je 0x17d4
leaq 0x1cd3(%rip), %rdi      # 0x34a0
movb $0x0, %al
callq 0x1050
jmp 0x17d6
movl -0x84(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x84(%rbp)
jmp 0x1792
leaq 0x1a2c(%rip), %rdi      # 0x321a
movb $0x0, %al
callq 0x1050
movl $0x22, %edi
callq 0x1180
movq %rax, -0x90(%rbp)
movq -0x90(%rbp), %rcx
movq -0x8(%rbp), %rax
movq %rcx, 0x550(%rax)
movq -0x8(%rbp), %rax
movq (%rax), %rcx
movq -0x90(%rbp), %rax
movq %rcx, (%rax)
movq -0x8(%rbp), %rax
movq 0x18(%rax), %rax
movl 0x28(%rax), %ecx
movq -0x90(%rbp), %rax
movl %ecx, 0x8(%rax)
movq -0x8(%rbp), %rax
movq 0x28(%rax), %rax
movl 0x34(%rax), %ecx
movq -0x90(%rbp), %rax
movl %ecx, 0xc(%rax)
movq -0x8(%rbp), %rax
movw 0x452(%rax), %cx
movq -0x90(%rbp), %rax
movw %cx, 0x10(%rax)
movq -0x90(%rbp), %rax
movq -0x8(%rbp), %rcx
movq 0x560(%rcx), %rdx
movq %rdx, 0x12(%rax)
movq 0x568(%rcx), %rcx
movq %rcx, 0x1a(%rax)
movl -0x54(%rbp), %edi
movq -0x90(%rbp), %rsi
movl $0x22, %edx
callq 0x13c0
movq %rax, -0x78(%rbp)
movq -0x78(%rbp), %rsi
leaq 0x1bf5(%rip), %rdi      # 0x34a2
movl $0x22, %edx
movb $0x0, %al
callq 0x1050
movq -0x90(%rbp), %rax
movq (%rax), %rsi
movq -0x90(%rbp), %rax
movl 0x8(%rax), %edx
leaq 0x1b8e(%rip), %rdi      # 0x3462
movb $0x0, %al
callq 0x1050
movq -0x90(%rbp), %rax
movzwl 0x10(%rax), %esi
movq -0x90(%rbp), %rax
movl 0xc(%rax), %edx
leaq 0x1b86(%rip), %rdi      # 0x347d
movb $0x0, %al
callq 0x1050
leaq 0x1b92(%rip), %rdi      # 0x3497
movb $0x0, %al
callq 0x1050
movq -0x90(%rbp), %rax
addq $0x12, %rax
movq %rax, -0x98(%rbp)
movl $0x0, -0x9c(%rbp)
cmpl $0x10, -0x9c(%rbp)
jge 0x1980
movq -0x98(%rbp), %rax
movslq -0x9c(%rbp), %rcx
movzbl (%rax,%rcx), %esi
leaq 0x1826(%rip), %rdi      # 0x3170
movb $0x0, %al
callq 0x1050
movl -0x9c(%rbp), %eax
andl $0x1, %eax
cmpl $0x0, %eax
je 0x196d
leaq 0x1b3a(%rip), %rdi      # 0x34a0
movb $0x0, %al
callq 0x1050
jmp 0x196f
movl -0x9c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x9c(%rbp)
jmp 0x1928
leaq 0x1893(%rip), %rdi      # 0x321a
movb $0x0, %al
callq 0x1050
movq -0x8(%rbp), %rax
movq 0x28(%rax), %rdi
callq 0x21e0
movl %eax, -0x50(%rbp)
movl -0x50(%rbp), %eax
movl %eax, -0xa8(%rbp)
movl -0x50(%rbp), %edi
callq 0x10a0
movl -0xa8(%rbp), %esi
movq %rax, %rdx
leaq 0x1afb(%rip), %rdi      # 0x34ba
movb $0x0, %al
callq 0x1050
movq -0x8(%rbp), %rax
movq 0x28(%rax), %rdi
movq -0x70(%rbp), %rax
movl 0xc(%rax), %esi
movq -0x70(%rbp), %rax
movw 0x10(%rax), %ax
movq -0x70(%rbp), %rcx
addq $0x12, %rcx
movzwl %ax, %edx
callq 0x2250
movl %eax, -0x50(%rbp)
movl -0x50(%rbp), %eax
movl %eax, -0xa4(%rbp)
movl -0x50(%rbp), %edi
callq 0x10a0
movl -0xa4(%rbp), %esi
movq %rax, %rdx
leaq 0x1ac9(%rip), %rdi      # 0x34da
movb $0x0, %al
callq 0x1050
movq -0x8(%rbp), %rax
movq 0x28(%rax), %rdi
callq 0x2320
movl %eax, -0x50(%rbp)
movl -0x50(%rbp), %eax
movl %eax, -0xa0(%rbp)
movl -0x50(%rbp), %edi
callq 0x10a0
movl -0xa0(%rbp), %esi
movq %rax, %rdx
leaq 0x1ab0(%rip), %rdi      # 0x34f9
movb $0x0, %al
callq 0x1050
addq $0xb0, %rsp
popq %rbp
retq
nopl (%rax)