// File: /workspace/github_cpp_makefile_star2_O1/davmac314[P]dinit/src/control.cc
// Function: control_conn_t::process_start_stop(cp_cmd)
bool control_conn_t::process_start_stop(cp_cmd pktType)
{
    using std::string;
    
    constexpr int pkt_size = 2 + sizeof(handle_t);
    
    if (rbuf.get_length() < pkt_size) {
        chklen = pkt_size;
        return true;
    }
    
    // 1 byte: packet type
    // 1 byte: flags
    //    bit 0: 0 = no pin, 1 = pin
    //    bit 1: 0 = force stop, 1 = not forced ("gentle")
    //    bit 2: 0 = don't restart, 1 = restart after stopping
    //      --- (reserved)
    //    bit 7: 0 = no pre-ack, 1 = issue pre-ack
    // 4 bytes: service handle
    
    bool do_pin = ((rbuf[1] & 1) == 1);
    handle_t handle;
    rbuf.extract((char *) &handle, 2, sizeof(handle));
    
    service_record *service = find_service_for_key(handle);
    if (service == nullptr) {
        // Service handle is bad
        char badreqRep[] = { (char)cp_rply::BADREQ };
        if (!queue_packet(badreqRep, 1)) return false;
        bad_conn_close = true;
        return true;
    }
    else {
        char ack_buf[1] = { (char)cp_rply::PREACK };
        if (rbuf[1] & 128) {
            // Issue PREACK before doing anything that might change service state (and cause a
            // service event info packet to be issued as a result). This allows the client to
            // determine whether the info packets were queued before or after the command was
            // processed.
            if (!queue_packet(ack_buf, 1)) return false;
        }

        ack_buf[0] = (char)cp_rply::ACK;
        
        switch (pktType) {
        case cp_cmd::STARTSERVICE:
            // start service, mark as required
            if (services->is_shutting_down()) {
                ack_buf[0] = (char)cp_rply::SHUTTINGDOWN;
                break;
            }
            if ((service->get_state() == service_state_t::STOPPED
                    || service->get_state() == service_state_t::STOPPING)
                    && service->is_stop_pinned()) {
                ack_buf[0] = (char)cp_rply::PINNEDSTOPPED;
                break;
            }
            if (do_pin) service->pin_start();
            service->start();
            services->process_queues();
            if (service->get_state() == service_state_t::STARTED) ack_buf[0] = (char)cp_rply::ALREADYSS;
            break;
        case cp_cmd::STOPSERVICE:
        {
            // force service to stop
            bool do_restart = ((rbuf[1] & 4) == 4);
            bool gentle = ((rbuf[1] & 2) == 2);
            if (do_restart && services->is_shutting_down()) {
                ack_buf[0] = (char)cp_rply::SHUTTINGDOWN;
                break;
            }
            if ((service->get_state() == service_state_t::STARTED
                    || service->get_state() == service_state_t::STARTING)
                    && service->is_start_pinned()) {
                ack_buf[0] = (char)cp_rply::PINNEDSTARTED;
                break;
            }
            if (gentle) {
                // Check dependents; return appropriate response if any will be affected
                bool has_dependents;
                if (!check_dependents(service, has_dependents)) {
                    return false;
                }
                if (has_dependents) {
                    // Reply packet has already been sent
                    goto clear_out;
                }
            }
            service_state_t wanted_state;
            if (do_restart) {
                if (! service->restart()) {
                    ack_buf[0] = (char)cp_rply::NAK;
                    break;
                }
                wanted_state = service_state_t::STARTED;
            }
            else {
                if (do_pin) service->pin_stop();
                service->stop(true);
                service->forced_stop();
                wanted_state = service_state_t::STOPPED;
            }
            services->process_queues();
            if (service->get_state() == wanted_state) ack_buf[0] = (char)cp_rply::ALREADYSS;
            break;
        }
        case cp_cmd::WAKESERVICE:
        {
            // re-attach a service to its (started) dependents, causing it to start.
            if (services->is_shutting_down()) {
                ack_buf[0] = (char)cp_rply::SHUTTINGDOWN;
                break;
            }
            if ((service->get_state() == service_state_t::STOPPED
                    || service->get_state() == service_state_t::STOPPING)
                    && service->is_stop_pinned()) {
                ack_buf[0] = (char)cp_rply::PINNEDSTOPPED;
                break;
            }
            bool found_dpt = false;
            for (auto dpt : service->get_dependents()) {
                if (dpt->is_only_ordering()) continue;
                auto from = dpt->get_from();
                auto from_state = from->get_state();
                if (from_state == service_state_t::STARTED || from_state == service_state_t::STARTING) {
                    found_dpt = true;
                    if (!dpt->holding_acq) {
                        dpt->get_from()->start_dep(*dpt);
                    }
                }
            }
            if (!found_dpt) {
                ack_buf[0] = (char)cp_rply::NAK;
            }

            if (do_pin) service->pin_start();
            services->process_queues();
            if (service->get_state() == service_state_t::STARTED) ack_buf[0] = (char)cp_rply::ALREADYSS;
            break;
        }
        case cp_cmd::RELEASESERVICE:
            // remove required mark, stop if not required by dependents
            if (do_pin) service->pin_stop();
            service->stop(false);
            services->process_queues();
            if (service->get_state() == service_state_t::STOPPED) ack_buf[0] = (char)cp_rply::ALREADYSS;
            break;
        default:
            // avoid warning for unhandled switch/case values
            return false;
        }
        
        if (!queue_packet(ack_buf, 1)) return false;
    }
    
    clear_out:
    // Clear the packet from the buffer
    rbuf.consume(pkt_size);
    chklen = 0;
    return true;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x18, %rsp
movq %rdi, %rbx
cmpl $0x5, 0x484(%rdi)
ja 0x2864a
movl $0x6, 0x7c(%rbx)
jmp 0x28a17
movl %esi, %ebp
leaq 0x80(%rbx), %r14
movl 0x480(%rbx), %r15d
leal 0x1(%r15), %eax
leal -0x3ff(%r15), %ecx
movl $0x400, %r12d           # imm = 0x400
cmpl %r12d, %eax
cmovbl %eax, %ecx
leal 0x2(%r15), %eax
addl $0xfffffc02, %r15d      # imm = 0xFFFFFC02
cmpl %r12d, %eax
cmovbl %eax, %r15d
movb 0x80(%rbx,%rcx), %r13b
leal -0x3fd(%r15), %eax
movl %r15d, %esi
cmpl $0xfffffbfe, %eax       # imm = 0xFFFFFBFE
ja 0x286ce
subl %r15d, %r12d
addq %r14, %rsi
leaq 0x10(%rsp), %rdi
movq %r12, %rdx
callq 0x84d0
leaq 0x10(%rsp), %rax
addq %rax, %r12
addl $0xfffffc04, %r15d      # imm = 0xFFFFFC04
movq %r12, %rdi
movq %r14, %rsi
movq %r15, %rdx
callq 0x84d0
jmp 0x286d6
movl (%r14,%rsi), %eax
movl %eax, 0x10(%rsp)
movl 0x10(%rsp), %esi
movq %rbx, %rdi
callq 0x2ba66
testq %rax, %rax
je 0x2879e
movq %rax, %r14
movb $0x4f, 0xe(%rsp)
movl 0x480(%rbx), %eax
leal 0x1(%rax), %ecx
addl $0xfffffc01, %eax       # imm = 0xFFFFFC01
cmpl $0x400, %ecx            # imm = 0x400
cmovbl %ecx, %eax
cmpb $0x0, 0x80(%rbx,%rax)
jns 0x28734
leaq 0xe(%rsp), %rsi
movl $0x1, %r15d
movq %rbx, %rdi
movl $0x1, %edx
callq 0x27fd2
testb %al, %al
je 0x289e1
movb $0x32, 0xe(%rsp)
movzbl %bpl, %eax
addl $-0x3, %eax
cmpl $0x3, %eax
ja 0x2890e
leaq 0xdd20(%rip), %rcx      # 0x36470
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq 0x70(%rbx), %rax
cmpb $0x0, 0x28(%rax)
je 0x2887d
movzbl 0x2c(%r14), %eax
cmpl $0x3, %eax
je 0x28775
testl %eax, %eax
jne 0x28783
testb $0x2, 0x10c(%r14)
jne 0x2897f
testb $0x1, %r13b
je 0x28791
movq %r14, %rdi
callq 0x2376e
movq %r14, %rdi
callq 0x228ae
jmp 0x28868
leaq 0x17(%rsp), %rsi
movb $0x34, (%rsi)
movq %rbx, %rdi
movl $0x1, %edx
callq 0x27fd2
testb %al, %al
je 0x28a19
movb $0x1, 0x78(%rbx)
jmp 0x28a19
movq 0x70(%rbx), %rax
cmpb $0x0, 0x28(%rax)
je 0x2887d
movzbl 0x2c(%r14), %eax
cmpl $0x3, %eax
je 0x287e0
testl %eax, %eax
jne 0x287ee
testb $0x2, 0x10c(%r14)
jne 0x2897f
movq %r14, %r15
addq $0x130, %r15            # imm = 0x130
movq 0x130(%r14), %r12
cmpq %r15, %r12
je 0x28855
movb %r13b, 0xf(%rsp)
xorl %ebp, %ebp
movq 0x10(%r12), %r13
movl 0x14(%r13), %eax
andl $-0x2, %eax
cmpl $0x4, %eax
je 0x28841
movq (%r13), %rax
movb 0x2c(%rax), %al
decb %al
cmpb $0x1, %al
ja 0x28841
movb $0x1, %bpl
cmpb $0x0, 0x11(%r13)
jne 0x28841
movq 0x8(%r13), %rdi
callq 0x22962
movb $0x1, 0x11(%r13)
movq (%r12), %r12
cmpq %r15, %r12
jne 0x2880b
testb $0x1, %bpl
movb 0xf(%rsp), %r13b
jne 0x2885a
movb $0x33, 0xe(%rsp)
testb $0x1, %r13b
je 0x28868
movq %r14, %rdi
callq 0x2376e
movq 0x70(%rbx), %rdi
callq 0xd8da
cmpb $0x2, 0x2c(%r14)
je 0x288b3
jmp 0x289c9
movb $0x45, 0xe(%rsp)
jmp 0x289c9
testb $0x1, %r13b
je 0x28895
orb $0x2, 0x10c(%r14)
movq %r14, %rdi
xorl %esi, %esi
callq 0x234e0
movq 0x70(%rbx), %rdi
callq 0xd8da
cmpb $0x0, 0x2c(%r14)
jne 0x289c9
movb $0x3d, 0xe(%rsp)
jmp 0x289c9
movl 0x480(%rbx), %eax
leal 0x1(%rax), %ecx
addl $0xfffffc01, %eax       # imm = 0xFFFFFC01
cmpl $0x400, %ecx            # imm = 0x400
cmovbl %ecx, %eax
movb 0x80(%rbx,%rax), %bpl
testb $0x4, %bpl
je 0x288f0
movq 0x70(%rbx), %rax
cmpb $0x0, 0x28(%rax)
je 0x28986
movb 0x2c(%r14), %al
decb %al
cmpb $0x1, %al
ja 0x28919
testb $0xc, 0x10c(%r14)
je 0x28919
movb $0x44, 0xe(%rsp)
jmp 0x289bd
movl $0x1, %r15d
jmp 0x289e1
testb $0x2, %bpl
je 0x28952
leaq 0x16(%rsp), %r15
movq %rbx, %rdi
movq %r14, %rsi
movq %r15, %rdx
callq 0x2b000
movzbl (%r15), %ecx
movl %ecx, %edx
andl $0x1, %edx
leal (%rdx,%rdx,2), %edx
testb %al, %al
movl $0x1, %r15d
cmovnel %edx, %r15d
notb %al
orb %cl, %al
testb $0x1, %al
jne 0x289c3
testb $0x4, %bpl
jne 0x2898d
testb $0x1, %r13b
je 0x28966
orb $0x2, 0x10c(%r14)
movq %r14, %rdi
movl $0x1, %esi
callq 0x234e0
movq %r14, %rdi
callq 0x23484
xorl %ebp, %ebp
jmp 0x2899c
movb $0x43, 0xe(%rsp)
jmp 0x289c9
movb $0x45, 0xe(%rsp)
jmp 0x289bd
movq %r14, %rdi
callq 0x2358a
movb $0x2, %bpl
testb %al, %al
je 0x289b8
movq 0x70(%rbx), %rdi
callq 0xd8da
movl $0x2, %r15d
cmpb %bpl, 0x2c(%r14)
jne 0x289c3
movb $0x3d, 0xe(%rsp)
jmp 0x289c3
movb $0x33, 0xe(%rsp)
movl $0x2, %r15d
cmpl $0x2, %r15d
jne 0x289e1
leaq 0xe(%rsp), %rsi
movq %rbx, %rdi
movl $0x1, %edx
callq 0x27fd2
xorb $0x1, %al
movzbl %al, %r15d
cmpl $0x3, %r15d
je 0x289ec
testl %r15d, %r15d
jne 0x28a28
movl 0x480(%rbx), %eax
leal 0x6(%rax), %ecx
addl $0xfffffc06, %eax       # imm = 0xFFFFFC06
cmpl $0x400, %ecx            # imm = 0x400
cmovbl %ecx, %eax
movl %eax, 0x480(%rbx)
addl $-0x6, 0x484(%rbx)
movl $0x0, 0x7c(%rbx)
movb $0x1, %al
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
xorl %eax, %eax
jmp 0x28a19