int rpc_start(rpc_t *rpc) { if (!rpc) { RPC_DEBUG("rpc is NULL"); goto fail; } if (!rpc->handler) { RPC_DEBUG("rpc handler is NULL"); goto fail; } if (pthread_create(&rpc->rpc_thread, NULL, do_rpc_thread, rpc)) { RPC_PERROR("pthread_create"); goto fail; } while (!rpc->active) { rpc_cond_wait(rpc); } return 0; fail: return -1; }
static int rpc_recv(struct rpc *rpc) { struct rpc_request_hdr_t hdr; struct rpc_reply_t reply; LOG_ENTRY; memset(&reply, 0, sizeof(reply)); if (rpc_read(rpc->fd, &hdr, sizeof(hdr)) < 0) { RPC_PERROR("rpc_read"); goto fail; } RPC_DEBUG("<<< header code %x", hdr.code); if (rpc->handler(&hdr, &reply)) { RPC_ERROR("failed to handle message"); goto fail; } RPC_DEBUG("<<< handled message %x", hdr.code); if (rpc_write(rpc->fd, &reply, sizeof(reply)) < 0) { RPC_PERROR("rpc_write"); goto fail; } RPC_DEBUG("<<< done with message %x", hdr.code); LOG_EXIT; return 0; fail: return -1; }
/** * @brief wrapper for connect api * * @param ip * @param port * @param timeout_ms * * @return */ int connect_ex(char *ip, unsigned short port, int timeout_ms) { /* create socket */ int fd = socket(PF_INET, SOCK_STREAM, 0); if (-1 == fd) { RPC_WARNING("socket() error, errno=%d", errno); return -1; } RPC_DEBUG("socket created, fd=%d", fd); /* set to nonblock socket */ if (-1 == set_nonblock(fd)) { RPC_WARNING("set_nonblock() error, errno=%d", errno); close(fd); return -1; } /* connect to remote server */ struct sockaddr_in remote_addr; memset(&remote_addr, 0, sizeof(remote_addr)); remote_addr.sin_family = AF_INET; remote_addr.sin_port = htons(port); remote_addr.sin_addr.s_addr = inet_addr(ip); int ret = connect(fd, (struct sockaddr*)&remote_addr, sizeof(remote_addr)); if (0 == ret) { RPC_DEBUG("connect_ex() succ, fd=%d, ip=%s, port=%u", fd, ip, port); return fd; } if (-1 != ret || EINPROGRESS != errno) { RPC_WARNING("connect() error, ret=%d, errno=%d", ret, errno); close(fd); return -1; } /* wait until fd is writable */ ret = wait_for_io(fd, 'o', timeout_ms); if (ret < 0) { RPC_WARNING("wait_for_io() timeout, fd=%d", fd); close(fd); return -1; } /* check socket status */ int socket_res; socklen_t res_len = sizeof(socket_res); if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &socket_res, &res_len) < 0) { RPC_WARNING("getsockopt() error, fd=%d, errno=%d", fd, errno); close(fd); } if (0 != socket_res) { RPC_WARNING("connect() error, remote not available, fd=%d", fd); close(fd); return -1; } RPC_DEBUG("connect_ex() succ, fd=%d, ip=%s, port=%u", fd, ip, port); return fd; }
static void* do_rpc_thread(void *data) { LOG_ENTRY; struct rpc *rpc = data; if (!rpc || !rpc->handler) { RPC_PUTS("bad rpc"); LOG_EXIT; return NULL; } rpc->active = 1; rpc_cond_signal(rpc); fd_set fds; while (rpc->active) { RPC_DEBUG("+loop"); FD_ZERO(&fds); FD_SET(rpc->fd, &fds); FD_SET(rpc->pipefd[READ_END], &fds); select(max(rpc->fd, rpc->pipefd[READ_END]) + 1, &fds, NULL, NULL, NULL); pthread_mutex_lock(&rpc->fd_mutex); if (FD_ISSET(rpc->fd, &fds)) { RPC_DEBUG("receiving RPC message"); if (rpc_recv(rpc) < 0) { RPC_ERROR("receive error"); rpc->active = 0; goto handled; } } if (FD_ISSET(rpc->pipefd[READ_END], &fds)) { RPC_DEBUG("calling remote party"); if (rpc_send(rpc) < 0) { RPC_ERROR("call error"); rpc->active = 0; goto handled; } } handled: pthread_mutex_unlock(&rpc->fd_mutex); RPC_DEBUG("-loop"); } rpc_cond_signal(rpc); LOG_EXIT; return NULL; }
static void xtra_cb_thread_func(void* unused) { LOG_ENTRY; while (pipe_xtra[0] >= 0) { struct rpc_request_hdr_t hdr; memset(&hdr, 0, sizeof(hdr)); if (read(pipe_xtra[READ_END], &hdr, sizeof(hdr)) != sizeof(hdr)) { RPC_ERROR("failed to read request header"); break; } char *buf = hdr.buffer; size_t idx = 0; RPC_DEBUG("%s: request code %d", __func__, hdr.code); switch (hdr.code) { case XTRA_REQUEST_CB: if (xtraCallbacks && xtraCallbacks->download_request_cb) { xtraCallbacks->download_request_cb(); } else { RPC_ERROR("xtraCallbacks == NULL"); } break; } fail: continue; } LOG_EXIT; }
static void ni_cb_thread_func(void* unused) { LOG_ENTRY; while (pipe_ni[0] >= 0) { struct rpc_request_hdr_t hdr; memset(&hdr, 0, sizeof(hdr)); if (read(pipe_ni[READ_END], &hdr, sizeof(hdr)) != sizeof(hdr)) { RPC_ERROR("failed to read request header"); break; } char *buf = hdr.buffer; size_t idx = 0; RPC_DEBUG("%s: request code %d", __func__, hdr.code); switch (hdr.code) { case NI_NOTIFY_CB: if (niCallbacks && niCallbacks->notify_cb) { GpsNiNotification nfy; memset(&nfy, 0, sizeof(nfy)); RPC_UNPACK(buf, idx, nfy); niCallbacks->notify_cb(&nfy); } else { RPC_ERROR("niCallbacks == NULL"); } break; } fail: continue; } LOG_EXIT; }
static void agps_cb_thread_func(void* unused) { LOG_ENTRY; while (pipe_agps[0] >= 0) { struct rpc_request_hdr_t hdr; memset(&hdr, 0, sizeof(hdr)); if (read(pipe_agps[READ_END], &hdr, sizeof(hdr)) != sizeof(hdr)) { RPC_ERROR("failed to read request header"); break; } char *buf = hdr.buffer; size_t idx = 0; RPC_DEBUG("%s: request code %d", __func__, hdr.code); switch (hdr.code) { case AGPS_STATUS_CB: if (aGpsCallbacks && aGpsCallbacks->status_cb) { AGpsStatus status; memset(&status, 0, sizeof(status)); RPC_UNPACK(buf, idx, status); aGpsCallbacks->status_cb(&status); } else { RPC_ERROR("aGpsCallbacks == NULL"); } break; } fail: continue; } LOG_EXIT; }
static int rpc_call_result(rpc_t *rpc, rpc_request_t *req) { LOG_ENTRY; int rc = -1; if (!rpc) { RPC_ERROR("rpc is NULL"); goto fail; } if (!req) { RPC_ERROR("request is NULL"); goto fail; } rc = rpc_call(rpc, req); if (rc < 0) { RPC_ERROR("rpc_call failed %d", rc); goto fail; } RPC_DEBUG("%s: rpc_call done", __func__); size_t idx = 0; RPC_UNPACK(req->reply.buffer, idx, rc); fail: LOG_EXIT; return rc; }
static int agps_data_conn_open(const char *apn) { LOG_ENTRY; struct rpc_request_t req = { .header = { .code = GPS_PROXY_AGPS_DATA_CONN_OPEN, }, }; int rc = -1; char *buf = req.header.buffer; size_t idx = 0; if (!apn) { RPC_DEBUG("%s: apn is NULL", __func__); goto fail; } memset(req.header.buffer, 0, RPC_PAYLOAD_MAX); RPC_PACK_S(buf, idx, apn); req.header.buffer[RPC_PAYLOAD_MAX - 1] = '\0'; rc = rpc_call_result(gps_rpc, &req); fail: LOG_EXIT; return rc; }
/** * @brief wrapper for recv api * * @param fd * @param buf * @param expect_len * @param flags * @param timeout_ms * * @return */ int recv_ex(int fd, char *buf, int expect_len, int flags, int timeout_ms) { int prev_ms = timeout_ms; int recv_len = 0; while (recv_len < expect_len) { unsigned long long prev_msec = get_cur_msec(); int ret = wait_for_io(fd, 'i', timeout_ms); timeout_ms = MAX(0, timeout_ms - (get_cur_msec() - prev_msec)); if (-1 == ret) { /* time expired or error */ RPC_WARNING("wait_for_io() timeout, fd=%d", fd); return -1; } else { /* handle I/O event */ int len = recv(fd, buf + recv_len, expect_len - recv_len, flags); if (len == 0) { RPC_WARNING("client closed socket, fd=%d", fd); return -1; } else if (len < 0) { RPC_WARNING("recv() error, fd=%d, errno=%d", fd, errno); return -1; } else { recv_len += len; } } } RPC_DEBUG("recv_ex() succ, fd=%d, recv_len=%d, cost_ms=%d", fd, recv_len, prev_ms - timeout_ms); return recv_len; }
/** * @brief wrapper for send api * * @param fd * @param buf * @param expect_len * @param flags * @param timeout_ms * * @return */ int send_ex(int fd, char *buf, int expect_len, int flags, int timeout_ms) { int prev_ms = timeout_ms; int send_len = 0; while (send_len < expect_len) { unsigned long long prev_msec = get_cur_msec(); int ret = wait_for_io(fd, 'o', timeout_ms); timeout_ms = MAX(0, timeout_ms - (get_cur_msec() - prev_msec)); if (-1 == ret) { /* time expired or error */ RPC_WARNING("wait_for_io() timeout, fd=%d", fd); return -1; } else { /* handle I/O event */ int len = send(fd, buf + send_len, expect_len - send_len, flags); if (len > 0) { send_len += len; } else { RPC_WARNING("send() error, fd=%d, errno=%d", fd, errno); return -1; } } } RPC_DEBUG("send_ex() succ, fd=%d, send_len=%d, cost_ms=%d", fd, send_len, prev_ms - timeout_ms); return send_len; }
/** * @brief notify process event(multi-threads call) */ void http_event::on_process() { RPC_DEBUG("compute %s", m_head.c_str()); this->set_response(m_head + "\r\n\r\n" + m_body); this->set_io_type('o'); this->set_state("write"); this->set_timeout(RPC_SEND_TIMEOUT); m_svr->add_io_event(this); }
int __rpc_call(struct rpc *rpc, struct rpc_request_t *req, int wait) { int ret = 0; LOG_ENTRY; int done = 0; req->reply_marker = &done; RPC_DEBUG("%s: writing to pipe code=%d", __func__, req->header.code); pthread_mutex_lock(&rpc->pipe_mtx); ret = write(rpc->pipefd[WRITE_END], req, sizeof(rpc_request_t)); pthread_mutex_unlock(&rpc->pipe_mtx); if (ret < 0) { RPC_PERROR("write"); goto fail; } if (!wait) { goto done; } while (!done && rpc->active) { RPC_DEBUG("%s: waiting for reply", __func__); rpc_cond_wait(rpc); } RPC_DEBUG("got reply"); done: ret = 0; if (!done || !rpc->active) { RPC_DEBUG("error"); ret = -1; } fail: LOG_EXIT; return ret; }
static int rpc_send(struct rpc *rpc) { LOG_ENTRY; struct rpc_request_t req; pthread_mutex_lock(&rpc->pipe_mtx); int rc = read(rpc->pipefd[READ_END], &req, sizeof(req)); pthread_mutex_unlock(&rpc->pipe_mtx); if (rc < 0) { RPC_PERROR("read"); goto fail; } RPC_DEBUG(">>> code %x", req.header.code); if (rpc_write(rpc->fd, &req.header, sizeof(rpc_request_hdr_t)) < 0) { RPC_PERROR("rpc_write"); goto fail; } RPC_DEBUG(">>> sent header"); if (rpc_read(rpc->fd, &req.reply, sizeof(rpc_reply_t)) < 0) { RPC_PERROR("rpc_read"); goto fail; } RPC_DEBUG(">>> reply code %x", req.reply.code); if (req.reply_marker) { req.reply_marker[0] = 1; } rpc_cond_signal(rpc); LOG_EXIT; return 0; fail: return -1; }
rpc_t *rpc_alloc(void) { rpc_t *ret = NULL; ret = (rpc_t*)malloc(sizeof(rpc_t)); if (!ret) { RPC_DEBUG("out of memory"); goto fail; } memset(ret, 0, sizeof(rpc_t)); return ret; fail: if (ret) { free(ret); } return NULL; }
static void ril_cb_thread_func(void* unused) { LOG_ENTRY; while (pipe_ril[0] >= 0) { struct rpc_request_hdr_t hdr; memset(&hdr, 0, sizeof(hdr)); if (read(pipe_ril[READ_END], &hdr, sizeof(hdr)) != sizeof(hdr)) { RPC_ERROR("failed to read request header"); break; } char *buf = hdr.buffer; size_t idx = 0; RPC_DEBUG("%s: request code %d", __func__, hdr.code); switch (hdr.code) { case RIL_SET_ID_CB: if (rilCallbacks && rilCallbacks->request_setid) { uint32_t flags; RPC_UNPACK(buf, idx, flags); rilCallbacks->request_setid(flags); } else { RPC_ERROR("rilCallbacks == NULL"); } break; case RIL_REF_LOC_CB: if (rilCallbacks && rilCallbacks->request_refloc) { uint32_t flags; RPC_UNPACK(buf, idx, flags); rilCallbacks->request_refloc(flags); } else { RPC_ERROR("rilCallbacks == NULL"); } break; } fail: continue; } LOG_EXIT; }
/** * @brief notify incoming read head event */ void http_event::on_read_head() { char buf[128] = { 0 }; int len = recv(m_fd, buf, sizeof(buf), 0); if (len == 0) { RPC_WARNING("client closed socket, fd=%d, ip=%s, port=%u", m_fd, m_ip.c_str(), m_port); return; } if (len < 0) { RPC_WARNING("recv() error, fd=%d, errno=%d, ip=%s, port=%u", m_fd, errno, m_ip.c_str(), m_port); return; } //RPC_DEBUG("recv head, fd=%d, read_len=%d", m_fd, len); m_head.append(buf, len); std::size_t pos = m_head.find("\r\n\r\n"); if (pos == std::string::npos) { /* read head not done */ this->set_state("read_head"); m_svr->add_io_event(this); } else { /* read head done */ RPC_DEBUG("read head done, fd=%d", m_fd); m_body = m_head.substr(pos + strlen("\r\n\r\n")); m_head = m_head.substr(0, pos); this->parse_http_head(); if (m_body.size() < m_content_len) { this->set_state("read_body"); m_svr->add_io_event(this); } else { m_body.resize(m_content_len); this->set_state("compute"); this->on_cmplt_pkg(); } } }
static const void *gps_get_extension(const char *name) { if (!name) { RPC_ERROR("%s: name is NULL", __func__); return NULL; } RPC_DEBUG("%s:%s", __func__, name); if (!strcmp(name, GPS_XTRA_INTERFACE)) { return &sGpsXtraInterface; } else if (!strcmp(name, AGPS_INTERFACE)) { return &sAGpsInterface; } else if (!strcmp(name, GPS_NI_INTERFACE)) { return &sGpsNiInterface; } else if (!strcmp(name, AGPS_RIL_INTERFACE)) { return &sRilInterface; } return NULL; }
/** * @brief notify incoming write event */ void http_event::on_write() { int len = send(m_fd, (char*)m_resp_data.data(), m_resp_data.size(), 0); if (len == 0) { RPC_WARNING("send() error, fd=%d, errno=%d, ip=%s, port=%u, forget resp_data?", m_fd, errno, m_ip.c_str(), m_port); return; } if (len < 0) { RPC_WARNING("send() error, fd=%d, errno=%d, ip=%s, port=%u", m_fd, errno, m_ip.c_str(), m_port); return; } //RPC_DEBUG("send, fd=%d, send_len=%d", m_fd, len); m_resp_data = m_resp_data.substr(len); if (m_resp_data.size() > 0) { this->set_state("write"); m_svr->add_io_event(this); } else { RPC_DEBUG("session over, fd=%d", m_fd); } }
/** * @brief parse http head */ void http_event::parse_http_head() { /* parse content length */ m_content_len = 0; char *pos_contlen = strcasestr((char*)m_head.c_str(), "content-length"); if (NULL != pos_contlen) { char *pos_colon = strcasestr(pos_contlen, ":"); if (NULL != pos_colon) { m_content_len = atoi(pos_colon + 1); } } RPC_DEBUG("extracted content_len, fd=%d, content_len=%d", m_fd, m_content_len); /* parse method and uri */ std::string line, method, uri; std::size_t pos_line = m_head.find("\r\n"); if (std::string::npos == pos_line) { line = m_head; } else { line = m_head.substr(0, pos_line); } const char *ch = line.c_str(); for (; *ch != '\0' && *ch != ' '; ++ch) { m_method += *ch; } for (; *ch != '\0' && *ch == ' '; ++ch) { } for (; *ch != '\0' && *ch != ' '; ++ch) { m_uri += *ch; } for (; *ch != '\0' && *ch == ' '; ++ch) { } for (; *ch != '\0' && *ch != ' '; ++ch) { m_version += *ch; } }
/** * @brief dispatch task into thread * * @param evt */ void svr_base::on_dispatch_task(io_event *evt) { int i = rand() % m_thrds_pool.size(); RPC_DEBUG("dispatch task to [%d]", i); m_thrds_pool[i]->add_task(evt); }
/****************************************************************************** * RPC Socket Interface *****************************************************************************/ static void gps_cb_thread_func(void* unused) { while (pipe_gps[0] >= 0) { struct rpc_request_hdr_t hdr; memset(&hdr, 0, sizeof(hdr)); if (read(pipe_gps[READ_END], &hdr, sizeof(hdr)) != sizeof(hdr)) { RPC_ERROR("failed to read request header"); break; } char *buf = hdr.buffer; size_t idx = 0; RPC_DEBUG("%s: request code %d", __func__, hdr.code); switch (hdr.code) { case GPS_LOC_CB: if (gpsCallbacks && gpsCallbacks->location_cb) { GpsLocation location; memset(&location, 0, sizeof(location)); RPC_UNPACK(buf, idx, location); gpsCallbacks->location_cb(&location); } else { RPC_ERROR("gpsCallbacks == NULL"); } break; case GPS_STATUS_CB: if (gpsCallbacks && gpsCallbacks->status_cb) { GpsStatus status; memset(&status, 0, sizeof(status)); RPC_UNPACK(buf, idx, status); gpsCallbacks->status_cb(&status); } else { RPC_ERROR("gpsCallbacks == NULL"); } break; case GPS_SV_STATUS_CB: if (gpsCallbacks && gpsCallbacks->sv_status_cb) { GpsSvStatus status; memset(&status, 0, sizeof(status)); RPC_UNPACK(buf, idx, status); gpsCallbacks->sv_status_cb(&status); } else { RPC_ERROR("gpsCallbacks == NULL"); } break; case GPS_NMEA_CB: if (gpsCallbacks && gpsCallbacks->nmea_cb) { char nmea[RPC_PAYLOAD_MAX] = {}; GpsUtcTime timestamp; int length; RPC_UNPACK(buf, idx, timestamp); RPC_UNPACK(buf, idx, length); RPC_UNPACK_RAW(buf, idx, nmea, length); gpsCallbacks->nmea_cb(timestamp, nmea, length); } else { RPC_ERROR("gpsCallbacks == NULL"); } break; case GPS_SET_CAPABILITIES_CB: if (gpsCallbacks && gpsCallbacks->set_capabilities_cb) { uint32_t caps = 0; RPC_UNPACK(buf, idx, caps); RPC_DEBUG("SET_CAPABILITIEST %x", caps); gpsCallbacks->set_capabilities_cb(caps); } else { RPC_ERROR("gpsCallbacks == NULL"); } break; case GPS_ACQUIRE_LOCK_CB: if (gpsCallbacks && gpsCallbacks->acquire_wakelock_cb) { gpsCallbacks->acquire_wakelock_cb(); } else { RPC_ERROR("gpsCallbacks == NULL"); } break; case GPS_RELEASE_LOCK_CB: if (gpsCallbacks && gpsCallbacks->release_wakelock_cb) { gpsCallbacks->release_wakelock_cb(); } else { RPC_ERROR("gpsCallbacks == NULL"); } break; case GPS_REQUEST_UTC_TIME_CB: if (gpsCallbacks && gpsCallbacks->request_utc_time_cb) { gpsCallbacks->request_utc_time_cb(); } else { RPC_ERROR("gpsCallbacks == NULL"); } break; } fail: continue; } }
int rpc_init(int fd, rpc_handler_t handler, rpc_t *rpc) { if (fd < 0) { RPC_DEBUG("bad fd %d", fd); goto fail; } if (!handler) { RPC_DEBUG("handler is NULL"); goto fail; } if (!rpc) { RPC_DEBUG("rpc is NULL"); goto fail; } if (pthread_mutex_init(&rpc->fd_mutex, NULL)) { RPC_PERROR("init fd mutex"); goto fail; } if (pthread_mutex_init(&rpc->cond_mtx, NULL)) { RPC_PERROR("init condition mutex"); goto fail_cond_mutex; } if (pthread_cond_init(&rpc->cond, NULL)) { RPC_PERROR("init condition"); goto fail_cond; } if (pthread_mutex_init(&rpc->pipe_mtx, NULL)) { RPC_ERROR("init pipe mutex"); goto fail_pipe_mutex; } if (pipe(rpc->pipefd) < 0) { RPC_PERROR("pipe"); goto fail_pipe; } set_nonblocking(rpc->pipefd[WRITE_END]); set_nonblocking(rpc->pipefd[READ_END]); set_nonblocking(fd); rpc->fd = fd; rpc->handler = handler; return 0; fail_pipe: pthread_mutex_destroy(&rpc->pipe_mtx); fail_pipe_mutex: pthread_cond_destroy(&rpc->cond); fail_cond: pthread_mutex_destroy(&rpc->cond_mtx); fail_cond_mutex: pthread_mutex_destroy(&rpc->fd_mutex); fail: return -1; }
int main(int argc, char *argv[]) { const char *ip = NULL; int port = 0; int threads_num = 4; /* command line options */ while (true) { static struct option long_options[] = { { "help", no_argument, 0, 'h'}, { "ip", required_argument, 0, 'i'}, { "port", required_argument, 0, 'p'}, { "threads", required_argument, 0, 't'}, { 0, 0, 0, 0 } }; int option_index = 0; int c = getopt_long(argc, argv, "ht:i:p:", long_options, &option_index); if (-1 == c) { break; } switch (c) { case 'h': usage(argc, argv); exit(0); case 't': threads_num = atoi(optarg); break; case 'i': ip = optarg; break; case 'p': port = atoi(optarg); break; default: usage(argc, argv); exit(0); } } if (0 == port || ip == NULL) { usage(argc, argv); exit(0); } /* start service */ RPC_DEBUG("threads num=%d", threads_num); RPC_INFO("register ip=%s", ip); RPC_INFO("register port=%d", port); signal(SIGINT, signal_proc); signal(SIGTERM, signal_proc); /* initialize server */ $name$_svr *svr = new $name$_svr; if (0 != svr->run(threads_num)) { RPC_WARNING("create threads error"); exit(-1); } if (0 != svr->bind(port)) { RPC_WARNING("bind error"); exit(-1); } /* register information */ if (0 != register_information(DS_IP, DS_PORT, RPC_ID, RPC_NAME, RPC_VERSION, ip, port)) { RPC_WARNING("register error"); } unsigned long long prev_msec = get_cur_msec(); while (running) { svr->run_routine(10); unsigned long long curr_msec = get_cur_msec(); if (curr_msec - prev_msec >= 10 * 1000) { /* update register information every 10 secs */ if (0 != register_information(DS_IP, DS_PORT, RPC_ID, RPC_NAME, RPC_VERSION, ip, port)) { RPC_WARNING("update register information error"); } prev_msec = curr_msec; } } svr->stop(); svr->join(); /* delete */ if (0 != unregister_information(DS_IP, DS_PORT, RPC_ID, RPC_NAME, RPC_VERSION, ip, port)) { RPC_WARNING("unregister error"); } delete svr; RPC_WARNING("server exit"); return 0; }