HEX
Server: Apache/2.4.59 (Debian)
System: Linux keymana 4.19.0-21-cloud-amd64 #1 SMP Debian 4.19.249-2 (2022-06-30) x86_64
User: lijunjie (1003)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: //home/lijunjie/swoole-cli/swoole-src-4.8.13/src/server/message_bus.cc
#include "swoole_server.h"

#include <assert.h>

using swoole::network::Address;
using swoole::network::Socket;

namespace swoole {

PacketPtr MessageBus::get_packet() const {
    PacketPtr pkt;
    if (buffer_->info.flags & SW_EVENT_DATA_PTR) {
        memcpy(&pkt, buffer_->data, sizeof(pkt));
    } else if (buffer_->info.flags & SW_EVENT_DATA_OBJ_PTR) {
        String *object;
        memcpy(&object, buffer_->data, sizeof(object));
        pkt.data = object->str;
        pkt.length = object->length;
    } else {
        pkt.data = buffer_->data;
        pkt.length = buffer_->info.len;
    }

    return pkt;
}

String *MessageBus::get_packet_buffer() {
    String *packet_buffer = nullptr;

    auto iter = packet_pool_.find(buffer_->info.msg_id);
    if (iter == packet_pool_.end()) {
        if (!buffer_->is_begin()) {
            return nullptr;
        }
        packet_buffer = make_string(buffer_->info.len, allocator_);
        packet_pool_.emplace(buffer_->info.msg_id, std::shared_ptr<String>(packet_buffer));
    } else {
        packet_buffer = iter->second.get();
    }

    return packet_buffer;
}

ReturnCode MessageBus::prepare_packet(uint16_t &recv_chunk_count, String *packet_buffer) {
    recv_chunk_count++;
    if (!buffer_->is_end()) {
        /**
         * if the reactor thread sends too many chunks to the worker process,
         * the worker process may receive chunks all the time,
         * resulting in the worker process being unable to handle other tasks.
         * in order to make the worker process handle tasks fairly,
         * the maximum number of consecutive chunks received by the worker is limited.
         */
        if (recv_chunk_count >= SW_WORKER_MAX_RECV_CHUNK_COUNT) {
            swoole_trace_log(SW_TRACE_WORKER,
                             "worker process[%u] receives the chunk data to the maximum[%d], return to event loop",
                             SwooleG.process_id,
                             recv_chunk_count);
            return SW_WAIT;
        }
        return SW_CONTINUE;
    } else {
        /**
         * Because we don't want to split the EventData parameters into DataHead and data,
         * we store the value of the worker_buffer pointer in EventData.data.
         * The value of this pointer will be fetched in the Server::get_pipe_packet() function.
         */
        buffer_->info.flags |= SW_EVENT_DATA_OBJ_PTR;
        memcpy(buffer_->data, &packet_buffer, sizeof(packet_buffer));
        swoole_trace("msg_id=%ld, len=%u", buffer_->info.msg_id, buffer_->info.len);

        return SW_READY;
    }
}

ssize_t MessageBus::read(Socket *sock) {
    ssize_t recv_n = 0;
    uint16_t recv_chunk_count = 0;
    DataHead *info = &buffer_->info;
    struct iovec buffers[2];

_read_from_pipe:
    recv_n = recv(sock->get_fd(), info, sizeof(buffer_->info), MSG_PEEK);
    if (recv_n < 0) {
        if (sock->catch_read_error(errno) == SW_WAIT) {
            return SW_OK;
        }
        return SW_ERR;
    } else if (recv_n == 0) {
        swoole_warning("receive data from socket#%d returns 0", sock->get_fd());
        return SW_ERR;
    }

    if (!buffer_->is_chunked()) {
        return sock->read(buffer_, sizeof(buffer_->info) + buffer_->info.len);
    }

    auto packet_buffer = get_packet_buffer();
    if (packet_buffer == nullptr) {
        swoole_error_log(SW_LOG_WARNING,
                         SW_ERROR_SERVER_WORKER_ABNORMAL_PIPE_DATA,
                         "abnormal pipeline data, msg_id=%ld, pipe_fd=%d, reactor_id=%d",
                         info->msg_id,
                         sock->get_fd(),
                         info->reactor_id);
        return SW_OK;
    }

    size_t remain_len = buffer_->info.len - packet_buffer->length;
    buffers[0].iov_base = info;
    buffers[0].iov_len = sizeof(buffer_->info);
    buffers[1].iov_base = packet_buffer->str + packet_buffer->length;
    buffers[1].iov_len = SW_MIN(buffer_size_ - sizeof(buffer_->info), remain_len);

    recv_n = readv(sock->get_fd(), buffers, 2);
    if (recv_n == 0) {
        swoole_warning("receive pipeline data error, pipe_fd=%d, reactor_id=%d", sock->get_fd(), info->reactor_id);
        return SW_ERR;
    }
    if (recv_n < 0 && sock->catch_read_error(errno) == SW_WAIT) {
        return SW_OK;
    }
    if (recv_n > 0) {
        packet_buffer->length += (recv_n - sizeof(buffer_->info));
        swoole_trace("append msgid=%ld, buffer=%p, n=%ld", buffer_->info.msg_id, packet_buffer, recv_n);
    }

    switch (prepare_packet(recv_chunk_count, packet_buffer)) {
    case SW_READY:
        return recv_n;
    case SW_CONTINUE:
        goto _read_from_pipe;
    case SW_WAIT:
        return SW_OK;
    default:
        assert(0);
        return SW_ERR;
    }
}

/**
 * Notice: only supports dgram type socket
 */
ssize_t MessageBus::read_with_buffer(network::Socket *sock) {
    ssize_t recv_n;
    uint16_t recv_chunk_count = 0;

_read_from_pipe:
    recv_n = sock->read(buffer_, buffer_size_);
    if (recv_n < 0) {
        if (sock->catch_read_error(errno) == SW_WAIT) {
            return SW_OK;
        }
        return SW_ERR;
    } else if (recv_n == 0) {
        swoole_warning("receive data from socket#%d returns 0", sock->get_fd());
        return SW_ERR;
    }

    recv_chunk_count++;

    if (!buffer_->is_chunked()) {
        return recv_n;
    }

    String *packet_buffer = get_packet_buffer();
    if (packet_buffer == nullptr) {
        swoole_error_log(SW_LOG_WARNING,
                         SW_ERROR_SERVER_WORKER_ABNORMAL_PIPE_DATA,
                         "abnormal pipeline data, msg_id=%ld, pipe_fd=%d, reactor_id=%d",
                         buffer_->info.msg_id,
                         sock->get_fd(),
                         buffer_->info.reactor_id);
        return SW_ERR;
    }
    packet_buffer->append(buffer_->data, recv_n - sizeof(buffer_->info));

    switch (prepare_packet(recv_chunk_count, packet_buffer)) {
    case SW_READY:
        return recv_n;
    case SW_CONTINUE:
        goto _read_from_pipe;
    case SW_WAIT:
        return SW_OK;
    default:
        assert(0);
        return SW_ERR;
    }
}

bool MessageBus::write(Socket *sock, SendData *resp) {
    const char *payload = resp->data;
    uint32_t l_payload = resp->info.len;
    off_t offset = 0;
    uint32_t copy_n;

    struct iovec iov[2];

    uint64_t msg_id = id_generator_();
    uint32_t max_length = buffer_size_ - sizeof(resp->info);
    resp->info.msg_id = msg_id;

    auto send_fn = [](Socket *sock, const iovec *iov, size_t iovcnt) {
        if (swoole_event_is_available()) {
            return swoole_event_writev(sock, iov, iovcnt);
        } else {
            return sock->writev_blocking(iov, iovcnt);
        }
    };

    if (l_payload == 0 || payload == nullptr) {
        resp->info.flags = 0;
        resp->info.len = 0;
        iov[0].iov_base = &resp->info;
        iov[0].iov_len = sizeof(resp->info);
        return send_fn(sock, iov, 1) == (ssize_t) iov[0].iov_len;
    }

    if (!always_chunked_transfer_ && l_payload <= max_length) {
        resp->info.flags = 0;
        resp->info.len = l_payload;
        iov[0].iov_base = &resp->info;
        iov[0].iov_len = sizeof(resp->info);
        iov[1].iov_base = (void *) payload;
        iov[1].iov_len = l_payload;

        if (send_fn(sock, iov, 2) == (ssize_t)(sizeof(resp->info) + l_payload)) {
            return true;
        }
        if (sock->catch_write_pipe_error(errno) == SW_REDUCE_SIZE && max_length > SW_BUFFER_SIZE_STD) {
            max_length = SW_IPC_BUFFER_SIZE;
        } else {
            return false;
        }
    }

    resp->info.flags = SW_EVENT_DATA_CHUNK | SW_EVENT_DATA_BEGIN;
    resp->info.len = l_payload;

    while (l_payload > 0) {
        if (l_payload > max_length) {
            copy_n = max_length;
        } else {
            resp->info.flags |= SW_EVENT_DATA_END;
            copy_n = l_payload;
        }

        iov[0].iov_base = &resp->info;
        iov[0].iov_len = sizeof(resp->info);
        iov[1].iov_base = (void *) (payload + offset);
        iov[1].iov_len = copy_n;

        swoole_trace("finish, type=%d|len=%u", resp->info.type, copy_n);

        if (send_fn(sock, iov, 2) < 0) {
            if (sock->catch_write_pipe_error(errno) == SW_REDUCE_SIZE && max_length > SW_BUFFER_SIZE_STD) {
                max_length = SW_IPC_BUFFER_SIZE;
                if (resp->info.flags & SW_EVENT_DATA_END) {
                    resp->info.flags &= ~SW_EVENT_DATA_END;
                }
                continue;
            }
            return false;
        }

        if (resp->info.flags & SW_EVENT_DATA_BEGIN) {
            resp->info.flags &= ~SW_EVENT_DATA_BEGIN;
        }

        l_payload -= copy_n;
        offset += copy_n;
    }

    return true;
}

size_t MessageBus::get_memory_size() {
    size_t size = buffer_size_;
    for (auto p : packet_pool_) {
        size += p.second->size;
    }
    return size;
}

}  // namespace swoole