Beispiel #1
0
static int ctrl_listen(const char *host, const char *port,
                       struct addrinfo **ai, struct options *opts,
                       struct callbacks *cb)
{
        struct addrinfo *result, *rp;
        int flags = AI_PASSIVE;
        int fd_listen = 0;

        result = do_getaddrinfo(host, port, flags, opts, cb);
        for (rp = result; rp != NULL; rp = rp->ai_next) {
                fd_listen = socket(rp->ai_family, rp->ai_socktype,
                                   rp->ai_protocol);
                if (fd_listen == -1) {
                        PLOG_ERROR(cb, "socket");
                        continue;
                }
                set_reuseport(fd_listen, cb);
                set_reuseaddr(fd_listen, 1, cb);
                if (bind(fd_listen, rp->ai_addr, rp->ai_addrlen) == 0)
                        break;
                PLOG_ERROR(cb, "bind");
                do_close(fd_listen);
        }
        if (rp == NULL)
                LOG_FATAL(cb, "Could not bind");
        *ai = copy_addrinfo(rp);
        freeaddrinfo(result);
        if (listen(fd_listen, opts->listen_backlog))
                PLOG_FATAL(cb, "listen");
        return fd_listen;
}
Beispiel #2
0
int GlobalChannel::Open() {
    int ret = Channel::Open();
    if (ret != 0) {
        PLOG_ERROR("%s open failed(%d).", m_name.c_str(), ret);
        return -1;
    }

    // 全局频道需要保存数据
    ChannelConfAdapter* conf = ChannelConfAdapter::Instance();
    if (!conf) {
        return -2;
    }

    ret = conf->OpenChannel(m_name);
    if (ret != 0) {
        PLOG_ERROR("%s open channel failed(%d).", m_name.c_str(), ret);
        return -3;
    }

    // 地址未配置也可以创建,适用手机客户端场景
    if (m_server_addr.empty()) {
        return 0;
    }

    // server打开频道后自然就加入了频道
    ret = conf->AddSubInstance(m_name, m_appid, m_server_addr);
    if (ret != 0) {
        PLOG_ERROR("%s add self(%s) failed(%d).", m_name.c_str(), m_appid.c_str(), ret);
        return -4;
    }

    return 0;
}
Beispiel #3
0
int main(int argc, char * argv[])
{
    gflags::ParseCommandLineFlags(&argc, &argv, false); 

    delay_init::call_all_level();
    PLOG_INFO("delay init total:",delay_init::total_cnt
        ," success:",delay_init::success_cnt
        ,", failed:",delay_init::failed_cnt);

    if(delay_init::failed_cnt>0)
    {
        PLOG_ERROR("delay init failed, failed num:", delay_init::failed_cnt);
        return 1;
    }

    if (prepare_data(FLAGS_data_file.c_str())) {
        PLOG_ERROR("read data failed!");
        return 1;
    }

    conet::init_conet_global_env();
    conet::init_conet_env();
    CONET_DEFER({
        conet::free_conet_env();
        conet::free_conet_global_env();
    });
Beispiel #4
0
pbool PIni::load(const pchar *filename)
{
    //
    // Look for the file in the specified path
    //
    const pchar* pathList[] =
    {
        ".",
        pPathGetApplicationDirectory(),
        pPathGetExternalStoragePath(),
    };

    for (size_t i = 0; i < sizeof(pathList) / sizeof(pathList[0]); ++i)
    {
        if (pathList[i] != P_NULL)
        {
            PString cfgPath = PString(pathList[i]) + PString(pPathGetDelimiter()) + PString(filename);
            PFile *fp = pfopen(cfgPath.c_str(), "rb");
            if (fp != P_NULL)
            {
                if (ini_parse_file((FILE *)(fp), iniHandler_internal, this) < 0)
                {
                    PLOG_ERROR("Failed to parse %s", cfgPath.c_str());
                    pfclose(fp);
                    return false;
                }
                pfclose(fp);

                return true;
            }
        }
    }

    //
    // Look for the ini file in asset
    //
    PAsset asset = pAssetOpen(filename);
    if (pAssetIsValid(&asset))
    {
        PIniBufferObject iniBufferObject;
        iniBufferObject.m_buffer = (const pchar*)pAssetGetBuffer(&asset);
        iniBufferObject.m_bufferSize = pAssetGetSize(&asset);
        iniBufferObject.m_position = 0;
        
        if (ini_parse_buffer(&iniBufferObject, iniHandler_internal, this) < 0)
        {
            PLOG_ERROR("Failed to parse %s", filename);
            pAssetClose(&asset);
            return false;
        }

        pAssetClose(&asset);
        
        return true;
    }

    PLOG_ERROR("Failed to find %s", filename);
    
    return false;
}
Beispiel #5
0
void* server_worker_t::main(void * arg)
{
    conet::init_conet_env();

    server_worker_t *self = (server_worker_t *)(arg);

    if (self->cpu_affinity && CPU_COUNT(self->cpu_affinity) > 0) {
        int ret = 0;
        pthread_t tid = pthread_self();
        ret = pthread_setaffinity_np(tid, sizeof(cpu_set_t), self->cpu_affinity);
        if (ret) {
            PLOG_ERROR("set affinity failed , ", (tid, ret));
        } else {
            PLOG_INFO("set affinity success, ", (tid));
        }
    }

    int size = self->conf.servers_size();

    for (int i=0; i<size; ++i)
    {
        RpcServer const & server_conf = self->conf.servers(i);
        rpc_pb_server_t *rpc_server =  self->build_rpc_server(server_conf);
        if (rpc_server) {
            self->rpc_servers.push_back(rpc_server);
        }
    }

    int ret = 0;
    size = self->rpc_servers.size();
    for (int i=0; i<size; ++i)
    { // 启动server
        ret = self->rpc_servers[i]->start();
        if (ret)
        {
            PLOG_ERROR("error start");
        }
    }

    coroutine_t *exit_co = NULL;

    while (likely(!self->exit_finsished)) 
    {
        if (unlikely(self->stop_flag && exit_co == NULL)) 
        {
            exit_co = conet::alloc_coroutine(
                    conet::ptr_cast<conet::co_main_func_t>(
                        &server_worker_t::proc_server_exit), self);
            conet::resume(exit_co);
        }
        conet::dispatch();
    }
    conet::free_coroutine(exit_co);
    conet::free_conet_env();
    return NULL;
}
Beispiel #6
0
void pMain(int argc, char* argv[])
{
    PASSERT(PActivity::s_activity != P_NULL);

    if (PActivity::s_activity != P_NULL)
    {
        PContextProperties contextProperties;
        contextProperties.m_contextName = PString("background");
        contextProperties.m_archiveName = PString("background.par");
        contextProperties.m_windowWidth = 640;
        contextProperties.m_windowHeight = 480;
#if defined P_WIN32
        contextProperties.m_multisamples = 2;
#endif

        PContext* context = PNEW(MyContext(contextProperties));
		context->addModule(PNEW(PResourceManager(context)));
		context->addModule(PNEW(PSceneManager(context)));
		// More modules
        PActivity::s_activity->addContext(context);
    }
    else
    {
        PLOG_ERROR("No running activity");
    }
}
Beispiel #7
0
int Channel::UnSubscribe(const ISubscriber* subscriber) {
    if (NULL == subscriber) {
        return -1;
    }

    int ret = 0;
    std::map<int64_t, ISubscriber*>::iterator it = m_subscribers.find(subscriber->Id());
    if (it != m_subscribers.end()) {
        m_subscribers.erase(it);
    } else {
        ret = -2;
        PLOG_ERROR("subscriber unexisted(%ld).", subscriber->Id());
    }

    int64_t session_id = const_cast<ISubscriber*>(subscriber)->SessionId();
    if (-1 == session_id) {
        return ret;
    }

    std::map<int64_t, ISubscriber*>::iterator sit = m_sessioned_subscribers.find(session_id);
    if (sit == m_sessioned_subscribers.end()) {
        PLOG_DEBUG("sessioned(%ld) subscriber unexisted.", session_id);
        return -3;
    }

    m_sessioned_subscribers.erase(sit);

    return ret;
}
pbool PPropertyColor::unpack(const pchar *value)
{
    const pchar *p = value;

    pfloat32 r;
    pfloat32 g;
    pfloat32 b;
    pfloat32 a;

    if ((p = pStringUnpackTrimAnnotation(p)) != P_NULL &&
        (p = pStringUnpackFloat(p, &r)) != P_NULL &&
        (p = pStringUnpackFloat(p, &g)) != P_NULL &&
        (p = pStringUnpackFloat(p, &b)) != P_NULL &&
        (p = pStringUnpackFloat(p, &a)) != P_NULL)
    {
        m_r = r;
        m_g = g;
        m_b = b;
        m_a = a;

        return true;
    }
        
    PLOG_ERROR("Failed to unpack a color property called %s", name());
    return false;
}
Beispiel #9
0
int main(int argc, char * argv[])
{
    gflags::ParseCommandLineFlags(&argc, &argv, false); 

    int num = FLAGS_task_num;

    std::vector<ip_port_t> ip_list;
    parse_ip_list(FLAGS_server_addr, &ip_list);
    if (ip_list.empty()) {
        fprintf(stderr, "server_addr:%s, format error!", FLAGS_server_addr.c_str());
        return 1;
    }

    if (prepare_data(FLAGS_data_file.c_str())) {
        PLOG_ERROR("read data failed!");
        return 1;
    }

    tasks = new ::task_t[num];
    for (int i=0; i<num; ++i) {
        tasks[i].ip = ip_list[0].ip;
        tasks[i].port = ip_list[0].port;
        tasks[i].file = FLAGS_data_file;
        tasks[i].co = conet::alloc_coroutine(proc_send, tasks+i);
        tasks[i].data = &g_data;
        resume(tasks[i].co);
    }

    while (g_finish_task_num < FLAGS_task_num) {
        conet::dispatch();
    }

    return 0;
}
pbool PFrameBuffer::createFramebuffer()
{
    // Create framebuffer object.
    m_framebufferObject = PNEW(PGlFramebuffer);
    if (!m_framebufferObject->create(m_width, 
                                     m_height, 
                                     m_colorBufferFormat,
                                     m_depthBufferFormat, 
                                     m_stencilBufferFormat))
    {
        PDELETE(m_framebufferObject);
        PLOG_ERROR("Failed to create framebuffer object %s", m_id);
        return false;
    }

    // Create texture
    if (m_framebufferObject)
    {
        PString textureName;
        if (m_framebufferObject->colorBuffer())
        {
            textureName = m_id;
            textureName += ":color-texture";
            m_colorTexture = PNEW(PTexture(textureName.c_str(), this));
        }
    }

    return true;
}
Beispiel #11
0
void pMain(int argc, char* argv[])
{
    PASSERT(PActivity::s_activity != P_NULL);

    if (PActivity::s_activity != P_NULL)
    {
        PContextProperties contextProperties;
        contextProperties.m_contextName = PString("loadscene");
        contextProperties.m_archiveName = PString("loadscene.par");
#if defined P_WIN32
        contextProperties.m_windowWidth = 480;
        contextProperties.m_windowHeight = 800;
        contextProperties.m_multisamples = 2;
#elif defined P_ANDROID
		 contextProperties.m_windowWidth = 0xffffffff;
        contextProperties.m_windowHeight = 0xffffffff;
#endif

        PContext* context = PNEW(MyContext(contextProperties));
		context->addModule(PNEW(PResourceManager(context)));
		context->addModule(PNEW(PSceneManager(context)));
		// TODO: initialize more modules here.

        PActivity::s_activity->addContext(context);
    }
    else
    {
        PLOG_ERROR("No running activity");
    }
}
Beispiel #12
0
int GlobalChannel::Broadcast() {
    if (m_messages.empty()) {
        return 0;
    }

    int num = 0;
    int ret = 0;
    for (std::map<int64_t, ISubscriber*>::iterator it = m_subscribers.begin();
        it != m_subscribers.end(); ++it) {
        // 向订阅者推送消息
        ret = (it->second)->Push(m_messages.front().m_message, m_messages.front().m_encode_type);
        if (ret != 0) {
            PLOG_ERROR("%s send message failed(%d).", m_name.c_str(), ret);
        }

        num++;
    }

    // 自己产生的广播消息要通知到其他server
    if (m_messages.front().m_forward) {
        num += Notify(m_messages.front().m_message, m_messages.front().m_encode_type);
    }

    m_messages.erase(m_messages.begin());

    return num;
}
Beispiel #13
0
pbool PResourceCache::getImages(const pchar *id, 
                              PImage **out_images, 
                              puint32 *out_numImages)
{
    PCacheObject *imageDataObject = findObject(id);
    if (imageDataObject == P_NULL)
    {
        PTextureCache *cache = PNEW(PTextureCache(this, id));
        if (cache->getNumberOfImages() == 0)
        {
            PLOG_ERROR("Failed to load image data at %s", id);
            PDELETE(cache);
            return false;
        }
        cache->getImages(out_images, out_numImages);
        insertObject(cache);

        return true;
    }
        
    PTextureCache *cache = dynamic_cast<PTextureCache *>(imageDataObject);
    cache->getImages(out_images, out_numImages);

    return true;
}
pbool PNetworkServer::send(PNetworkPeer *peer, const puint8 *message, pint32 length)
{
    if (m_state == NETWORK_CONNECTED)
    {
        PMap<puint32, PNetworkPeer*>::iterator it = m_peers.find(peer->id());
        if (it != m_peers.end())
        {
            if (length == -1)
            {
                m_data->packet->dataLength = pstrlen((const pchar *)message) + 1;
            }
            else
            {
                m_data->packet->dataLength = length;
            }
            
            pmemcpy(m_data->packet->data, message, m_data->packet->dataLength);
            if (enet_peer_send(peer->data()->peer, 0, m_data->packet) < 0)
            {
                PLOG_ERROR("Failed to send message to peer (%d).", peer->id());
                return false;
            }

            return true;
        }
    }

    return false;
}
pbool PDir::makeDirectory(const pchar *path)
{
    if (!mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP))
    {
        if (errno == EEXIST)
        {
            PLOG_ERROR("directory (%s) already exists.", path);
        }
        else if (errno == ENOENT)
        {
            PLOG_ERROR("some intermediate directories in the path (%s) are missing.", path);
        }
        
        return false;
    }

    return true;
}
pbool PDir::makeDirectory(const pchar *path)
{
    if (!CreateDirectoryA(path, NULL))
    {
        DWORD err = GetLastError();
        if (err == ERROR_ALREADY_EXISTS)
        {
            PLOG_ERROR("Directory (%s) already exists.", path);
        }
        else if (err == ERROR_PATH_NOT_FOUND)
        {
            PLOG_ERROR("Some intermediate directories in the path (%s) are missing.", path);
        }
        
        return false;
    }

    return true;
}
Beispiel #17
0
int proc_send(void *arg)
{
    conet::enable_sys_hook();
    conet::enable_pthread_hook();
    task_t *task = (task_t *)(arg);

    int ret = 0;
    EchoReq req;
    EchoResp resp;
    std::string method = FLAGS_cmd_name;
    uint64_t cmd_id = FLAGS_cmd_id;
    std::string errmsg;
    if (!method.empty())
    {
        cmd_id = 0;
    }
    int fd = task->lb->get();
    for (int i=0, len = g_data.size(); i<len; ++i) {
        req.set_msg(*g_data[i]);
        int retcode=0;

        if (fd < 0) break;
        if (cmd_id) {
            ret = conet::rpc_pb_call(fd, cmd_id, &req, &resp, &retcode, &errmsg);
        } else {
            ret = conet::rpc_pb_call(fd, method, &req, &resp, &retcode, &errmsg);
        }

        if (ret) {
            PLOG_ERROR((ret));
            close(fd);
            fd = task->lb->get();
            continue;
        }

        if (retcode)
            PLOG_ERROR("ret_code:",retcode," errmsg ",errmsg," resposne:",resp.DebugString());
    }
    if (fd >= 0) close(fd);
    ++g_finish_task_num;
    return 0;
}
Beispiel #18
0
int Channel::Publish(const char* msg, size_t len, int encode_type, bool forward) {
    if (NULL == msg) {
        PLOG_ERROR("msg is NULL.");
        return -1;
    }

    if (0 == len) {
        PLOG_DEBUG("msg len = 0.");
        return 0;
    }

    if (m_messages.size() >= m_queue_size) {
        PLOG_ERROR("msg queue is full.");
        return -2;
    }

    m_messages.push_back(BroadcastMessage(msg, len, encode_type, forward)); // NOLINT

    return 0;
}
void PAnimationInstance::setTarget(PNode *target, const pchar *propertyName)
{
    m_target = target;
    m_property = m_target->property(propertyName);
    PASSERT(m_property != P_NULL);
    if (m_property == P_NULL)
    {
        PLOG_ERROR("Failed to find such property value (%s) in target", propertyName);
        // Reset the target and value.
        m_target = P_NULL;
    }
}
Beispiel #20
0
void GlobalChannel::Close() {
    Channel::Close();

    // 删除存储数据
    ChannelConfAdapter* conf = ChannelConfAdapter::Instance();
    if (!conf) {
        return;
    }

    int ret = conf->RmvSubInstance(m_name, m_appid);
    if (ret != 0) {
        PLOG_ERROR("%s rmv self(%s) failed(%d).", m_name.c_str(), m_appid.c_str(), ret);
    }

    // 是否需要删除其他client节点?

    ret = conf->CloseChannel(m_name);
    if (ret != 0) {
        PLOG_ERROR("%s close channel failed(%d).", m_name.c_str(), ret);
    }
}
Beispiel #21
0
int GlobalChannel::Subscribe(const ISubscriber* subscriber) {
    if (NULL == subscriber) {
        return -1;
    }
    ISubscriber* sub = const_cast<ISubscriber*>(subscriber);
    // 如果手机侧client,需要注册到zk,不保存本地,否则重复
    if (0 == sub->IsDirectConnect()) {
        // 对同一会话的用户限制,不能重复加入频道
        int64_t session_id = sub->SessionId();
        if (session_id != -1
            && m_sessioned_subscribers.find(session_id) != m_sessioned_subscribers.end()) {
            PLOG_ERROR("session %ld is already existed.", session_id);
            return -2;
        }

        ChannelConfAdapter* conf = ChannelConfAdapter::Instance();
        if (!conf) { return -3; }

        // 非直连节点存储信息格式: name: pipe:addr, value: addr
        std::ostringstream name;
        name << "pipe:" << sub->PeerAddress();
        std::ostringstream value;
        value << sub->PeerAddress();

        int ret = conf->AddSubInstance(m_name, name.str(), value.str());
        if (ret != 0) {
            PLOG_ERROR("add %s to %s failed(%d).", name.str().c_str(), m_name.c_str(), ret);
            return -4;
        }

        if (session_id != -1) {
            m_sessioned_subscribers[session_id] = sub;
        }

        return 0;
    }

    return Channel::Subscribe(subscriber);
}
Beispiel #22
0
void PNode::removeChild(const pchar *name)
{
    PStringMap<PNode *>::iterator it = m_children.find(const_cast<pchar*>(name));
    if (it != m_children.end())
    {
        m_children.erase(it);

        onChildRemoved(it.value());
    }
    else
    {
        PLOG_ERROR("Failed to find the child %s in node %s", name, m_name.toString().c_str());
    }
}
pbool PPropertyInt::unpack(const pchar *value)
{
    pint32 v;

    if ((pStringUnpackInt(value, &v)) != P_NULL) 
    {
        operator=(v);

        return true;
    }
        
    PLOG_ERROR("Failed to unpack an int property called %s", name());
    return false;
}
Beispiel #24
0
void PResourceCache::destroyObject(const pchar *id)
{
    PStringMap<PCacheObject *>::iterator it = m_objects.find(const_cast<pchar*>(id));
    if (it != m_objects.end())
    {
        PCacheObject *object = it.value();
        m_objects.erase(it);
        PDELETE(object);
    }
    else
    {
        PLOG_ERROR("Failed to find the asset called %s", id);
    }
}
Beispiel #25
0
void PNode::addChild(PNode *child)
{
    if (this->child(child->m_name.toString().c_str()) != P_NULL)
    {
        PLOG_ERROR("Cannot add another %s to the parent node %s ",
            m_name.toString().c_str(), child->m_name.toString().c_str());
    }
    else
    {
        pchar *name = const_cast<pchar*>(child->name().c_str());
        m_children.insert(name, child);
        
        onChildAdded(child);
    }
}
Beispiel #26
0
pbool PScene::load(const pchar *path)
{
    PResourceManager *resourceManager = context()->module<PResourceManager>("resource-manager");
    PArchiveFile *archive = resourceManager->archive();
    PInputStream inputStream;
    if (!archive->createInputStream(path, &inputStream))
    {
        PLOG_ERROR("Failed to read scene configuration file at %s", path);
        return false;
    }

    PXmlDocument xmlDocument;
    if (!xmlDocument.parse(inputStream))
    {
        PLOG_ERROR("The syntax is wrong in %s.", path);
        return false;
    }
        
    PXmlElement firstNode = xmlDocument.firstChildElement();

    pbool ret = unpack(&firstNode);

    return ret;
}
Beispiel #27
0
static int ctrl_accept(int ctrl_port, int *num_incidents, struct callbacks *cb,
                       int magic)
{
        char buf[1024], dump[8192], host[NI_MAXHOST], port[NI_MAXSERV];
        struct sockaddr_storage cli_addr;
        socklen_t cli_len;
        int ctrl_conn, s;
        ssize_t len;
retry:
        cli_len = sizeof(cli_addr);
        while ((ctrl_conn = accept(ctrl_port, (struct sockaddr *)&cli_addr,
                                   &cli_len)) == -1) {
                if (errno == EINTR || errno == ECONNABORTED)
                        continue;
                PLOG_FATAL(cb, "accept");
        }
        s = getnameinfo((struct sockaddr *)&cli_addr, cli_len,
                        host, sizeof(host), port, sizeof(port),
                        NI_NUMERICHOST | NI_NUMERICSERV);
        if (s) {
                LOG_ERROR(cb, "getnameinfo: %s", gai_strerror(s));
                strcpy(host, "(unknown)");
                strcpy(port, "(unknown)");
        }
        memset(buf, 0, sizeof(buf));
        while ((len = read(ctrl_conn, buf, sizeof(buf))) == -1) {
                if (errno == EINTR)
                        continue;
                PLOG_ERROR(cb, "read");
                do_close(ctrl_conn);
                goto retry;
        }
        if (memcmp(buf, control_port_secret, SECRET_SIZE) != 0) {
                if (num_incidents)
                        (*num_incidents)++;
                if (hexdump(buf, len, dump, sizeof(dump))) {
                        LOG_WARN(cb, "Invalid secret from %s:%s\n%s", host,
                                 port, dump);
                } else
                        LOG_WARN(cb, "Invalid secret from %s:%s", host, port);
                do_close(ctrl_conn);
                goto retry;
        }
        /* tell client that authentication passes */
        send_magic(ctrl_conn, magic, cb, __func__);
        LOG_INFO(cb, "Control connection established with %s:%s", host, port);
        return ctrl_conn;
}
Beispiel #28
0
puint32 PImage::bpp(PImagePixelFormatEnum pixelFormat)
{
    switch (pixelFormat)
    {
        case P_IMAGE_PIXELFORMAT_RGBA8888: return 4;
        case P_IMAGE_PIXELFORMAT_RGB888: return 3;
        case P_IMAGE_PIXELFORMAT_R8: return 1;
        case P_IMAGE_PIXELFORMAT_LUMINANCE: return 1;
        case P_IMAGE_PIXELFORMAT_COLOR_INDEX: return 1;
        case P_IMAGE_PIXELFORMAT_UNKNOWN: return 0;
        default:
            PLOG_ERROR("Unknown image pixel format");
            return 0;
    }

    return 0;
}
pbool PFrameBuffer::restoreResource()
{
    m_framebufferObject = PNEW(PGlFramebuffer);
    if (!m_framebufferObject->create(m_width, 
                                     m_height, 
                                     m_colorBufferFormat,
                                     m_depthBufferFormat, 
                                     m_stencilBufferFormat))
    {
        PDELETE(m_framebufferObject);
        PLOG_ERROR("Failed to create framebuffer object %s", m_id);
        return false;
    }

    m_colorTexture->restoreResource(const_cast<PGlTexture *>(m_framebufferObject->colorBuffer()));

    return true;
}
Beispiel #30
0
static int ctrl_connect(const char *host, const char *port,
                        struct addrinfo **ai, struct options *opts,
                        struct callbacks *cb)
{
        int ctrl_conn, magic, optval = 1;
        ctrl_conn = try_connect(host, port, ai, opts, cb);
        if (setsockopt(ctrl_conn, IPPROTO_TCP, TCP_NODELAY, &optval,
                       sizeof(optval)))
                PLOG_ERROR(cb, "setsockopt(TCP_NODELAY)");
        while (write(ctrl_conn, control_port_secret, SECRET_SIZE) == -1) {
                if (errno == EINTR)
                        continue;
                PLOG_FATAL(cb, "write");
        }
        /* if authentication passes, server should write back a magic number */
        magic = recv_magic(ctrl_conn, cb, __func__);
        if (magic != opts->magic)
                LOG_FATAL(cb, "magic mismatch: %d != %d", magic, opts->magic);
        return ctrl_conn;
}