// return 0 when failed static int report_accept(struct socket_server *ss, struct socket *s, struct socket_message *result) { union sockaddr_all u; socklen_t len = sizeof(u); int client_fd = accept(s->fd, &u.s, &len); if (client_fd < 0) { return 0; } int id = reserve_id(ss); if (id < 0) { close(client_fd); return 0; } sp_nonblocking(client_fd); struct socket *ns = new_fd(ss, id, client_fd, s->opaque, false); if (ns == NULL) { close(client_fd); return 0; } ns->type = SOCKET_TYPE_PACCEPT; result->opaque = s->opaque; result->id = s->id; result->ud = id; result->data = NULL; void * sin_addr = (u.s.sa_family == AF_INET) ? (void*)&u.v4.sin_addr : (void *)&u.v6.sin6_addr; if (inet_ntop(u.s.sa_family, sin_addr, ss->buffer, sizeof(ss->buffer))) { result->data = ss->buffer; } return 1; }
int socket_server_udp(struct socket_server *ss, uintptr_t opaque, const char * addr, int port) { int fd; int family; if (port != 0 || addr != NULL) { // bind fd = do_bind(addr, port, IPPROTO_UDP, &family); if (fd < 0) { return -1; } } else { family = AF_INET; fd = socket(family, SOCK_DGRAM, 0); if (fd < 0) { return -1; } } sp_nonblocking(fd); int id = reserve_id(ss); if (id < 0) { close(fd); return -1; } struct request_package request; request.u.udp.id = id; request.u.udp.fd = fd; request.u.udp.opaque = opaque; request.u.udp.family = family; send_request(ss, &request, 'U', sizeof(request.u.udp)); return id; }
// return 0 when failed static int report_accept(struct socket_server *ss, struct socket *s, union socket_message *result) { union sockaddr_all u; socklen_t len = sizeof(u); int client_fd = accept(s->fd, &u.s, &len); if (client_fd < 0) { return 0; } sp_nonblocking(client_fd); struct socket *ns = new_fd(ss, client_fd); if (ns == NULL) { close(client_fd); return 0; } ns->type = SOCKET_TYPE_CONNECTED; result->open.id = ns->id; result->open.session = s->session; result->open.fd = s->fd; result->open.addr = NULL; void * sin_addr = (u.s.sa_family == AF_INET) ? (void*)&u.v4.sin_addr : (void *)&u.v6.sin6_addr; if (inet_ntop(u.s.sa_family, sin_addr, ss->buffer, sizeof(ss->buffer))) { result->open.addr = ss->buffer; } return 1; }
// return 0 when failed, or -1 when file limit // static int report_accept(struct socket_server *ss, struct socket *s, struct socket_message *result) { union sockaddr_all u; socklen_t len = sizeof(u); // 生成被动套接字 int client_fd = accept(s->fd, &u.s, &len); if (client_fd < 0) { if (errno == EMFILE || errno == ENFILE) { result->opaque = s->opaque; result->id = s->id; result->ud = 0; result->data = strerror(errno); return -1; } else { return 0; } } // 分配id int id = reserve_id(ss); if (id < 0) { close(client_fd); return 0; } // 设置keepalive和非阻塞 socket_keepalive(client_fd); sp_nonblocking(client_fd); // 创建socket实例 struct socket *ns = new_fd(ss, id, client_fd, PROTOCOL_TCP, s->opaque, false); if (ns == NULL) { close(client_fd); return 0; } // 设置socket类型为PACCEPT ns->type = SOCKET_TYPE_PACCEPT; result->opaque = s->opaque; result->id = s->id; // 服务器套接字id result->ud = id; // 被动套接字id result->data = NULL; // 连接客户端ip地址:port端口 void * sin_addr = (u.s.sa_family == AF_INET) ? (void*)&u.v4.sin_addr : (void *)&u.v6.sin6_addr; int sin_port = ntohs((u.s.sa_family == AF_INET) ? u.v4.sin_port : u.v6.sin6_port); char tmp[INET6_ADDRSTRLEN]; if (inet_ntop(u.s.sa_family, sin_addr, tmp, sizeof(tmp))) { snprintf(ss->buffer, sizeof(ss->buffer), "%s:%d", tmp, sin_port); result->data = ss->buffer; } return 1; }
static int bind_socket(struct socket_server *ss, struct request_bind *request, union socket_message *result) { struct socket *s = new_fd(ss, request->fd); if (s == NULL) { result->error.session = request->session; result->error.id = 0; return SOCKET_ERROR; } sp_nonblocking(request->fd); s->type = SOCKET_TYPE_BIND; result->open.id = s->id; result->open.session = request->session; result->open.fd = request->fd; return SOCKET_OPEN; }
static int bind_socket(struct socket_server *ss, struct request_bind *request, struct socket_message *result) { int id = request->id; result->id = id; result->opaque = request->opaque; result->ud = 0; struct socket *s = new_fd(ss, id, request->fd, request->opaque, true); if (s == NULL) { result->data = NULL; return SOCKET_ERROR; } sp_nonblocking(request->fd); s->type = SOCKET_TYPE_BIND; result->data = "binding"; return SOCKET_OPEN; }
// 绑定其他类型的文件描述符,比如stdin和stdout // 创建socket实例并加入事件循环 static int bind_socket(struct socket_server *ss, struct request_bind *request, struct socket_message *result) { int id = request->id; result->id = id; result->opaque = request->opaque; result->ud = 0; struct socket *s = new_fd(ss, id, request->fd, PROTOCOL_TCP, request->opaque, true); if (s == NULL) { result->data = "reach skynet socket number limit"; return SOCKET_ERROR; } // 套接字设置为非阻塞 sp_nonblocking(request->fd); s->type = SOCKET_TYPE_BIND; result->data = "binding"; return SOCKET_OPEN; }
// return 0 when failed static int report_accept(struct socket_server *ss, struct socket *s, struct socket_message *result) { union sockaddr_all u; socklen_t len = sizeof(u); int client_fd = accept(s->fd, &u.s, &len); if (client_fd < 0) { //printf("accept error : %s\n", strerror(errno)); return 0; } int id = reserve_id(ss); if (id < 0) { close(client_fd); return 0; } socket_keepalive(client_fd); sp_nonblocking(client_fd); struct socket *ns = new_fd(ss, id, client_fd, s->opaque, false); if (ns == NULL) { close(client_fd); return 0; } ns->type = SOCKET_TYPE_PACCEPT; result->opaque = s->opaque; result->id = s->id; result->ud = id; result->data = NULL; void * sin_addr = (u.s.sa_family == AF_INET) ? (void*)&u.v4.sin_addr : (void *)&u.v6.sin6_addr; int sin_port = ntohs((u.s.sa_family == AF_INET) ? u.v4.sin_port : u.v6.sin6_port); char tmp[INET6_ADDRSTRLEN]; if (inet_ntop(u.s.sa_family, sin_addr, tmp, sizeof(tmp))) { snprintf(ss->buffer, sizeof(ss->buffer), "%s:%d", tmp, sin_port); result->data = ss->buffer; } return 1; }
static int connect_to(struct client* c, int ssh_id){ if (c->cnt >= TOTAL_CONNECTION) { fprintf(stderr, "%s client max connection.....\n", get_time()); return -1; } const char* ip; int port; if (ssh_id < 0) { if (c->free_connection > 0) return -1; struct timeval tv; gettimeofday(&tv, NULL); if (tv.tv_sec - c->time < FREE_CONNECT_TIME) { return -1; }else { c->time = tv.tv_sec; } ip = c->remote_ip; port = c->remote_port; } else { ip = "0.0.0.0"; port = c->ssh_port; } int id; int idx; struct client_info* info; struct ring_buffer* rb; struct addrinfo hints; struct addrinfo* res = NULL; struct addrinfo* ai_ptr = NULL; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; char portstr[16]; sprintf(portstr, "%d", port); int status = getaddrinfo(ip, portstr, &hints, &res); if (status != 0) { return -1; } int sock = -1; for (ai_ptr = res; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next) { sock = socket(ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol); if (sock < 0) { continue; } set_keep_alive(sock); sp_nonblocking(sock); status = connect(sock, ai_ptr->ai_addr, ai_ptr->ai_addrlen); if (status != 0 && errno != EINPROGRESS) { close(sock); sock = -1; continue; } break; } if (sock < 0) { goto _failed; } id = get_id(c); assert(id != -1); idx = id % TOTAL_CONNECTION; info = &c->all_fds[idx]; info->fd = sock; info->id = id; info->to_id = ssh_id; snprintf(info->client_ip, sizeof(info->client_ip), "%s:%d", ip, port); rb = alloc_ring_buffer(MAX_CLIENT_BUFFER); info->buffer = rb; c->all_ids[c->cnt++] = id; if (ssh_id < 0) { c->free_connection += 1; } if (status != 0) { //connect no block, need check after FD_SET(sock, &c->fd_wset); info->connect_type = SOCKET_CONNECTING; }else { //success FD_SET(sock, &c->fd_rset); info->connect_type = SOCKET_CONNECTED; struct sockaddr* addr = ai_ptr->ai_addr; void* sin_addr = (ai_ptr->ai_family == AF_INET) ? (void*)&((struct sockaddr_in*)addr)->sin_addr : (void*)&((struct sockaddr_in6*)addr)->sin6_addr; inet_ntop(ai_ptr->ai_family, sin_addr, info->client_ip, sizeof(info->client_ip)); fprintf(stderr, "%s connected to %s. \n", get_time(), info->client_ip); } if (c->max_fd < sock + 1) { c->max_fd = sock + 1; } return id; _failed: freeaddrinfo(res); return -1; }
static void* client_thread(void* param) { struct client_param* cp = (struct client_param*)param; struct client c; memset(&c, 0, sizeof(c)); sprintf(c.remote_ip, "%s", cp->remote_ip); c.remote_port = cp->p1; c.ssh_port = cp->p2; c.wait_closed = alloc_ring_buffer(sizeof(int) * TOTAL_CONNECTION); FD_ZERO(&c.fd_rset); FD_ZERO(&c.fd_wset); FD_SET(cp->pid, &c.fd_rset); c.max_fd = cp->pid + 1; sp_nonblocking(cp->pid); while (1) { pre_check_close(&c); if (connect_to(&c, -1) == -1 && c.cnt == 0) { c.max_fd = cp->pid + 1; int buff = 0; int n = (int)read(cp->pid, &buff, sizeof(int)); if (n > 0) { break; } sleep(1); continue; } fd_set r_set = c.fd_rset; fd_set w_set = c.fd_wset; int cnt = select(c.max_fd, &r_set, &w_set, NULL, NULL); if (cnt == -1) { fprintf(stderr, "%s select error: %s.\n", get_time(), strerror(errno)); continue; } int i; for (i = c.cnt - 1; i >= 0 && cnt > 0; --i) { int id = c.all_ids[i] % TOTAL_CONNECTION; struct client_info* info = &c.all_fds[id]; assert(c.all_ids[i] == info->id); int fd = info->fd; assert(fd > 0); if (FD_ISSET(fd, &r_set)) { // read --cnt; if (do_read(&c, info) == -1) continue; } if (FD_ISSET(fd, &w_set)) { //write --cnt; if (do_write(&c, info, 0) == -1) continue; } } if (FD_ISSET(cp->pid, &r_set)) { //exit break; } } fprintf(stderr, "%s ====================CLIENT: SEND LAST DATA BEGIN===================.\n", get_time()); int i; for (i = c.cnt - 1; i >= 0; --i) { int id = c.all_ids[i] % TOTAL_CONNECTION; struct client_info* info = &c.all_fds[id]; assert(c.all_ids[i] == info->id); if (do_write(&c, info, 1) != -1) { do_close(&c, info); } } fprintf(stderr, "%s ====================CLIENT: SEND LAST DATA END=====================.\n", get_time()); free_ring_buffer(c.wait_closed); assert(c.cnt == 0); return NULL; }
// return -1 when connecting static int open_socket(struct socket_server *ss, struct request_open * request, struct socket_message *result) { int id = request->id; result->opaque = request->opaque; result->id = id; result->ud = 0; result->data = NULL; struct socket *ns; int status; struct addrinfo ai_hints; struct addrinfo *ai_list = NULL; struct addrinfo *ai_ptr = NULL; char port[16]; sprintf(port, "%d", request->port); memset( &ai_hints, 0, sizeof( ai_hints ) ); ai_hints.ai_family = AF_UNSPEC; ai_hints.ai_socktype = SOCK_STREAM; ai_hints.ai_protocol = IPPROTO_TCP; status = getaddrinfo( request->host, port, &ai_hints, &ai_list ); if ( status != 0 ) { goto _failed; } int sock= -1; for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next ) { sock = socket( ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol ); if ( sock < 0 ) { continue; } socket_keepalive(sock); sp_nonblocking(sock); status = connect( sock, ai_ptr->ai_addr, ai_ptr->ai_addrlen); if ( status != 0 && errno != EINPROGRESS) { close(sock); sock = -1; continue; } break; } if (sock < 0) { goto _failed; } ns = new_fd(ss, id, sock, request->opaque, true); if (ns == NULL) { close(sock); goto _failed; } if(status == 0) { ns->type = SOCKET_TYPE_CONNECTED; struct sockaddr * addr = ai_ptr->ai_addr; void * sin_addr = (ai_ptr->ai_family == AF_INET) ? (void*)&((struct sockaddr_in *)addr)->sin_addr : (void*)&((struct sockaddr_in6 *)addr)->sin6_addr; if (inet_ntop(ai_ptr->ai_family, sin_addr, ss->buffer, sizeof(ss->buffer))) { result->data = ss->buffer; } freeaddrinfo( ai_list ); return SOCKET_OPEN; } else { ns->type = SOCKET_TYPE_CONNECTING; sp_write(ss->event_fd, ns->fd, ns, true); } freeaddrinfo( ai_list ); return -1; _failed: freeaddrinfo( ai_list ); ss->slot[HASH_ID(id)].type = SOCKET_TYPE_INVALID; return SOCKET_ERROR; }
// return -1 when connecting // 打开套接字 // 正常返回 SOCKET_OPEN // 其他返回 -1,包括 连接中 的情况 static int open_socket(struct socket_server *ss, struct request_open * request, struct socket_message *result) { int id = request->id; result->opaque = request->opaque; result->id = id; result->ud = 0; result->data = NULL; struct socket *ns; int status; struct addrinfo ai_hints; struct addrinfo *ai_list = NULL; struct addrinfo *ai_ptr = NULL; char port[16]; sprintf(port, "%d", request->port); memset(&ai_hints, 0, sizeof( ai_hints ) ); // 地址族暂不指定 ai_hints.ai_family = AF_UNSPEC; ai_hints.ai_socktype = SOCK_STREAM; ai_hints.ai_protocol = IPPROTO_TCP; // host和port获取地址,支持ipv4和ipv6 status = getaddrinfo( request->host, port, &ai_hints, &ai_list ); if ( status != 0 ) { result->data = (void *)gai_strerror(status); goto _failed; } int sock= -1; for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next ) { // 创建socket套接字 sock = socket( ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol ); if ( sock < 0 ) { continue; } // 设置keepalive和非阻塞 socket_keepalive(sock); sp_nonblocking(sock); // 连接套接字 status = connect( sock, ai_ptr->ai_addr, ai_ptr->ai_addrlen); if ( status != 0 && errno != EINPROGRESS) { // O_NONBLOCK is set for the file descriptor for the socket and the connection cannot be immediately established; the connection shall be established asynchronously. // 当套接字被设置为非阻塞后,连接不会被立即建立,所以errno会返回EINPROGRESS close(sock); sock = -1; continue; } break; } if (sock < 0) { result->data = strerror(errno); goto _failed; } // 创建socket实例 ns = new_fd(ss, id, sock, PROTOCOL_TCP, request->opaque, true); if (ns == NULL) { close(sock); result->data = "reach skynet socket number limit"; goto _failed; } if(status == 0) { // socket修改为已连接类型 ns->type = SOCKET_TYPE_CONNECTED; struct sockaddr * addr = ai_ptr->ai_addr; // 区分ipv4和ipv6,ip地址放入result->data void * sin_addr = (ai_ptr->ai_family == AF_INET) ? (void*)&((struct sockaddr_in *)addr)->sin_addr : (void*)&((struct sockaddr_in6 *)addr)->sin6_addr; if (inet_ntop(ai_ptr->ai_family, sin_addr, ss->buffer, sizeof(ss->buffer))) { result->data = ss->buffer; } freeaddrinfo( ai_list ); return SOCKET_OPEN; } else { // socket修改为连接中类型,在socket_server_poll方法中调用report_connect方法修改为SOCKET_TYPE_CONNECTED,并返回SOCKET_OPEN ns->type = SOCKET_TYPE_CONNECTING; // 打开事件循环中fd的可写权限 sp_write(ss->event_fd, ns->fd, ns, true); } freeaddrinfo( ai_list ); return -1; _failed: freeaddrinfo( ai_list ); ss->slot[HASH_ID(id)].type = SOCKET_TYPE_INVALID; return SOCKET_ERROR; }
int socket_proxy::_connect(bool blocking) { bool ret; int status; struct addrinfo ai_hints; struct addrinfo *ai_list = NULL; struct addrinfo *ai_ptr = NULL; char port[16]; sprintf(port, "%d", this->port); memset( &ai_hints, 0, sizeof( ai_hints ) ); ai_hints.ai_family = AF_UNSPEC; ai_hints.ai_socktype = SOCK_STREAM; ai_hints.ai_protocol = IPPROTO_TCP; int sock= -1; // 获取地址列表,(不用gethostbyname、gethostbyadd,这两个函数仅支持IPV4) // 第一个参数是IP地址或主机名称,第二个参数是服务名(可以是端口或服务名称,如ftp、http等) status = getaddrinfo( this->host, port, &ai_hints, &ai_list ); if ( status != 0 ) { goto _failed; } for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next ) { sock = socket( ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol ); if ( sock < 0 ) { continue; } socket_keepalive(sock); if (!blocking) { sp_nonblocking(sock); // blocking为false,设置为非阻塞模式,即用非阻塞connect } status = ::connect( sock, ai_ptr->ai_addr, ai_ptr->ai_addrlen); if ( status != 0 && errno != EINPROGRESS) { close(sock); sock = -1; continue; // 连接出错,跳过本循环,连接下一个地址 } if (blocking) { sp_nonblocking(sock); //到此为止,不管blocking是真是假,都设置为非阻塞模式,即IO模型使用的是non blocking } break; } if (sock < 0) { goto _failed; } this->fd = sock; ret = ss->new_fd(this, true); // 加入epoll管理 if (!ret) { close(sock); goto _failed; } if(status == 0) { //说明connect已连接成功 this->type = SOCKET_TYPE_CONNECTED; struct sockaddr * addr = ai_ptr->ai_addr; void * sin_addr = (ai_ptr->ai_family == AF_INET) ? (void*)&((struct sockaddr_in *)addr)->sin_addr : (void*)&((struct sockaddr_in6 *)addr)->sin6_addr; if (inet_ntop(ai_ptr->ai_family, sin_addr, ss->buffer, sizeof(ss->buffer))) { //result->data = ss->buffer; } freeaddrinfo( ai_list ); return SOCKET_OPEN; } else { // 说明非阻塞套接字尝试连接中 this->type = SOCKET_TYPE_CONNECTING; sp_write(ss->event_fd, this->fd, this, true); // 非阻塞字尝试连接中,必需将关注其可写事件,稍后epoll触发才可以捕捉到已连接 } freeaddrinfo( ai_list ); return -1; _failed: freeaddrinfo( ai_list ); //ss->slot[id % MAX_SOCKET].type = SOCKET_TYPE_INVALID; this->type = SOCKET_TYPE_INVALID; return 0; }