int SelectPoll::unregisterFd(SOCKET_FD fd) { KUMA_INFOTRACE("SelectPoll::unregisterFd, fd="<<fd); int max_fd = int(poll_items_.size() - 1); if (fd < 0 || fd > max_fd) { KUMA_WARNTRACE("SelectPoll::unregisterFd, failed, max_fd=" << max_fd); return KUMA_ERROR_INVALID_PARAM; } updateFdSet(fd, 0); int idx = poll_items_[fd].idx; if (fd == max_fd) { poll_items_.pop_back(); } else { poll_items_[fd].fd = INVALID_FD; poll_items_[fd].cb = nullptr; poll_items_[fd].idx = -1; } int last_idx = int(poll_fds_.size() - 1); if (idx > last_idx || -1 == idx) { return KUMA_ERROR_NOERR; } if (idx != last_idx) { std::iter_swap(poll_fds_.begin() + idx, poll_fds_.end() - 1); poll_items_[poll_fds_[idx].fd].idx = idx; } poll_fds_.pop_back(); return KUMA_ERROR_NOERR; }
KMError VPoll::unregisterFd(SOCKET_FD fd) { int max_fd = int(poll_items_.size() - 1); KUMA_INFOTRACE("VPoll::unregisterFd, fd="<<fd<<", max_fd="<<max_fd); if (fd < 0 || -1 == max_fd || fd > max_fd) { KUMA_WARNTRACE("VPoll::unregisterFd, failed, max_fd="<<max_fd); return KMError::INVALID_PARAM; } int idx = poll_items_[fd].idx; if(fd < max_fd) { poll_items_[fd].reset(); } else if (fd == max_fd) { poll_items_.pop_back(); } int last_idx = int(poll_fds_.size() - 1); if (idx > last_idx || -1 == idx) { return KMError::NOERR; } if (idx != last_idx) { std::iter_swap(poll_fds_.begin()+idx, poll_fds_.end()-1); poll_items_[poll_fds_[idx].fd].idx = idx; } poll_fds_.pop_back(); return KMError::NOERR; }
int EPoll::unregisterFd(SOCKET_FD fd) { KUMA_INFOTRACE("EPoll::unregisterFd, fd="<<fd); epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, fd, NULL); if(fd < poll_items_.size()) { poll_items_[fd].fd = INVALID_FD; poll_items_[fd].cb = nullptr; } return KUMA_ERROR_NOERR; }
void HttpParserImpl::onHeaderComplete() { header_complete_ = true; auto it = header_map_.find("Content-Length"); if(it != header_map_.end()) { content_length_ = atoi(it->second.c_str()); has_content_length_ = true; KUMA_INFOTRACE("HttpParser::onHeaderComplete, Content-Length="<<content_length_); } it = header_map_.find("Transfer-Encoding"); if(it != header_map_.end()) { is_chunked_ = is_equal("chunked", it->second); KUMA_INFOTRACE("HttpParser::onHeaderComplete, Transfer-Encoding="<<it->second); } it = header_map_.find("Upgrade"); if(it != header_map_.end()) { upgrade_ = true; KUMA_INFOTRACE("HttpParser::onHeaderComplete, Upgrade="<<it->second); } if(cb_event_) cb_event_(HTTP_HEADER_COMPLETE); }
void EventLoopImpl::loop(uint32_t max_wait_ms) { while (!stop_loop_) { loopOnce(max_wait_ms); } LoopCallback cb; while (cb_queue_.dequeue(cb)) { if (cb) { cb(); } } KUMA_INFOTRACE("EventLoop::loop, stopped"); }
KMError KQueue::wait(uint32_t wait_ms) { timespec tval = { 0, 0 }; if(wait_ms != -1) { tval.tv_sec = wait_ms/1000; tval.tv_nsec = (wait_ms - tval.tv_sec*1000)*1000*1000; } struct kevent kevents[MAX_EVENT_NUM]; int nevents = kevent(kqueue_fd_, 0, 0, kevents, MAX_EVENT_NUM, wait_ms == -1 ? NULL : &tval); if (nevents < 0) { if(errno != EINTR) { KUMA_ERRTRACE("KQueue::wait, errno="<<errno); } KUMA_INFOTRACE("KQueue::wait, nevents="<<nevents<<", errno="<<errno); } else { SOCKET_FD fds[MAX_EVENT_NUM] = { INVALID_FD }; int nfds = 0; int max_fd = int(poll_items_.size() - 1); for (int i=0; i<nevents; ++i) { SOCKET_FD fd = (SOCKET_FD)kevents[i].ident; if(fd >= 0 && fd <= max_fd) { uint32_t revents = 0; if (kevents[i].filter == EVFILT_READ) { revents |= KUMA_EV_READ; } else if (kevents[i].filter == EVFILT_WRITE) { revents |= KUMA_EV_WRITE; } if (kevents[i].flags & EV_ERROR) { revents |= KUMA_EV_ERROR; } if (!revents) { continue; } if (poll_items_[fd].revents == 0) { fds[nfds++] = fd; } poll_items_[fd].revents = revents; } } for (int i=0; i<nfds; ++i) { SOCKET_FD fd = fds[i]; if (fd < poll_items_.size()) { uint32_t revents = poll_items_[fd].revents; poll_items_[fd].revents = 0; IOCallback &cb = poll_items_[fd].cb; if(cb) cb(revents); } } } return KMError::NOERR; }
int EPoll::updateFd(SOCKET_FD fd, uint32_t events) { if(fd >= poll_items_.size() || INVALID_FD == poll_items_[fd].fd) { return KUMA_ERROR_FAILED; } struct epoll_event evt = {0}; evt.data.ptr = (void*)(long)fd; evt.events = get_events(events); if(epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, fd, &evt) < 0) { KUMA_INFOTRACE("EPoll::updateFd error, fd="<<fd<<", errno="<<errno); return KUMA_ERROR_FAILED; } return KUMA_ERROR_NOERR; }
int OpenSslLib::verifyCallback(int ok, X509_STORE_CTX *ctx) { if(NULL == ctx) { return -1; } if(ctx->current_cert) { char *s, buf[1024]; s = X509_NAME_oneline(X509_get_subject_name(ctx->current_cert), buf, sizeof(buf)); if(s != NULL) { if(ok) { KUMA_INFOTRACE("verifyCallback ok, depth="<<ctx->error_depth<<", subject="<<buf); if(X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf, sizeof(buf))) { KUMA_INFOTRACE("verifyCallback, issuer="<<buf); } } else { KUMA_ERRTRACE("verifyCallback failed, depth="<<ctx->error_depth <<", err="<<ctx->error<<", subject="<<buf); } } } if (0 == ok) { KUMA_INFOTRACE("verifyCallback, err="<<X509_verify_cert_error_string(ctx->error)); switch (ctx->error) { //case X509_V_ERR_CERT_NOT_YET_VALID: //case X509_V_ERR_CERT_HAS_EXPIRED: case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: KUMA_INFOTRACE("verifyCallback, ... ignored, err="<<ctx->error); ok = 1; break; } } return ok; }
int SelectPoll::registerFd(SOCKET_FD fd, uint32_t events, IOCallback& cb) { KUMA_INFOTRACE("SelectPoll::registerFd, fd="<<fd); resizePollItems(fd); if (INVALID_FD == poll_items_[fd].fd || -1 == poll_items_[fd].idx) { PollFD pfd; pfd.fd = fd; pfd.events = events; poll_fds_.push_back(pfd); poll_items_[fd].idx = int(poll_fds_.size() - 1); } poll_items_[fd].fd = fd; poll_items_[fd].cb = cb; updateFdSet(fd, events); return KUMA_ERROR_NOERR; }
KMError KQueue::registerFd(SOCKET_FD fd, uint32_t events, IOCallback cb) { if (fd < 0) { return KMError::INVALID_PARAM; } resizePollItems(fd); struct kevent kevents[2]; int nchanges = 0; if (INVALID_FD != poll_items_[fd].fd) { if (!!(poll_items_[fd].events & KUMA_EV_READ) && !(events & KUMA_EV_READ)) { EV_SET(&kevents[nchanges++], fd, EVFILT_READ, EV_DELETE, 0, 0, 0); poll_items_[fd].events &= ~KUMA_EV_READ; } if (!!(poll_items_[fd].events & KUMA_EV_WRITE) && !(events & KUMA_EV_WRITE)) { EV_SET(&kevents[nchanges++], fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0); poll_items_[fd].events &= ~KUMA_EV_WRITE; } ::kevent(kqueue_fd_, kevents, nchanges, 0, 0, 0); if (poll_items_[fd].events == events) { poll_items_[fd].cb = std::move(cb); return KMError::NOERR; } } nchanges = 0; unsigned short op = EV_ADD; if (work_on_et_mode_) { op |= EV_CLEAR; } if (events & KUMA_EV_READ) { EV_SET(&kevents[nchanges++], fd, EVFILT_READ, op , 0, 0, 0); } if (events & KUMA_EV_WRITE) { EV_SET(&kevents[nchanges++], fd, EVFILT_WRITE, op , 0, 0, 0); } poll_items_[fd].fd = fd; poll_items_[fd].events = events; poll_items_[fd].cb = std::move(cb); if(::kevent(kqueue_fd_, kevents, nchanges, 0, 0, 0) == -1) { KUMA_ERRTRACE("KQueue::registerFd error, fd=" << fd << ", ev=" << events << ", errno=" << errno); return KMError::FAILED; } KUMA_INFOTRACE("KQueue::registerFd, fd=" << fd << ", ev=" << events); return KMError::NOERR; }
int EPoll::wait(uint32_t wait_ms) { struct epoll_event events[MAX_EVENT_NUM]; int nfds = epoll_wait(epoll_fd_, events, MAX_EVENT_NUM , wait_ms); if (nfds < 0) { if(errno != EINTR) { KUMA_ERRTRACE("EPoll::wait, errno="<<errno); } KUMA_INFOTRACE("EPoll::wait, epoll_wait, nfds="<<nfds<<", errno="<<errno); } else { for (int i=0; i<nfds; ++i) { SOCKET_FD fd = (SOCKET_FD)(long)events[i].data.ptr; if(fd < poll_items_.size()) { IOCallback &cb = poll_items_[fd].cb; if(cb) cb(get_kuma_events(events[i].events)); } } } return KUMA_ERROR_NOERR; }
int EPoll::registerFd(SOCKET_FD fd, uint32_t events, IOCallback&& cb) { resizePollItems(fd); int epoll_op = EPOLL_CTL_ADD; if (INVALID_FD != poll_items_[fd].fd) { epoll_op = EPOLL_CTL_MOD; } poll_items_[fd].fd = fd; poll_items_[fd].cb = std::move(cb); struct epoll_event evt = {0}; evt.data.ptr = (void*)(long)fd; evt.events = get_events(events);//EPOLLIN | EPOLLOUT | EPOLLERR | EPOLLHUP | EPOLLET; if(epoll_ctl(epoll_fd_, epoll_op, fd, &evt) < 0) { KUMA_ERRTRACE("EPoll::registerFd error, fd=" << fd << ", ev=" << evt.events << ", errno=" << errno); return KUMA_ERROR_FAILED; } KUMA_INFOTRACE("EPoll::registerFd, fd=" << fd << ", ev=" << evt.events); return KUMA_ERROR_NOERR; }
KMError VPoll::registerFd(SOCKET_FD fd, KMEvent events, IOCallback cb) { if (fd < 0) { return KMError::INVALID_PARAM; } resizePollItems(fd); int idx = -1; if (INVALID_FD == poll_items_[fd].fd || -1 == poll_items_[fd].idx) { // new pollfd pfd; pfd.fd = fd; pfd.events = get_events(events); poll_fds_.push_back(pfd); idx = int(poll_fds_.size() - 1); poll_items_[fd].idx = idx; } poll_items_[fd].fd = fd; poll_items_[fd].events = events; poll_items_[fd].cb = std::move(cb); KUMA_INFOTRACE("VPoll::registerFd, fd="<<fd<<", events="<<events<<", index="<<idx); return KMError::NOERR; }
KMError KQueue::unregisterFd(SOCKET_FD fd) { int max_fd = int(poll_items_.size() - 1); KUMA_INFOTRACE("KQueue::unregisterFd, fd="<<fd<<", max_fd="<<max_fd); if (fd < 0 || fd > max_fd) { KUMA_WARNTRACE("KQueue::unregisterFd, failed, max_fd=" << max_fd); return KMError::INVALID_PARAM; } struct kevent kevents[2]; int nchanges = 0; if (poll_items_[fd].events & KUMA_EV_READ) { EV_SET(&kevents[nchanges++], fd, EVFILT_READ, EV_DELETE, 0, 0, 0); } if (poll_items_[fd].events & KUMA_EV_WRITE) { EV_SET(&kevents[nchanges++], fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0); } ::kevent(kqueue_fd_, kevents, nchanges, 0, 0, 0); if(fd < max_fd) { poll_items_[fd].reset(); } else if (fd == max_fd) { poll_items_.pop_back(); } return KMError::NOERR; }
int TcpSocketImpl::bind(const char *bind_host, uint16_t bind_port) { KUMA_INFOTRACE("bind, bind_host="<<bind_host<<", bind_port="<<bind_port); if(getState() != ST_IDLE) { KUMA_ERRXTRACE("bind, invalid state, state="<<getState()); return KUMA_ERROR_INVALID_STATE; } if(fd_ != INVALID_FD) { cleanup(); } sockaddr_storage ss_addr = {0}; struct addrinfo hints = {0}; hints.ai_family = AF_UNSPEC; hints.ai_flags = AI_NUMERICHOST;//AI_ADDRCONFIG; // will block 10 seconds in some case if not set AI_ADDRCONFIG if(km_set_sock_addr(bind_host, bind_port, &hints, (struct sockaddr*)&ss_addr, sizeof(ss_addr)) != 0) { return KUMA_ERROR_INVALID_PARAM; } fd_ = ::socket(ss_addr.ss_family, SOCK_STREAM, 0); if(INVALID_FD == fd_) { KUMA_ERRXTRACE("bind, socket failed, err="<<getLastError()); return KUMA_ERROR_FAILED; } int addr_len = sizeof(ss_addr); #ifdef KUMA_OS_MAC if(AF_INET == ss_addr.ss_family) addr_len = sizeof(sockaddr_in); else addr_len = sizeof(sockaddr_in6); #endif int ret = ::bind(fd_, (struct sockaddr*)&ss_addr, addr_len); if(ret < 0) { KUMA_ERRXTRACE("bind, bind failed, err="<<getLastError()); return KUMA_ERROR_FAILED; } return KUMA_ERROR_NOERR; }
int OpenSslLib::appVerifyCallback(X509_STORE_CTX *ctx, void *arg) { if(!ctx || !arg) { return -1; } int ok = 1; struct app_verify_arg *cb_arg = (struct app_verify_arg *)arg; if (cb_arg->app_verify) { char *s = NULL, buf[256]; if(ctx->cert) { s = X509_NAME_oneline(X509_get_subject_name(ctx->cert), buf, 256); } if(s != NULL) { KUMA_INFOTRACE("appVerifyCallback, depth="<<ctx->error_depth<<", "<<buf); } return 1; } ok = X509_verify_cert(ctx); return ok; }
void EventLoopImpl::stop() { KUMA_INFOTRACE("EventLoop::stop"); stop_loop_ = true; poll_->notify(); }
HttpParserImpl::ParseState HttpParserImpl::parseChunk(const char*& cur_pos, const char* end) { const char* p_line = nullptr; const char* p_end = nullptr; bool b_line = false; while (cur_pos < end) { switch (chunk_state_) { case CHUNK_READ_SIZE: { b_line = getLine(cur_pos, end, p_line, p_end); if(!b_line) {// need more data, save remain data. if(saveData(cur_pos, end) != KUMA_ERROR_NOERR) { return PARSE_STATE_ERROR; } cur_pos = end; return PARSE_STATE_CONTINUE; } std::string str; if(!str_buf_.empty()) { str.swap(str_buf_); clearBuffer(); } str.append(p_line, p_end); // need not parse chunk extension chunk_size_ = (uint32_t)strtol(str.c_str(), NULL, 16); KUMA_INFOTRACE("HttpParser::parseChunk, chunk_size="<<chunk_size_); if(0 == chunk_size_) {// chunk completed chunk_state_ = CHUNK_READ_TRAILER; } else { chunk_bytes_read_ = 0; chunk_state_ = CHUNK_READ_DATA; } break; } case CHUNK_READ_DATA: { uint32_t cur_len = uint32_t(end - cur_pos); if(chunk_size_ - chunk_bytes_read_ <= cur_len) {// data enough const char* notify_data = cur_pos; uint32_t notify_len = chunk_size_ - chunk_bytes_read_; total_bytes_read_ += notify_len; chunk_bytes_read_ = chunk_size_ = 0; // reset chunk_state_ = CHUNK_READ_DATA_CR; cur_pos += notify_len; bool destroyed = false; destroy_flag_ptr_ = &destroyed; if(cb_data_) cb_data_(notify_data, notify_len); if(destroyed) { return PARSE_STATE_DESTROY; } destroy_flag_ptr_ = nullptr; } else {// need more data const char* notify_data = cur_pos; total_bytes_read_ += cur_len; chunk_bytes_read_ += cur_len; cur_pos += cur_len; if(cb_data_) cb_data_(notify_data, cur_len); return PARSE_STATE_CONTINUE; } break; } case CHUNK_READ_DATA_CR: { if(*cur_pos != CR) { KUMA_ERRTRACE("HttpParser::parseChunk, can not find data CR"); read_state_ = HTTP_READ_ERROR; return PARSE_STATE_ERROR; } ++cur_pos; chunk_state_ = CHUNK_READ_DATA_LF; break; } case CHUNK_READ_DATA_LF: { if(*cur_pos != LF) { KUMA_ERRTRACE("HttpParser::parseChunk, can not find data LF"); read_state_ = HTTP_READ_ERROR; return PARSE_STATE_ERROR; } ++cur_pos; chunk_state_ = CHUNK_READ_SIZE; break; } case CHUNK_READ_TRAILER: { b_line = getLine(cur_pos, end, p_line, p_end); if(b_line) { if(p_line == p_end && bufferEmpty()) { // blank line, http completed read_state_ = HTTP_READ_DONE; onComplete(); return PARSE_STATE_DONE; } clearBuffer(); // discard trailer } else { // need more data if(saveData(cur_pos, end) != KUMA_ERROR_NOERR) { return PARSE_STATE_ERROR; } cur_pos = end; // all data was consumed return PARSE_STATE_CONTINUE; } break; } } } return HTTP_READ_DONE == read_state_?PARSE_STATE_DONE:PARSE_STATE_CONTINUE; }
void HttpParserImpl::onComplete() { KUMA_INFOTRACE("HttpParser::onComplete"); if(cb_event_) cb_event_(HTTP_COMPLETE); }