📄 socket.c
字号:
goto done; } if (isc_log_wouldlog(isc_lctx, IOEVENT_LEVEL)) { isc__strerror(*recv_errno, strbuf, sizeof(strbuf)); socket_log(sock, NULL, IOEVENT, isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_DOIORECV, "startio_recv: recvmsg(%d) %d bytes, " "err %d/%s", sock->fd, *nbytes, *recv_errno, strbuf); } status = completeio_recv(sock, dev, msghdr, *nbytes, *recv_errno); goto done; } dev->result = ISC_R_SUCCESS; status = DOIO_SOFT;done: return (status);}/* * Returns: * DOIO_SUCCESS The operation succeeded. dev->result contains * ISC_R_SUCCESS. * * DOIO_HARD A hard or unexpected I/O error was encountered. * dev->result contains the appropriate error. * * DOIO_SOFT A soft I/O error was encountered. No senddone * event was sent. The operation should be retried. * * No other return values are possible. */static intcompleteio_send(isc_socket_t *sock, isc_socketevent_t *dev, struct msghdr *messagehdr, int cc, int send_errno){ char addrbuf[ISC_SOCKADDR_FORMATSIZE]; char strbuf[ISC_STRERRORSIZE]; if(send_errno != 0) { if (SOFT_ERROR(send_errno)) return (DOIO_SOFT);#define SOFT_OR_HARD(_system, _isc) \ if (send_errno == _system) { \ if (sock->connected) { \ dev->result = _isc; \ return (DOIO_HARD); \ } \ return (DOIO_SOFT); \ }#define ALWAYS_HARD(_system, _isc) \ if (send_errno == _system) { \ dev->result = _isc; \ return (DOIO_HARD); \ } SOFT_OR_HARD(WSAEACCES, ISC_R_NOPERM); SOFT_OR_HARD(WSAEAFNOSUPPORT, ISC_R_ADDRNOTAVAIL); SOFT_OR_HARD(WSAECONNREFUSED, ISC_R_CONNREFUSED); SOFT_OR_HARD(WSAENOTCONN, ISC_R_CONNREFUSED); SOFT_OR_HARD(WSAECONNRESET, ISC_R_CONNECTIONRESET); SOFT_OR_HARD(WSAECONNABORTED, ISC_R_CONNECTIONRESET); SOFT_OR_HARD(WSAENETRESET, ISC_R_CONNECTIONRESET); SOFT_OR_HARD(WSAEDISCON, ISC_R_CONNECTIONRESET); SOFT_OR_HARD(WSAENETDOWN, ISC_R_NETDOWN); ALWAYS_HARD(ERROR_OPERATION_ABORTED, ISC_R_CONNECTIONRESET); ALWAYS_HARD(ERROR_PORT_UNREACHABLE, ISC_R_HOSTUNREACH); ALWAYS_HARD(ERROR_HOST_UNREACHABLE, ISC_R_HOSTUNREACH); ALWAYS_HARD(ERROR_NETWORK_UNREACHABLE, ISC_R_NETUNREACH); ALWAYS_HARD(WSAEADDRNOTAVAIL, ISC_R_ADDRNOTAVAIL); ALWAYS_HARD(WSAEHOSTUNREACH, ISC_R_HOSTUNREACH); ALWAYS_HARD(WSAEHOSTDOWN, ISC_R_HOSTUNREACH); ALWAYS_HARD(WSAENETUNREACH, ISC_R_NETUNREACH); ALWAYS_HARD(WSAENOBUFS, ISC_R_NORESOURCES); ALWAYS_HARD(EPERM, ISC_R_HOSTUNREACH); ALWAYS_HARD(EPIPE, ISC_R_NOTCONNECTED);#undef SOFT_OR_HARD#undef ALWAYS_HARD /* * The other error types depend on whether or not the * socket is UDP or TCP. If it is UDP, some errors * that we expect to be fatal under TCP are merely * annoying, and are really soft errors. * * However, these soft errors are still returned as * a status. */ isc_sockaddr_format(&dev->address, addrbuf, sizeof(addrbuf)); isc__strerror(send_errno, strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, "completeio_send: %s: %s", addrbuf, strbuf); dev->result = isc__errno2result(send_errno); return (DOIO_HARD); } /* * If we write less than we expected, update counters, poke. */ dev->n += cc; if ((size_t)cc != sock->totalBytes) return (DOIO_SOFT); /* * Exactly what we wanted to write. We're done with this * entry. Post its completion event. */ dev->result = ISC_R_SUCCESS; return (DOIO_SUCCESS);}static intstartio_send(isc_socket_t *sock, isc_socketevent_t *dev, int *nbytes, int *send_errno){ char *cmsg = NULL; char strbuf[ISC_STRERRORSIZE]; IoCompletionInfo *lpo; int status; struct msghdr *msghdr; lpo = (IoCompletionInfo *) HeapAlloc(hHeapHandle, HEAP_ZERO_MEMORY, sizeof(IoCompletionInfo)); lpo->request_type = SOCKET_SEND; lpo->dev = dev; msghdr = &lpo->messagehdr; memset(msghdr, 0, sizeof(struct msghdr)); build_msghdr_send(sock, dev, msghdr, cmsg, sock->iov, &(sock->totalBytes)); *nbytes = internal_sendmsg(sock, lpo, msghdr, 0, send_errno); if (*nbytes < 0) { if (SOFT_ERROR(*send_errno)) { status = DOIO_SOFT; goto done; } if (isc_log_wouldlog(isc_lctx, IOEVENT_LEVEL)) { isc__strerror(*send_errno, strbuf, sizeof(strbuf)); socket_log(sock, NULL, IOEVENT, isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALSEND, "startio_send: internal_sendmsg(%d) %d " "bytes, err %d/%s", sock->fd, *nbytes, *send_errno, strbuf); } status = completeio_send(sock, dev, msghdr, *nbytes, *send_errno); goto done; } dev->result = ISC_R_SUCCESS; status = DOIO_SOFT;done: return (status);}/* * Kill. * * Caller must ensure that the socket is not locked and no external * references exist. */static voiddestroy_socket(isc_socket_t **sockp) { isc_socket_t *sock = *sockp; isc_socketmgr_t *manager = sock->manager; isc_boolean_t dofree = ISC_TRUE; REQUIRE(sock != NULL); socket_log(sock, NULL, CREATION, isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_DESTROYING, "destroying socket %d", sock->fd); INSIST(ISC_LIST_EMPTY(sock->accept_list)); INSIST(ISC_LIST_EMPTY(sock->recv_list)); INSIST(ISC_LIST_EMPTY(sock->send_list)); INSIST(sock->connect_ev == NULL); LOCK(&manager->lock); LOCK(&sock->lock); socket_close(sock); if (sock->pending_recv != 0 || sock->pending_send != 0) { dofree = ISC_FALSE; sock->pending_free = 1; } ISC_LIST_UNLINK(manager->socklist, sock, link); UNLOCK(&sock->lock); if (ISC_LIST_EMPTY(manager->socklist)) SIGNAL(&manager->shutdown_ok); /* * XXX should reset manager->maxfd here */ UNLOCK(&manager->lock); if (dofree) free_socket(sockp);}static isc_result_tallocate_socket(isc_socketmgr_t *manager, isc_sockettype_t type, isc_socket_t **socketp) { isc_socket_t *sock; isc_result_t ret; sock = isc_mem_get(manager->mctx, sizeof(*sock)); if (sock == NULL) return (ISC_R_NOMEMORY); ret = ISC_R_UNEXPECTED; sock->magic = 0; sock->references = 0; sock->manager = manager; sock->type = type; sock->fd = INVALID_SOCKET; ISC_LINK_INIT(sock, link); /* * set up list of readers and writers to be initially empty */ ISC_LIST_INIT(sock->recv_list); ISC_LIST_INIT(sock->send_list); ISC_LIST_INIT(sock->accept_list); sock->connect_ev = NULL; sock->pending_accept = 0; sock->pending_close = 0; sock->pending_recv = 0; sock->pending_send = 0; sock->pending_free = 0; sock->iocp = 0; sock->listener = 0; sock->connected = 0; sock->connecting = 0; sock->bound = 0; sock->hEvent = NULL; sock->hAlert = NULL; sock->evthread_id = 0; sock->wait_type = 0; /* * initialize the lock */ if (isc_mutex_init(&sock->lock) != ISC_R_SUCCESS) { sock->magic = 0; UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_mutex_init() %s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, ISC_MSG_FAILED, "failed")); ret = ISC_R_UNEXPECTED; goto error; } /* * Initialize readable and writable events */ ISC_EVENT_INIT(&sock->readable_ev, sizeof(intev_t), ISC_EVENTATTR_NOPURGE, NULL, ISC_SOCKEVENT_INTR, NULL, sock, sock, NULL, NULL); ISC_EVENT_INIT(&sock->writable_ev, sizeof(intev_t), ISC_EVENTATTR_NOPURGE, NULL, ISC_SOCKEVENT_INTW, NULL, sock, sock, NULL, NULL); sock->magic = SOCKET_MAGIC; *socketp = sock; return (ISC_R_SUCCESS); error: isc_mem_put(manager->mctx, sock, sizeof(*sock)); return (ret);}/* * This event requires that the various lists be empty, that the reference * count be 1, and that the magic number is valid. The other socket bits, * like the lock, must be initialized as well. The fd associated must be * marked as closed, by setting it to INVALID_SOCKET on close, or this * routine will also close the socket. */static voidfree_socket(isc_socket_t **socketp) { isc_socket_t *sock = *socketp; INSIST(sock->references == 0); INSIST(VALID_SOCKET(sock)); INSIST(!sock->connecting); INSIST(!sock->pending_accept); INSIST(ISC_LIST_EMPTY(sock->recv_list)); INSIST(ISC_LIST_EMPTY(sock->send_list)); INSIST(ISC_LIST_EMPTY(sock->accept_list)); INSIST(!ISC_LINK_LINKED(sock, link)); sock->magic = 0; DESTROYLOCK(&sock->lock); isc_mem_put(sock->manager->mctx, sock, sizeof(*sock)); *socketp = NULL;}/* * Create a new 'type' socket managed by 'manager'. Events * will be posted to 'task' and when dispatched 'action' will be * called with 'arg' as the arg value. The new socket is returned * in 'socketp'. */isc_result_tisc_socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, isc_socket_t **socketp) { isc_socket_t *sock = NULL; isc_result_t result;#if defined(USE_CMSG) || defined(SO_BSDCOMPAT) int on = 1;#endif int socket_errno; char strbuf[ISC_STRERRORSIZE]; REQUIRE(VALID_MANAGER(manager)); REQUIRE(socketp != NULL && *socketp == NULL); result = allocate_socket(manager, type, &sock); if (result != ISC_R_SUCCESS) return (result); sock->pf = pf; switch (type) { case isc_sockettype_udp: sock->fd = socket(pf, SOCK_DGRAM, IPPROTO_UDP); if (sock->fd != INVALID_SOCKET) { result = connection_reset_fix(sock->fd); if (result != ISC_R_SUCCESS) { closesocket(sock->fd); free_socket(&sock); return (result); } } break; case isc_sockettype_tcp: sock->fd = socket(pf, SOCK_STREAM, IPPROTO_TCP); break; } if (sock->fd == INVALID_SOCKET) { socket_errno = WSAGetLastError(); free_socket(&sock); switch (socket_errno) { case WSAEMFILE: case WSAENOBUFS: return (ISC_R_NORESOURCES); case WSAEPROTONOSUPPORT: case WSAEPFNOSUPPORT: case WSAEAFNOSUPPORT: return (ISC_R_FAMILYNOSUPPORT); default: isc__strerror(socket_errno, strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, "socket() %s: %s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, ISC_MSG_FAILED, "failed"), strbuf); return (ISC_R_UNEXPECTED); } } result = make_nonblock(sock->fd); if (result != ISC_R_SUCCESS) { free_socket(&sock); return (result); }#if defined(USE_CMSG) if (type == isc_sockettype_udp) {#if defined(ISC_PLATFORM_HAVEIPV6)#ifdef IPV6_RECVPKTINFO /* 2292bis */ if ((pf == AF_INET6) && (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, (void *)&on, sizeof(on)) < 0)) { isc__strerror(WSAGetLastError(), strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, "setsockopt(%d, IPV6_RECVPKTINFO) " "%s: %s", sock->fd, isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, ISC_MSG_FAILED, "failed"), strbuf); }#else /* 2292 */ if ((pf == AF_INET6) && (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_PKTINFO, (void *)&on, sizeof(on)) < 0)) { isc__strerror(WSAGetLastError(), strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, "setsockopt(%d, IPV6_PKTINFO) %s: %s", sock->fd, isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, ISC_MSG_FAILED, "failed"), strbuf); }#endif /* IPV6_RECVPKTINFO */#ifdef IPV6_USE_MIN_MTU /*2292bis, not too common yet*/ /* use minimum MTU */ if (pf == AF_INET6) { (void)setsockopt(sock->fd, IPPROTO_IPV6, IPV6_USE_MIN_MTU, (void *)&on, sizeof(on)); }#endif#endif /* ISC_PLATFORM_HAVEIPV6 */ }#endif /* USE_CMSG */ sock->references = 1; *socketp = sock; LOCK(&manager->lock); /* * Note we don't have to lock the socket like we normally would because * there are no external references to it yet. */ ISC_LIST_APPEND(manager->socklist, sock, link); UNLOCK(&manager->lock); socket_log(sock, NULL, CREATION, isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_CREATED, "created %u", sock->fd); return (ISC_R_SUCCESS);}/* * Attach to a socket. Caller must explicitly detach when it is done. */voidisc_socket_attach(isc_socket_t *sock, isc_socket_t **socketp) { REQUIRE(VALID_SOCKET(sock)); REQUIRE(socketp != NULL && *socketp == NULL); LOCK(&sock->lock); sock->references++; UNLOCK(&sock->lock); *socketp = sock;}/* * Dereference a socket. If this is the last reference to it, clean things * up by destroying the socket. */voidisc_socket_detach(isc_socket_t **socketp) { isc_socket_t *sock; isc_boolean_t kill_socket = ISC_FALSE; REQUIRE(socketp != NULL); sock = *socketp; REQUIRE(VALID_SOCKET(sock)); LOCK(&sock->lock); REQUIRE(sock->references > 0); sock->references--; if (sock->references == 0) kill_socket = ISC_TRUE; UNLOCK(&sock->lock); if (kill_socket) destroy_socket(&sock); *socketp = NULL;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -