// File: /workspace/github_c_makefile_star2_O2/TimeToogo[P]ff-proxy/client/c/client.c
// Function: ff_client_send_request
uint8_t ff_client_send_request(struct ff_client_config *config, struct ff_client_packet *packets, uint32_t packets_count)
{
    uint8_t ret;
    int err;
    int sockfd = 0;
    struct addrinfo hints;
    struct addrinfo *res = NULL;
    int sent_length = 0;
    int chunk_length = 0;
    char ip_string[INET6_ADDRSTRLEN + 1] = {0};

    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_DGRAM;
    err = getaddrinfo(config->ip_address, config->port, &hints, &res);
    if (err)
    {
        ff_log(FF_FATAL, "Failed to perform DNS lookup for host: %s", config->ip_address);
        goto error;
    }

    ff_log(FF_DEBUG, "Creating socket");
    sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);

    if (sockfd < 0)
    {
        ff_log(FF_FATAL, "Failed to create socket");
        goto error;
    }

    if (res->ai_family == AF_INET)
    {
        inet_ntop(AF_INET, &((struct sockaddr_in *)res->ai_addr)->sin_addr, ip_string, INET_ADDRSTRLEN);
    }
    else
    {
        inet_ntop(AF_INET6, &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, ip_string, INET6_ADDRSTRLEN);
    }
    ff_log(FF_INFO, "Sending request to %s%s%s:%s",
           strchr(ip_string, ':') ? "[" : "", ip_string, strchr(ip_string, ':') ? "]" : "", config->port);

    int flag = true;
    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)) < 0)
    {
        ff_log(FF_WARNING, "Failed to set socket option (errno: %d)", errno);
    }


    for (uint16_t i = 0; i < packets_count; i++)
    {
        ff_log(
            FF_INFO, "sending packet %d byte range [%d, %d]", 
            i, 0, (int)packets[i].length
        );
        chunk_length = sendto(
            sockfd, 
            packets[i].value, 
            (int)packets[i].length, 
            0, 
            res->ai_addr, 
            res->ai_addrlen
        );

        if (chunk_length <= 0)
        {
            printf("errno: %d\n", errno);
            ff_log(FF_FATAL, "Failed to send UDP datagrams during byte range %d - %hu", 0, packets[i].length);
            goto error;
        }

        sent_length += chunk_length;
    }

    ff_log(FF_DEBUG, "Finished sending %d bytes", sent_length);
    goto done;

done:
    ret = 0;
    goto cleanup;

error:
    ret = EXIT_FAILURE;
    goto cleanup;

cleanup:
    if (res != NULL)
    {
        freeaddrinfo(res);
    }

    if (close(sockfd))
    {
        ff_log(FF_WARNING, "Failed to close socket");
    }

    return ret;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x78, %rsp
