// 启动socket,加入事件循环 // 成功时返回SOCKET_OPEN static int start_socket(struct socket_server *ss, struct request_start *request, struct socket_message *result) { int id = request->id; result->id = id; result->opaque = request->opaque; result->ud = 0; result->data = NULL; struct socket *s = &ss->slot[HASH_ID(id)]; if (s->type == SOCKET_TYPE_INVALID || s->id !=id) { result->data = "invalid socket"; return SOCKET_ERROR; } if (s->type == SOCKET_TYPE_PACCEPT || s->type == SOCKET_TYPE_PLISTEN) { // 套接字加入事件循环 if (sp_add(ss->event_fd, s->fd, s)) { force_close(ss, s, result); result->data = strerror(errno); return SOCKET_ERROR; } // SOCKET_TYPE_PACCEPT -> SOCKET_TYPE_CONNECTED // SOCKET_TYPE_PLISTEN -> SOCKET_TYPE_LISTEN s->type = (s->type == SOCKET_TYPE_PACCEPT) ? SOCKET_TYPE_CONNECTED : SOCKET_TYPE_LISTEN; s->opaque = request->opaque; result->data = "start"; return SOCKET_OPEN; } else if (s->type == SOCKET_TYPE_CONNECTED) { // todo: maybe we should send a message SOCKET_TRANSFER to s->opaque s->opaque = request->opaque; result->data = "transfer"; return SOCKET_OPEN; } // if s->type == SOCKET_TYPE_HALFCLOSE , SOCKET_CLOSE message will send later return -1; }
int64_t socket_server_udp_send(struct socket_server *ss, int id, const struct socket_udp_address *addr, const void *buffer, int sz) { struct socket * s = &ss->slot[HASH_ID(id)]; if (s->id != id || s->type == SOCKET_TYPE_INVALID) { free_buffer(ss, buffer, sz); return -1; } struct request_package request; request.u.send_udp.send.id = id; request.u.send_udp.send.sz = sz; request.u.send_udp.send.buffer = (char *)buffer; const uint8_t *udp_address = (const uint8_t *)addr; int addrsz; switch (udp_address[0]) { case PROTOCOL_UDP: addrsz = 1+2+4; // 1 type, 2 port, 4 ipv4 break; case PROTOCOL_UDPv6: addrsz = 1+2+16; // 1 type, 2 port, 16 ipv6 break; default: free_buffer(ss, buffer, sz); return -1; } memcpy(request.u.send_udp.address, udp_address, addrsz); send_request(ss, &request, 'A', sizeof(request.u.send_udp.send)+addrsz); return s->wb_size; }
// 创建新的socket实例 // id,通过reserve_id分配的alloc_id // fd, 通过socket创建的套接字 // add, true则加入事件循环 static struct socket * new_fd(struct socket_server *ss, int id, int fd, int protocol, uintptr_t opaque, bool add) { struct socket * s = &ss->slot[HASH_ID(id)]; // 正常情况下,socket已在reserve_id中赋值为保留类型 assert(s->type == SOCKET_TYPE_RESERVE); if (add) { // 加入事件循环 if (sp_add(ss->event_fd, fd, s)) { // 如果加入失败,socket重置为初始类型 s->type = SOCKET_TYPE_INVALID; return NULL; } } // 初始化变量 s->id = id; s->fd = fd; s->protocol = protocol; s->p.size = MIN_READ_BUFFER; s->opaque = opaque; s->wb_size = 0; check_wb_list(&s->high); check_wb_list(&s->low); return s; }
static int socket_req_start(struct _start_req *req, struct socket_message *msg) { struct socket *sock; msg->id = req->id; msg->ud = req->ud; sock = &S.slot[HASH_ID(req->id)]; if (sock->type == SOCKET_TYPE_INVALID || sock->id != req->id) { msg->data = "socket invalid id"; return SOCKET_ERR; } if (sock->type == SOCKET_TYPE_PACCEPT || sock->type == SOCKET_TYPE_PLISTEN) { if (event_add(S.event_fd, sock->fd, sock)) { sock->type = SOCKET_TYPE_INVALID; msg->data = strerror(errno); return SOCKET_ERR; } sock->type = (sock->type == SOCKET_TYPE_PACCEPT) ? SOCKET_TYPE_OPENED : SOCKET_TYPE_LISTEN; sock->ud = req->ud; msg->data = "start"; return SOCKET_OPEN; } else if (sock->type == SOCKET_TYPE_OPENED) { sock->ud = req->ud; msg->data = "transfer"; return SOCKET_OPEN; } return -1; }
// 递增分配id进行hash,并返回匹配的socket static int reserve_id(struct socket_server *ss) { int i; for (i=0;i<MAX_SOCKET;i++) { // 递增 int id = ATOM_INC(&(ss->alloc_id)); if (id < 0) { // 回绕 id = ATOM_AND(&(ss->alloc_id), 0x7fffffff); } // 哈希匹配 struct socket *s = &ss->slot[HASH_ID(id)]; if (s->type == SOCKET_TYPE_INVALID) { // 如果是初始类型,修改为保留类型 if (ATOM_CAS(&s->type, SOCKET_TYPE_INVALID, SOCKET_TYPE_RESERVE)) { s->id = id; s->fd = -1; return id; } else { // 否则,重试 // retry --i; } } } return -1; }
long socket_udpsend(int id, const struct socket_udp_address *address, const void *data, int size) { const uint8_t *udp_address; int addrsize; struct socket_req req; struct socket * sock = &S.slot[HASH_ID(id)]; if (sock->id != id || sock->type == SOCKET_TYPE_INVALID) { freebuffer((void *)data, size); return -1; } memset(&req, 0, sizeof req); req.req = SOCKET_REQ_SENDUDP; req.u.send.id = id; req.u.send.data = (char *)data; req.u.send.size = size; udp_address = (const uint8_t *)address; switch (udp_address[0]) { case PROTOCOL_UDP: addrsize = 1 + 2 + 4; break; case PROTOCOL_UDPv6: addrsize = 1 + 2 + 16; break; default: freebuffer((void *)data, size); return -1; } memcpy(req.u.sendudp.address, udp_address, addrsize); socket_send_req(&req); return sock->wb_size; }
static int close_socket(struct socket_server *ss, struct request_close *request, struct socket_message *result) { int id = request->id; struct socket * s = &ss->slot[HASH_ID(id)]; if (s->type == SOCKET_TYPE_INVALID || s->id != id) { result->id = id; result->opaque = request->opaque; result->ud = 0; result->data = NULL; return SOCKET_CLOSE; } if (!send_buffer_empty(s)) { int type = send_buffer(ss,s,result); if (type != -1) return type; } if (send_buffer_empty(s)) { force_close(ss,s,result); result->id = id; result->opaque = request->opaque; return SOCKET_CLOSE; } s->type = SOCKET_TYPE_HALFCLOSE; return -1; }
static int start_socket(struct socket_server *ss, struct request_start *request, struct socket_message *result) { int id = request->id; result->id = id; result->opaque = request->opaque; result->ud = 0; result->data = NULL; struct socket *s = &ss->slot[HASH_ID(id)]; if (s->type == SOCKET_TYPE_INVALID || s->id !=id) { return SOCKET_ERROR; } if (s->type == SOCKET_TYPE_PACCEPT || s->type == SOCKET_TYPE_PLISTEN) { if (sp_add(ss->event_fd, s->fd, s)) { s->type = SOCKET_TYPE_INVALID; return SOCKET_ERROR; } s->type = (s->type == SOCKET_TYPE_PACCEPT) ? SOCKET_TYPE_CONNECTED : SOCKET_TYPE_LISTEN; s->opaque = request->opaque; result->data = "start"; return SOCKET_OPEN; } else if (s->type == SOCKET_TYPE_CONNECTED) { s->opaque = request->opaque; result->data = "transfer"; return SOCKET_OPEN; } return -1; }
static int socket_req_opt(struct _opt_req *req, struct socket_message *msg) { struct socket *sock; sock = &S.slot[HASH_ID(req->id)]; if (sock->type == SOCKET_TYPE_INVALID || sock->id != req->id) { return -1; } setsockopt(sock->fd, IPPROTO_TCP, req->what, (const char *)&req->value, sizeof(req->value)); return -1; }
static void setopt_socket(struct socket_server *ss, struct request_setopt *request) { int id = request->id; struct socket *s = &ss->slot[HASH_ID(id)]; if (s->type == SOCKET_TYPE_INVALID || s->id !=id) { return; } int v = request->value; setsockopt(s->fd, IPPROTO_TCP, request->what, &v, sizeof(v)); }
void socket_server_send_lowpriority(struct socket_server *ss, int id, const void * buffer, int sz) { struct socket * s = &ss->slot[HASH_ID(id)]; if (s->id != id || s->type == SOCKET_TYPE_INVALID) { return; } struct request_package request; request.u.send.id = id; request.u.send.sz = sz; request.u.send.buffer = (char *)buffer; send_request(ss, &request, 'P', sizeof(request.u.send)); }
static int socket_req_listen(struct _listen_req *req, struct socket_message *msg) { struct socket *sock = socket_new(req->fd, req->id, PROTOCOL_TCP, req->ud, 0); if (sock == 0) { goto _failed; } sock->type = SOCKET_TYPE_PLISTEN; return -1; _failed: close(req->fd); msg->ud = req->ud; msg->id = req->id; msg->data = "socket limit"; S.slot[HASH_ID(req->id)].type = SOCKET_TYPE_INVALID; return SOCKET_ERR; }
// return -1 when error // send_socket HIGH int64_t socket_server_send(struct socket_server *ss, int id, const void * buffer, int sz) { struct socket * s = &ss->slot[HASH_ID(id)]; if (s->id != id || s->type == SOCKET_TYPE_INVALID) { free_buffer(ss, buffer, sz); return -1; } struct request_package request; request.u.send.id = id; request.u.send.sz = sz; request.u.send.buffer = (char *)buffer; send_request(ss, &request, 'D', sizeof(request.u.send)); return s->wb_size; }
long socket_send(int id, const void *data, int size, int priority) { struct socket_req req; struct socket * sock = &S.slot[HASH_ID(id)]; if (sock->id != id || sock->type == SOCKET_TYPE_INVALID) { freebuffer((void *)data, size); return -1; } memset(&req, 0, sizeof req); req.req = SOCKET_REQ_SEND; req.u.send.id = id; req.u.send.data = (char *)data; req.u.send.size = size; req.u.send.priority = priority; socket_send_req(&req); return sock->wb_size; }
static void add_udp_socket(struct socket_server *ss, struct request_udp *udp) { int id = udp->id; int protocol; if (udp->family == AF_INET6) { protocol = PROTOCOL_UDPv6; } else { protocol = PROTOCOL_UDP; } struct socket *ns = new_fd(ss, id, udp->fd, protocol, udp->opaque, true); if (ns == NULL) { close(udp->fd); ss->slot[HASH_ID(id)].type = SOCKET_TYPE_INVALID; return; } ns->type = SOCKET_TYPE_CONNECTED; memset(ns->p.udp_address, 0, sizeof(ns->p.udp_address)); }
static int socket_req_udp(struct _udp_req *req, struct socket_message *msg) { int id = req->id; int protocol; struct socket *sock; if (req->family == AF_INET6) { protocol = PROTOCOL_UDPv6; } else { protocol = PROTOCOL_UDP; } sock = socket_new(req->fd, id, protocol, req->ud, 1); if (!sock) { close(req->fd); S.slot[HASH_ID(id)].type = SOCKET_TYPE_INVALID; return -1; } sock->type = SOCKET_TYPE_OPENED; memset(sock->p.udp_address, 0, sizeof(sock->p.udp_address)); return -1; }
int socket_server::listen_socket(struct request_listen * request, struct socket_message * result) { int id = request->id; int listen_fd = request->fd; struct socket * s = new_socket(id, listen_fd, PROTOCOL_TCP, request->opaque, false); if (s == nullptr) { goto _failed; } s->type = SOCKET_TYPE_PLISTEN; return -1; _failed: close(listen_fd); result->opaque = request->opaque; result->id = id; result->ud = 0; result->data = nullptr; slot[HASH_ID(id)].type = SOCKET_TYPE_INVALID; return SOCKET_ERROR; }
static int socket_next_id(void) { int i; for (i = 0; i < MAX_SOCKET; i++) { struct socket *sock; int id = atom_inc(&(S.next_id)); if (id < 0) { id = atom_and(&(S.next_id), 0x7fffffff); } sock = &S.slot[HASH_ID(id)]; if (sock->type == SOCKET_TYPE_INVALID) { if (atom_cas(&(sock->type), SOCKET_TYPE_INVALID, SOCKET_TYPE_RESERVE)) { sock->id = id; sock->fd = -1; return id; } --i; } } return -1; }
struct socket * socket_server::new_socket(int id, int fd, int protocol, uintptr_t opaque, bool add) { struct socket * s = &slot[HASH_ID(id)]; assert(s->type == SOCKET_TYPE_RESERVE); if (add) { if (event_fd.add(fd, s)) { s->type = SOCKET_TYPE_INVALID; return nullptr; } } s->id = id; s->fd = fd; s->protocol = protocol; s->opaque = opaque; return s; }
static int listen_socket(struct socket_server *ss, struct request_listen * request, struct socket_message *result) { int id = request->id; int listen_fd = request->fd; struct socket *s = new_fd(ss, id, listen_fd, request->opaque, false); if (s == NULL) { goto _failed; } s->type = SOCKET_TYPE_PLISTEN; return -1; _failed: close(listen_fd); result->opaque = request->opaque; result->id = id; result->ud = 0; result->data = NULL; ss->slot[HASH_ID(id)].type = SOCKET_TYPE_INVALID; return SOCKET_ERROR; }
int socket_server::reserve_id() { for (int i = 0; i < MAX_SOCKET; i++) { int id = __sync_add_and_fetch(&alloc_id, 1); if (id < 0) { id = __sync_and_and_fetch(&alloc_id, 0x7fffffff); } struct socket *s = &slot[HASH_ID(id)]; if (s->type == SOCKET_TYPE_INVALID) { if (__sync_bool_compare_and_swap(&s->type, SOCKET_TYPE_INVALID, SOCKET_TYPE_RESERVE)) { s->id = id; s->fd = -1; return id; } else { --i; } } } return -1; }
static struct socket *socket_new(int fd, int id, int protocol, void *ud, int add) { struct socket *sock; sock = &S.slot[HASH_ID(id)]; assert(sock->type == SOCKET_TYPE_RESERVE); sock->id = id; sock->fd = fd; sock->ud = ud; sock->p.size = MIN_SOCK_BUFF; sock->wb_size = 0; sock->protocol = protocol; sock->high.head = sock->high.tail = 0; sock->low.head = sock->low.tail = 0; if (add) { if (event_add(S.event_fd, fd, sock)) { sock->type = SOCKET_TYPE_INVALID; fprintf(stderr, "event_add error:%d.\n", errno); return 0; } } return sock; }
static struct socket * new_fd(struct socket_server *ss, int id, int fd, uintptr_t opaque, bool add) { struct socket * s = &ss->slot[HASH_ID(id)]; assert(s->type == SOCKET_TYPE_RESERVE); if (add) { if (sp_add(ss->event_fd, fd, s)) { s->type = SOCKET_TYPE_INVALID; return NULL; } } s->id = id; s->fd = fd; s->size = MIN_READ_BUFFER; s->opaque = opaque; s->wb_size = 0; check_wb_list(&s->high); check_wb_list(&s->low); return s; }
// 监听套接字 static int listen_socket(struct socket_server *ss, struct request_listen * request, struct socket_message *result) { int id = request->id; int listen_fd = request->fd; // 创建socket实例,并修改为PListen类型 struct socket *s = new_fd(ss, id, listen_fd, PROTOCOL_TCP, request->opaque, false); if (s == NULL) { goto _failed; } s->type = SOCKET_TYPE_PLISTEN; return -1; _failed: close(listen_fd); result->opaque = request->opaque; result->id = id; result->ud = 0; result->data = "reach skynet socket number limit"; ss->slot[HASH_ID(id)].type = SOCKET_TYPE_INVALID; return SOCKET_ERROR; }
/* 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) { int id = request->id; struct socket * s = &ss->slot[HASH_ID(id)]; if (s->type == SOCKET_TYPE_INVALID || s->id != id || s->type == SOCKET_TYPE_HALFCLOSE || s->type == SOCKET_TYPE_PACCEPT) { FREE(request->buffer); return -1; } assert(s->type != SOCKET_TYPE_PLISTEN && s->type != SOCKET_TYPE_LISTEN); if (send_buffer_empty(s) && s->type == SOCKET_TYPE_CONNECTED) { int n = write(s->fd, request->buffer, request->sz); if (n<0) { switch(errno) { case EINTR: case EAGAIN: n = 0; break; default: fprintf(stderr, "socket-server: write to %d (fd=%d) error.",id,s->fd); force_close(ss,s,result); return SOCKET_CLOSE; } } if (n == request->sz) { FREE(request->buffer); return -1; } append_sendbuffer(s, request, n); // add to high priority list, even priority == PRIORITY_LOW sp_write(ss->event_fd, s->fd, s, true); } else { if (priority == PRIORITY_LOW) { append_sendbuffer_low(s, request); } else { append_sendbuffer(s, request, 0); } } return -1; }
static int reserve_id(struct socket_server *ss) { int i; for (i=0;i<MAX_SOCKET;i++) { int id = __sync_add_and_fetch(&(ss->alloc_id), 1); if (id < 0) { id = __sync_and_and_fetch(&(ss->alloc_id), 0x7fffffff); } struct socket *s = &ss->slot[HASH_ID(id)]; if (s->type == SOCKET_TYPE_INVALID) { if (__sync_bool_compare_and_swap(&s->type, SOCKET_TYPE_INVALID, SOCKET_TYPE_RESERVE)) { s->id = id; s->fd = -1; return id; } else { // retry --i; } } } return -1; }
static int socket_req_setudp(struct _setudp_req *req, struct socket_message *msg) { int id = req->id; int type; struct socket *sock; sock = &S.slot[HASH_ID(req->id)]; if (sock->type == SOCKET_TYPE_INVALID || sock->id != id) { return -1; } type = req->address[0]; if (type != sock->protocol) { msg->ud = sock->ud; msg->id = id; msg->data = "socket protocol mismatch"; return SOCKET_ERR; } if (type == PROTOCOL_UDP) { memcpy(sock->p.udp_address, req->address, 1 + 2 + 4); } else { memcpy(sock->p.udp_address, req->address, 1 + 2 + 16); } return -1; }
static int socket_req_close(struct _close_req *req, struct socket_message *msg) { struct socket * sock = &S.slot[HASH_ID(req->id)]; if (sock->type == SOCKET_TYPE_INVALID || sock->id != req->id) { msg->id = req->id; msg->ud = req->ud; msg->data = "closed"; return SOCKET_CLOSE; } if (sock->high.head != 0 || sock->low.head != 0) { int type = socket_send_buffer(sock, msg); if (type != -1) return type; } if (sock->high.head == 0 && sock->low.head == 0) { socket_force_close(sock, msg); msg->id = req->id; msg->ud = req->ud; msg->data = "closed"; msg->size = 0; return SOCKET_CLOSE; } sock->type = SOCKET_TYPE_HALFCLOSE; return -1; }
static int set_udp_address(struct socket_server *ss, struct request_setudp *request, struct socket_message *result) { int id = request->id; struct socket *s = &ss->slot[HASH_ID(id)]; if (s->type == SOCKET_TYPE_INVALID || s->id !=id) { return -1; } int type = request->address[0]; if (type != s->protocol) { // protocol mismatch result->opaque = s->opaque; result->id = s->id; result->ud = 0; result->data = "protocol mismatch"; return SOCKET_ERROR; } if (type == PROTOCOL_UDP) { memcpy(s->p.udp_address, request->address, 1+2+4); // 1 type, 2 port, 4 ipv4 } else { memcpy(s->p.udp_address, request->address, 1+2+16); // 1 type, 2 port, 16 ipv6 } return -1; }
int socket_server::send_socket(struct request_send * request, struct socket_message * result, int priority) { int id = request->id; struct socket *s = &slot[HASH_ID(id)]; if (s->type == SOCKET_TYPE_INVALID || s->id != id || s->type == SOCKET_TYPE_HALFCLOSE || s->type == SOCKET_TYPE_PACCEPT) { return -1; } assert(s->type != SOCKET_TYPE_PLISTEN && s->type != SOCKET_TYPE_LISTEN); if (send_buffer_empty(s) && s->type == SOCKET_TYPE_CONNECTED) { if (s->protocol == PROTOCOL_TCP) { int n = write(s->fd, request->buffer, request->sz); if (n < 0) { switch (errno) { case EINTR: case EAGAIN: n = 0; break; default: fprintf(stderr, "socket-server: write to %d (fd=%d) error: %s.\n", id, s->fd, strerror(errno)); force_close(s, result); return SOCKET_CLOSE; } } if (n == request->sz) { return -1; } event_fd.write(s->fd, s, true); } } return -1; }