static int send_list_udp(struct socket_server *ss, struct socket *s, struct wb_list *list, struct socket_message *result) { while (list->head) { struct write_buffer * tmp = list->head; union sockaddr_all sa; socklen_t sasz = udp_socket_address(s, tmp->udp_address, &sa); int err = sendto(s->fd, tmp->ptr, tmp->sz, 0, &sa.s, sasz); if (err < 0) { switch(errno) { case EINTR: case AGAIN_WOULDBLOCK: return -1; } fprintf(stderr, "socket-server : udp (%d) sendto error %s.\n",s->id, strerror(errno)); return -1; /* // ignore udp sendto error result->opaque = s->opaque; result->id = s->id; result->ud = 0; result->data = NULL; return SOCKET_ERROR; */ } s->wb_size -= tmp->sz; list->head = tmp->next; write_buffer_free(ss,tmp); } list->tail = NULL; return -1; }
/* When send a package , we can assign the priority : PRIORITY_HIGH or PRIORITY_LOW If socket buffer is empty, write to fd directly. If write a part, append the rest part to high list. (Even priority is PRIORITY_LOW) Else append package to high (PRIORITY_HIGH) or low (PRIORITY_LOW) list. */ static int send_socket(struct socket_server *ss, struct request_send * request, struct socket_message *result, int priority, const uint8_t *udp_address) { int id = request->id; struct socket * s = &ss->slot[HASH_ID(id)]; struct send_object so; send_object_init(ss, &so, request->buffer, request->sz); if (s->type == SOCKET_TYPE_INVALID || s->id != id || s->type == SOCKET_TYPE_HALFCLOSE || s->type == SOCKET_TYPE_PACCEPT) { so.free_func(request->buffer); return -1; } if (s->type == SOCKET_TYPE_PLISTEN || s->type == SOCKET_TYPE_LISTEN) { fprintf(stderr, "socket-server: write to listen fd %d.\n", id); so.free_func(request->buffer); return -1; } if (send_buffer_empty(s) && s->type == SOCKET_TYPE_CONNECTED) { // 如果已连接且发送缓冲区为空 if (s->protocol == PROTOCOL_TCP) { // 直接写入套接字 int n = write(s->fd, so.buffer, so.sz); if (n<0) { switch(errno) { case EINTR: case AGAIN_WOULDBLOCK: // 信号中断或者缓冲区写满 n = 0; break; default: fprintf(stderr, "socket-server: write to %d (fd=%d) error :%s.\n",id,s->fd,strerror(errno)); force_close(ss,s,result); so.free_func(request->buffer); return SOCKET_CLOSE; } } if (n == so.sz) { // 如果全部发送完,释放数据缓冲区,返回-1 so.free_func(request->buffer); return -1; } // 如果没有发送完,剩余数据放到高优先级写缓冲区链表 append_sendbuffer(ss, s, request, n); // add to high priority list, even priority == PRIORITY_LOW } else { // udp if (udp_address == NULL) { udp_address = s->p.udp_address; } union sockaddr_all sa; socklen_t sasz = udp_socket_address(s, udp_address, &sa); int n = sendto(s->fd, so.buffer, so.sz, 0, &sa.s, sasz); if (n != so.sz) { append_sendbuffer_udp(ss,s,priority,request,udp_address); } else { so.free_func(request->buffer); return -1; } } // 打开事件循环中fd的可写权限 sp_write(ss->event_fd, s->fd, s, true); } else { if (s->protocol == PROTOCOL_TCP) { if (priority == PRIORITY_LOW) { append_sendbuffer_low(ss, s, request); } else { append_sendbuffer(ss, s, request, 0); } } else { if (udp_address == NULL) { udp_address = s->p.udp_address; } append_sendbuffer_udp(ss,s,priority,request,udp_address); } } return -1; }
static int socket_req_send(struct _send_req *req, struct socket_message *msg, const uint8_t *udp_address) { struct socket * sock = &S.slot[HASH_ID(req->id)]; struct socket_send_object so; socket_send_object_init(&so, req->data, req->size); if (sock->type == SOCKET_TYPE_INVALID || sock->id != req->id || sock->type == SOCKET_TYPE_HALFCLOSE || sock->type == SOCKET_TYPE_PACCEPT) { so.free(req->data); return -1; } if (sock->type == SOCKET_TYPE_PLISTEN || sock->type == SOCKET_TYPE_LISTEN) { fprintf(stderr, "socket_req_send: write to listen fd:%d\n", sock->id); so.free(req->data); return -1; } if (sock->high.head == 0 && sock->low.head == 0 && sock->type == SOCKET_TYPE_OPENED) { if (sock->protocol == PROTOCOL_TCP) { int n = write(sock->fd, so.data, so.size); if (n < 0) { switch (errno) { case EINTR: case EAGAIN: n = 0; break; default: fprintf(stderr, "socket_req_send: write to %d (fd=%d) error:%d\n", sock->id, sock->fd, errno); socket_force_close(sock, msg); so.free(req->data); return SOCKET_CLOSE; } } if (n == so.size) { so.free(req->data); return -1; } socket_append_sendbuffer(sock, req, n); } else { int n; union sockaddr_all sa; socklen_t sa_size; if (!udp_address) { udp_address = sock->p.udp_address; } sa_size = udp_socket_address(sock, udp_address, &sa); n = sendto(sock->fd, so.data, so.size, 0, &sa.s, sa_size); if (n != req->size) { socket_append_udp_sendbuffer(sock, req, udp_address); } else { so.free(req->data); return -1; } } event_write(S.event_fd, sock->fd, sock, 1); } else { if (sock->protocol == PROTOCOL_TCP) { socket_append_sendbuffer(sock, req, 0); } else { if (!udp_address) { udp_address = sock->p.udp_address; } socket_append_udp_sendbuffer(sock, req, udp_address); } } if (sock->wb_size > 1024 * 1024) { msg->id = sock->id; msg->size = (int)(sock->wb_size / 1024); msg->data = 0; msg->ud = sock->ud; return SOCKET_WARNING; } return -1; }