movl %edx, %r13d
movq %rsi, %r14
leaq -0x38(%rbp), %rcx
andq $0x0, (%rcx)
movq %rdi, %r12
xorps %xmm0, %xmm0
movups %xmm0, -0x51(%rbp)
movaps %xmm0, -0x60(%rbp)
movaps %xmm0, -0x70(%rbp)
leaq -0xa0(%rbp), %rdx
movaps %xmm0, (%rdx)
movaps %xmm0, 0x10(%rdx)
movaps %xmm0, 0x20(%rdx)
movl $0x2, 0x8(%rdx)
movq (%rdi), %rsi
movq 0x8(%rdi), %rdi
callq 0x21f0
testl %eax, %eax
je 0x2965
movq 0x8(%r12), %rdx
leaq 0x27f0(%rip), %rsi      # 0x5104
movl $0x0, -0x2c(%rbp)
pushq $0x5
popq %rdi
xorl %eax, %eax
callq 0x37ac
movb $0x1, %r14b
movq -0x38(%rbp), %rdi
testq %rdi, %rdi
je 0x2936
callq 0x2200
movl -0x2c(%rbp), %edi
callq 0x2300
testl %eax, %eax
je 0x2953
leaq 0x28d7(%rip), %rsi      # 0x5220
pushq $0x3
popq %rdi
xorl %eax, %eax
callq 0x37ac
movl %r14d, %eax
addq $0x78, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x27c2(%rip), %rsi      # 0x512e
pushq $0x1
popq %rdi
xorl %eax, %eax
callq 0x37ac
movq -0x38(%rbp), %rax
movl 0x4(%rax), %edi
movl 0x8(%rax), %esi
movl 0xc(%rax), %edx
callq 0x2080
movl %eax, -0x2c(%rbp)
testl %eax, %eax
js 0x29ac
movq -0x38(%rbp), %rax
cmpl $0x2, 0x4(%rax)
movq 0x18(%rax), %rsi
jne 0x29c2
addq $0x4, %rsi
pushq $0x2
popq %rdi
leaq -0x70(%rbp), %rdx
pushq $0x10
jmp 0x29cf
leaq 0x278b(%rip), %rsi      # 0x513e
pushq $0x5
popq %rdi
xorl %eax, %eax
callq 0x37ac
jmp 0x2925
addq $0x8, %rsi
pushq $0xa
popq %rdi
leaq -0x70(%rbp), %rdx
pushq $0x2e
popq %rcx
callq 0x2190
leaq -0x70(%rbp), %rbx
pushq $0x3a
popq %rsi
movq %rbx, %rdi
callq 0x20b0
testq %rax, %rax
leaq 0x2942(%rip), %rax      # 0x5330
leaq 0x277e(%rip), %rdx      # 0x5173
cmoveq %rax, %rdx
leaq 0x27c1(%rip), %r8       # 0x51c1
cmoveq %rax, %r8
movq (%r12), %r9
leaq 0x2747(%rip), %rsi      # 0x5156
pushq $0x2
popq %r15
movl %r15d, %edi
movq %rbx, %rcx
xorl %eax, %eax
callq 0x37ac
leaq -0x3c(%rbp), %rcx
movl $0x1, (%rcx)
pushq $0x1
popq %rsi
pushq $0x4
popq %r8
movl -0x2c(%rbp), %edi
movl %r15d, %edx
callq 0x22d0
testl %eax, %eax
jns 0x2a58
callq 0x2030
movl (%rax), %edx
leaq 0x2727(%rip), %rsi      # 0x5175
pushq $0x3
popq %rdi
xorl %eax, %eax
callq 0x37ac
xorl %r12d, %r12d
xorl %ebx, %ebx
movzwl %bx, %ebx
cmpl %r13d, %ebx
jae 0x2ab8
movl %r13d, %r15d
movl %ebx, %r13d
shll $0x4, %r13d
movzwl 0x8(%r14,%r13), %r8d
pushq $0x2
popq %rdi
leaq 0x271e(%rip), %rsi      # 0x519d
movl %ebx, %edx
xorl %ecx, %ecx
xorl %eax, %eax
callq 0x37ac
movq (%r14,%r13), %rsi
movzwl 0x8(%r14,%r13), %edx
movq -0x38(%rbp), %rax
movq 0x18(%rax), %r8
movl 0x10(%rax), %r9d
movl -0x2c(%rbp), %edi
xorl %ecx, %ecx
callq 0x2050
testl %eax, %eax
jle 0x2ad4
addl %eax, %r12d
incl %ebx
movl %r15d, %r13d
jmp 0x2a5d
leaq 0x2747(%rip), %rsi      # 0x5206
xorl %r14d, %r14d
pushq $0x1
popq %rdi
movl %r12d, %edx
xorl %eax, %eax
callq 0x37ac
jmp 0x2928
addq %r13, %r14
callq 0x2030
movl (%rax), %esi
leaq 0x26de(%rip), %rdi      # 0x51c3
xorl %eax, %eax
callq 0x2040
movzwl 0x8(%r14), %ecx
leaq 0x26d6(%rip), %rsi      # 0x51ce
pushq $0x5
popq %rdi
xorl %edx, %edx
xorl %eax, %eax
callq 0x37ac
jmp 0x2925