static void send_msg_udp(struct silly_socket *ss, struct socket *s) { struct wlist *w; w = s->wlhead.next; assert(w); while (w) { ssize_t sz; sz = sendudp(s->fd, w->buff + w->offset, w->size, &w->udpaddress); if (sz == -2) //EAGAIN, so block it break; assert(sz == -1 || sz == w->size); //send fail && send ok will clear s->wlhead.next = w->next; silly_free(w->buff); silly_free(w); w = s->wlhead.next; if (w == NULL) {//send all s->wltail = &s->wlhead; sp_write_enable(ss->spfd, s->fd, s, 0); if (s->type == STYPE_HALFCLOSE) delsocket(ss, s); } } return ; }
static int tryudpsend(struct silly_socket *ss, struct cmdpacket *cmd) { struct socket *s = checksocket(ss, cmd->u.udpsend.sid); uint8_t *data = cmd->u.udpsend.data; size_t sz = cmd->u.udpsend.size; const struct sockaddr *addr = &cmd->u.udpsend.to; if (s == NULL) { silly_free(data); return 0; } assert(s->protocol == PROTOCOL_UDP); if (s->type == STYPE_SOCKET) //udp client need no address addr = NULL; if (wlist_empty(s)) {//try send ssize_t n = sendudp(s->fd, data, sz, addr); if (n == -1 || n >= 0) { //occurs error or send ok silly_free(data); return 0; } assert(n == -2); //EAGAIN wlist_append(s, data, 0, sz, addr); } else { wlist_append(s, data, 0, sz, addr); } return 0; }
static void send_msg_tcp(struct silly_socket *ss, struct socket *s) { struct wlist *w; w = s->wlhead.next; assert(w); while (w) { ssize_t sz; sz = sendn(s->fd, w->buff + w->offset, w->size); if (sz < 0) { report_close(ss, s, errno); delsocket(ss, s); return ; } if (sz < w->size) {//send some w->size -= sz; w->offset += sz; return ; } assert(sz == w->size); s->wlhead.next = w->next; silly_free(w->buff); silly_free(w); w = s->wlhead.next; if (w == NULL) {//send ok s->wltail = &s->wlhead; sp_write_enable(ss->spfd, s->fd, s, 0); if (s->type == STYPE_HALFCLOSE) delsocket(ss, s); } } return ; }
static int trysend(struct silly_socket *ss, struct cmdpacket *cmd) { struct socket *s = checksocket(ss, cmd->u.send.sid); uint8_t *data = cmd->u.send.data; size_t sz = cmd->u.send.size; if (s == NULL) { silly_free(data); return 0; } if (wlist_empty(s)) {//try send ssize_t n = sendn(s->fd, data, sz); if (n < 0) { silly_free(data); report_close(ss, s, errno); delsocket(ss, s); return -1; } else if (n < sz) { wlist_append(s, data, n, sz, NULL); sp_write_enable(ss->spfd, s->fd, s, 1); } else { assert(n == sz); silly_free(data); } } else { wlist_append(s, data, 0, sz, NULL); } return 0; }
static int forward_msg_tcp(struct silly_socket *ss, struct socket *s) { ssize_t sz; ssize_t presize = s->presize; uint8_t *buff = (uint8_t *)silly_malloc(presize); sz = readn(s->fd, buff, presize); //half close socket need no data if (sz > 0 && s->type != STYPE_HALFCLOSE) { report_data(ss, s, SILLY_SDATA, buff, sz); //to predict the pakcet size if (sz == presize) { s->presize *= 2; } else if (presize > MIN_READBUFF_LEN) { //s->presize at leatest is 2 * MIN_READBUFF_LEN int half = presize / 2; if (sz < half) s->presize = half; } } else { silly_free(buff); if (sz < 0) { report_close(ss, s, errno); delsocket(ss, s); return -1; } return 0; } return sz; }
int silly_socket_udpsend(int sid, uint8_t *buff, size_t sz, const char *addr, size_t addrlen) { struct cmdpacket cmd; struct socket *s = checksocket(SSOCKET, sid); if (s == NULL) { silly_free(buff); return -1; } assert(s->protocol = PROTOCOL_UDP); assert(s->type == STYPE_UDPBIND || s->type == STYPE_SOCKET); if (s->type == STYPE_UDPBIND && addr == NULL) { fprintf(stderr, "[socket] udpsend udpbind socket must specify dest addr\n"); return -1; } cmd.type = 'U'; cmd.u.udpsend.sid = sid; cmd.u.udpsend.data= buff; cmd.u.udpsend.size = sz; if (s->type == STYPE_UDPBIND) {//udp bind socket need sendto address assert(addrlen == sizeof(cmd.u.udpsend.to)); memcpy(&cmd.u.udpsend.to, addr, sizeof(cmd.u.udpsend.to)); } pipe_blockwrite(SSOCKET->ctrlsendfd, &cmd); return 0; }
void silly_worker_exit() { lua_close(W->L); silly_queue_free(W->queue); silly_free(W); }
static void wlist_free(struct socket *s) { struct wlist *w; struct wlist *t; w = s->wlhead.next; while (w) { t = w; w = w->next; assert(t->buff); silly_free(t->buff); silly_free(t); } s->wlhead.next = NULL; s->wltail = &s->wlhead; return ; }
static int _ldrop(lua_State *L) { struct silly_message *m = (struct silly_message *)lua_touserdata(L, 1); if (m->type == SILLY_SOCKET_DATA) { struct silly_message_socket *sm = (struct silly_message_socket *)(m + 1); assert(sm->data); silly_free(sm->data); } return 0; }
int silly_socket_send(int sid, uint8_t *buff, size_t sz) { struct cmdpacket cmd; struct socket *s = checksocket(SSOCKET, sid); if (s == NULL) { silly_free(buff); return -1; } if (sz == 0) { silly_free(buff); return -1; } cmd.type = 'S'; cmd.u.send.sid = sid; cmd.u.send.data = buff; cmd.u.send.size = sz; pipe_blockwrite(SSOCKET->ctrlsendfd, &cmd); return 0; }
static void * lua_alloc(void *ud, void *ptr, size_t osize, size_t nsize) { (void) ud; (void) osize; if (nsize == 0) { silly_free(ptr); return NULL; } else { return silly_realloc(ptr, nsize); } }
void silly_socket_exit() { int i; assert(SSOCKET); sp_free(SSOCKET->spfd); close(SSOCKET->ctrlsendfd); close(SSOCKET->ctrlrecvfd); struct socket *s = &SSOCKET->socketpool[0]; for (i = 0; i < MAX_SOCKET_COUNT; i++) { int isnormal = 0; enum stype type = s->type; isnormal += type == STYPE_SOCKET ? 1 : 0; isnormal += type == STYPE_LISTEN ? 1 : 0; isnormal += type == STYPE_HALFCLOSE ? 1 : 0; if (isnormal > 0) close(s->fd); } silly_free(SSOCKET->eventbuff); silly_free(SSOCKET->socketpool); silly_free(SSOCKET); return ; }
void silly_queue_free(struct silly_queue *q) { struct silly_message *next, *tmp; lock(q); next = q->head.next; while (next) { tmp = next; next = next->next; silly_message_free(tmp); } unlock(q); silly_free(q); return ; }
int silly_socket_init() { int err; sp_t spfd = SP_INVALID; int fd[2] = {-1, -1}; struct socket *s = NULL; struct silly_socket *ss = silly_malloc(sizeof(*ss)); memset(ss, 0, sizeof(*ss)); socketpool_init(ss); spfd = sp_create(EVENT_SIZE); if (spfd == SP_INVALID) goto end; s = allocsocket(ss, STYPE_CTRL, PROTOCOL_PIPE); assert(s); err = pipe(fd); //use the pipe and not the socketpair because the pipe will be automatic when the data size small than BUFF_SIZE if (err < 0) goto end; err = sp_add(spfd, fd[0], s); if (err < 0) goto end; ss->spfd = spfd; ss->ctrlsendfd = fd[1]; ss->ctrlrecvfd = fd[0]; ss->eventindex = 0; ss->eventcount = 0; resize_eventbuff(ss, EVENT_SIZE); FD_ZERO(&ss->ctrlfdset); SSOCKET = ss; return 0; end: if (s) freesocket(ss, s); if (spfd != SP_INVALID) sp_free(spfd); if (fd[0] >= 0) close(fd[0]); if (fd[1] >= 0) close(fd[0]); if (ss) silly_free(ss); return -errno; }
static inline void freenode(struct node *n) { silly_free(n); return ; }