static int setup_pollfds(void) { size_t numfds; size_t i; struct fp_pollfd *fpfds; GSource *gsource = g_source_new(&sourcefuncs, sizeof(struct fdsource)); fdsource = (struct fdsource *) gsource; fdsource->pollfds = NULL; numfds = fp_get_pollfds(&fpfds); if (numfds < 0) { if (fpfds) free(fpfds); return (int) numfds; } else if (numfds > 0) { for (i = 0; i < numfds; i++) { struct fp_pollfd *fpfd = &fpfds[i]; pollfd_add(fpfd->fd, fpfd->events); } } free(fpfds); fp_set_pollfd_notifiers(pollfd_added_cb, pollfd_removed_cb); g_source_attach(gsource, NULL); return 0; }
static void main_loop(int listen_fd, int event_sub_fd) { int i, nready; int new_fd; int deleted_entry; struct sockaddr_in client_addr; socklen_t client_len; pollfd_add(pfdinfo, listen_fd, POLLIN, NULL); pollfd_add(pfdinfo, event_sub_fd, POLLIN, NULL); /* Main loop */ while(1) { deleted_entry = 0; GDEBUG(1, "Before poll():"); PRINT_POLLFDINFO(pfdinfo); /* Poll */ nready = poll(pfdinfo->pollfd, pfdinfo->nfds, -1); /* There is an error? */ if(nready == -1) { fprintf(stderr, "poll() error: %s; I continue.\n", strerror(errno)); continue; } for(i = 0; i < pfdinfo->nfds; i++) { if(pfdinfo->pollfd[i].revents == 0) continue; GDEBUG(1, "fd = %d is ready for event 0x%X\n", pfdinfo->pollfd[i].fd, pfdinfo->pollfd[i].revents); /* If there is an error, I close the connection */ if( pfdinfo->pollfd[i].revents & POLLERR || pfdinfo->pollfd[i].revents & POLLHUP || pfdinfo->pollfd[i].revents & POLLNVAL) { /* printf("Error, getchar():\n"); getchar(); */ close_connection(pfdinfo, i); deleted_entry = 1; if(--nready < 0) break; continue; } /*********************************************/ /* New Connection/Event Subscribe management */ /*********************************************/ if((pfdinfo->pollfd[i].fd == listen_fd || pfdinfo->pollfd[i].fd == event_sub_fd) && pfdinfo->pollfd[i].revents & POLLIN) { enum client_type type; int size; enum client_state state; if(pfdinfo->pollfd[i].fd == listen_fd) { type = REQ_RESP; size = sizeof(struct handshake); state = WAITING_ARCH; } else { type = EVENT_SUB; size = sizeof(struct rsc_es_hdr); state = CONN_READING_HDR; } bzero(&client_addr, sizeof(client_addr)); client_len = sizeof(client_addr); /* I accept the new connection */ new_fd = accept(pfdinfo->pollfd[i].fd, (struct sockaddr *)&client_addr, &client_len); if(new_fd == -1) { fprintf(stderr, "Accept() error: %s\n", strerror(errno)); } else { /* I create the new client structure */ struct client *new_client; void *data; new_client = create_client(new_fd, type, state); data = malloc(sizeof(struct handshake)); if(data == NULL) { close(new_fd); if(--nready < 0) break; continue; } if(new_client == NULL || data == NULL) { fprintf(stderr, "I cannot create a new client struct for fd %d\n", new_fd); if(new_client == NULL) free(new_client); if(data == NULL); free(data); close(new_fd); } else { buff_enq(new_client->rbuf, data, size); GDEBUG(1, "Accepting new connection from "); print_addr_port(new_client->fd); GDEBUG(1, " (fd = %d).\n", new_client->fd); pollfd_add(pfdinfo, new_client->fd, POLLIN, new_client); } } if(--nready <= 0) break; /*************************************************************************/ /* Management of descriptors ready to read of type REQ_RESP or EVENT_SUB */ /*************************************************************************/ } else if(pfdinfo->clients[i]->type == REQ_RESP || pfdinfo->clients[i]->type == EVENT_SUB) { struct client *client = pfdinfo->clients[i]; /***********************************************/ /* POLLIN */ /***********************************************/ if(pfdinfo->pollfd[i].revents & POLLIN) { void *buf; int size, nread; /* If there are data to read, but the read buffer is empty * I create a new message */ if(client->rbuf->first == NULL) { int size = 0; void *data; if(pfdinfo->clients[i]->type == REQ_RESP && pfdinfo->clients[i]->state == CONN_READING_HDR) size = sizeof(struct req_header); else if(pfdinfo->clients[i]->type == EVENT_SUB && pfdinfo->clients[i]->state == CONN_READING_HDR) size = sizeof(struct rsc_es_hdr); if(size != 0) { data = malloc(size); if(data == NULL) { close_connection(pfdinfo, i); deleted_entry = 1; if(--nready < 0) break; continue; } buff_enq(client->rbuf, data, size); } } GDEBUG(1, "There are data ready do be read for fd %d", pfdinfo->pollfd[i].fd); /* I read the data from the first message */ buf = client->rbuf->first->data + client->rbuf->first->n; size = client->rbuf->first->tot - client->rbuf->first->n; nread = read(client->fd, buf, size); if(nread <= 0 ) { /* If there is an error or the connection was close, * I close the connection from my side */ close_connection(pfdinfo, i); deleted_entry = 1; if(--nready <= 0) break; continue; } else { client->rbuf->first->n += nread; } /* If I've read all the data, I remove the buffer from client->rbuf * and I process the data */ if(client->rbuf->first->n == client->rbuf->first->tot) { void *read_data = buff_deq(client->rbuf); if(pfdinfo->clients[i]->type == REQ_RESP) { if(client->state == WAITING_ARCH) { /* I read the architecture of the client */ struct handshake *client_arch, *server_arch; client_arch = (struct handshake *)read_data; client->arch = ntohl(client_arch->arch); GDEBUG(1, "Client (%d) architecture is %s\n", client->fd, aconv_arch2str(client->arch)); free(read_data); /* Now I can send my architecture */ client->state = SENDING_ARCH; server_arch = calloc(1, sizeof(struct handshake)); if(server_arch == NULL) { close_connection(pfdinfo, i); deleted_entry = 1; if(--nready < 0) break; continue; } server_arch->arch = htonl(my_arch); buff_enq(client->wbuf, server_arch, sizeof(struct handshake)); pfdinfo->pollfd[i].events |= POLLOUT; client->state = SENDING_ARCH; }else if(client->state == CONN_READING_HDR) { struct req_header *req_hd; struct msg *m; int req_size; void *new_data; /* I've read all the request header, now I've to read all the request body */ client->state = CONN_READING_BODY; req_hd = (struct req_header *)read_data; req_size = rsc_req_msg_size(req_hd); new_data = realloc(read_data, req_size); if(new_data == NULL) { close_connection(pfdinfo, i); deleted_entry = 1; if(--nready < 0) break; continue; } m = buff_enq(client->rbuf, new_data, req_size); /* I've already read the req_header, so I need to update m->n field */ m->n = sizeof(struct req_header); }else if(client->state == CONN_READING_BODY) { /* Now I've read all the request and I can pass it to RSC function */ struct iovec *resp; resp = rscs_manage_request(client->arch, read_data); /* If there is an error, I close the connection */ if(resp == NULL) { close_connection(pfdinfo, i); deleted_entry = 1; if(--nready < 0) break; continue; } buff_enq(client->wbuf, resp[0].iov_base, resp[0].iov_len); pfdinfo->pollfd[i].events |= POLLOUT; client->state = CONN_SENDING_RESP; free(read_data); } } else { /* type == EVENT_SUB */ if(client->state == CONN_READING_HDR) { struct rsc_es_hdr *hdr; int size; void *new_data; struct msg *m; hdr = (struct rsc_es_hdr *)read_data; size = rsc_es_msg_size(hdr->type); if(size == -1) { close_connection(pfdinfo, i); deleted_entry = 1; if(--nready < 0) break; continue; } new_data = realloc(read_data, size); if(new_data == NULL) { close_connection(pfdinfo, i); deleted_entry = 1; if(--nready < 0) break; continue; } m = buff_enq(client->rbuf, new_data, size); m->n = sizeof(struct rsc_es_hdr); client->state = CONN_READING_BODY; } else if(client->state == CONN_READING_BODY) { struct rsc_es_ack *ack; ack = rscs_es_manage_msg(client->fd, read_data); free(read_data); /* I take the appropriate action based on ack->response field. * If the response is ACK_FD_REG I've to insert the fd into the * pollfd set. If the response is ACK_FD_DEREG_NOT_READY or ACK_FD_READY, * I remove the fd from the pollfd. */ if(ack->response == ACK_FD_REG) { struct client *c; /* Into the client structure I insert the stream fd and not the * fd to subscribe, In this way I can know where to send data */ c = create_client(client->fd, SUBSCRIBED_FD, CONN_SENDING_RESP); if(c == NULL) { close_connection(pfdinfo, i); deleted_entry = 1; if(--nready < 0) break; continue; } c->esfd_index = i; pollfd_add(pfdinfo, ntohl(ack->fd), ntohl(ack->how), c); } else if(ack->response == ACK_FD_DEREG_NOT_READY || ack->response == ACK_FD_DEREG_READY) { int j; for(j = 0; j < pfdinfo->size; j++) if( pfdinfo->pollfd[j].fd != -1 && pfdinfo->clients[j] != NULL && pfdinfo->clients[j]->type == SUBSCRIBED_FD && pfdinfo->clients[j]->fd == client->fd && pfdinfo->pollfd[j].fd == ntohl(ack->fd) && pfdinfo->pollfd[j].events == ntohl(ack->how)) break; if(j < pfdinfo->size) pollfd_del(pfdinfo, j); } GDEBUG(1, "After rscem_manage_msg:"); PRINT_POLLFDINFO(pfdinfo); /* Now I can send ack back */ buff_enq(client->wbuf, ack, sizeof(struct rsc_es_ack)); pfdinfo->pollfd[i].events |= POLLOUT; /* It's not an error, I don't need to keep trace of the sending state */ client->state = CONN_READING_HDR; } } } /***********************************************/ /* POLLOUT */ /***********************************************/ } else if(pfdinfo->pollfd[i].revents & POLLOUT) { void *buf; int size, nwrite; /* If write buffer is empty, I remove the POLLOUT event and I continue */ if(client->wbuf->first == NULL) { pfdinfo->pollfd[i].events &= (~POLLOUT); if(--nready <= 0) break; continue; } GDEBUG(1, "There are data ready do be written for fd %d", pfdinfo->pollfd[i].fd); buf = client->wbuf->first->data + client->wbuf->first->n; size = client->wbuf->first->tot - client->wbuf->first->n; nwrite = write(client->fd, buf, size); if(nwrite < 0) { close_connection(pfdinfo, i); deleted_entry = 1; if(--nready < 0) break; continue; } else { client->wbuf->first->n += nwrite; } if(client->wbuf->first->n == client->wbuf->first->tot) { /* I remove the message from the buffer and I free it */ void *data = buff_deq(client->wbuf); free(data); /* If it's a request/response fd and I've sent an arch or response message, * I change my state to reading header */ if( pfdinfo->clients[i]->type == REQ_RESP && ( client->state == SENDING_ARCH || client->state == CONN_SENDING_RESP) ) client->state = CONN_READING_HDR; /* if client->type is EVENT_SUB there is nothing to do: I need only * to continue to send the buffered data */ } } if(--nready <= 0) break; /*******************************************/ /* An event subscribed fd is waken up */ /*******************************************/ /* The event is occurred, I send back a response I didn't it before */ }else if(pfdinfo->clients[i]->type == SUBSCRIBED_FD) { struct rsc_es_resp *resp; int esfd_index = pfdinfo->clients[i]->esfd_index; resp = rscs_es_event_occurred(pfdinfo->pollfd[esfd_index].fd, pfdinfo->pollfd[i].fd, pfdinfo->pollfd[i].revents); if(resp != NULL) { buff_enq(pfdinfo->clients[esfd_index]->wbuf, resp, sizeof(struct rsc_es_resp)); pfdinfo->pollfd[esfd_index].events |= POLLOUT; } if(--nready <= 0) break; } } /* for(i = 0; i < nready; i++) */ /* If I've deleted a pfdinfo, I compact it */ if(deleted_entry) pollfd_compact(pfdinfo); } /* while(1) */ }
static void pollfd_added_cb(int fd, short events) { g_message("now monitoring fd %d", fd); pollfd_add(fd, events); }
void loop2(void) { int i, listenfd, clifd, nread; char buf[MAXLENLINE]; uid_t uid; struct pollfd *pollfd = NULL; int numfd = 1; pollfd_wrap *pfd_wrap; struct pollfd *default_pfd; default_pfd->fd = -1; default_pfd->events = POLLIN; default_pfd->events = 0; pfd_wrap->pfd = default_pfd; pfd_wrap->maxfd = NALLOC; pollfd_init(pfd_wrap, default_pfd); pollfd = pfd_wrap->pfd; int maxfd = pfd_wrap->maxfd; if ((listenfd = serv_listen(CS_OPEN)) < 0) { //log_sys("serv_listen error"); } client_add(listenfd, 0); pollfd[0].fd = listenfd; for (;;) { if (poll(pollfd, numfd, -1) < 0) { //log_sys("poll error"); } if (pollfd[0].revents & POLLIN) { if ((clifd = serv_accept(listenfd, &uid)) < 0) { //log_sys("serv_accept error: %d", clifd); } client_add(clifd,uid); if (numfd == pfd_wrap->maxfd) { default_pfd->fd = -1; pollfd_alloc(pfd_wrap, default_pfd); } else { default_pfd->fd = clifd; pollfd_add(pfd_wrap, default_pfd); } pollfd = pfd_wrap->pfd; pollfd[numfd].fd = clifd; pollfd[numfd].events = POLLIN; pollfd[numfd].revents = 0; numfd++; //log_msg("new connection: uid %d, fd %d, uid, clifd"); } for (i = 1; i < numfd; i++) { if (pollfd[i].revents & POLLHUP) { goto hungup; } else if(pollfd[i].revents & POLLIN) { if ((nread = read(pollfd[i].fd, buf, MAXLENLINE)) < 0) { //log_sys("read error on fd %d",pollfd[i].fd); } else if(nread == 0) { hungup: //log_msg("closed: fd %d", pollfd[i].fd); client_del(pollfd[i].fd); close(pollfd[i].fd); //pack the pollfd //TODO there is a drawback, if you allocate //many pollfds, it cannot be released if you //needn't them; if (i < (numfd-1)) { pollfd[i].fd = pollfd[numfd-1].fd; pollfd[i].events = pollfd[numfd-1].events; pollfd[i].revents = pollfd[numfd-1].revents; i--; } numfd--; } else { handle_request(buf, nread, pollfd[i].fd,client[i].uid); } } } } }