// 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; } 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; if (inet_ntop(u.s.sa_family, sin_addr, ss->buffer, sizeof(ss->buffer))) { result->data = ss->buffer; } return 1; }
// 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 gboolean server_socket_in_event(G_GNUC_UNUSED GIOChannel *source, G_GNUC_UNUSED GIOCondition condition, gpointer data) { struct one_socket *s = data; struct sockaddr_storage address; size_t address_length = sizeof(address); int fd = accept_cloexec_nonblock(s->fd, (struct sockaddr*)&address, &address_length); if (fd >= 0) { if (socket_keepalive(fd)) g_warning("Could not set TCP keepalive option: %s", g_strerror(errno)); s->parent->callback(fd, (const struct sockaddr*)&address, address_length, get_remote_uid(fd), s->parent->callback_ctx); } else { g_warning("accept() failed: %s", g_strerror(errno)); } return true; }
// 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; }
// connect, for client // net pool, ip address, port int net_connect(struct net_pool* np, const char* host, int port) { log_debug("connect : host(ipaddress) = %s, port = %d\n", host, port); // hint the system what do here need struct addrinfo ai_hints; // reserve the result chain struct addrinfo* ai_list = NULL; // as the element of result chain struct addrinfo* ai_ptr; char strport[16]; memset(strport, 0, 16); sprintf(strport, "%d", port); // set hint information memset(&ai_hints, 0, sizeof(struct addrinfo)); ai_hints.ai_family = AF_UNSPEC; // point that sin_family is unspecified, other choose : AF_INET, AF_INET6 ai_hints.ai_socktype = SOCK_STREAM; ai_hints.ai_protocol = IPPROTO_TCP; int status = getaddrinfo(host, strport, &ai_hints, &ai_list); if(status != 0) { freeaddrinfo(ai_list); return -1; } // the sockfd, connected to server int fd = -1; for(ai_ptr =ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next) { fd = socket(ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol); if(fd < 0) { log_error("socket failure ..."); continue; } socket_keepalive(fd); poll_setnonblocking(fd); // connect to server status = connect(fd, ai_ptr->ai_addr, ai_ptr->ai_addrlen); if((status != 0) && (errno != EINPROGRESS)) { socket_close(fd); fd = -1; continue; } break; } if(fd < 0) { freeaddrinfo(ai_list); return -1; } struct net_socket* ns = net_socket_new(np, fd, true); if(ns == NULL) { socket_close(fd); freeaddrinfo(ai_list); return -1; } if(status == 0) { ns->status = SOCKET_STATUS_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); // save ip address to ns->info inet_ntop(ai_ptr->ai_family, sin_addr, ns->info, sizeof(ns->info)); log_info("connected immediately id = %d\n", ns->id); np->onconnected(np, ns->id); } else { ns->status = SOCKET_STATUS_CONNECTING; poll_write(np->eventfd, ns->fd, ns, true); } freeaddrinfo(ai_list); return ns->id; }
static int socket_req_open(struct _open_req *req, struct socket_message *msg) { struct socket *sock; int status; int fd = -1; struct addrinfo ai_hints; struct addrinfo *ai_list = 0; struct addrinfo *ai_ptr = 0; char port[16]; msg->id = req->id; msg->ud = req->ud; sprintf(port, "%d", req->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(req->host, port, &ai_hints, &ai_list); if (status != 0) { msg->data = (void *)gai_strerror(status); goto _failed; } for (ai_ptr = ai_list; ai_ptr != 0; ai_ptr = ai_ptr->ai_next) { fd = socket(ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol); if (fd < 0) { continue; } socket_keepalive(fd); socket_nonblocking(fd); status = connect(fd, ai_ptr->ai_addr, ai_ptr->ai_addrlen); if (status != 0 && errno != EINPROGRESS) { close(fd); fd = -1; continue; } break; } if (fd < 0) { msg->data = strerror(errno); goto _failed; } sock = socket_new(fd, req->id, PROTOCOL_TCP, req->ud, 1); if (sock == 0) { close(fd); msg->data = "socket limit"; goto _failed; } if (status == 0) { sock->type = SOCKET_TYPE_OPENED; 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; int sin_port = ntohs((ai_ptr->ai_family == AF_INET) ? ((struct sockaddr_in *)addr)->sin_port : ((struct sockaddr_in6 *)addr)->sin6_port); char tmp[INET6_ADDRSTRLEN]; if (inet_ntop(ai_ptr->ai_family, sin_addr, tmp, sizeof(tmp))) { snprintf(S.buffer, sizeof(S.buffer), "%s:%d", tmp, sin_port); msg->data = S.buffer; } freeaddrinfo(ai_list); return SOCKET_OPEN; } else { sock->type = SOCKET_TYPE_OPENING; event_write(S.event_fd, sock->fd, sock, 1); } freeaddrinfo(ai_list); return -1; _failed: freeaddrinfo(ai_list); S.slot[HASH_ID(req->id)].type = SOCKET_TYPE_INVALID; return SOCKET_ERR; }
socket_t socket_connect(const char* host, WORD port) { socket_t s = 0; struct sockaddr_in server_addr; int rslt; /* 소켓주소 구조체 초기화 */ memset(&server_addr, 0, sizeof(server_addr)); if (isdigit(*host)) server_addr.sin_addr.s_addr = inet_addr(host); else { struct hostent *hp; if ((hp = gethostbyname(host)) == NULL) { sys_err("socket_connect(): can not connect to %s:%d", host, port); return -1; } thecore_memcpy((char* ) &server_addr.sin_addr, hp->h_addr, sizeof(server_addr.sin_addr)); } server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port); if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket"); return -1; } socket_keepalive(s); socket_sndbuf(s, 233016); socket_rcvbuf(s, 233016); socket_timeout(s, 10, 0); socket_lingeron(s); /* 연결요청 */ if ((rslt = connect(s, (struct sockaddr *) &server_addr, sizeof(server_addr))) < 0) { socket_close(s); #ifdef __WIN32__ switch (WSAGetLastError()) #else switch (rslt) #endif { #ifdef __WIN32__ case WSAETIMEDOUT: #else case EINTR: #endif sys_err("HOST %s:%d connection timeout.", host, port); break; #ifdef __WIN32__ case WSAECONNREFUSED: #else case ECONNREFUSED: #endif sys_err("HOST %s:%d port is not opened. connection refused.", host, port); break; #ifdef __WIN32__ case WSAENETUNREACH: #else case ENETUNREACH: #endif sys_err("HOST %s:%d is not reachable from this host.", host, port); break; default: sys_err("HOST %s:%d, could not connect.", host, port); break; } perror("connect"); return (-1); } return (s); }
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; }