#include "mread.h" #include "ringbuffer.h" #include #include #include #include #include #include #include #include #include #include #include #include #define BACKLOG 32 #define READQUEUE 32 #define READBLOCKSIZE 2048 #define RINGBUFFER_DEFAULT 1024 * 1024 #define SOCKET_INVALID 0 #define SOCKET_CLOSED 1 #define SOCKET_SUSPEND 2 #define SOCKET_READ 3 #define SOCKET_POLLIN 4 #define SOCKET_ALIVE SOCKET_SUSPEND #define LISTENSOCKET (void *)((intptr_t)~0) struct socket { int fd; struct ringbuffer_block * node; struct ringbuffer_block * temp; int status; }; struct mread_pool { int listen_fd; int epoll_fd; int max_connection; int closed; int active; int skip; struct socket * sockets; struct socket * free_socket; int queue_len; int queue_head; struct epoll_event ev[READQUEUE]; struct ringbuffer * rb; }; static struct socket * _create_sockets(int max) { int i; struct socket * s = malloc(max * sizeof(struct socket)); for (i=0;ilisten_fd = listen_fd; self->epoll_fd = epoll_fd; self->max_connection = max; self->closed = 0; self->active = -1; self->skip = 0; self->sockets = _create_sockets(max); self->free_socket = &self->sockets[0]; self->queue_len = 0; self->queue_head = 0; if (buffer_size == 0) { self->rb = _create_rb(RINGBUFFER_DEFAULT); } else { self->rb = _create_rb(buffer_size); } return self; } void mread_close(struct mread_pool *self) { if (self == NULL) return; int i; struct socket * s = self->sockets; for (i=0;imax_connection;i++) { if (s[i].status >= SOCKET_ALIVE) { close(s[i].fd); } } free(s); if (self->listen_fd >= 0) { close(self->listen_fd); } close(self->epoll_fd); _release_rb(self->rb); free(self); } static int _read_queue(struct mread_pool * self, int timeout) { self->queue_head = 0; int n = epoll_wait(self->epoll_fd , self->ev, READQUEUE, timeout); if (n == -1) { self->queue_len = 0; return -1; } self->queue_len = n; return n; } inline static struct socket * _read_one(struct mread_pool * self) { if (self->queue_head >= self->queue_len) { return NULL; } return self->ev[self->queue_head ++].data.ptr; } static struct socket * _alloc_socket(struct mread_pool * self) { if (self->free_socket == NULL) { return NULL; } struct socket * s = self->free_socket; int next_free = s->fd; if (next_free < 0 ) { self->free_socket = NULL; } else { self->free_socket = &self->sockets[next_free]; } return s; } static struct socket * _add_client(struct mread_pool * self, int fd) { struct socket * s = _alloc_socket(self); if (s == NULL) { close(fd); return NULL; } struct epoll_event ev; ev.events = EPOLLIN; ev.data.ptr = s; if (epoll_ctl(self->epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) { close(fd); return NULL; } s->fd = fd; s->node = NULL; s->status = SOCKET_SUSPEND; return s; } static int _report_closed(struct mread_pool * self) { int i; for (i=0;imax_connection;i++) { if (self->sockets[i].status == SOCKET_CLOSED) { self->active = i; return i; } } assert(0); return -1; } int mread_poll(struct mread_pool * self , int timeout) { self->skip = 0; if (self->active >= 0) { struct socket * s = &self->sockets[self->active]; if (s->status == SOCKET_READ) { return self->active; } } if (self->closed > 0 ) { return _report_closed(self); } if (self->queue_head >= self->queue_len) { if (_read_queue(self, timeout) == -1) { self->active = -1; return -1; } } for (;;) { struct socket * s = _read_one(self); if (s == NULL) { self->active = -1; return -1; } if (s == LISTENSOCKET) { struct sockaddr_in remote_addr; socklen_t len = sizeof(struct sockaddr_in); int client_fd = accept(self->listen_fd , (struct sockaddr *)&remote_addr , &len); if (client_fd >= 0) { // printf("MREAD connect %s:%u (fd=%d)\n",inet_ntoa(remote_addr.sin_addr),ntohs(remote_addr.sin_port), client_fd); struct socket * s = _add_client(self, client_fd); if (s) { self->active = -1; return s - self->sockets; } } } else { int index = s - self->sockets; assert(index >=0 && index < self->max_connection); self->active = index; s->status = SOCKET_POLLIN; return index; } } } int mread_socket(struct mread_pool * self, int index) { return self->sockets[index].fd; } static void _link_node(struct ringbuffer * rb, int id, struct socket * s , struct ringbuffer_block * blk) { if (s->node) { ringbuffer_link(rb, s->node , blk); } else { blk->id = id; s->node = blk; } } void mread_close_client(struct mread_pool * self, int id) { struct socket * s = &self->sockets[id]; s->status = SOCKET_CLOSED; s->node = NULL; s->temp = NULL; close(s->fd); // printf("MREAD close %d (fd=%d)\n",id,s->fd); epoll_ctl(self->epoll_fd, EPOLL_CTL_DEL, s->fd , NULL); ++self->closed; } static void _close_active(struct mread_pool * self) { int id = self->active; struct socket * s = &self->sockets[id]; ringbuffer_free(self->rb, s->temp); ringbuffer_free(self->rb, s->node); mread_close_client(self, id); } static char * _ringbuffer_read(struct mread_pool * self, int *size) { struct socket * s = &self->sockets[self->active]; if (s->node == NULL) { *size = 0; return NULL; } int sz = *size; void * ret; *size = ringbuffer_data(self->rb, s->node, sz , self->skip, &ret); return ret; } void * mread_pull(struct mread_pool * self , int size) { if (self->active == -1) { return NULL; } struct socket *s = &self->sockets[self->active]; int rd_size = size; char * buffer = _ringbuffer_read(self, &rd_size); if (buffer) { self->skip += size; return buffer; } switch (s->status) { case SOCKET_READ: s->status = SOCKET_SUSPEND; case SOCKET_CLOSED: case SOCKET_SUSPEND: return NULL; default: assert(s->status == SOCKET_POLLIN); break; } int sz = size - rd_size; int rd = READBLOCKSIZE; if (rd < sz) { rd = sz; } int id = self->active; struct ringbuffer * rb = self->rb; struct ringbuffer_block * blk = ringbuffer_alloc(rb , rd); while (blk == NULL) { int collect_id = ringbuffer_collect(rb); mread_close_client(self , collect_id); if (id == collect_id) { return NULL; } blk = ringbuffer_alloc(rb , rd); } buffer = (char *)(blk + 1); for (;;) { int bytes = recv(s->fd, buffer, rd, MSG_DONTWAIT); if (bytes > 0) { ringbuffer_resize(rb, blk , bytes); if (bytes < sz) { _link_node(rb, self->active, s , blk); s->status = SOCKET_SUSPEND; return NULL; } s->status = SOCKET_READ; break; } if (bytes == 0) { ringbuffer_resize(rb, blk, 0); _close_active(self); return NULL; } if (bytes == -1) { switch(errno) { case EWOULDBLOCK: ringbuffer_resize(rb, blk, 0); s->status = SOCKET_SUSPEND; return NULL; case EINTR: continue; default: ringbuffer_resize(rb, blk, 0); _close_active(self); return NULL; } } } _link_node(rb, self->active , s , blk); void * ret; int real_rd = ringbuffer_data(rb, s->node , size , self->skip, &ret); if (ret) { self->skip += size; return ret; } assert(real_rd == size); struct ringbuffer_block * temp = ringbuffer_alloc(rb, size); while (temp == NULL) { int collect_id = ringbuffer_collect(rb); mread_close_client(self , collect_id); if (id == collect_id) { return NULL; } temp = ringbuffer_alloc(rb , size); } temp->id = id; if (s->temp) { ringbuffer_link(rb, temp, s->temp); } s->temp = temp; ret = ringbuffer_copy(rb, s->node, self->skip, temp); assert(ret); self->skip += size; return ret; } void mread_yield(struct mread_pool * self) { if (self->active == -1) { return; } struct socket *s = &self->sockets[self->active]; ringbuffer_free(self->rb , s->temp); s->temp = NULL; if (s->status == SOCKET_CLOSED && s->node == NULL) { --self->closed; s->status = SOCKET_INVALID; s->fd = self->free_socket - self->sockets; self->free_socket = s; self->skip = 0; self->active = -1; } else { if (s->node) { s->node = ringbuffer_yield(self->rb, s->node, self->skip); } self->skip = 0; if (s->node == NULL) { self->active = -1; } } } int mread_closed(struct mread_pool * self) { if (self->active == -1) { return 0; } struct socket * s = &self->sockets[self->active]; if (s->status == SOCKET_CLOSED && s->node == NULL) { mread_yield(self); return 1; } return 0; }