// File: davmac314[P]dinit/src/includes/dinit-client.h
// Function: wait_for_reply(cpbuffer<1024u>&, int, unsigned int, observed_states_t*)
inline void wait_for_reply(cpbuffer_t &rbuffer, int fd, dinit_cptypes::handle_t handle, observed_states_t *seen_states)
{
    fill_buffer_to(rbuffer, fd, 1);

    while (rbuffer[0] >= 100) {
        // Information packet; discard.
        cp_info pkt_type = (cp_info) rbuffer[0];
        fill_buffer_to(rbuffer, fd, 2);
        unsigned pktlen = (unsigned char) rbuffer[1];

        rbuffer.consume(1);  // Consume one byte so we'll read one byte of the next packet
        fill_buffer_to(rbuffer, fd, pktlen);

        if (value(pkt_type).is_in(cp_info::SERVICEEVENT, cp_info::SERVICEEVENT5)
                && seen_states != nullptr) {

            // earlier versions do not include status info, the size in that case is
            // base_pkt_size:
            constexpr unsigned base_pkt_size = 2 + sizeof(dinit_cptypes::handle_t) + 1;

            if (pktlen < base_pkt_size) {
                throw dinit_protocol_error();
            }

            // Extract handle, check for match
            dinit_cptypes::handle_t ev_handle;
            rbuffer.extract((char *)&ev_handle, 1, sizeof(ev_handle));
            service_event_t event = static_cast<service_event_t>(rbuffer[1 + sizeof(ev_handle)]);

            if (ev_handle == handle) {
                if (event == service_event_t::STOPPED) {
                    seen_states->stopped = true;
                }
                if (event == service_event_t::STARTED) {
                    seen_states->started = true;
                }
                if (event == service_event_t::FAILEDSTART) {
                    stopped_reason_t stop_reason =
                            static_cast<stopped_reason_t>(rbuffer[base_pkt_size + 2]);

                    seen_states->failed_start = true;
                    seen_states->stop_reason = stop_reason;

                    int exit_status;
                    int exit_si_code;
                    int exit_si_status;
                    rbuffer.extract((char *)&exit_status, base_pkt_size + 5, sizeof(exit_status));
                    if (pkt_type == cp_info::SERVICEEVENT5) {
                        if (pktlen < base_pkt_size + STATUS_BUFFER5_SIZE) {
                            throw dinit_protocol_error();
                        }
                        exit_si_code = exit_status;
                        rbuffer.extract((char *)&exit_si_status,
                                base_pkt_size + 5 + sizeof(exit_si_code), sizeof(exit_si_status));

                        seen_states->exit_si_code = exit_si_code;
                        seen_states->exit_si_status = exit_si_status;
                    }

                    seen_states->exit_status = exit_status;
                }
            }
        }

        rbuffer.consume(pktlen - 1);
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x50, %rsp
movq %rdi, -0x8(%rbp)
movl %esi, -0xc(%rbp)
movl %edx, -0x10(%rbp)
movq %rcx, -0x18(%rbp)
movq -0x8(%rbp), %rdi
movl -0xc(%rbp), %esi
movl $0x1, %edx
callq 0x11440
movq -0x8(%rbp), %rdi
xorl %esi, %esi
callq 0x113e0
movsbl %al, %eax
cmpl $0x64, %eax
jl 0x11e68
movq -0x8(%rbp), %rdi
xorl %esi, %esi
callq 0x113e0
movb %al, -0x19(%rbp)
movq -0x8(%rbp), %rdi
movl -0xc(%rbp), %esi
movl $0x2, %edx
callq 0x11440
movq -0x8(%rbp), %rdi
movl $0x1, %esi
callq 0x113e0
movzbl %al, %eax
movl %eax, -0x20(%rbp)
movq -0x8(%rbp), %rdi
movl $0x1, %esi
callq 0x115f0
movq -0x8(%rbp), %rdi
movl -0xc(%rbp), %esi
movl -0x20(%rbp), %edx
callq 0x11440
leaq -0x19(%rbp), %rdi
callq 0x125d0
movq %rax, -0x28(%rbp)
movb $0x64, -0x29(%rbp)
movb $0x65, -0x2a(%rbp)
leaq -0x28(%rbp), %rdi
leaq -0x29(%rbp), %rsi
leaq -0x2a(%rbp), %rdx
callq 0x12600
movb %al, %cl
xorl %eax, %eax
testb $0x1, %cl
movb %al, -0x49(%rbp)
jne 0x11d12
jmp 0x11d1d
cmpq $0x0, -0x18(%rbp)
setne %al
movb %al, -0x49(%rbp)
movb -0x49(%rbp), %al
testb $0x1, %al
jne 0x11d29
jmp 0x11e54
movl $0x7, -0x30(%rbp)
cmpl $0x7, -0x20(%rbp)
jae 0x11d53
movl $0x1, %edi
callq 0x51c0
movq %rax, %rdi
leaq 0x1fd96(%rip), %rsi     # 0x31ae0
xorl %eax, %eax
movl %eax, %edx
callq 0x56b0
movq -0x8(%rbp), %rdi
leaq -0x34(%rbp), %rsi
movl $0x1, %edx
movl $0x4, %ecx
callq 0x11540
movq -0x8(%rbp), %rdi
movl $0x5, %esi
callq 0x113e0
movsbl %al, %eax
movl %eax, -0x38(%rbp)
movl -0x34(%rbp), %eax
cmpl -0x10(%rbp), %eax
jne 0x11e52
cmpl $0x1, -0x38(%rbp)
jne 0x11d98
movq -0x18(%rbp), %rax
movb $0x1, 0x1(%rax)
cmpl $0x0, -0x38(%rbp)
jne 0x11da5
movq -0x18(%rbp), %rax
movb $0x1, (%rax)
cmpl $0x2, -0x38(%rbp)
jne 0x11e50
movq -0x8(%rbp), %rdi
movl $0x9, %esi
callq 0x113e0
movsbl %al, %eax
movl %eax, -0x3c(%rbp)
movq -0x18(%rbp), %rax
movb $0x1, 0x2(%rax)
movl -0x3c(%rbp), %ecx
movq -0x18(%rbp), %rax
movl %ecx, 0x4(%rax)
movq -0x8(%rbp), %rdi
leaq -0x40(%rbp), %rsi
movl $0xc, %edx
movl $0x4, %ecx
callq 0x11540
cmpb $0x65, -0x19(%rbp)
jne 0x11e46
cmpl $0x15, -0x20(%rbp)
jae 0x11e15
movl $0x1, %edi
callq 0x51c0
movq %rax, %rdi
leaq 0x1fcd4(%rip), %rsi     # 0x31ae0
xorl %eax, %eax
movl %eax, %edx
callq 0x56b0
movl -0x40(%rbp), %eax
movl %eax, -0x44(%rbp)
movq -0x8(%rbp), %rdi
leaq -0x48(%rbp), %rsi
movl $0x10, %edx
movl $0x4, %ecx
callq 0x11540
movl -0x44(%rbp), %ecx
movq -0x18(%rbp), %rax
movl %ecx, 0xc(%rax)
movl -0x48(%rbp), %ecx
movq -0x18(%rbp), %rax
movl %ecx, 0x10(%rax)
movl -0x40(%rbp), %ecx
movq -0x18(%rbp), %rax
movl %ecx, 0x8(%rax)
jmp 0x11e52
jmp 0x11e54
movq -0x8(%rbp), %rdi
movl -0x20(%rbp), %esi
subl $0x1, %esi
callq 0x115f0
jmp 0x11c77
addq $0x50, %rsp
popq %rbp
retq
nop