// File: /workspace/github_c_makefile_star2_O2/GregorR[P]lstg/source/lst_socket_primitives.c
// Function: lstSocketPrimitive
struct object *
lstSocketPrimitive(int primitiveNumber, struct object *args, int *failed)
{
    struct object *returnedValue = nilObject;
    switch (integerValue(args->data[0])) {

        case 0:     /* constants */
            switch (integerValue(args->data[1])) {
            case 0:
                returnedValue = newInteger(AF_INET); break;
            case 1:
                returnedValue = newInteger(AF_INET6); break;
            case 2:
                returnedValue = newInteger(AF_LOCAL); break;
            case 10:
                returnedValue = newInteger(SOCK_STREAM); break;
            case 11:
                returnedValue = newInteger(SOCK_DGRAM); break;
            case 12:
                returnedValue = newInteger(SOCK_RAW); break;
            case 20:
                returnedValue = newInteger(IPPROTO_TCP); break;
            case 21:
                returnedValue = newInteger(IPPROTO_UDP); break;
#ifdef IPPROTO_SCTP
            case 22:
                returnedValue = newInteger(IPPROTO_SCTP); break;
#endif
            case 30:
                returnedValue = newInteger(SHUT_RD); break;
            case 31:
                returnedValue = newInteger(SHUT_WR); break;
            case 32:
                returnedValue = newInteger(SHUT_RDWR); break;
            }
            break;

        case 10: {   /* create socket */
            int family = integerValue(args->data[1]);
            int socketType = integerValue(args->data[2]);
            int protocol = integerValue(args->data[3]);
            int sockfd = socket(family, socketType, protocol);
            if (sockfd >= 0)
                returnedValue = newInteger(sockfd);
            break;
        }

        case 11: {   /* create TCP socket */
            int sockfd = socket(AF_INET, SOCK_STREAM, 0);
            if (sockfd >= 0)
                returnedValue = newInteger(sockfd);
            break;
        }

        case 12: {   /* create UDP socket */
            int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
            if (sockfd >= 0)
                returnedValue = newInteger(sockfd);
            break;
        }

        case 20: {   /* close */
            int sockfd = integerValue(args->data[1]);
            int rc = close(sockfd);
            returnedValue = newInteger(rc);
            break;
        }

        case 21: {   /* shutdown */
            int sockfd = integerValue(args->data[1]);
            int how = integerValue(args->data[2]);
            int rc = shutdown(sockfd, how);
            returnedValue = newInteger(rc);
            break;
        }

        case 30: {   /* bind */
            int sockfd = integerValue(args->data[1]);
            struct byteObject *addrObj = (struct byteObject *) args->data[2];
            int rc = bind(sockfd, (struct sockaddr *) addrObj->bytes, SIZE(addrObj));
            returnedValue = newInteger(rc);
            break;
        }

        case 40: {   /* listen */
            int sockfd = integerValue(args->data[1]);
            int backlog = integerValue(args->data[2]);
            int rc = listen(sockfd, backlog);
            returnedValue = newInteger(rc);
            break;
        }

        case 50: {   /* accept */
            int sockfd = integerValue(args->data[1]);
            int newsockfd = accept(sockfd, NULL, NULL);
            returnedValue = newInteger(newsockfd);
            break;
        }

        case 60: {   /* connect */
            int sockfd = integerValue(args->data[1]);
            struct byteObject *addrObj = (struct byteObject *) args->data[2];
#if defined(DEBUG) && defined(TRACE)
            struct sockaddr_in *p = (struct sockaddr_in*) addrObj->bytes;
printf("before connect()\n");
printf("    sockfd=%d\n", sockfd);
printf("    family=%d\n", p->sin_family);
printf("    port=%d\n", ntohs(p->sin_port));
printf("    addr=%s\n", inet_ntoa(p->sin_addr));
#endif
            int rc = connect(sockfd, (struct sockaddr *) addrObj->bytes, SIZE(addrObj));
#if defined(DEBUG) && defined(TRACE)
printf("connect() returns %d\n", rc);
#endif
            returnedValue = newInteger(rc);
            break;
        }

        case 70: {   /* send */
            int sockfd = integerValue(args->data[1]);
            struct byteObject *bufObj = (struct byteObject *) args->data[2];
            int n = integerValue(args->data[3]);
            if ((LstUInt) n > SIZE(bufObj)) {
                *failed = 1;
                break;
            }
            ssize_t sent = send(sockfd, bufObj->bytes, n, 0);
            returnedValue = newInteger(sent);
            break;
        }

        case 71: {   /* sendto */
            int sockfd = integerValue(args->data[1]);
            struct byteObject *bufObj = (struct byteObject *) args->data[2];
            int n = integerValue(args->data[3]);
            if ((LstUInt) n > SIZE(bufObj)) {
                *failed = 1;
                break;
            }
            struct byteObject *addrObj = (struct byteObject *) args->data[4];
            ssize_t sent = sendto(sockfd, bufObj->bytes, n, 0,
                    (struct sockaddr *) addrObj->bytes, SIZE(addrObj));
            returnedValue = newInteger(sent);
            break;
        }

        case 80: {   /* recv */
            int sockfd = integerValue(args->data[1]);
            struct byteObject *bufObj = (struct byteObject *) args->data[2];
            int n = integerValue(args->data[3]);
            if ((LstUInt) n > SIZE(bufObj)) {
                *failed = 1;
                break;
            }
            ssize_t got = recv(sockfd, bufObj->bytes, n, 0);
            returnedValue = newInteger(got);
            break;
        }

        case 81: {  /* recvfrom */
            int sockfd = integerValue(args->data[1]);
            struct byteObject *bufObj = (struct byteObject *) args->data[2];
            int n = integerValue(args->data[3]);
            if ((LstUInt) n > SIZE(bufObj)) {
                *failed = 1;
                break;
            }
            struct sockaddr_storage ss;
            socklen_t len = sizeof(ss);
            ssize_t got = recvfrom(sockfd, bufObj->bytes, n, 0,
                    (struct sockaddr *) &ss, &len);
            /* TODO , how to return both ssize_t and peer address? */
            returnedValue = newInteger(got);
            break;
        }

        case 90: {   /* getsockopt */
            /*
            int sockfd = integerValue(args->data[1]);
            int level = integerValue(args->data[2]);
            int optname = integerValue(args->data[3]);
            */
            // TODO
            break;
        }

        case 91: {   /* setsockopt */
            // TODO
            break;
        }

        case 92: {  /* select on a single fd */
#define LST_WAIT_R 1
#define LST_WAIT_W 2
            int fd = integerValue(args->data[1]);
            int waitfor = integerValue(args->data[2]);
            struct timeval timeout, *p = NULL;
            if (SIZE(args) > 3) {
                int timeout_in_milliseconds = integerValue(args->data[3]);
                timeout.tv_sec = (timeout_in_milliseconds) / 1000;
                timeout.tv_usec = (timeout_in_milliseconds) % 1000 * 1000;
                p = &timeout;
            }
            fd_set rfds, wfds, *rp = NULL, *wp = NULL;
            if (waitfor & LST_WAIT_R) { FD_ZERO(&rfds); FD_SET(fd, &rfds); rp = &rfds; }
            if (waitfor & LST_WAIT_W) { FD_ZERO(&wfds); FD_SET(fd, &wfds); wp = &wfds; }
            int rc = select(fd + 1, rp, wp, NULL, p);
            if (rc > 0) {
                rc = 0;
                if ((waitfor & LST_WAIT_R) && FD_ISSET(fd, &rfds)) rc |= LST_WAIT_R;
                if ((waitfor & LST_WAIT_W) && FD_ISSET(fd, &wfds)) rc |= LST_WAIT_W;
            }
#undef LST_WAIT_R
#undef LST_WAIT_W
            returnedValue = newInteger(rc);
            break;
        }

        case 93: {  /* getsockname */
            struct sockaddr_storage ss;
            socklen_t len = sizeof(ss);
            int sockfd = integerValue(args->data[1]);
            if (getsockname(sockfd, (struct sockaddr *) &ss, &len) >= 0)
                returnedValue = lstNewBinary(&ss, len);
            break;
        }

        case 94: {  /* getpeername */
            struct sockaddr_storage ss;
            socklen_t len = sizeof(ss);
            int sockfd = integerValue(args->data[1]);
            if (getpeername(sockfd, (struct sockaddr *) &ss, &len) >= 0)
                returnedValue = lstNewBinary(&ss, len);
            break;
        }

    }
    return returnedValue;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %rbx
subq $0x118, %rsp            # imm = 0x118
leaq 0x3fe86(%rip), %rax     # 0x45938
movq (%rax), %rbx
movq 0x10(%rsi), %rax
sarq %rax
leaq -0xa(%rax), %rcx
cmpq $0xb, %rcx
jbe 0x5b69
cmpq $0x5e, %rax
je 0x5c47
cmpq $0x1e, %rax
je 0x5be1
cmpq $0x28, %rax
je 0x5d7b
cmpq $0x32, %rax
je 0x5c68
cmpq $0x3c, %rax
je 0x5d90
cmpq $0x46, %rax
je 0x5d01
cmpq $0x47, %rax
je 0x5d5b
cmpq $0x50, %rax
je 0x5d2e
cmpq $0x51, %rax
je 0x5bff
cmpq $0x5c, %rax
je 0x5cbd
cmpq $0x5d, %rax
je 0x5c7d
testq %rax, %rax
jne 0x5db3
movq 0x18(%rsi), %rax
sarq %rax
cmpq $0xc, %rax
ja 0x5ece
leaq 0x1aa3(%rip), %rcx      # 0x75fc
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
pushq $0x15
jmp 0x5f0d
leaq 0x1a5c(%rip), %rax      # 0x75cc
movslq (%rax,%rcx,4), %rcx
addq %rax, %rcx
jmpq *%rcx
movq 0x18(%rsi), %rdi
movq 0x20(%rsi), %rax
shrq %rdi
shrq %rax
movq 0x28(%rsi), %rdx
shrq %rdx
movl %eax, %esi
jmp 0x5bb2
movq 0x18(%rsi), %rdi
shrq %rdi
callq 0x2170
jmp 0x5da9
pushq $0x2
popq %rdi
movl %edi, %esi
jmp 0x5bb0
pushq $0x2
popq %rdi
pushq $0x1
popq %rsi
xorl %edx, %edx
callq 0x2380
leal 0x1(,%rax,2), %ecx
testl %eax, %eax
cmovnsq %rcx, %rbx
jmp 0x5db3
movq 0x18(%rsi), %rdi
movq 0x20(%rsi), %rsi
shrq %rdi
shrq %rsi
callq 0x20f0
jmp 0x5da9
movq 0x18(%rsi), %rdi
movq 0x20(%rsi), %rsi
shrq %rdi
movl (%rsi), %edx
addq $0x10, %rsi
shrl $0x2, %edx
callq 0x2280
jmp 0x5da9
movq 0x20(%rsi), %rax
movq 0x28(%rsi), %rcx
shrq %rcx
movl (%rax), %edi
shrl $0x2, %edi
cmpl %ecx, %edi
jb 0x5d73
movq 0x18(%rsi), %rdi
shrq %rdi
leaq 0x8(%rsp), %r9
movl $0x80, (%r9)
addq $0x10, %rax
movl %ecx, %edx
leaq 0x88(%rsp), %r8
movq %rax, %rsi
xorl %ecx, %ecx
callq 0x2240
jmp 0x5dab
leaq 0x8(%rsp), %rdx
movl $0x80, (%rdx)
movq 0x18(%rsi), %rdi
shrq %rdi
leaq 0x88(%rsp), %rsi
callq 0x20d0
jmp 0x5c9c
movq 0x18(%rsi), %rdi
shrq %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x22d0
jmp 0x5da9
leaq 0x8(%rsp), %rdx
movl $0x80, (%rdx)
movq 0x18(%rsi), %rdi
shrq %rdi
leaq 0x88(%rsp), %rsi
callq 0x22e0
testl %eax, %eax
js 0x5db3
movl 0x8(%rsp), %esi
leaq 0x88(%rsp), %rdi
callq 0x51f4
movq %rax, %rbx
jmp 0x5db3
movq 0x18(%rsi), %rbx
movq 0x20(%rsi), %r14
shrq %rbx
shrq %r14
cmpl $0x10, (%rsi)
jb 0x5dc4
movq 0x28(%rsi), %rax
shrq %rax
movl $0x3e8, %ecx            # imm = 0x3E8
cltd
idivl %ecx
cltq
leaq 0x108(%rsp), %r8
movq %rax, (%r8)
imull $0x3e8, %edx, %eax      # imm = 0x3E8
cltq
movq %rax, 0x8(%r8)
jmp 0x5dc7
movq 0x20(%rsi), %rax
movq 0x28(%rsi), %rcx
shrq %rcx
movl (%rax), %edi
shrl $0x2, %edi
cmpl %ecx, %edi
jb 0x5d73
movq 0x18(%rsi), %rdi
shrq %rdi
addq $0x10, %rax
movl %ecx, %edx
movq %rax, %rsi
xorl %ecx, %ecx
callq 0x2120
jmp 0x5dab
movq 0x20(%rsi), %rax
movq 0x28(%rsi), %rcx
shrq %rcx
movl (%rax), %edi
shrl $0x2, %edi
cmpl %ecx, %edi
jb 0x5d73
movq 0x18(%rsi), %rdi
shrq %rdi
addq $0x10, %rax
movl %ecx, %edx
movq %rax, %rsi
xorl %ecx, %ecx
callq 0x2070
jmp 0x5dab
movq 0x20(%rsi), %rax
movq 0x28(%rsi), %rcx
shrq %rcx
movl (%rax), %edi
shrl $0x2, %edi
cmpl %ecx, %edi
jae 0x5ea3
movl $0x1, (%rdx)
jmp 0x5db3
movq 0x18(%rsi), %rdi
movq 0x20(%rsi), %rsi
shrq %rdi
shrq %rsi
callq 0x2230
jmp 0x5da9
movq 0x18(%rsi), %rdi
movq 0x20(%rsi), %rsi
shrq %rdi
movl (%rsi), %edx
addq $0x10, %rsi
shrl $0x2, %edx
callq 0x2330
cltq
leaq 0x1(,%rax,2), %rbx
movq %rbx, %rax
addq $0x118, %rsp            # imm = 0x118
popq %rbx
popq %r14
popq %r15
popq %rbp
retq
xorl %r8d, %r8d
pushq $0x40
popq %rbp
testb $0x1, %r14b
jne 0x5dd4
xorl %esi, %esi
jmp 0x5e0f
xorl %eax, %eax
cmpq $0x10, %rax
je 0x5dea
andq $0x0, 0x88(%rsp,%rax,8)
incq %rax
jmp 0x5dd6
movl %ebx, %eax
cltd
idivl %ebp
movslq %eax, %rdx
shll $0x6, %eax
movl %ebx, %ecx
subl %eax, %ecx
pushq $0x1
popq %rax
shlq %cl, %rax
orq %rax, 0x88(%rsp,%rdx,8)
leaq 0x88(%rsp), %rsi
testb $0x2, %r14b
jne 0x5e19
xorl %edx, %edx
jmp 0x5e4b
xorl %eax, %eax
cmpq $0x10, %rax
je 0x5e2c
andq $0x0, 0x8(%rsp,%rax,8)
incq %rax
jmp 0x5e1b
movl %ebx, %eax
cltd
idivl %ebp
movslq %eax, %rdx
shll $0x6, %eax
movl %ebx, %ecx
subl %eax, %ecx
pushq $0x1
popq %rax
shlq %cl, %rax
orq %rax, 0x8(%rsp,%rdx,8)
leaq 0x8(%rsp), %rdx
leal 0x1(%rbx), %edi
xorl %r15d, %r15d
xorl %ecx, %ecx
callq 0x2200
testl %eax, %eax
jle 0x5ef0
testb $0x1, %r14b
je 0x5e80
movl %ebx, %eax
cltd
idivl %ebp
cltq
movq 0x88(%rsp,%rax,8), %rax
xorl %r15d, %r15d
btq %rdx, %rax
setb %r15b
testb $0x2, %r14b
je 0x5ef3
movl %ebx, %eax
cltd
idivl %ebp
cltq
movq 0x8(%rsp,%rax,8), %rax
leal 0x2(%r15), %ecx
btq %rdx, %rax
cmovael %r15d, %ecx
movl %ecx, %r15d
jmp 0x5ef3
movq 0x18(%rsi), %rdi
movq 0x30(%rsi), %r8
shrq %rdi
addq $0x10, %rax
movl %ecx, %edx
movl (%r8), %r9d
addq $0x10, %r8
shrl $0x2, %r9d
movq %rax, %rsi
xorl %ecx, %ecx
callq 0x2150
jmp 0x5dab
addq $-0x14, %rax
cmpq $0xc, %rax
ja 0x5db3
leaq 0x174d(%rip), %rcx      # 0x7630
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
pushq $0xd
jmp 0x5f0d
movl %eax, %r15d
movslq %r15d, %rax
jmp 0x5dab
pushq $0x5
jmp 0x5f0d
pushq $0x3
jmp 0x5f0d
pushq $0x7
jmp 0x5f0d
pushq $0x1
jmp 0x5f0d
pushq $0x23
popq %rbx
jmp 0x5db3
movl $0x109, %ebx            # imm = 0x109
jmp 0x5db3