void call_udpl_epoll(struct sockaddr_in servaddr, unsigned expected_size, unsigned *latency, size_t sender_buf_size) { int sockfd; char buf[BUF_SIZE]; struct timespec start; struct timespec end; int n, i; size_t sent_size=0; size_t max_send_size=0; struct epoll_event ev, events[MAX_EVENTS]; int nfds, epollfd; struct timespec wait_for_server={.tv_sec=0, .tv_nsec=INTERVAL}; assert(sender_buf_size <= BUF_SIZE); nanosleep(&wait_for_server, NULL); sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (setNonblocking(sockfd) != 0) perror("setNonblocking"); epollfd = epoll_create(16); if (epollfd == -1) { perror("epoll_create"); exit(EXIT_FAILURE); } ev.events = EPOLLIN; ev.data.fd = sockfd; // need not care about blocking if (epoll_ctl(epollfd, EPOLL_CTL_ADD, sockfd, &ev) == -1) { perror("epoll_ctl: sockfd"); exit(EXIT_FAILURE); } max_send_size = MIN(MAX_UDP_SIZE, MIN(expected_size, sender_buf_size)); clock_gettime(CLOCK_MONOTONIC, &start); // send something first n = sendton(sockfd, buf, max_send_size, 0, (struct sockaddr *)&servaddr, sizeof(servaddr)); if (n < 0) perror("client sendto"); while (sent_size < expected_size) { nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1); if (nfds == -1) { perror("epoll_pwait"); exit(EXIT_FAILURE); } for (i = 0; i < nfds; ++i) { if (events[i].events & EPOLLIN) { // readable n = Readn(events[i].data.fd, buf, BUF_SIZE); sent_size += n; // only the echoed size is effective if (DEBUG) printf("%u / %u<<<<%u / %u echo rate\n", n, MIN(max_send_size, expected_size - sent_size), sent_size, expected_size); if (sendton(sockfd, buf, MIN(max_send_size, expected_size - sent_size), 0, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) perror("client sendto"); } } } clock_gettime(CLOCK_MONOTONIC, &end); *latency = ((end.tv_sec - start.tv_sec) * 1000000000 + end.tv_nsec - start.tv_nsec) / 2; close(sockfd); } void call_udpt_epoll(struct sockaddr_in servaddr, unsigned expected_size, unsigned *latency, size_t sender_buf_size, size_t *received) { int sockfd; char buf[BUF_SIZE]; struct timespec start; struct timespec end; int n, i, ret; size_t sent_size=0; size_t max_send_size, send_size; struct epoll_event ev, events[MAX_EVENTS]; int nfds, epollfd; struct timespec wait_for_server={.tv_sec=0, .tv_nsec=INTERVAL}; assert(sender_buf_size <= BUF_SIZE); nanosleep(&wait_for_server, NULL); sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (setNonblocking(sockfd) != 0) perror("setNonblocking"); epollfd = epoll_create(16); if (epollfd == -1) { perror("epoll_create"); exit(EXIT_FAILURE); } ev.events = EPOLLIN; ev.data.fd = sockfd; // need not care about blocking if (epoll_ctl(epollfd, EPOLL_CTL_ADD, sockfd, &ev) == -1) { perror("epoll_ctl: sockfd"); exit(EXIT_FAILURE); } max_send_size = MIN(MAX_UDP_SIZE, MIN(expected_size, sender_buf_size)); *received = 0; clock_gettime(CLOCK_MONOTONIC, &start); // when performing throughput, sender needs not to care about receiver while (sent_size < expected_size) { send_size = MIN(max_send_size, expected_size - sent_size); Sendton(sockfd, buf, send_size, 0, (struct sockaddr *)&servaddr, sizeof(servaddr)); if (DEBUG) printf("%u>>>>%u / %u sendto\n", send_size, sent_size, expected_size); sent_size += send_size; } if (DEBUG) printf("client finished throughput sent %u\n", sent_size); // the second while is used to receive multiple reply while (1) { nfds = epoll_wait(epollfd, events, MAX_EVENTS, EPOLL_MILLI_TIMEOUT); if (nfds == -1) { perror("epoll_pwait"); exit(EXIT_FAILURE); } else if (nfds == 0) break; for (i = 0; i < nfds; ++i) { if (events[i].events & EPOLLIN) { // readable while (1) { // since server will respond to every sent packet, there may be multiple responds ret = read(events[i].data.fd, &n, sizeof(int)); if (ret < 0) { if (!((errno == EAGAIN) || (errno == EWOULDBLOCK))) perror("read error other than nonblock read"); break; } else if (ret == 0) // end of file break; else { // single "ack" response contributes a small amount of time clock_gettime(CLOCK_MONOTONIC, &end); *received += n; if (DEBUG) printf("<<<<%u echoed\n", n); } } if (DEBUG) printf("%i / %u ack Received\n", *received, expected_size); } } } *latency = (end.tv_sec - start.tv_sec) * 1000000000 + end.tv_nsec - start.tv_nsec; close(sockfd); } #ifdef CLIENT_MAIN int main(int argc, char**argv) { struct sockaddr_in servaddr; unsigned chunk_size[] = {4, 16, 64, 256, 1024, 4*1024, 16*1024, 64*1024, 256*1024, 512*1024, 32*1024, 48*1024, 96*1024, 128*1024}; //unsigned chunk_size[] = {4, 16, 64, 256, 1024, 4*1024, 16*1024, 32*1024, 64*1024, 96*1024, 128*1024}; unsigned latency, total_time; size_t received; int i; int repeat=1; size_t sender_buf_size=1024; if (argc >= 5) sender_buf_size = atoi(argv[4]); if (argc >= 4) repeat = atoi(argv[3]); if (argc < 3) { printf("usage: [udp|tcp] <IP address> <repeat times> <sender_buf_size=1024>\n"); exit(1); } bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr=inet_addr(argv[2]); servaddr.sin_port=htons(PORT); while (repeat) { if (strcmp(argv[1], "udp") == 0) { printf("SIZE\tUDP latency us\tUDP througput MB/s\tLOST\tLOSS rate%%\n"); for (i=0; i<sizeof(chunk_size) / sizeof(chunk_size[0]); i++) { call_udp(servaddr, 1, chunk_size[i], &latency, NULL); call_udp(servaddr, 0, chunk_size[i], &total_time, &received); printf("%8u\t%8u\t%8.2f\t%8u\t%8.2f\n", chunk_size[i], latency / 1000, chunk_size[i] * 1000000000.0 / total_time / 1024 / 1024, chunk_size[i] - received, (chunk_size[i] - received) * 100.0 / chunk_size[i]); } } else if (strcmp(argv[1], "udpl") == 0) { printf("SIZE\tUDP latency us\tsender_buf_size: %i\n", sender_buf_size); for (i=0; i<sizeof(chunk_size) / sizeof(chunk_size[0]); i++) { call_udpl_epoll(servaddr, chunk_size[i], &latency, sender_buf_size); printf("%8u\t%8u\n", chunk_size[i], latency / 1000); } } else if (strcmp(argv[1], "udpt") == 0) { printf("SIZE\tUDP throughput MB/s\tLOST\tLOSS Rate%%\tsender_buf_size: %i\n", sender_buf_size); for (i=0; i<sizeof(chunk_size) / sizeof(chunk_size[0]); i++) { call_udpt_epoll(servaddr, chunk_size[i], &latency, sender_buf_size, &received); printf("%8u\t%8.2f\t%8u\t%8.2f\n", chunk_size[i], chunk_size[i] * 1000000000.0 / latency / 1024 / 1024, chunk_size[i] - received, (chunk_size[i] - received) * 100.0 / chunk_size[i]); } } else if (strcmp(argv[1], "tcp") == 0) { printf("SIZE\tTCP latency us\tTCP througput MB/s\tLOST\tLOSS rate\n"); for (i=0; i<sizeof(chunk_size) / sizeof(chunk_size[0]); i++) { call_tcp(servaddr, 1, chunk_size[i], &latency, NULL); call_tcp(servaddr, 0, chunk_size[i], &total_time, &received); printf("%8u\t%8u\t%8.2f\t%8u\t%8.2f\n", chunk_size[i], latency / 1000, chunk_size[i] * 1000000000.0 / total_time / 1024 / 1024, chunk_size[i] - received, (chunk_size[i] - received) * 100.0 / chunk_size[i]); } } repeat--; } }
int network_glue(void) { struct sockaddr_in s4; struct sockaddr_in6 s6; struct sockaddr_storage ss; int sfd, s; int efd; struct epoll_event event; socklen_t len; int optval; if (strlen(ip4) > 0) { s4.sin_family = AF_INET; inet_pton(AF_INET, ip4, &(s4.sin_addr)); s4.sin_port = htons(port); memcpy(&ss, &s4, sizeof(s4)); } else if (strlen(ip6) > 0) { s6.sin6_family = AF_INET6; inet_pton(AF_INET6, ip6, &(s6.sin6_addr)); s6.sin6_port = htons(port); memcpy(&ss, &s6, sizeof(s6)); } else { fprintf(stderr, "IPv4/IPv6 unspecified\n"); return EXIT_FAILURE; } sfd = socket(ss.ss_family, SOCK_STREAM, 0); if (sfd == -1) { perror("socket() failed"); return EXIT_FAILURE; } make_socket_non_blocking(sfd); #ifndef WIN32 int one = 1; if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1) { perror("setsockopt() failed"); close(sfd); return EXIT_FAILURE; } #endif if (bind(sfd, (struct sockaddr *)&ss, sizeof(ss)) < 0) { perror("bind() failed"); close(sfd); return EXIT_FAILURE; } if (listen(sfd, num_daemons) < 0) { perror("listen() failed"); close(sfd); return EXIT_FAILURE; } efd = epoll_create1(0); if (efd == -1) { perror("epoll_create() failed"); close(sfd); return EXIT_FAILURE; } event.data.fd = sfd; event.events = EPOLLIN | EPOLLET; // set edge-trigger s = epoll_ctl(efd, EPOLL_CTL_ADD, sfd, &event); if (s == -1) { perror("epoll_ctl(sfd) failed"); close(sfd); return EXIT_FAILURE; } events = calloc(num_daemons, sizeof event); // the event loop while (1) { int n, i; n = epoll_wait(efd, events, num_daemons, -1); for (i = 0; i < n; i++) { if ((events[i].events & EPOLLERR) || (events[i].events & EPOLLHUP) || (!(events[i].events & EPOLLIN))) { // an error has occured on this fd, or the socket is not // ready for reading // (happens when the client closes the connection due to timeout) //fprintf(stderr, "epoll error\n"); st.queries_timeout++; close(events[i].data.fd); continue; } else if (sfd == events[i].data.fd) { // we have a notification on the listening socket, which // means one or more incoming connections. while (1) { struct sockaddr in_addr; socklen_t in_len; int infd; in_len = sizeof in_addr; infd = accept(sfd, &in_addr, &in_len); if (infd == -1) { if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { // we have processed all incoming // connections. break; } else { perror("accept() failed"); break; } } #ifdef CONFIG_VERBOSE char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; s = getnameinfo(&in_addr, in_len, hbuf, sizeof hbuf, sbuf, sizeof sbuf, NI_NUMERICHOST | NI_NUMERICSERV); if (s == 0) { printf("new connection - fd %d, host %s, port %s\n", infd, hbuf, sbuf); } #endif // make the incoming socket non-blocking and add it to the // list of fds to monitor. s = make_socket_non_blocking(infd); if (s == -1) { perror("make_socket_non_blocking(infd) failed"); st.queries_failed++; close(infd); break; } event.data.fd = infd; event.events = EPOLLIN | EPOLLET; s = epoll_ctl(efd, EPOLL_CTL_ADD, infd, &event); if (s == -1) { perror("epoll_ctl(infd) failed"); st.queries_failed++; close(infd); break; } } continue; } else { // data is present on the fd and it's ready to be read if (getsockopt(events[i].data.fd, SOL_SOCKET, SO_ERROR, &optval, &len) == 0) { if (optval == 0) { io_handler(events[i].data.fd); } } } } } close(sfd); return EXIT_SUCCESS; }
void fDns_poll(void) { again: fDns_result = 0; if (eventc == 0) { // fprintf(stderr, "(%s:%s:%i) epoll_wait\n", __FILE__, __func__, __LINE__); rc = epoll_wait (epoll_fd, events, MAXEVENTS, -1); if (rc < 1) { fDns_result = rc; return; } eventc = rc; ec = -1; } // fprintf(stderr, "(%s:%s:%i) eventc: %i \n", __FILE__, __func__, __LINE__, eventc); while (eventc) { ec++; e = events[ec].data.ptr; // fprintf(stderr, "(%s:%s:%i) e->fd: %i, ec: %i \n", __FILE__, __func__, __LINE__, e->fd, ec); if ((events[ec].events & EPOLLERR) || (events[ec].events & EPOLLHUP) || (!(events[ec].events & EPOLLIN))) { /* An error has occured on this fd, or the socket is not ready for reading (why were we notified then?) */ if (e->fd == fDns_socket) { fprintf(stderr, "(%s:%s:%i) e->fd == fDns_socket \n", __FILE__, __func__, __LINE__); } else if (e->fd == fDns_notify_fd) { fprintf(stderr, "(%s:%s:%i) e->fd == fDns_notify_fd\n", __FILE__, __func__, __LINE__); } else { // fprintf(stderr, "(%s:%s:%i) fDns_socket: %i, fDns_inotify_fd %i, epoll_fd: %i, error on: %i\n", __FILE__, __func__, __LINE__, fDns_socket, fDns_inotify_fd, epoll_fd, e->fd); event_delete(e); } eventc--; continue; } else if (e->fd == fDns_notify_fd) { fprintf(stderr, "(%s:%s:%i) fDns_notify_fd... \n", __FILE__, __func__, __LINE__); fDns_notify(); eventc--; continue; } else if (e->fd == fDns_socket) { // fprintf(stderr, "(%s:%s:%i) fDns_socket... \n", __FILE__, __func__, __LINE__); fDns_client_sa_len = sizeof(struct sockaddr_storage); // fprintf(stderr, "(%s:%s:%i) got an tcp connection... \n", __FILE__, __func__, __LINE__); /* We have a notification on the listening socket, which means one or more incoming connections. */ while (1) { event_new->sas_len = sizeof(struct sockaddr_storage); fDns_socket_infd = accept(fDns_socket, (struct sockaddr *) &event_new->sas, &event_new->sas_len); if (fDns_socket_infd == -1) { if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { /* We have processed all incoming connections. */ // fprintf(stderr, "(%s:%s:%i) accepted all incomming connections...\n", __FILE__, __func__, __LINE__); break; } else { fprintf(stderr, "(%s:%s:%i) accept: '%s' \n", __FILE__, __func__, __LINE__, strerror(errno)); break; } } if (event_new->sas_len > sizeof(struct sockaddr_storage)) { fprintf(stderr, "(%s:%s:%i) event_new->sas_len %i > sizeof(struct sockaddr_storage) %lu \n", __FILE__, __func__, __LINE__, event_new->sas_len, sizeof(struct sockaddr_storage)); close(fDns_socket_infd); continue; } rc = fDns_tcp_socket_non_blocking(fDns_socket_infd); if (rc == -1) { close(fDns_socket_infd); continue; } event_new->fd = fDns_socket_infd; event.data.ptr = event_new; event.events = EPOLLIN | EPOLLET; rc = epoll_ctl (epoll_fd, EPOLL_CTL_ADD, fDns_socket_infd, &event); if (rc == -1) { fprintf(stderr, "(%s:%s:%i) epoll_ctl ADD: '%s' \n", __FILE__, __func__, __LINE__, strerror(errno)); close(fDns_socket_infd); continue; } e = event_new; event_new = calloc(1, sizeof(struct event_struct)); if (event_new == NULL) { fprintf(stderr, "(%s:%s:%i) calloc of struct event_struct: '%s' \n", __FILE__, __func__, __LINE__, strerror(errno)); close(fDns_socket_infd); continue; } e->next = event_new; event_new->prev = e; // fprintf(stderr, "(%s:%s:%i) got an connection: %i \n", __FILE__, __func__, __LINE__, fDns_socket_infd); } eventc--; continue; } else { // fprintf(stderr, "(%s:%s:%i) ec: %i, socket: %i\n", __FILE__, __func__, __LINE__, ec, e->fd); done = 0; fDns_bl = 0; while(1) { rc = recv(e->fd, &fDns_br[fDns_bl], FDNS_BUFFER_SIZE - fDns_bl, 0); if (rc == -1) { /* If errno == EAGAIN, that means we have read all data. So go back to the main loop. */ if (errno != EAGAIN) { done = 1; } break; } else if (rc == 0) { /* End of file. The remote has closed the connection. */ // fprintf(stderr, "(%s:%s:%i) rc: %i fDns_bl: %u\n", __FILE__, __func__, __LINE__, rc, fDns_bl); done = 1; break; } else if (rc >= FDNS_BUFFER_SIZE - fDns_bl) { fprintf(stderr, "(%s:%s:%i) rc: %i fDns_bl: %u\n", __FILE__, __func__, __LINE__, rc, fDns_bl); //hony, it is to big for me. done = 1; break; } fDns_bl += rc; // fprintf(stderr, "(%s:%s:%i) rc: %i fDns_bl: %u\n", __FILE__, __func__, __LINE__, rc, fDns_bl); } if (done) { // fprintf(stderr, "(%s:%s:%i) closeing: %i\n", __FILE__, __func__, __LINE__, e->fd); event_delete(e); eventc--; continue; } else { //we now have something in the buffer to process. fDns_result = fDns_bl; fDns_client_sa = &e->sas; fDns_client_sa_len = e->sas_len; fDns_socket_infd = e->fd; eventc--; //we break and will be returing to mainloop() again. break; } } } if (fDns_result == 0) goto again; }
void close_conn( int epoll_fd, int sockfd ) { epoll_ctl( epoll_fd, EPOLL_CTL_DEL, sockfd, 0 ); close( sockfd ); }
int resetEPOLL(int ed, int sd) { epoll_ctl(ed, EPOLL_CTL_DEL, sd, NULL); return 0; }
int main(int argc, const char* argv[]) { struct sockaddr_in sAddr; struct epoll_event ev; struct epoll_event evlist[MAX_EVENTS]; int ready, i; int listensock = 0; int result=0, val = 0; //init epoll if( init_epoll() ){ exit(-1); } printf("epoll instance created success! \n"); //create socket if ( -1 == (listensock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))) { perror("create socket error!"); exit(1); } val = 1; result = setsockopt(listensock, SOL_SOCKET, SO_REUSEADDR, &val,sizeof(val)); if( result < 0 ){ perror("set socket option error!"); exit(1); } sAddr.sin_family = AF_INET; sAddr.sin_port = htons(g_server_port); sAddr.sin_addr.s_addr = INADDR_ANY; //now bind the address and port result = bind(listensock, (struct sockaddr*)&sAddr, sizeof(sAddr)); if ( result < 0 ) { perror("bind error!"); exit(1); } //print server ready info printf("Server get ready at port : %d \n", g_server_port); result = listen(listensock, 5); if( result < 0 ) { perror("listen error!"); exit(1); } setnonblocking(listensock); //set nonblocking ev.events = EPOLLIN|EPOLLET; //edge-trigged ev.data.fd = listensock; if( epoll_ctl(epfd, EPOLL_CTL_ADD, listensock, &ev) == -1 ){ perror("epoll_ctl add error!"); exit(-1); } //now we will epoll_wait the event // while(1) { //Fetch up to MAX_EVENTS items from the ready list //printf("About to epoll_wait() \n"); ready = epoll_wait(epfd, evlist, MAX_EVENTS, -1); if( ready == -1 ){ if( errno == EINTR ){ printf("Get a intr signal!\n"); continue; } else { perror("epoll_wait error!"); exit(-1); } } for(i=0;i<ready;i++){ /* printf("fd=%d, events: %s%s%s%s \n",evlist[i].data.fd, (evlist[i].events & EPOLLIN)? "EPOLLIN ":"", (evlist[i].events & EPOLLOUT)? "EPOLLOUT ":"", (evlist[i].events & EPOLLHUP)? "EPOLLHUP ":"", (evlist[i].events & EPOLLERR)? "EPOLLERR ":""); */ //deal with events if( evlist[i].events & (EPOLLIN|EPOLLPRI) ){ if( evlist[i].data.fd == listensock ){ handle_accept(evlist[i].data.fd); } else { handle_read(evlist[i].data.ptr); } } else if( evlist[i].events & EPOLLOUT){ handle_write(evlist[i].data.ptr); } else if( evlist[i].events &(EPOLLHUP|EPOLLERR)){ printf("Client on descriptor #%d disconnetcted. on epoll_wait() \n", evlist[i].data.fd); close_free_echo_data(evlist[i].data.ptr);//free echo data } }//end of for ready }//end of while return 0; }
int main(int argc, char *argv[]) { int epfd, ready, fd, s, j, numOpenFds; struct epoll_event ev; struct epoll_event evlist[MAX_EVENTS]; char buf[MAX_BUF]; if (argc < 2 || strcmp(argv[1], "--help") == 0) usageErr("%s file...\n", argv[0]); epfd = epoll_create(argc - 1); if (epfd == -1) errExit("epoll_create"); /* Open each file on command line, and add it to the "interest list" for the epoll instance */ for (j = 1; j < argc; j++) { fd = open(argv[j], O_RDONLY); if (fd == -1) errExit("open"); printf("Opened \"%s\" on fd %d\n", argv[j], fd); ev.events = EPOLLIN; /* Only interested in input events */ ev.data.fd = fd; if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1) errExit("epoll_ctl"); } numOpenFds = argc - 1; while (numOpenFds > 0) { /* Fetch up to MAX_EVENTS items from the ready list of the epoll instance */ printf("About to epoll_wait()\n"); ready = epoll_wait(epfd, evlist, MAX_EVENTS, -1); if (ready == -1) { if (errno == EINTR) continue; /* Restart if interrupted by signal */ else errExit("epoll_wait"); } printf("Ready: %d\n", ready); /* Deal with returned list of events */ for (j = 0; j < ready; j++) { printf(" fd=%d; events: %s%s%s\n", evlist[j].data.fd, (evlist[j].events & EPOLLIN) ? "EPOLLIN " : "", (evlist[j].events & EPOLLHUP) ? "EPOLLHUP " : "", (evlist[j].events & EPOLLERR) ? "EPOLLERR " : ""); if (evlist[j].events & EPOLLIN) { s = read(evlist[j].data.fd, buf, MAX_BUF); if (s == -1) errExit("read"); printf(" read %d bytes: %.*s\n", s, s, buf); } else if (evlist[j].events & (EPOLLHUP | EPOLLERR)) { /* After the epoll_wait(), EPOLLIN and EPOLLHUP may both have been set. But we'll only get here, and thus close the file descriptor, if EPOLLIN was not set. This ensures that all outstanding input (possibly more than MAX_BUF bytes) is consumed (by further loop iterations) before the file descriptor is closed. */ printf(" closing fd %d\n", evlist[j].data.fd); if (close(evlist[j].data.fd) == -1) errExit("close"); numOpenFds--; } } } printf("All file descriptors closed; bye\n"); exit(EXIT_SUCCESS); }
int32_t CNetworkUtil::UnregisterEvent( const int32_t epoll_fd, const int32_t fd) { return epoll_ctl( epoll_fd, EPOLL_CTL_DEL, fd, NULL ); }
int Looper::addFd(int fd, int ident, int events, ALooper_callbackFunc callback, void* data) { #if DEBUG_CALLBACKS ALOGD("%p ~ addFd - fd=%d, ident=%d, events=0x%x, callback=%p, data=%p", this, fd, ident, events, callback, data); #endif if (! callback) { if (! mAllowNonCallbacks) { LOGE("Invalid attempt to set NULL callback but not allowed for this looper."); return -1; } if (ident < 0) { LOGE("Invalid attempt to set NULL callback with ident <= 0."); return -1; } } #ifdef LOOPER_USES_EPOLL int epollEvents = 0; if (events & ALOOPER_EVENT_INPUT) epollEvents |= EPOLLIN; if (events & ALOOPER_EVENT_OUTPUT) epollEvents |= EPOLLOUT; { // acquire lock AutoMutex _l(mLock); Request request; request.fd = fd; request.ident = ident; request.callback = callback; request.data = data; struct epoll_event eventItem; memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union eventItem.events = epollEvents; eventItem.data.fd = fd; ssize_t requestIndex = mRequests.indexOfKey(fd); if (requestIndex < 0) { int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem); if (epollResult < 0) { LOGE("Error adding epoll events for fd %d, errno=%d", fd, errno); return -1; } mRequests.add(fd, request); } else { int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, & eventItem); if (epollResult < 0) { LOGE("Error modifying epoll events for fd %d, errno=%d", fd, errno); return -1; } mRequests.replaceValueAt(requestIndex, request); } } // release lock #else int pollEvents = 0; if (events & ALOOPER_EVENT_INPUT) pollEvents |= POLLIN; if (events & ALOOPER_EVENT_OUTPUT) pollEvents |= POLLOUT; wakeAndLock(); // acquire lock struct pollfd requestedFd; requestedFd.fd = fd; requestedFd.events = pollEvents; Request request; request.fd = fd; request.ident = ident; request.callback = callback; request.data = data; ssize_t index = getRequestIndexLocked(fd); if (index < 0) { mRequestedFds.push(requestedFd); mRequests.push(request); } else { mRequestedFds.replaceAt(requestedFd, size_t(index)); mRequests.replaceAt(request, size_t(index)); } mLock.unlock(); // release lock #endif return 1; }
static void do_TCP_epoll(TCP_Server *TCP_server) { #define MAX_EVENTS 16 struct epoll_event events[MAX_EVENTS]; int nfds; while ((nfds = epoll_wait(TCP_server->efd, events, MAX_EVENTS, 0)) > 0) { int n; for (n = 0; n < nfds; ++n) { sock_t sock = events[n].data.u64 & 0xFFFFFFFF; int status = (events[n].data.u64 >> 32) & 0xFFFF, index = (events[n].data.u64 >> 48); if ((events[n].events & EPOLLERR) || (events[n].events & EPOLLHUP)) { switch (status) { case TCP_SOCKET_LISTENING: { //should never happen break; } case TCP_SOCKET_INCOMING: { kill_TCP_connection(&TCP_server->incomming_connection_queue[index]); break; } case TCP_SOCKET_UNCONFIRMED: { kill_TCP_connection(&TCP_server->unconfirmed_connection_queue[index]); break; } case TCP_SOCKET_CONFIRMED: { kill_accepted(TCP_server, index); break; } } continue; } if (!(events[n].events & EPOLLIN)) { continue; } switch (status) { case TCP_SOCKET_LISTENING: { //socket is from socks_listening, accept connection struct sockaddr_storage addr; unsigned int addrlen = sizeof(addr); sock_t sock_new; sock_new = accept(sock, (struct sockaddr *)&addr, &addrlen); int index_new = TCP_server->incomming_connection_queue_index % MAX_INCOMMING_CONNECTIONS; if (!accept_connection(TCP_server, sock_new)) { break; } struct epoll_event ev = { .events = EPOLLIN | EPOLLET, .data.u64 = sock_new | ((uint64_t)TCP_SOCKET_INCOMING << 32) | ((uint64_t)index_new << 48) }; if (epoll_ctl(TCP_server->efd, EPOLL_CTL_ADD, sock_new, &ev) == -1) { kill_TCP_connection(&TCP_server->incomming_connection_queue[index_new]); break; } break; } case TCP_SOCKET_INCOMING: { int index_new; if ((index_new = do_incoming(TCP_server, index)) != -1) { events[n].events = EPOLLIN | EPOLLET; events[n].data.u64 = sock | ((uint64_t)TCP_SOCKET_UNCONFIRMED << 32) | ((uint64_t)index_new << 48); if (epoll_ctl(TCP_server->efd, EPOLL_CTL_MOD, sock, &events[n]) == -1) { kill_TCP_connection(&TCP_server->unconfirmed_connection_queue[index_new]); break; } } break; } case TCP_SOCKET_UNCONFIRMED: { int index_new; if ((index_new = do_unconfirmed(TCP_server, index)) != -1) { events[n].events = EPOLLIN | EPOLLET; events[n].data.u64 = sock | ((uint64_t)TCP_SOCKET_CONFIRMED << 32) | ((uint64_t)index_new << 48); if (epoll_ctl(TCP_server->efd, EPOLL_CTL_MOD, sock, &events[n]) == -1) { //remove from confirmed connections kill_accepted(TCP_server, index_new); break; } } break; } case TCP_SOCKET_CONFIRMED: { do_confirmed_recv(TCP_server, index); break; } } } } #undef MAX_EVENTS } #endif void do_TCP_server(TCP_Server *TCP_server) { unix_time_update(); #ifdef TCP_SERVER_USE_EPOLL do_TCP_epoll(TCP_server); #else do_TCP_accept_new(TCP_server); do_TCP_incomming(TCP_server); do_TCP_unconfirmed(TCP_server); #endif do_TCP_confirmed(TCP_server); }
TCP_Server *new_TCP_server(uint8_t ipv6_enabled, uint16_t num_sockets, uint16_t *ports, uint8_t *public_key, uint8_t *secret_key, Onion *onion) { if (num_sockets == 0 || ports == NULL) return NULL; if (networking_at_startup() != 0) { return NULL; } TCP_Server *temp = calloc(1, sizeof(TCP_Server)); if (temp == NULL) return NULL; temp->socks_listening = calloc(num_sockets, sizeof(sock_t)); if (temp->socks_listening == NULL) { free(temp); return NULL; } #ifdef TCP_SERVER_USE_EPOLL temp->efd = epoll_create1(0); if (temp->efd == -1) { free(temp); return NULL; } #endif uint8_t family; if (ipv6_enabled) { family = AF_INET6; } else { family = AF_INET; } uint32_t i; #ifdef TCP_SERVER_USE_EPOLL struct epoll_event ev; #endif for (i = 0; i < num_sockets; ++i) { sock_t sock = new_listening_TCP_socket(family, ports[i]); if (sock_valid(sock)) { #ifdef TCP_SERVER_USE_EPOLL ev.events = EPOLLIN; ev.data.u64 = sock | ((uint64_t)TCP_SOCKET_LISTENING << 32); if (epoll_ctl(temp->efd, EPOLL_CTL_ADD, sock, &ev) == -1) { continue; } #endif temp->socks_listening[temp->num_listening_socks] = sock; ++temp->num_listening_socks; } } if (temp->num_listening_socks == 0) { free(temp); return NULL; } if (onion) { temp->onion = onion; set_callback_handle_recv_1(onion, &handle_onion_recv_1, temp); } memcpy(temp->public_key, public_key, crypto_box_PUBLICKEYBYTES); memcpy(temp->secret_key, secret_key, crypto_box_SECRETKEYBYTES); bs_list_init(&temp->accepted_key_list, crypto_box_PUBLICKEYBYTES, 8); return temp; }
// Set of threads which talk to client over the connection for doing the needful // processing. Note that once fd is assigned to a thread all the work on that fd // is done by that thread. Fair fd usage is expected of the client. First thread // is special - also does accept [listens for new connections]. It is the only // thread which does it. void * thr_demarshal(void *arg) { cf_socket_cfg *s, *ls; // Create my epoll fd, register in the global list. struct epoll_event ev; int nevents, i, n, epoll_fd; cf_clock last_fd_print = 0; #if defined(USE_SYSTEMTAP) uint64_t nodeid = g_config.self_node; #endif // Early stage aborts; these will cause faults in process scope. cf_assert(arg, AS_DEMARSHAL, CF_CRITICAL, "invalid argument"); s = &g_config.socket; ls = &g_config.localhost_socket; #ifdef USE_JEM int orig_arena; if (0 > (orig_arena = jem_get_arena())) { cf_crash(AS_DEMARSHAL, "Failed to get original arena for thr_demarshal()!"); } else { cf_info(AS_DEMARSHAL, "Saved original JEMalloc arena #%d for thr_demarshal()", orig_arena); } #endif // Figure out my thread index. pthread_t self = pthread_self(); int thr_id; for (thr_id = 0; thr_id < MAX_DEMARSHAL_THREADS; thr_id++) { if (0 != pthread_equal(g_demarshal_args->dm_th[thr_id], self)) break; } if (thr_id == MAX_DEMARSHAL_THREADS) { cf_debug(AS_FABRIC, "Demarshal thread could not figure own ID, bogus, exit, fu!"); return(0); } // First thread accepts new connection at interface socket. if (thr_id == 0) { demarshal_file_handle_init(); epoll_fd = epoll_create(EPOLL_SZ); if (epoll_fd == -1) cf_crash(AS_DEMARSHAL, "epoll_create(): %s", cf_strerror(errno)); memset(&ev, 0, sizeof (ev)); ev.events = EPOLLIN | EPOLLERR | EPOLLHUP; ev.data.fd = s->sock; if (0 > epoll_ctl(epoll_fd, EPOLL_CTL_ADD, s->sock, &ev)) cf_crash(AS_DEMARSHAL, "epoll_ctl(): %s", cf_strerror(errno)); cf_info(AS_DEMARSHAL, "Service started: socket %s:%d", s->addr, s->port); if (ls->sock) { ev.events = EPOLLIN | EPOLLERR | EPOLLHUP; ev.data.fd = ls->sock; if (0 > epoll_ctl(epoll_fd, EPOLL_CTL_ADD, ls->sock, &ev)) cf_crash(AS_DEMARSHAL, "epoll_ctl(): %s", cf_strerror(errno)); cf_info(AS_DEMARSHAL, "Service also listening on localhost socket %s:%d", ls->addr, ls->port); } } else { epoll_fd = epoll_create(EPOLL_SZ); if (epoll_fd == -1) cf_crash(AS_DEMARSHAL, "epoll_create(): %s", cf_strerror(errno)); } g_demarshal_args->epoll_fd[thr_id] = epoll_fd; cf_detail(AS_DEMARSHAL, "demarshal thread started: id %d", thr_id); int id_cntr = 0; // Demarshal transactions from the socket. for ( ; ; ) { struct epoll_event events[EPOLL_SZ]; cf_detail(AS_DEMARSHAL, "calling epoll"); nevents = epoll_wait(epoll_fd, events, EPOLL_SZ, -1); if (0 > nevents) { cf_debug(AS_DEMARSHAL, "epoll_wait() returned %d ; errno = %d (%s)", nevents, errno, cf_strerror(errno)); } cf_detail(AS_DEMARSHAL, "epoll event received: nevents %d", nevents); uint64_t now_ns = cf_getns(); uint64_t now_ms = now_ns / 1000000; // Iterate over all events. for (i = 0; i < nevents; i++) { if ((s->sock == events[i].data.fd) || (ls->sock == events[i].data.fd)) { // Accept new connections on the service socket. int csocket = -1; struct sockaddr_in caddr; socklen_t clen = sizeof(caddr); char cpaddr[64]; if (-1 == (csocket = accept(events[i].data.fd, (struct sockaddr *)&caddr, &clen))) { // This means we're out of file descriptors - could be a SYN // flood attack or misbehaving client. Eventually we'd like // to make the reaper fairer, but for now we'll just have to // ignore the accept error and move on. if ((errno == EMFILE) || (errno == ENFILE)) { if (last_fd_print != (cf_getms() / 1000L)) { cf_info(AS_DEMARSHAL, " warning: hit OS file descript limit (EMFILE on accept), consider raising limit"); last_fd_print = cf_getms() / 1000L; } continue; } cf_crash(AS_DEMARSHAL, "accept: %s (errno %d)", cf_strerror(errno), errno); } // Get the client IP address in string form. if (caddr.sin_family == AF_INET) { if (NULL == inet_ntop(AF_INET, &caddr.sin_addr.s_addr, (char *)cpaddr, sizeof(cpaddr))) { cf_crash(AS_DEMARSHAL, "inet_ntop(): %s (errno %d)", cf_strerror(errno), errno); } } else if (caddr.sin_family == AF_INET6) { struct sockaddr_in6* addr_in6 = (struct sockaddr_in6*)&caddr; if (NULL == inet_ntop(AF_INET6, &addr_in6->sin6_addr, (char *)cpaddr, sizeof(cpaddr))) { cf_crash(AS_DEMARSHAL, "inet_ntop(): %s (errno %d)", cf_strerror(errno), errno); } } else { cf_crash(AS_DEMARSHAL, "unknown address family %u", caddr.sin_family); } cf_detail(AS_DEMARSHAL, "new connection: %s (fd %d)", cpaddr, csocket); // Validate the limit of protocol connections we allow. uint32_t conns_open = g_config.proto_connections_opened - g_config.proto_connections_closed; if (conns_open > g_config.n_proto_fd_max) { if ((last_fd_print + 5000L) < cf_getms()) { // no more than 5 secs cf_warning(AS_DEMARSHAL, "dropping incoming client connection: hit limit %d connections", conns_open); last_fd_print = cf_getms(); } shutdown(csocket, SHUT_RDWR); close(csocket); csocket = -1; continue; } // Set the socket to nonblocking. if (-1 == cf_socket_set_nonblocking(csocket)) { cf_info(AS_DEMARSHAL, "unable to set client socket to nonblocking mode"); shutdown(csocket, SHUT_RDWR); close(csocket); csocket = -1; continue; } // Create as_file_handle and queue it up in epoll_fd for further // communication on one of the demarshal threads. as_file_handle *fd_h = cf_rc_alloc(sizeof(as_file_handle)); if (!fd_h) { cf_crash(AS_DEMARSHAL, "malloc"); } sprintf(fd_h->client, "%s:%d", cpaddr, ntohs(caddr.sin_port)); fd_h->fd = csocket; fd_h->last_used = cf_getms(); fd_h->reap_me = false; fd_h->trans_active = false; fd_h->proto = 0; fd_h->proto_unread = 0; fd_h->fh_info = 0; fd_h->security_filter = as_security_filter_create(); // Insert into the global table so the reaper can manage it. Do // this before queueing it up for demarshal threads - once // EPOLL_CTL_ADD is done it's difficult to back out (if insert // into global table fails) because fd state could be anything. cf_rc_reserve(fd_h); pthread_mutex_lock(&g_file_handle_a_LOCK); int j; bool inserted = true; if (0 != cf_queue_pop(g_freeslot, &j, CF_QUEUE_NOWAIT)) { inserted = false; } else { g_file_handle_a[j] = fd_h; } pthread_mutex_unlock(&g_file_handle_a_LOCK); if (!inserted) { cf_info(AS_DEMARSHAL, "unable to add socket to file handle table"); shutdown(csocket, SHUT_RDWR); close(csocket); csocket = -1; cf_rc_free(fd_h); // will free even with ref-count of 2 } else { // Place the client socket in the event queue. memset(&ev, 0, sizeof(ev)); ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP ; ev.data.ptr = fd_h; // Round-robin pick up demarshal thread epoll_fd and add // this new connection to epoll. int id; while (true) { id = (id_cntr++) % g_demarshal_args->num_threads; if (g_demarshal_args->epoll_fd[id] != 0) { break; } } fd_h->epoll_fd = g_demarshal_args->epoll_fd[id]; if (0 > (n = epoll_ctl(fd_h->epoll_fd, EPOLL_CTL_ADD, csocket, &ev))) { cf_info(AS_DEMARSHAL, "unable to add socket to event queue of demarshal thread %d %d", id, g_demarshal_args->num_threads); pthread_mutex_lock(&g_file_handle_a_LOCK); fd_h->reap_me = true; as_release_file_handle(fd_h); fd_h = 0; pthread_mutex_unlock(&g_file_handle_a_LOCK); } else { cf_atomic_int_incr(&g_config.proto_connections_opened); } } } else { bool has_extra_ref = false; as_file_handle *fd_h = events[i].data.ptr; if (fd_h == 0) { cf_info(AS_DEMARSHAL, "event with null handle, continuing"); goto NextEvent; } cf_detail(AS_DEMARSHAL, "epoll connection event: fd %d, events 0x%x", fd_h->fd, events[i].events); // Process data on an existing connection: this might be more // activity on an already existing transaction, so we have some // state to manage. as_proto *proto_p = 0; int fd = fd_h->fd; if (events[i].events & (EPOLLRDHUP | EPOLLERR | EPOLLHUP)) { cf_detail(AS_DEMARSHAL, "proto socket: remote close: fd %d event %x", fd, events[i].events); // no longer in use: out of epoll etc goto NextEvent_FD_Cleanup; } if (fd_h->trans_active) { goto NextEvent; } // If pointer is NULL, then we need to create a transaction and // store it in the buffer. if (fd_h->proto == NULL) { as_proto proto; int sz; /* Get the number of available bytes */ if (-1 == ioctl(fd, FIONREAD, &sz)) { cf_info(AS_DEMARSHAL, "unable to get number of available bytes"); goto NextEvent_FD_Cleanup; } // If we don't have enough data to fill the message buffer, // just wait and we'll come back to this one. However, we'll // let messages with zero size through, since they are // likely errors. We don't cleanup the FD in this case since // we'll get more data on it. if (sz < sizeof(as_proto) && sz != 0) { goto NextEvent; } // Do a preliminary read of the header into a stack- // allocated structure, so that later on we can allocate the // entire message buffer. if (0 >= (n = cf_socket_recv(fd, &proto, sizeof(as_proto), MSG_WAITALL))) { cf_detail(AS_DEMARSHAL, "proto socket: read header fail: error: rv %d sz was %d errno %d", n, sz, errno); goto NextEvent_FD_Cleanup; } if (proto.version != PROTO_VERSION && // For backward compatibility, allow version 0 with // security messages. ! (proto.version == 0 && proto.type == PROTO_TYPE_SECURITY)) { cf_warning(AS_DEMARSHAL, "proto input from %s: unsupported proto version %u", fd_h->client, proto.version); goto NextEvent_FD_Cleanup; } // Swap the necessary elements of the as_proto. as_proto_swap(&proto); if (proto.sz > PROTO_SIZE_MAX) { cf_warning(AS_DEMARSHAL, "proto input from %s: msg greater than %d, likely request from non-Aerospike client, rejecting: sz %"PRIu64, fd_h->client, PROTO_SIZE_MAX, proto.sz); goto NextEvent_FD_Cleanup; } #ifdef USE_JEM // Attempt to peek the namespace and set the JEMalloc arena accordingly. size_t peeked_data_sz = 0; size_t min_field_sz = sizeof(uint32_t) + sizeof(char); size_t min_as_msg_sz = sizeof(as_msg) + min_field_sz; size_t peekbuf_sz = 2048; // (Arbitrary "large enough" size for peeking the fields of "most" AS_MSGs.) uint8_t peekbuf[peekbuf_sz]; if (PROTO_TYPE_AS_MSG == proto.type) { size_t offset = sizeof(as_msg); // Number of bytes to peek from the socket. // size_t peek_sz = peekbuf_sz; // Peak up to the size of the peek buffer. size_t peek_sz = MIN(proto.sz, peekbuf_sz); // Peek only up to the minimum necessary number of bytes. if (!(peeked_data_sz = cf_socket_recv(fd, peekbuf, peek_sz, 0))) { // That's actually legitimate. The as_proto may have gone into one // packet, the as_msg into the next one, which we haven't yet received. // This just "never happened" without async. cf_detail(AS_DEMARSHAL, "could not peek the as_msg header, expected %zu byte(s)", peek_sz); } if (peeked_data_sz > min_as_msg_sz) { // cf_debug(AS_DEMARSHAL, "(Peeked %zu bytes.)", peeked_data_sz); if (peeked_data_sz > proto.sz) { cf_warning(AS_DEMARSHAL, "Received unexpected extra data from client %s socket %d when peeking as_proto!", fd_h->client, fd); log_as_proto_and_peeked_data(&proto, peekbuf, peeked_data_sz); goto NextEvent_FD_Cleanup; } if (((as_msg*)peekbuf)->info1 & AS_MSG_INFO1_BATCH) { jem_set_arena(orig_arena); } else { uint16_t n_fields = ntohs(((as_msg *) peekbuf)->n_fields), field_num = 0; bool found = false; // cf_debug(AS_DEMARSHAL, "Found %d AS_MSG fields", n_fields); while (!found && (field_num < n_fields)) { as_msg_field *field = (as_msg_field *) (&peekbuf[offset]); uint32_t value_sz = ntohl(field->field_sz) - 1; // cf_debug(AS_DEMARSHAL, "Field #%d offset: %lu", field_num, offset); // cf_debug(AS_DEMARSHAL, "\tvalue_sz %u", value_sz); // cf_debug(AS_DEMARSHAL, "\ttype %d", field->type); if (AS_MSG_FIELD_TYPE_NAMESPACE == field->type) { if (value_sz >= AS_ID_NAMESPACE_SZ) { cf_warning(AS_DEMARSHAL, "namespace too long (%u) in as_msg", value_sz); goto NextEvent_FD_Cleanup; } char ns[AS_ID_NAMESPACE_SZ]; found = true; memcpy(ns, field->data, value_sz); ns[value_sz] = '\0'; // cf_debug(AS_DEMARSHAL, "Found ns \"%s\" in field #%d.", ns, field_num); jem_set_arena(as_namespace_get_jem_arena(ns)); } else { // cf_debug(AS_DEMARSHAL, "Message field %d is not namespace (type %d) ~~ Reading next field", field_num, field->type); field_num++; offset += sizeof(as_msg_field) + value_sz; if (offset >= peeked_data_sz) { break; } } } if (!found) { cf_warning(AS_DEMARSHAL, "Can't get namespace from AS_MSG (peeked %zu bytes) ~~ Using default thr_demarshal arena.", peeked_data_sz); jem_set_arena(orig_arena); } } } else { jem_set_arena(orig_arena); } } else { jem_set_arena(orig_arena); } #endif // Allocate the complete message buffer. proto_p = cf_malloc(sizeof(as_proto) + proto.sz); cf_assert(proto_p, AS_DEMARSHAL, CF_CRITICAL, "allocation: %zu %s", (sizeof(as_proto) + proto.sz), cf_strerror(errno)); memcpy(proto_p, &proto, sizeof(as_proto)); #ifdef USE_JEM // Jam in the peeked data. if (peeked_data_sz) { memcpy(proto_p->data, &peekbuf, peeked_data_sz); } fd_h->proto_unread = proto_p->sz - peeked_data_sz; #else fd_h->proto_unread = proto_p->sz; #endif fd_h->proto = (void *) proto_p; } else { proto_p = fd_h->proto; } if (fd_h->proto_unread > 0) { // Read the data. n = cf_socket_recv(fd, proto_p->data + (proto_p->sz - fd_h->proto_unread), fd_h->proto_unread, 0); if (0 >= n) { if (errno == EAGAIN) { continue; } cf_info(AS_DEMARSHAL, "receive socket: fail? n %d errno %d %s closing connection.", n, errno, cf_strerror(errno)); goto NextEvent_FD_Cleanup; } // Decrement bytes-unread counter. cf_detail(AS_DEMARSHAL, "read fd %d (%d %d)", fd, n, fd_h->proto_unread); fd_h->proto_unread -= n; } // Check for a finished read. if (0 == fd_h->proto_unread) { // It's only really live if it's injecting a transaction. fd_h->last_used = now_ms; thr_demarshal_pause(fd_h); // pause reading while the transaction is in progress fd_h->proto = 0; fd_h->proto_unread = 0; // INIT_TR as_transaction tr; as_transaction_init(&tr, NULL, (cl_msg *)proto_p); cf_rc_reserve(fd_h); has_extra_ref = true; tr.proto_fd_h = fd_h; tr.start_time = now_ns; // set transaction start time tr.preprocessed = false; if (! as_proto_is_valid_type(proto_p)) { cf_warning(AS_DEMARSHAL, "unsupported proto message type %u", proto_p->type); // We got a proto message type we don't recognize, so it // may not do any good to send back an as_msg error, but // it's the best we can do. At least we can keep the fd. as_transaction_demarshal_error(&tr, AS_PROTO_RESULT_FAIL_UNKNOWN); cf_atomic_int_incr(&g_config.proto_transactions); goto NextEvent; } if (g_config.microbenchmarks) { histogram_insert_data_point(g_config.demarshal_hist, now_ns); tr.microbenchmark_time = cf_getns(); } // Check if it's compressed. if (tr.msgp->proto.type == PROTO_TYPE_AS_MSG_COMPRESSED) { // Decompress it - allocate buffer to hold decompressed // packet. uint8_t *decompressed_buf = NULL; size_t decompressed_buf_size = 0; int rv = 0; if ((rv = as_packet_decompression((uint8_t *)proto_p, &decompressed_buf, &decompressed_buf_size))) { cf_warning(AS_DEMARSHAL, "as_proto decompression failed! (rv %d)", rv); cf_warning_binary(AS_DEMARSHAL, proto_p, sizeof(as_proto) + proto_p->sz, CF_DISPLAY_HEX_SPACED, "compressed proto_p"); as_transaction_demarshal_error(&tr, AS_PROTO_RESULT_FAIL_UNKNOWN); cf_atomic_int_incr(&g_config.proto_transactions); goto NextEvent; } // Count the packets. cf_atomic_int_add(&g_config.stat_compressed_pkts_received, 1); // Free the compressed packet since we'll be using the // decompressed packet from now on. cf_free(proto_p); proto_p = NULL; // Get original packet. tr.msgp = (cl_msg *)decompressed_buf; as_proto_swap(&(tr.msgp->proto)); if (! as_proto_wrapped_is_valid(&tr.msgp->proto, decompressed_buf_size)) { cf_warning(AS_DEMARSHAL, "decompressed unusable proto: version %u, type %u, sz %lu [%lu]", tr.msgp->proto.version, tr.msgp->proto.type, tr.msgp->proto.sz, decompressed_buf_size); as_transaction_demarshal_error(&tr, AS_PROTO_RESULT_FAIL_UNKNOWN); cf_atomic_int_incr(&g_config.proto_transactions); goto NextEvent; } } // Security protocol transactions. if (tr.msgp->proto.type == PROTO_TYPE_SECURITY) { as_security_transact(&tr); cf_atomic_int_incr(&g_config.proto_transactions); goto NextEvent; } // Info protocol requests. if (tr.msgp->proto.type == PROTO_TYPE_INFO) { if (as_info(&tr)) { cf_warning(AS_DEMARSHAL, "Info request failed to be enqueued ~~ Freeing protocol buffer"); goto NextEvent_FD_Cleanup; } cf_atomic_int_incr(&g_config.proto_transactions); goto NextEvent; } ASD_TRANS_DEMARSHAL(nodeid, (uint64_t) tr.msgp); // Fast path for batch requests. if (tr.msgp->msg.info1 & AS_MSG_INFO1_BATCH) { as_batch_queue_task(&tr); cf_atomic_int_incr(&g_config.proto_transactions); goto NextEvent; } // Either process the transaction directly in this thread, // or queue it for processing by another thread (tsvc/info). if (0 != thr_tsvc_process_or_enqueue(&tr)) { cf_warning(AS_DEMARSHAL, "Failed to queue transaction to the service thread"); goto NextEvent_FD_Cleanup; } else { cf_atomic_int_incr(&g_config.proto_transactions); } } // Jump the proto message free & FD cleanup. If we get here, the // above operations went smoothly. The message free & FD cleanup // job is handled elsewhere as directed by // thr_tsvc_process_or_enqueue(). goto NextEvent; NextEvent_FD_Cleanup: // If we allocated memory for the incoming message, free it. if (proto_p) { cf_free(proto_p); fd_h->proto = 0; } // If fd has extra reference for transaction, release it. if (has_extra_ref) { cf_rc_release(fd_h); } // Remove the fd from the events list. if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, 0) < 0) { cf_crash(AS_DEMARSHAL, "unable to remove socket FD %d from epoll instance FD %d: %d (%s)", fd, epoll_fd, errno, cf_strerror(errno)); } pthread_mutex_lock(&g_file_handle_a_LOCK); fd_h->reap_me = true; as_release_file_handle(fd_h); fd_h = 0; pthread_mutex_unlock(&g_file_handle_a_LOCK); NextEvent: ; } // We should never be canceled externally, but just in case... pthread_testcancel(); } } return NULL; }
void CepollServer::Run() { // static struct epoll_event event,events[EPOLL_SIZE]; while(true) { int epoll_events_count = epoll_wait(m_efd,events,EPOLL_SIZE,-1); for(int i=0;i<epoll_events_count;i++) { int userfd = events[i].data.fd; if(userfd==m_listenfd)//new user { sockaddr_in userAddr; socklen_t userAddr_len = sizeof(userAddr); int newuserfd = accept(m_listenfd,(sockaddr*)&userAddr,&userAddr_len); printf("client connection from: %s:% d userfd = %d \n", inet_ntoa(userAddr.sin_addr), ntohs(userAddr.sin_port), newuserfd); char name[255]={0}; read(newuserfd,name,sizeof(name)-1); user_fd_map.insert(make_pair(name,newuserfd)); addfd(newuserfd,name); } else if(events[i].events&EPOLLIN) { char buf[1024]={0}; string strbuf; int counter=0; while(true) { counter = read(userfd,buf,sizeof(buf)); if(counter<0) break; strbuf.append(buf,counter); memset(buf,0,sizeof(buf)); if(counter<sizeof(buf)) { break; } } if(counter==-1) { if(errno==EAGAIN||errno==EWOULDBLOCK) { continue;//buf is empty } else { perror("read failed!"); } } if(counter==0) { cout<<"connect is disconnecting!"<<endl; close(userfd); epoll_ctl(m_efd,EPOLL_CTL_DEL,userfd,&events[i]); continue; } //cout<<"receive buf: "<<strbuf<<endl; auto fromfd = strbuf.find_last_of("-"); auto tofd = strbuf.find_first_of("-"); auto iter =user_fd_map.find(strbuf.substr(0,tofd)); //cout<<tofd->second<<endl; if(iter!=user_fd_map.end()) { //string s = strbuf.substr(tofd+1,fromfd-1); strbuf = strbuf.substr(fromfd+1)+"--say-you->: "+strbuf.substr(tofd+1,fromfd-tofd-1); fd_msg_map.insert(make_pair(iter->second,strbuf)); event.data.fd=iter->second; event.events = EPOLLOUT | EPOLLET; epoll_ctl(m_efd,EPOLL_CTL_MOD,event.data.fd,&event); } else//unknown user { //TODO: //strbuf clear; strbuf.clear(); } } else if(events[i].events&EPOLLOUT) { char buf[255]={0}; auto a = fd_msg_map.find(userfd); string strtemp;//deal message if(a!=fd_msg_map.end()) { strtemp = a->second; strcpy(buf,strtemp.c_str()); fd_msg_map.erase(a); int pos=0; int need_be_write_count=sizeof(buf); int counter; while(1) { counter = write(userfd,buf+pos,sizeof(buf)-pos); if(counter<0) break; if(counter<need_be_write_count) { pos+=counter; need_be_write_count-=counter; } else { break;//write complete; } } if(counter==-1) { if(errno==EAGAIN||errno==EWOULDBLOCK) { continue;//buf is full } } if(counter==0) { cout<<"client close"<<endl; close(userfd); epoll_ctl(m_efd,EPOLL_CTL_DEL,userfd,&events[i]); continue; } } event.data.fd = userfd; event.events = EPOLLIN | EPOLLET; epoll_ctl(m_efd,EPOLL_CTL_MOD,userfd,&event); } } } }
int serverStart() { int pid = fork(); if(pid ==0 ){ return 0; } int serverFd; //创建服务器fd serverFd = socket(PF_INET, SOCK_STREAM, 0); setnonblocking(serverFd); //创建epoll,并把serverFd放入监听队列 int epFd = epoll_create(EPOLL_SIZE); struct epoll_event ev, evs[EVENT_ARR]; ev.data.fd = serverFd; ev.events = EPOLLIN | EPOLLET; epoll_ctl(epFd, EPOLL_CTL_ADD, serverFd, &ev); //绑定服务器端口 struct sockaddr_in serverAddr; socklen_t serverLen = sizeof (struct sockaddr); serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); serverAddr.sin_port = htons(PORT); serverAddr.sin_family = AF_INET; // if (bind(serverFd, (struct sockaddr *) &serverAddr, sizeof (struct sockaddr))== -1) { // perror("bind"); // exit(1); // } if (bind(serverFd, (struct sockaddr *) &serverAddr, sizeof (struct sockaddr)) == -1) { printf("bind() fail:%s.\n", strerror(errno)); exit(-1); } else { printf("bind() success.\n"); } //打开监听 if (listen(serverFd, BACK_QUEUE)) { printf("Listen fail.\n"); exit(-1); } else { printf("listen() success.\n"); } //死循环处理 int clientFd; struct sockaddr_in clientAddr; socklen_t clientLen; char buf[BUF_SIZE]; while (1) { //等待epoll事件的到来,最多取EVENT_ARR个事件 int nfds = epoll_wait(epFd, evs, EVENT_ARR, 2); //处理事件 for (int i = 0; i < nfds; i++) { if (evs[i].data.fd == serverFd && evs[i].data.fd & EPOLLIN) { //如果是serverFd,表明有新连接连入 if ((clientFd = accept(serverFd, (struct sockaddr *) &clientAddr, &clientLen)) < 0) { printf("accept fail.\n"); } printf("Connect from %s:%d\n", inet_ntoa(clientAddr.sin_addr),htons(clientAddr.sin_port)); setnonblocking(clientFd); //注册accept()到的连接 ev.data.fd = clientFd; ev.events = EPOLLIN | EPOLLET; epoll_ctl(epFd, EPOLL_CTL_ADD, clientFd, &ev); } else if (evs[i].events & EPOLLIN) { //如果不是serverFd,则是client的可读 if ((clientFd = evs[i].data.fd) > 0) { int len = handle_message(clientFd); //先进行试探性读取 //int len = read(clientFd, buf, BUF_SIZE); if (len > 0) { continue; } else if (len == 0) { //出发了EPOLLIN事件,却没有可以读取的,表示断线 printf("Client closed at %d\n", clientFd); epoll_ctl(epFd, EPOLL_CTL_DEL, clientFd, &ev); close(clientFd); evs[i].data.fd = -1; break; } else if (len == EAGAIN) { continue; } else { //client读取出错 printf("read() fail."); } } } else { printf("other event.\n"); } } } return 0; }
int handle_read(void* p) { int nread = 0, be_close = 0; struct epoll_event ev; struct echo_data* ptr = (struct echo_data*)p; int fd = ptr->fd; char* buf = ptr->rptr; char ch; int unused = 0; //already full, return. and in write mode, to change the trigger if( ptr->wptr > ptr->rptr ){//unused space! unused = ptr->wptr - ptr->rptr -1; //one byte not used! } else { unused = ptr->size - (ptr->rptr - ptr->buffer) ; if( ptr->wptr == ptr->buffer ){ unused -= 1; //last one byte not used! } } buf = ptr->rptr; //printf("read -->\n"); while(unused>0){ nread = recv(fd, buf, unused, 0); if( nread == -1 ) { //error occur if( (errno == EAGAIN) || (errno == EWOULDBLOCK) ) { //no more data to read! //printf("\n ----> \n"); } else{ perror("recv error!"); //return -1; be_close = 1; //error! } break; } else if( nread ==0 ){//peer already close be_close = 1; //use to write , so do not close it! //printf("recv() and get peer closed!\n "); break; } else { ch = buf[nread-1]; buf[nread-1] = '\0'; printf("%s%c",buf,ch); buf[nread-1] = ch; //adjuct rptr if( ptr->rptr + nread >= ptr->buffer + ptr->size ){ ptr->rptr = ptr->buffer; } else { ptr->rptr += nread; } buf = ptr->rptr; // if( ptr->wptr > ptr->rptr ){ unused = ptr->wptr - ptr->rptr -1; //one byte not used! } else { unused = ptr->size - (ptr->rptr - ptr->buffer); if( ptr->wptr == ptr->buffer ){ unused -= 1; //last one byte not used! } } } }; //end of while if( be_close ) { printf("Client with descriptor #%d disconnected! in recv() \n",fd); close_free_echo_data(ptr); //epoll_ctl(epfd, EPOLL_CTL_DEL,fd,NULL); //close will automatically remove it from epoll instance! } else { ev.data.ptr = ptr; ev.events = EPOLLOUT|EPOLLET; if( unused > 0 ){ ev.events |= (EPOLLIN|EPOLLPRI); //can read more! } if( -1 == epoll_ctl(epfd, EPOLL_CTL_MOD, fd,&ev)) { perror("epoll_ctl mod error"); return -1; } } return 0; }
Looper::Looper(bool allowNonCallbacks) : mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false), mResponseIndex(0), mNextMessageUptime(LLONG_MAX) { int wakeFds[2]; int result = pipe(wakeFds); LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno); mWakeReadPipeFd = wakeFds[0]; mWakeWritePipeFd = wakeFds[1]; result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK); LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d", errno); result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK); LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d", errno); #ifdef LOOPER_USES_EPOLL // Allocate the epoll instance and register the wake pipe. mEpollFd = epoll_create(EPOLL_SIZE_HINT); LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d", errno); struct epoll_event eventItem; memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union eventItem.events = EPOLLIN; eventItem.data.fd = mWakeReadPipeFd; result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem); LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d", errno); #else // Add the wake pipe to the head of the request list with a null callback. struct pollfd requestedFd; requestedFd.fd = mWakeReadPipeFd; requestedFd.events = POLLIN; mRequestedFds.push(requestedFd); Request request; request.fd = mWakeReadPipeFd; request.callback = NULL; request.ident = 0; request.data = NULL; mRequests.push(request); mPolling = false; mWaiters = 0; #endif #ifdef LOOPER_STATISTICS mPendingWakeTime = -1; mPendingWakeCount = 0; mSampledWakeCycles = 0; mSampledWakeCountSum = 0; mSampledWakeLatencySum = 0; mSampledPolls = 0; mSampledZeroPollCount = 0; mSampledZeroPollLatencySum = 0; mSampledTimeoutPollCount = 0; mSampledTimeoutPollLatencySum = 0; #endif }
int handle_write(void* p) { int be_close = 0; struct echo_data* ptr = (struct echo_data*)p; struct epoll_event ev; int nwrite = 0, ntotal=0; char *ptrCur; int fd = ptr->fd; if( NULL == p ) return -1; ptrCur = ptr->wptr; if( ptr->wptr < ptr->rptr ){ ntotal = ptr->rptr - ptr->wptr; } else { ntotal = ptr->size - (ptr->wptr - ptr->buffer); ntotal %= ptr->size; //avoid empty! } //printf("write --> ntotal = %d\n",ntotal); while(ntotal>0){ nwrite = send(fd, ptrCur, ntotal, 0); if( nwrite == -1 ) {//no more to write! if( (errno == EAGAIN) || (errno == EWOULDBLOCK) ){ //printf("\n ---->\n"); //break; } else { perror("send error!"); //return -1; be_close = 1; } break; } if( ptr->wptr + nwrite >= ptr->buffer + ptr->size ){ ptr->wptr = ptr->buffer; //move to first } else { ptr->wptr += nwrite; } ptrCur = ptr->wptr; //move forward to write! if( ptr->wptr == ptr->rptr ){ ntotal = 0; }else if( ptr->wptr < ptr->rptr ){ ntotal = ptr->rptr - ptr->wptr; } else { ntotal = ptr->size - (ptr->wptr - ptr->buffer); ntotal %= ptr->size; } }//end of while if( be_close ){ close_free_echo_data(ptr); printf("Client with descriptor #%d disconnected! error in send() \n",fd); } else { ev.data.ptr = ptr; ev.events = EPOLLIN|EPOLLPRI|EPOLLET; //edge trigger if( ntotal > 0){ //can write again! ev.events |= EPOLLOUT; } if( -1 == epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &ev) ){ perror("epoll_ctl mod read error"); return -1; } } return 0; }
int main(int argc, char **argv) { struct sockaddr_in serv_addr; /* Local address */ struct sockaddr_in client_addr; /* Client address */ unsigned short server_port; /* Server port */ unsigned int client_len; /* Length of client address data structure */ int server_fd; int client_fd; int output_fd; int i; int efd; struct epoll_event e; struct epoll_event *events; int flags; if (argc != 2) /* Test for correct number of arguments */ { //fprintf(stderr, "Usage: %s <Server Port>\n", argv[0]); exit(1); } server_port = atoi(argv[1]); /* First arg: local port */ /* Open up the output file, which is supposed to be a mess */ output_fd = open(OUTPUT_FILE, O_WRONLY|O_CREAT, 0644); if (output_fd == -1) { return 1; } /* Create socket for incoming connections */ if ((server_fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { return 1; } memset(&serv_addr, 0, sizeof(serv_addr)); /* Zero out structure */ serv_addr.sin_family = AF_INET; /* Internet address family */ serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */ serv_addr.sin_port = htons(server_port); /* Local port */ if (bind(server_fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { return 1; } /* Must make the listening socket to be non-blocking */ if (flags = fcntl(server_fd, F_GETFL, 0) == -1) { //perror("fcntl error"); return 1; } flags |= O_NONBLOCK; if (fcntl(server_fd, F_SETFL, flags) == -1) { //perror("fcntl error"); return 1; } if (listen(server_fd, 30) < 0) { return 1; } efd = epoll_create1(0); /* Create epoll fd */ if (efd == -1) { //perror("epoll_create error"); return 1; } e.data.fd = server_fd; /* Register the listening socket */ e.events = EPOLLIN; if (epoll_ctl(efd, EPOLL_CTL_ADD, server_fd, &e) == -1) { //perror("epoll_ctl error"); return 1; } events = malloc(MAX_EVENTS * sizeof(struct epoll_event)); client_len = sizeof(client_addr); for (;;) { int n, i; n = epoll_wait(efd, events, MAX_EVENTS, -1); //printf("%d events are here\n", n); for (i = 0; i < n; i++) { if ((events[i].events & EPOLLERR) || (events[i].events & EPOLLHUP) || (!(events[i].events & EPOLLIN))) { /* The epoll has gone wrong */ //printf("wrong %d\n", events[i].events); close(events[i].data.fd); } else if (events[i].data.fd == server_fd) { /* The listening socket is ready */ //printf("accept event on %d\n", i); if ((client_fd = accept(server_fd, (struct sockaddr *) &client_addr, &client_len)) < 0) { return 1; } /* Must make the socket to be non-blocking */ if (flags = fcntl(client_fd, F_GETFL, 0) == -1) { //perror("fcntl error"); return 1; } flags |= O_NONBLOCK; if (fcntl(client_fd, F_SETFL, flags) == -1) { //perror("fcntl error"); return 1; } /* Register the client socket */ e.data.fd = client_fd; e.events = EPOLLIN | EPOLLET; if (epoll_ctl(efd, EPOLL_CTL_ADD, client_fd, &e) == -1) { //perror("epoll_ctl error"); return 1; } } else { //printf("read event on %d\n", i); /* Finally a socket is ready to read */ int nr = 0; int fd; char buf[256]; fd = events[i].data.fd; do { nr = read(fd, buf, sizeof(buf)); write(output_fd, buf, nr); } while (nr > 0); epoll_ctl(efd, EPOLL_CTL_DEL, fd, &events[i]); } } } free(events); close(server_fd); return 0; }
ph_result_t ph_nbio_emitter_apply_io_mask( struct ph_nbio_emitter *emitter, ph_job_t *job, ph_iomask_t mask) { struct epoll_event evt; int res; int want_mask; if (job->fd == -1) { return PH_OK; } switch (mask & (PH_IOMASK_READ|PH_IOMASK_WRITE)) { case PH_IOMASK_READ|PH_IOMASK_WRITE: want_mask = EPOLLIN|EPOLLOUT|DEFAULT_POLL_MASK; break; case PH_IOMASK_READ: want_mask = EPOLLIN|DEFAULT_POLL_MASK; break; case PH_IOMASK_WRITE: want_mask = EPOLLOUT|DEFAULT_POLL_MASK; break; case 0: default: want_mask = 0; break; } if (want_mask == 0) { job->mask = 0; job->kmask = 0; res = epoll_ctl(emitter->io_fd, EPOLL_CTL_DEL, job->fd, &evt); if (res < 0 && errno == ENOENT) { res = 0; } } else { int op = job->kmask ? EPOLL_CTL_MOD : EPOLL_CTL_ADD; evt.events = want_mask; evt.data.ptr = job; // Set the masks on the job before we epoll_ctl as it // may arrive at another thread *before* epoll_ctl returns job->kmask = want_mask; job->mask = mask; res = epoll_ctl(emitter->io_fd, op, job->fd, &evt); if (res == -1 && errno == EEXIST && op == EPOLL_CTL_ADD) { // This can happen when we're transitioning between distinct job // pointers, for instance, when we're moving from an async connect // to setting up the sock job res = epoll_ctl(emitter->io_fd, EPOLL_CTL_MOD, job->fd, &evt); } else if (res == -1 && errno == ENOENT && op == EPOLL_CTL_MOD) { res = epoll_ctl(emitter->io_fd, EPOLL_CTL_ADD, job->fd, &evt); } if (res == -1 && errno == EEXIST) { res = 0; } } if (res == -1) { ph_log(PH_LOG_ERR, "fd=%d (callback=%p) epoll_ctl: setting mask to %02x -> %d `Pe%d", job->fd, (void*)(uintptr_t)job->callback, mask, errno, errno); ph_log_stacktrace(PH_LOG_ERR); return PH_ERR; } return PH_OK; }
status_t EventHub::openDeviceLocked(const char *devicePath) { char buffer[80]; ALOGV("Opening device: %s", devicePath); int fd = open(devicePath, O_RDWR); if(fd < 0) { ALOGE("could not open %s, %s\n", devicePath, strerror(errno)); return -1; } InputDeviceIdentifier identifier; // Get device name. if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) { //fprintf(stderr, "could not get device name for %s, %s\n", devicePath, strerror(errno)); } else { buffer[sizeof(buffer) - 1] = '\0'; identifier.name.setTo(buffer); } // Check to see if the device is on our excluded list for (size_t i = 0; i < mExcludedDevices.size(); i++) { const String8& item = mExcludedDevices.itemAt(i); if (identifier.name == item) { ALOGI("ignoring event id %s driver %s\n", devicePath, item.string()); close(fd); return -1; } } // Get device driver version. int driverVersion; if(ioctl(fd, EVIOCGVERSION, &driverVersion)) { ALOGE("could not get driver version for %s, %s\n", devicePath, strerror(errno)); close(fd); return -1; } // Get device identifier. struct input_id inputId; if(ioctl(fd, EVIOCGID, &inputId)) { ALOGE("could not get device input id for %s, %s\n", devicePath, strerror(errno)); close(fd); return -1; } identifier.bus = inputId.bustype; identifier.product = inputId.product; identifier.vendor = inputId.vendor; identifier.version = inputId.version; // Get device physical location. if(ioctl(fd, EVIOCGPHYS(sizeof(buffer) - 1), &buffer) < 1) { //fprintf(stderr, "could not get location for %s, %s\n", devicePath, strerror(errno)); } else { buffer[sizeof(buffer) - 1] = '\0'; identifier.location.setTo(buffer); } // Get device unique id. if(ioctl(fd, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer) < 1) { //fprintf(stderr, "could not get idstring for %s, %s\n", devicePath, strerror(errno)); } else { buffer[sizeof(buffer) - 1] = '\0'; identifier.uniqueId.setTo(buffer); } // Make file descriptor non-blocking for use with poll(). if (fcntl(fd, F_SETFL, O_NONBLOCK)) { ALOGE("Error %d making device file descriptor non-blocking.", errno); close(fd); return -1; } // Allocate device. (The device object takes ownership of the fd at this point.) int32_t deviceId = mNextDeviceId++; Device* device = new Device(fd, deviceId, String8(devicePath), identifier); #if 0 ALOGI("add device %d: %s\n", deviceId, devicePath); ALOGI(" bus: %04x\n" " vendor %04x\n" " product %04x\n" " version %04x\n", identifier.bus, identifier.vendor, identifier.product, identifier.version); ALOGI(" name: \"%s\"\n", identifier.name.string()); ALOGI(" location: \"%s\"\n", identifier.location.string()); ALOGI(" unique id: \"%s\"\n", identifier.uniqueId.string()); ALOGI(" driver: v%d.%d.%d\n", driverVersion >> 16, (driverVersion >> 8) & 0xff, driverVersion & 0xff); #endif // Load the configuration file for the device. loadConfigurationLocked(device); // Figure out the kinds of events the device reports. ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(device->keyBitmask)), device->keyBitmask); ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(device->absBitmask)), device->absBitmask); ioctl(fd, EVIOCGBIT(EV_REL, sizeof(device->relBitmask)), device->relBitmask); ioctl(fd, EVIOCGBIT(EV_SW, sizeof(device->swBitmask)), device->swBitmask); ioctl(fd, EVIOCGBIT(EV_LED, sizeof(device->ledBitmask)), device->ledBitmask); ioctl(fd, EVIOCGPROP(sizeof(device->propBitmask)), device->propBitmask); // See if this is a keyboard. Ignore everything in the button range except for // joystick and gamepad buttons which are handled like keyboards for the most part. bool haveKeyboardKeys = containsNonZeroByte(device->keyBitmask, 0, sizeof_bit_array(BTN_MISC)) || containsNonZeroByte(device->keyBitmask, sizeof_bit_array(KEY_OK), sizeof_bit_array(KEY_MAX + 1)); bool haveGamepadButtons = containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_MISC), sizeof_bit_array(BTN_MOUSE)) || containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_JOYSTICK), sizeof_bit_array(BTN_DIGI)); if (haveKeyboardKeys || haveGamepadButtons) { device->classes |= INPUT_DEVICE_CLASS_KEYBOARD; } // See if this is a cursor device such as a trackball or mouse. if (test_bit(BTN_MOUSE, device->keyBitmask) && test_bit(REL_X, device->relBitmask) && test_bit(REL_Y, device->relBitmask)) { device->classes |= INPUT_DEVICE_CLASS_CURSOR; } // See if this is a touch pad. // Is this a new modern multi-touch driver? if (test_bit(ABS_MT_POSITION_X, device->absBitmask) && test_bit(ABS_MT_POSITION_Y, device->absBitmask)) { // Some joysticks such as the PS3 controller report axes that conflict // with the ABS_MT range. Try to confirm that the device really is // a touch screen. if (test_bit(BTN_TOUCH, device->keyBitmask) || !haveGamepadButtons) { device->classes |= INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_TOUCH_MT; } // Is this an old style single-touch driver? } else if (test_bit(BTN_TOUCH, device->keyBitmask) && test_bit(ABS_X, device->absBitmask) && test_bit(ABS_Y, device->absBitmask)) { device->classes |= INPUT_DEVICE_CLASS_TOUCH; } // See if this device is a joystick. // Assumes that joysticks always have gamepad buttons in order to distinguish them // from other devices such as accelerometers that also have absolute axes. if (haveGamepadButtons) { uint32_t assumedClasses = device->classes | INPUT_DEVICE_CLASS_JOYSTICK; for (int i = 0; i <= ABS_MAX; i++) { if (test_bit(i, device->absBitmask) && (getAbsAxisUsage(i, assumedClasses) & INPUT_DEVICE_CLASS_JOYSTICK)) { device->classes = assumedClasses; break; } } } // Check whether this device has switches. for (int i = 0; i <= SW_MAX; i++) { if (test_bit(i, device->swBitmask)) { device->classes |= INPUT_DEVICE_CLASS_SWITCH; break; } } // Configure virtual keys. if ((device->classes & INPUT_DEVICE_CLASS_TOUCH)) { // Load the virtual keys for the touch screen, if any. // We do this now so that we can make sure to load the keymap if necessary. status_t status = loadVirtualKeyMapLocked(device); if (!status) { device->classes |= INPUT_DEVICE_CLASS_KEYBOARD; } } // Load the key map. // We need to do this for joysticks too because the key layout may specify axes. status_t keyMapStatus = NAME_NOT_FOUND; if (device->classes & (INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_JOYSTICK)) { // Load the keymap for the device. keyMapStatus = loadKeyMapLocked(device); } // Configure the keyboard, gamepad or virtual keyboard. if (device->classes & INPUT_DEVICE_CLASS_KEYBOARD) { // Register the keyboard as a built-in keyboard if it is eligible. if (!keyMapStatus && mBuiltInKeyboardId == -1 && isEligibleBuiltInKeyboard(device->identifier, device->configuration, &device->keyMap)) { mBuiltInKeyboardId = device->id; } // 'Q' key support = cheap test of whether this is an alpha-capable kbd if (hasKeycodeLocked(device, AKEYCODE_Q)) { device->classes |= INPUT_DEVICE_CLASS_ALPHAKEY; } // See if this device has a DPAD. if (hasKeycodeLocked(device, AKEYCODE_DPAD_UP) && hasKeycodeLocked(device, AKEYCODE_DPAD_DOWN) && hasKeycodeLocked(device, AKEYCODE_DPAD_LEFT) && hasKeycodeLocked(device, AKEYCODE_DPAD_RIGHT) && hasKeycodeLocked(device, AKEYCODE_DPAD_CENTER)) { device->classes |= INPUT_DEVICE_CLASS_DPAD; } // See if this device has a gamepad. for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES)/sizeof(GAMEPAD_KEYCODES[0]); i++) { if (hasKeycodeLocked(device, GAMEPAD_KEYCODES[i])) { device->classes |= INPUT_DEVICE_CLASS_GAMEPAD; break; } } } // If the device isn't recognized as something we handle, don't monitor it. if (device->classes == 0) { ALOGV("Dropping device: id=%d, path='%s', name='%s'", deviceId, devicePath, device->identifier.name.string()); delete device; return -1; } // Determine whether the device is external or internal. if (isExternalDeviceLocked(device)) { device->classes |= INPUT_DEVICE_CLASS_EXTERNAL; } // Register with epoll. struct epoll_event eventItem; memset(&eventItem, 0, sizeof(eventItem)); eventItem.events = EPOLLIN; eventItem.data.u32 = deviceId; if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) { ALOGE("Could not add device fd to epoll instance. errno=%d", errno); delete device; return -1; } ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, " "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s", deviceId, fd, devicePath, device->identifier.name.string(), device->classes, device->configurationFile.string(), device->keyMap.keyLayoutFile.string(), device->keyMap.keyCharacterMapFile.string(), toString(mBuiltInKeyboardId == deviceId)); mDevices.add(deviceId, device); device->next = mOpeningDevices; mOpeningDevices = device; return 0; }
int EventLoop::DeleteEvent(IOEvent *e) { if (e->fd_ < 0) return -1; epoll_event ev; // kernel before 2.6.9 requires return epoll_ctl(epfd_, EPOLL_CTL_DEL, e->fd_, &ev); }
void Epoll::delFd(int fd) { epoll_ctl(epollFd_,EPOLL_CTL_DEL,fd,0); close(fd); }
int main (int argc, char *argv[]) { int sfd, s; int efd; struct epoll_event event; struct epoll_event *events; if (argc != 2) { fprintf (stderr, "Usage: %s [port]\n", argv[0]); exit (EXIT_FAILURE); } sfd = create_and_bind (argv[1]); if (sfd == -1) abort (); s = make_socket_non_blocking (sfd); if (s == -1) abort (); s = listen (sfd, SOMAXCONN); if (s == -1) { perror ("listen"); abort (); } efd = epoll_create1 (0); if (efd == -1) { perror ("epoll_create"); abort (); } event.data.fd = sfd; event.events = EPOLLIN | EPOLLET; s = epoll_ctl (efd, EPOLL_CTL_ADD, sfd, &event); if (s == -1) { perror ("epoll_ctl"); abort (); } /* Buffer where events are returned */ events = calloc (MAXEVENTS, sizeof event); /* The event loop */ while (1) { int n, i; n = epoll_wait (efd, events, MAXEVENTS, -1); for (i = 0; i < n; i++) { if ((events[i].events & EPOLLERR) || (events[i].events & EPOLLHUP) || (!(events[i].events & EPOLLIN))) { /* An error has occured on this fd, or the socket is not ready for reading (why were we notified then?) */ fprintf (stderr, "epoll error\n"); close (events[i].data.fd); continue; } else if (sfd == events[i].data.fd) { /* We have a notification on the listening socket, which means one or more incoming connections. */ while (1) { struct sockaddr in_addr; socklen_t in_len; int infd; char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; in_len = sizeof in_addr; infd = accept (sfd, &in_addr, &in_len); if (infd == -1) { if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { /* We have processed all incoming connections. */ break; } else { perror ("accept"); break; } } s = getnameinfo (&in_addr, in_len, hbuf, sizeof hbuf, sbuf, sizeof sbuf, NI_NUMERICHOST | NI_NUMERICSERV); if (s == 0) { printf("Accepted connection on descriptor %d " "(host=%s, port=%s)\n", infd, hbuf, sbuf); } /* Make the incoming socket non-blocking and add it to the list of fds to monitor. */ s = make_socket_non_blocking (infd); if (s == -1) abort (); event.data.fd = infd; event.events = EPOLLIN | EPOLLET; s = epoll_ctl (efd, EPOLL_CTL_ADD, infd, &event); if (s == -1) { perror ("epoll_ctl"); abort (); } } continue; } else { /* We have data on the fd waiting to be read. Read and display it. We must read whatever data is available completely, as we are running in edge-triggered mode and won't get a notification again for the same data. */ int done = 0; while (1) { ssize_t count; char buf[512]; count = read (events[i].data.fd, buf, sizeof buf); if (count == -1) { /* If errno == EAGAIN, that means we have read all data. So go back to the main loop. */ if (errno != EAGAIN) { perror ("read"); done = 1; } break; } else if (count == 0) { /* End of file. The remote has closed the connection. */ done = 1; break; } /* Write the buffer to standard output */ s = write (1, buf, count); if (s == -1) { perror ("write"); abort (); } } if (done) { printf ("Closed connection on descriptor %d\n", events[i].data.fd); /* Closing the descriptor will make epoll remove it from the set of descriptors which are monitored. */ close (events[i].data.fd); } } } } free (events); close (sfd); return EXIT_SUCCESS; }
void io_wantwrite_really(fd_t d, io_entry* e) { int64 newfd; assert(!e->kernelwantwrite); /* we should not be here if we already told the kernel we want to write */ newfd = (!e->kernelwantread); io_wanted_fds += newfd; #ifdef HAVE_EPOLL if(io_waitmode == EPOLL) { struct epoll_event x; byte_zero(&x, sizeof(x)); /* to shut up valgrind */ x.events = EPOLLOUT; if(e->kernelwantread) x.events |= EPOLLIN; x.data.fd = d; epoll_ctl(io_master, e->kernelwantread ? EPOLL_CTL_MOD : EPOLL_CTL_ADD, d, &x); } #endif #ifdef HAVE_KQUEUE if(io_waitmode == KQUEUE) { struct kevent kev; struct timespec ts; EV_SET(&kev, d, EVFILT_WRITE, EV_ADD | EV_ENABLE, 0, 0, 0); ts.tv_sec = 0; ts.tv_nsec = 0; kevent(io_master, &kev, 1, 0, 0, &ts); } #endif #ifdef HAVE_SIGIO if(io_waitmode == _SIGIO) { struct pollfd p; p.fd = d; p.events = POLLOUT; switch(poll(&p, 1, 0)) { case 1: e->canwrite = 1; break; case 0: e->canwrite = 0; break; case -1: return; } if(e->canwrite) { debug_printf(("io_wantwrite: enqueueing %lld in normal write queue before %ld\n", d, first_readable)); e->next_write = first_writeable; first_writeable = d; } } #endif #ifdef USE_SELECT #elif WINDOWS_NATIVE printf("e->wantwrite == %d\n", e->wantwrite); if(!e->wantwrite) { e->next_write = first_writeable; e->canwrite = 1; first_writeable = d; debug_printf(("queueing write, setting first_writeable to %ld\n", (long)d)); } #endif e->wantwrite = 1; e->kernelwantwrite = 1; }
int main(int argc, char * const argv[]) { int pfd = -1; int fd = -1; int ret = EXIT_FAILURE; struct epoll_event epoll_event; static struct options_t options = { .timeout = -1, }; size_t size = 0; int argi = parse_arguments(&options, argc, argv); if (argi < 0) { exit(EXIT_FAILURE); } else if (argc - argi >= 1) { usage(stdout, argv[0]); fprintf(stderr, "Error: Too many arguments!\n"); exit(EXIT_FAILURE); } pfd = epoll_create(1); if (pfd < 0) { perror("epoll_create"); exit(EXIT_FAILURE); } fd = STDIN_FILENO; epoll_event.events = EPOLLIN; epoll_event.data.fd = fd; ret = epoll_ctl(pfd, EPOLL_CTL_ADD, fd, &epoll_event); if (ret) { perror("epoll_ctl"); fd = -1; goto exit; } DUMPFOOTER = 0; DUMPADDR = 1; for (;;) { ssize_t s; char buf[BUFSIZE]; __memset(buf, 0); ret = epoll_wait(pfd, &epoll_event, 1, options.timeout); if (ret < 0) { perror("epoll_wait"); break; } else if (!ret) { fprintf(stderr, "%s: %s\n", "epoll_wait", strerror(ETIME)); ret = -1; break; } s = read(fd, buf, sizeof(buf)); if (s < 0) { perror("read"); ret = s; break; } else if (!s) { break; } buf[s] = 0; hexdump(size, buf, s); size += s; if (size) DUMPHEADER = 0; } if (size) printf("%08x\n", size); exit: if (fd > -1) { epoll_ctl(pfd, EPOLL_CTL_DEL, fd, &epoll_event); } if (pfd) { close(pfd); pfd = -1; } return !ret ? EXIT_SUCCESS : EXIT_FAILURE; }
struct mavlink_drone *mavlink_drone_new(struct mavlink_drone_cfg *cfg) { struct mavlink_drone *c; struct epoll_event ev; struct epoll_event events[3]; struct itimerspec timeout; struct mavlink_comm_cfg comm_cfg = { .local_port = 14551, .remote_port = 14550, .cb = &callback}; if (!cfg) return NULL; c = calloc(1, sizeof(struct mavlink_drone)); if (!c) return NULL; c->remote_system_id = cfg->remote_system_id; c->remote_component_id = cfg->remote_component_id; c->update_status_cb = cfg->update_status_cb; comm_cfg.remote_addr = NULL; c->comm = mavlink_comm_new(&comm_cfg); if (!c->comm) { printf("bad init comm\n"); goto error; } c->exitfd = eventfd(0,0); bzero(&timeout, sizeof(timeout)); timeout.it_value.tv_sec = 1; timeout.it_value.tv_nsec = 0; timeout.it_interval.tv_sec = 1; timeout.it_interval.tv_nsec = 0; c->fd_1hz = timerfd_init(&timeout); if (c->fd_1hz < 0) { printf("Failed to create timerfd 1hz\n"); goto error; } printf("size %lu\n", sizeof(events) / sizeof(events[0])); c->epollfd = epoll_create(sizeof(events) / sizeof(events[0])); if (c->epollfd < 0) { printf("epoll_create failed\n"); goto error; } ev.events = EPOLLIN; ev.data.fd = c->fd_1hz; if (epoll_ctl(c->epollfd, EPOLL_CTL_ADD, c->fd_1hz, &ev) == -1) { printf("failed to add fd_1hz\n"); goto error; } ev.events = EPOLLIN; ev.data.fd = mavlink_comm_get_sockfd(c->comm); if (epoll_ctl(c->epollfd, EPOLL_CTL_ADD, ev.data.fd, &ev) == -1) { printf ("failed to add sockfd\n"); goto error; } ev.events = EPOLLIN; ev.data.fd = c->exitfd; if (epoll_ctl(c->epollfd, EPOLL_CTL_ADD, c->exitfd, &ev) == -1) { printf("failed to add eventfd\n"); goto error; } return c; error: if (c->comm) mavlink_comm_destroy(c->comm); if (c->fd_1hz > 0) close(c->fd_1hz); if (c->epollfd > 0) close(c->epollfd); free(c); return NULL; } void mavlink_drone_destroy(struct mavlink_drone *c) { if (!c) return; if (c->epollfd > 0) close(c->epollfd); free(c); } static void mavlink_drone_send_status(struct mavlink_drone *ctrl) { mavlink_message_t msg; struct mavlink_info_cache *c = &ctrl->cache; int ret; if (ctrl->update_status_cb) (ctrl->update_status_cb)(c); mavlink_msg_heartbeat_pack(ctrl->remote_system_id, ctrl->remote_component_id, &msg, c->hb.type, c->hb.autopilot, c->hb.base_mode, 0, c->hb.system_status); ret = mavlink_comm_send_msg(ctrl->comm, &msg); if (ret < 0) printf("%d error %d\n", __LINE__, ret); /* Send Status */ mavlink_msg_sys_status_pack(ctrl->remote_system_id, ctrl->remote_component_id, &msg, c->sys_stat.onboard_control_sensors_present, c->sys_stat.onboard_control_sensors_enabled, c->sys_stat.onboard_control_sensors_health, c->sys_stat.load, c->sys_stat.voltage_battery, c->sys_stat.current_battery, c->sys_stat.drop_rate_comm, c->sys_stat.errors_comm, c->sys_stat.errors_count1, c->sys_stat.errors_count2, c->sys_stat.errors_count3, c->sys_stat.errors_count4, c->sys_stat.battery_remaining); ret = mavlink_comm_send_msg(ctrl->comm, &msg); if (ret < 0) printf("%d error %d\n", __LINE__, ret); /* Send Local Position */ mavlink_msg_local_position_ned_pack(ctrl->remote_system_id, ctrl->remote_component_id, &msg, c->lpn.time_boot_ms, c->lpn.x, c->lpn.y, c->lpn.z, c->lpn.vx, c->lpn.vy, c->lpn.vz); ret = mavlink_comm_send_msg(ctrl->comm, &msg); if (ret < 0) printf("%d error %d\n", __LINE__, ret); /* Send attitude */ mavlink_msg_attitude_pack(ctrl->remote_system_id, ctrl->remote_component_id, &msg, c->att.time_boot_ms, c->att.roll, c->att.pitch, c->att.yaw, c->att.rollspeed, c->att.pitchspeed, c->att.yawspeed); ret = mavlink_comm_send_msg(ctrl->comm, &msg); if (ret < 0) printf("%d error %d\n", __LINE__, ret); }
int main() { int listen_fd, connect_fd, fork_pid; struct sockaddr_in servaddr; struct epoll_event event; struct epoll_event events[MAXEVENTS]; int aaaa[64]; char buf[5120]; //Set SIGCHLD signals to be ignored, which causes child process //results to be automatically discarded when they terminate: signal(SIGCHLD,SIG_IGN); //Create socket for server to listen on: if ((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("Server: socket call failed"); exit(EXIT_FAILURE); } //Set up socket so port can be immediately reused: int i=1; setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)); //Set up server address struct (simplified vs. text): memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(PORTNUM); servaddr.sin_addr.s_addr = htonl(INADDR_ANY); //Means accept all local interfaces. //As an alternative for setting up address, could have had for declaration: //struct sockaddr_in servaddr = {AF_INET, htons(PORTNUM), htonl(INADDR_ANY)}; //Give socket a name/address by binding to a port: if (bind(listen_fd, (struct sockaddr *) &servaddr, sizeof(servaddr)) == -1) { perror("Server: bind call failed"); exit(EXIT_FAILURE); } //Start socket listening: if (listen(listen_fd, 10) == -1) { perror("Server: listen call failed"); exit(EXIT_FAILURE); } #ifdef DEBUG print_id_info("Server starting: "); #endif //creating epoll int efd = epoll_create1 (0); if (efd == -1) { perror ("epoll_create"); abort (); } event.data.fd = listen_fd; event.events = EPOLLIN | EPOLLET; int s = epoll_ctl (efd, EPOLL_CTL_ADD, listen_fd, &event); if (s == -1) { perror ("epoll_ctl"); abort (); } /* Buffer where events are returned */ //events = calloc (MAXEVENTS, sizeof event); /* The event loop */ while (1) { int n, i; n = epoll_wait (efd, events, MAXEVENTS, -1); for (i = 0; i < n; i++) { if ((events[i].events & EPOLLERR) || (events[i].events & EPOLLHUP) || (!(events[i].events & EPOLLIN))) { /* An error has occured on this fd, or the socket is not ready for reading (why were we notified then?) */ close (aaaa[events[i].data.fd]); close (events[i].data.fd); continue; } else if (listen_fd == events[i].data.fd) { //Accept a new connection and get socket to use for client: connect_fd = accept(listen_fd, (struct sockaddr *) NULL, NULL); int stdin_fd, stdout_fd, stderr_fd; char *sock_input; char *server1 = "<rembash2>\n"; char *server2 = "<ok>\n"; //Write initial protocol ID to client: if (write(connect_fd,server1,strlen(server1)) == -1) { perror("Server: Error writing to socket"); exit(EXIT_FAILURE); } //Check if correct shared secret was received: if ((sock_input = input_matches_protocol(connect_fd,SECRET)) != NULL) { fprintf(stderr,"Client: Invalid shared secret received from client: %s\n",sock_input); exit(EXIT_FAILURE); } //Send OK response to client: if (write(connect_fd, server2, strlen(server2)) == -1) { perror("Server: Error writing OK to connection socket"); exit(EXIT_FAILURE); //Make child to run bash in: } #ifdef DEBUG print_id_info("Subprocess to exec bash, after setsid(): "); #endif event.data.fd = connect_fd; event.events = EPOLLIN | EPOLLET; int s = epoll_ctl (efd, EPOLL_CTL_ADD, connect_fd, &event); if (s == -1) { perror ("epoll_ctl"); abort (); } //Setup stdin, stdout, and stderr redirection: int masterfd, pid; if ((pid = forkpty(&masterfd, NULL, NULL, NULL)) < 0) perror("FORK"); else if (pid == 0) { if (execlp("bash","bash","--noediting","-i",NULL)<0) { perror("execvp"); exit(2); } } else { event.data.fd = masterfd; event.events = EPOLLIN | EPOLLET; int m = epoll_ctl (efd, EPOLL_CTL_ADD, masterfd, &event); aaaa[connect_fd] = masterfd; aaaa[masterfd] = connect_fd; } } else { int done = 0; int count; count = read (events[i].data.fd, buf, 5120); if (count == -1) { /* If errno == EAGAIN, that means we have read all data. So go back to the main loop. */ if (errno != EAGAIN) { perror ("read"); done = 1; } } else if (count == 0) { /* End of file. The remote has closed the connection. */ done = 1; } else { /* Write the buffer to standard output */ s = write (aaaa[events[i].data.fd], buf, count); if (s == -1) { perror ("write"); } } if (done) { printf ("Closed connection on descriptor %d\n", events[i].data.fd); /* Closing the descriptor will make epoll remove it from the set of descriptors which are monitored. */ close (events[i].data.fd); close(aaaa[events[i].data.fd]); } } } }}
int main(int argc, char **argv) { pid_t pid; int ptype = 0; if (argc > 1) { int i; for (i = 0; i < argc; i++) { if (strcmp("-d", argv[i]) == 0) { ptype = 1; break; } } } /** * 守护进程 */ if (ptype > 0) { if ( (pid = fork()) < 0) { return 0; } else if (pid > 0) { return 0; } } int listenfd, connfd; struct sockaddr_in servaddr; char buff[MAXLINE]; time_t ticks; listenfd = socket(AF_INET, SOCK_STREAM, 0); if (listenfd < 0) { printf("socket error %d\n", listenfd); return 0; } bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(10023); int errno; errno = bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); if (errno < 0) { printf("bind error %d\n", errno); return 0; } if (listen(listenfd, LISTEN_BACKLOG) == -1) { printf("listen error\n"); return 0; } else { printf("listen success\n"); } fd_set rset; FD_ZERO(&rset); int clients[5]; int i; for (i = 0; i < 5; ++i) { clients[i] = -1; } int total = 0; int max_connfd = 0; int maxi = 0; max_connfd = listenfd; FD_SET(listenfd, &rset); int epollfd; epollfd = epoll_create(10); if (epollfd == -1) { printf("epoll_create\n"); return 0; } struct epoll_event ev, events[10]; ev.events = EPOLLIN; ev.data.fd = listenfd; if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listenfd, &ev) == -1) { printf("epoll_ctl: listen_sock\n"); return 0; } for ( ; ; ) { int nfds; nfds = epoll_wait(epollfd, events, 10, -1); if (nfds == -1) { return 0; } printf("nfds n %d\n", nfds); int i; for (i = 0; i < nfds; ++i) { if (events[i].data.fd == listenfd) { int conn_sock; conn_sock = accept(listenfd, (struct sockaddr *)NULL, NULL); if (conn_sock == -1) { return 0; } // setnonblocking(conn_sock); ev.events = EPOLLIN | EPOLLET; ev.data.fd = conn_sock; if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock, &ev) == -1) { return 0; } printf("new conn %d\n", conn_sock); } else { int n; char str[50]; base_msg* pmsg = (base_msg*)str; printf("recv conn %d\n", events[i].data.fd); n = read(events[i].data.fd, str, MAXLINE); printf("readlen %d\n", n); if (n == 0) { close(events[i].data.fd); epoll_ctl(epollfd, EPOLL_CTL_DEL, events[i].data.fd, NULL); } else { write(events[i].data.fd, str, n); } /* pmsg->id = 1; pmsg->type = 2; pmsg->size = 3; */ // write(events[i].data.fd, str, 3 * sizeof(unsigned int)); } } } }
int main(int argc, char **argv) { liao_log("liao_server", LOG_PID|LOG_NDELAY, LOG_MAIL); if (argc != 3) { usage(argv[0]); exit(0); } if (chdir(LIAO_HOME) == -1) { log_alert("cannot start: unable to switch to home directory"); exit(0); } snprintf(msg_id, sizeof(msg_id), "00000000"); char cfg_file[MAX_LINE] = CFG_FILE; int c; const char *args = "c:h"; while ((c = getopt(argc, argv, args)) != -1) { switch (c) { case 'c': snprintf(cfg_file, sizeof(cfg_file), "%s", optarg); break; case 'h': default: usage(argv[0]); exit(0); } } // 处理配置文件 if (conf_init(cfg_file)) { fprintf(stderr, "Unable to read control files:%s\n", cfg_file); log_error("Unable to read control files:%s", cfg_file); exit(1); } /* // 检查队列目录 if (strlen(config_st.queue_path) <= 0) { fprintf(stderr, "Unable to read queue path.\n"); log_error("Unable to read queue path."); exit(1); } if ( access(config_st.queue_path, F_OK) ) { fprintf(stderr, "Queue path:%s not exists:%s, so create it.\n", config_st.queue_path, strerror(errno)); log_error("Queue path:%s not exists:%s, so create it.", config_st.queue_path, strerror(errno)); umask(0); mkdir(config_st.queue_path, 0777); }*/ online_d = dictionary_new(atoi(config_st.max_works) + 1); child_st = (struct childs *)malloc((atoi(config_st.max_works) + 1) * sizeof(struct childs)); if (!child_st) { log_error("malloc childs [%d] failed:[%d]%s", (atoi(config_st.max_works) + 1), errno, strerror(errno)); exit(1); } int i = 0; for (i=0; i<(atoi(config_st.max_works) + 1); i++) { child_st[i].used = 0; child_st[i].pid = -1; child_st[i].client_fd = -1; child_st[i].pipe_r_in = -1; child_st[i].pipe_r_out = -1; child_st[i].pipe_w_in = -1; child_st[i].pipe_w_out = -1; memset(child_st[i].mid, 0, sizeof(child_st[i].mid)); child_st[i].mfp_out = NULL; } // 开始服务 int connfd, epfd, sockfd, n, nread; struct sockaddr_in local, remote; socklen_t addrlen; // 初始化buffer char buf[BUF_SIZE]; size_t pbuf_len = 0; size_t pbuf_size = BUF_SIZE + 1; char *pbuf = (char *)calloc(1, pbuf_size); if (pbuf == NULL) { log_error("calloc fail: size[%d]", pbuf_size); exit(1); } // 创建listen socket int bind_port = atoi(config_st.bind_port); if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { log_error("socket failed:[%d]:%s", errno, strerror(errno)); exit(1); } if (setnonblocking(listenfd) > 0) { exit(1); } bzero(&local, sizeof(local)); local.sin_family = AF_INET; local.sin_addr.s_addr = htonl(INADDR_ANY); local.sin_port = htons(bind_port); if (bind(listenfd, (struct sockaddr *)&local, sizeof(local)) < 0) { log_error("bind local %d failed:[%d]%s", bind_port, errno, strerror(errno)); exit(1); } log_info("bind local %d succ", bind_port); if (listen(listenfd, atoi(config_st.max_works)) != 0) { log_error("listen fd[%d] max_number[%d] failed:[%d]%s", listenfd, atoi(config_st.max_works), errno, strerror(errno)); exit(1); } // 忽略pipe信号 sig_pipeignore(); // 捕抓子进程退出信号 sig_catch(SIGCHLD, sigchld); // epoll create fd epoll_event_num = atoi(config_st.max_works) + 1; epoll_evts = NULL; epoll_fd = -1; epoll_nfds = -1; int epoll_i = 0; epoll_evts = (struct epoll_event *)malloc(epoll_event_num * sizeof(struct epoll_event)); if (epoll_evts == NULL) { log_error("alloc epoll event failed"); _exit(111); } epoll_fd = epoll_create(epoll_event_num); if (epoll_fd == -1) { log_error("epoll_create max_number[%d] failed:[%d]%s", epoll_event_num, errno, strerror(errno)); exit(1); } struct epoll_event ev; ev.events = EPOLLIN; ev.data.fd = listenfd; if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, ev.data.fd, &ev) == -1) { log_error("epoll_ctl: listen_socket failed:[%d]%s", errno, strerror(errno)); exit(1); } epoll_num_running = 1; for (;;) { epoll_nfds = epoll_wait(epoll_fd, epoll_evts, epoll_event_num, -1); if (epoll_nfds == -1) { if (errno == EINTR) { // 收到中断信号 log_info("epoll_wait recive EINTR signal, continue"); continue; } _exit(111); } log_debug("epoll_num_running:%d nfds:%d", epoll_num_running, epoll_nfds); for (epoll_i = 0; epoll_i < epoll_nfds; epoll_i++) { sig_childblock(); int evt_fd = epoll_evts[epoll_i].data.fd; if (evt_fd == listenfd) { if ((connfd = accept(listenfd, (struct sockaddr *) &remote, &addrlen)) > 0) { char *ipaddr = inet_ntoa(remote.sin_addr); log_info("accept client:%s", ipaddr); char greetting[512] = {0}; char hostname[1024] = {0}; if (gethostname(hostname, sizeof(hostname)) != 0) { snprintf(hostname, sizeof(hostname), "unknown"); } // 取客户端IP,Port char client_ip[20] = {0}; char client_port[20] = {0}; struct sockaddr_in sa; int len = sizeof(sa); if (!getpeername(connfd, (struct sockaddr *)&sa, &len)) { snprintf(client_ip, sizeof(client_ip), "%s", inet_ntoa(sa.sin_addr)); snprintf(client_port, sizeof(client_port), "%d", ntohs(sa.sin_port)); } // 取一个新的client int i = new_idx_from_child_st(); if (i == -1) { log_error("new_idx_from_client_st fail: maybe client queue is full."); // send error snprintf(greetting, sizeof(greetting), "%s ERR %s%s", TAG_GREET, hostname, DATA_END); write(connfd, greetting, strlen(greetting)); log_debug("send fd[%d]:%s", connfd, greetting); continue; } child_st[i].used = 1; int pir[2]; int piw[2]; if (pipe(pir) == -1) { log_error("unable to create pipe:%s", strerror(errno)); // send error snprintf(greetting, sizeof(greetting), "%s ERR %s%s", TAG_GREET, hostname, DATA_END); write(connfd, greetting, strlen(greetting)); log_debug("send fd[%d]:%s", connfd, greetting); continue; } if (pipe(piw) == -1) { log_error("unable to create pipe:%s", strerror(errno)); close(pir[0]); close(pir[1]); pir[0] = -1; pir[1] = -1; // send error snprintf(greetting, sizeof(greetting), "%s ERR %s%s", TAG_GREET, hostname, DATA_END); write(connfd, greetting, strlen(greetting)); log_debug("send fd[%d]:%s", connfd, greetting); continue; } log_debug("create pir[0]:%d pir[1]:%d", pir[0], pir[1]); log_debug("create piw[0]:%d piw[1]:%d", piw[0], piw[1]); // 当程序执行exec函数时本fd将被系统自动关闭,表示不传递给exec创建的新进程 //fcntl(pir[0], F_SETFD, FD_CLOEXEC); //fcntl(piw[1], F_SETFD, FD_CLOEXEC); int f = fork(); if (f < 0) { log_error("fork fail:%s", strerror(errno)); close(pir[0]); close(pir[1]); pir[0] = -1; pir[1] = -1; close(piw[0]); close(piw[1]); piw[0] = -1; piw[1] = -1; child_st[i].used = 0; // send error snprintf(greetting, sizeof(greetting), "%s ERR %s%s", TAG_GREET, hostname, DATA_END); write(connfd, greetting, strlen(greetting)); log_debug("send fd[%d]:%s", connfd, greetting); continue; } struct timeval tm; gettimeofday(&tm, NULL); snprintf(child_st[i].mid, sizeof(child_st[i].mid), "%05u%u", (uint32_t)tm.tv_usec, (uint32_t)f); snprintf(msg_id, sizeof(msg_id), "%s", child_st[i].mid); if (f == 0) { // 子进程 close(pir[0]); close(piw[1]); close(listenfd); char _cmid[512] = {0}; char _cchild_st[512] = {0}; char _ccip[20] = {0}; char _ccport[20] = {0}; snprintf(_cmid, sizeof(_cmid), "-m%s", child_st[i].mid); snprintf(_cchild_st, sizeof(_cchild_st), "-c%s", config_st.child_cf); snprintf(_ccip, sizeof(_ccip), "-i%s", client_ip); snprintf(_ccport, sizeof(_ccport), "-p%s", client_port); char *args[6]; args[0] = "./liao_command"; args[1] = _cmid; args[2] = _cchild_st; args[3] = _ccip; args[4] = _ccport; args[5] = 0; if (fd_move(0, connfd) == -1) { log_info("%s fd_move(0, %d) failed:%d %s", child_st[i].mid, connfd, errno, strerror(errno)); _exit(111); } if (fd_move(1, pir[1]) == -1) { log_info("%s fd_move(pipe_w, %d) failed:%d %s", child_st[i].mid, pir[1], errno, strerror(errno)); _exit(111); } if (fd_move(2, piw[0]) == -1) { log_info("%s fd_move(pipe_r, %d) failed:%d %s", child_st[i].mid, piw[0], errno, strerror(errno)); _exit(111); } if (execvp(*args, args) == -1) { log_error("execp fail:%s", strerror(errno)); _exit(111); } //if (error_temp(errno)) // _exit(111); log_debug("execp succ"); _exit(100); } close(connfd); child_st[i].pipe_r_in = pir[0]; close(pir[1]); pir[1] = -1; child_st[i].pipe_r_out = -1; child_st[i].pipe_w_out = piw[1]; close(piw[0]); piw[0] = -1; child_st[i].pipe_w_in = -1; child_st[i].pid = f; if (setnonblocking(child_st[i].pipe_r_in) != 0) { log_error("setnonblocking fd[%d] failed", child_st[i].pipe_r_in); } struct epoll_event pipe_in_ev; pipe_in_ev.events = EPOLLIN | EPOLLET; pipe_in_ev.data.fd = child_st[i].pipe_r_in; if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, pipe_in_ev.data.fd, &pipe_in_ev) == -1) { log_error("epoll_ctl client fd[%d] EPOLL_CTL_ADD failed:[%d]%s", pipe_in_ev.data.fd, errno, strerror(errno)); } log_debug("epoll_add fd[%d]", pipe_in_ev.data.fd); } else if (connfd == -1) { if (errno != EAGAIN && errno != ECONNABORTED && errno != EPROTO && errno != EINTR) { log_error("accept failed:[%d]%s", errno, strerror(errno)); } continue; } } else if (epoll_evts[epoll_i].events & EPOLLIN) { int ci = get_idx_with_sockfd(evt_fd); if (ci < 0) { log_error("socket fd[%d] get_idx_with_sockfd fail", evt_fd); continue; } log_debug("%s get event EPOLLIN: epoll_i[%d] fd[%d] get d_i[%d] fd[%d], used[%d]", child_st[ci].mid, epoll_i, epoll_evts[epoll_i].data.fd, child_st[ci].pipe_r_in, child_st[ci].used); // 读取内容 ---------------------- char inbuf[BUF_SIZE] = {0}; char *pinbuf = inbuf; int inbuf_size = BUF_SIZE; int inbuf_len = 0; char ch; do { i = 0; nread = read(child_st[ci].pipe_r_in, inbuf, inbuf_size); log_debug("%s read from liao_command:[%d]", child_st[ci].mid, nread); if (nread == -1) { // read error on a readable pipe? be serious //log_error("it is failed from fd[%d] read. error:%d %s", child_st[ci].fd_in, errno, strerror(errno)); //log_debug("it is failed from fd[%d] read. error:%d %s", child_st[ci].pipe_r_in, errno, strerror(errno)); break; } else if (nread > 0) { if (child_st[ci].mfp_out == NULL) { child_st[ci].mfp_out = mopen(MAX_BLOCK_SIZE, NULL, NULL); if (child_st[ci].mfp_out == NULL) { log_debug("%s mopen for body fail", child_st[ci].mid); break; } } while (i < nread) { ch = inbuf[i]; if ((inbuf_size - inbuf_len) < 2) { int r = fast_write(child_st[ci].mfp_out, inbuf, inbuf_len); if (r == 0) { log_error("%s fast_write fail", child_st[ci].mid); break; } memset(inbuf, 0, inbuf_size); inbuf_len = 0; } mybyte_copy(pinbuf + inbuf_len, 1, &ch); inbuf_len++; if (ch == '\n') { if (inbuf_len > 0) { int r = fast_write(child_st[ci].mfp_out, inbuf, inbuf_len); if (r == 0) { log_error("%s fast_write fail", child_st[ci].mid); break; } memset(inbuf, 0, inbuf_size); inbuf_len = 0; } // 处理当前指令 // ... process_system(&child_st[ci]); // ... // 处理完成后 if (child_st[ci].mfp_out != NULL) { mclose(child_st[ci].mfp_out); child_st[ci].mfp_out = NULL; child_st[ci].mfp_out = mopen(MAX_BLOCK_SIZE, NULL, NULL); if (child_st[ci].mfp_out == NULL) { log_error("mopen fail for mfp_out"); break; } } pinbuf = inbuf + 0; } i++; } } else { break; } } while (1); } else if ((epoll_evts[epoll_i].events & EPOLLHUP) && (epoll_evts[epoll_i].data.fd != listenfd)) { int ci = get_idx_with_sockfd(evt_fd); if ( ci < 0 ) { log_error("get_idx_with_sockfd(%d) fail, so not write", evt_fd); continue; } log_debug("%s get event EPOLLHUP: epoll_i[%d] fd[%d] get d_i[%d] fd[%d], used[%d]", child_st[ci].mid, epoll_i, epoll_evts[epoll_i].data.fd, child_st[ci].pipe_r_in, child_st[ci].used); epoll_delete_evt(epoll_fd, child_st[ci].pipe_r_in); continue; } } sig_childunblock(); } close(epoll_fd); close(listenfd); log_info("i'm finish"); return 0; }
int main(int argc, const char *argv[]) { int i = 0; size_t client_capacity = 100; size_t total_capacity = 101; //+1 extra for server socket int srv_fd = -1; struct sockaddr_in srv_addr; int epoll_fd = -1; struct epoll_event e, *es; if (argc == 2) { client_capacity = atoi(argv[1]); //read capacity from program argument list total_capacity = client_capacity + 1; } USER_LIST = create_ul(client_capacity); memset(&srv_addr, 0, sizeof(srv_addr)); memset(&e, 0, sizeof(e)); es = malloc((total_capacity) * sizeof(struct epoll_event)); srv_fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); if (srv_fd < 0) { printf("Cannot create socket\n"); return 1; } srv_addr.sin_family = AF_INET; srv_addr.sin_addr.s_addr = htonl(INADDR_ANY); srv_addr.sin_port = htons(5553); if (bind(srv_fd, (struct sockaddr*) &srv_addr, sizeof(srv_addr)) < 0) { printf("Cannot bind socket\n"); close(srv_fd); return 1; } if (listen(srv_fd, total_capacity) < 0) { printf("Cannot listen\n"); close(srv_fd); return 1; } epoll_fd = epoll_create(total_capacity); if (epoll_fd < 0) { printf("Cannot create epoll\n"); close(srv_fd); return 1; } e.events = EPOLLIN; e.data.fd = srv_fd; if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, srv_fd, &e) < 0) { printf("Cannot add server socket to epoll\n"); close(epoll_fd); close(srv_fd); return 1; } for(;;) { i = epoll_wait(epoll_fd, es, total_capacity, -1); if (i < 0) { printf("Cannot wait for events\n"); close(epoll_fd); close(srv_fd); return 1; } for (--i; i > -1; --i) { if (es[i].data.fd == srv_fd) { if (server_service(srv_fd, epoll_fd)) { return 1; } } else { client_service(es[i].data.fd, es[i].events, epoll_fd); } } } return 0; }