// File: /workspace/github_c_makefile_star2_O3/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, %ebx
movq %rsi, %r14
movq %rdi, %r12
leaq -0x38(%rbp), %rcx
movq $0x0, (%rcx)
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 0x2b36
movq 0x8(%r12), %rdx
leaq 0x2623(%rip), %rsi      # 0x5104
movl $0x0, -0x2c(%rbp)
movl $0x5, %edi
xorl %eax, %eax
callq 0x3a20
movb $0x1, %r14b
movq -0x38(%rbp), %rdi
testq %rdi, %rdi
je 0x2b05
callq 0x2200
movl -0x2c(%rbp), %edi
callq 0x2300
testl %eax, %eax
je 0x2b24
leaq 0x2708(%rip), %rsi      # 0x5220
movl $0x3, %edi
xorl %eax, %eax
callq 0x3a20
movl %r14d, %eax
addq $0x78, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x25f1(%rip), %rsi      # 0x512e
movl $0x1, %edi
xorl %eax, %eax
callq 0x3a20
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 0x2b84
movq -0x38(%rbp), %rax
cmpl $0x2, 0x4(%rax)
movq 0x18(%rax), %rsi
jne 0x2b9c
addq $0x4, %rsi
leaq -0x70(%rbp), %rdx
movl $0x2, %edi
movl $0x10, %ecx
jmp 0x2bae
leaq 0x25b3(%rip), %rsi      # 0x513e
movl $0x5, %edi
xorl %eax, %eax
callq 0x3a20
jmp 0x2af4
addq $0x8, %rsi
leaq -0x70(%rbp), %rdx
movl $0xa, %edi
movl $0x2e, %ecx
callq 0x2190
leaq -0x70(%rbp), %r13
movq %r13, %rdi
movl $0x3a, %esi
callq 0x20b0
testq %rax, %rax
leaq 0x2762(%rip), %rax      # 0x5330
leaq 0x259e(%rip), %rdx      # 0x5173
cmoveq %rax, %rdx
leaq 0x25e1(%rip), %r8       # 0x51c1
cmoveq %rax, %r8
movq (%r12), %r9
leaq 0x2567(%rip), %rsi      # 0x5156
xorl %r12d, %r12d
movl $0x2, %edi
movq %r13, %rcx
xorl %eax, %eax
callq 0x3a20
leaq -0x3c(%rbp), %rcx
movl $0x1, (%rcx)
movl -0x2c(%rbp), %edi
movl $0x1, %esi
movl $0x2, %edx
movl $0x4, %r8d
callq 0x22d0
testl %eax, %eax
jns 0x2c41
callq 0x2030
movl (%rax), %edx
leaq 0x2540(%rip), %rsi      # 0x5175
movl $0x3, %edi
xorl %eax, %eax
callq 0x3a20
testl %ebx, %ebx
je 0x2ca2
xorl %edx, %edx
xorl %r13d, %r13d
xorl %r12d, %r12d
movzwl %r13w, %r15d
shll $0x4, %r15d
movzwl 0x8(%r14,%r15), %r8d
movl $0x2, %edi
leaq 0x2536(%rip), %rsi      # 0x519d
xorl %ecx, %ecx
xorl %eax, %eax
callq 0x3a20
movq (%r14,%r15), %rsi
movzwl 0x8(%r14,%r15), %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 0x2cc0
addl %eax, %r12d
incl %r13d
movzwl %r13w, %edx
cmpl %ebx, %edx
jb 0x2c4d
leaq 0x255d(%rip), %rsi      # 0x5206
xorl %r14d, %r14d
movl $0x1, %edi
movl %r12d, %edx
xorl %eax, %eax
callq 0x3a20
jmp 0x2af7
addq %r15, %r14
callq 0x2030
movl (%rax), %esi
leaq 0x24f2(%rip), %rdi      # 0x51c3
xorl %eax, %eax
callq 0x2040
movzwl 0x8(%r14), %ecx
leaq 0x24ea(%rip), %rsi      # 0x51ce
movl $0x5, %edi
xorl %edx, %edx
xorl %eax, %eax
callq 0x3a20
jmp 0x2af4