📄 socket.c
字号:
UNUSED(dev);#ifdef ISC_NET_BSD44MSGHDR#ifdef MSG_TRUNC if ((msg->msg_flags & MSG_TRUNC) == MSG_TRUNC) dev->attributes |= ISC_SOCKEVENTATTR_TRUNC;#endif#ifdef MSG_CTRUNC if ((msg->msg_flags & MSG_CTRUNC) == MSG_CTRUNC) dev->attributes |= ISC_SOCKEVENTATTR_CTRUNC;#endif#ifndef USE_CMSG return;#else if (msg->msg_controllen == 0U || msg->msg_control == NULL) return;#ifdef SO_TIMESTAMP timevalp = NULL;#endif#ifdef ISC_PLATFORM_HAVEIPV6 pktinfop = NULL;#endif cmsgp = CMSG_FIRSTHDR(msg); while (cmsgp != NULL) { socket_log(sock, NULL, TRACE, isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_PROCESSCMSG, "processing cmsg %p", cmsgp);#ifdef ISC_PLATFORM_HAVEIPV6 if (cmsgp->cmsg_level == IPPROTO_IPV6 && cmsgp->cmsg_type == IPV6_PKTINFO) { pktinfop = (struct in6_pktinfo *)CMSG_DATA(cmsgp); memcpy(&dev->pktinfo, pktinfop, sizeof(struct in6_pktinfo)); dev->attributes |= ISC_SOCKEVENTATTR_PKTINFO; socket_log(sock, NULL, TRACE, isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_IFRECEIVED, "interface received on ifindex %u", dev->pktinfo.ipi6_ifindex); if (IN6_IS_ADDR_MULTICAST(&pktinfop->ipi6_addr)) dev->attributes |= ISC_SOCKEVENTATTR_MULTICAST; goto next; }#endif#ifdef SO_TIMESTAMP if (cmsgp->cmsg_level == SOL_SOCKET && cmsgp->cmsg_type == SCM_TIMESTAMP) { timevalp = (struct timeval *)CMSG_DATA(cmsgp); dev->timestamp.seconds = timevalp->tv_sec; dev->timestamp.nanoseconds = timevalp->tv_usec * 1000; dev->attributes |= ISC_SOCKEVENTATTR_TIMESTAMP; goto next; }#endif next: cmsgp = CMSG_NXTHDR(msg, cmsgp); }#endif /* USE_CMSG */#endif /* ISC_NET_BSD44MSGHDR */}/* * Construct an iov array and attach it to the msghdr passed in. This is * the SEND constructor, which will use the used region of the buffer * (if using a buffer list) or will use the internal region (if a single * buffer I/O is requested). * * Nothing can be NULL, and the done event must list at least one buffer * on the buffer linked list for this function to be meaningful. * * If write_countp != NULL, *write_countp will hold the number of bytes * this transaction can send. */static voidbuild_msghdr_send(isc_socket_t *sock, isc_socketevent_t *dev, struct msghdr *msg, struct iovec *iov, size_t *write_countp){ unsigned int iovcount; isc_buffer_t *buffer; isc_region_t used; size_t write_count; size_t skip_count; memset(msg, 0, sizeof(*msg)); if (sock->type == isc_sockettype_udp) { msg->msg_name = (void *)&dev->address.type.sa; msg->msg_namelen = dev->address.length; } else { msg->msg_name = NULL; msg->msg_namelen = 0; } buffer = ISC_LIST_HEAD(dev->bufferlist); write_count = 0; iovcount = 0; /* * Single buffer I/O? Skip what we've done so far in this region. */ if (buffer == NULL) { write_count = dev->region.length - dev->n; iov[0].iov_base = (void *)(dev->region.base + dev->n); iov[0].iov_len = write_count; iovcount = 1; goto config; } /* * Multibuffer I/O. * Skip the data in the buffer list that we have already written. */ skip_count = dev->n; while (buffer != NULL) { REQUIRE(ISC_BUFFER_VALID(buffer)); if (skip_count < isc_buffer_usedlength(buffer)) break; skip_count -= isc_buffer_usedlength(buffer); buffer = ISC_LIST_NEXT(buffer, link); } while (buffer != NULL) { INSIST(iovcount < MAXSCATTERGATHER_SEND); isc_buffer_usedregion(buffer, &used); if (used.length > 0) { iov[iovcount].iov_base = (void *)(used.base + skip_count); iov[iovcount].iov_len = used.length - skip_count; write_count += (used.length - skip_count); skip_count = 0; iovcount++; } buffer = ISC_LIST_NEXT(buffer, link); } INSIST(skip_count == 0U); config: msg->msg_iov = iov; msg->msg_iovlen = iovcount;#ifdef ISC_NET_BSD44MSGHDR msg->msg_control = NULL; msg->msg_controllen = 0; msg->msg_flags = 0;#if defined(USE_CMSG) && defined(ISC_PLATFORM_HAVEIPV6) if ((sock->type == isc_sockettype_udp) && ((dev->attributes & ISC_SOCKEVENTATTR_PKTINFO) != 0)) { struct cmsghdr *cmsgp; struct in6_pktinfo *pktinfop; socket_log(sock, NULL, TRACE, isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_SENDTODATA, "sendto pktinfo data, ifindex %u", dev->pktinfo.ipi6_ifindex); msg->msg_controllen = cmsg_space(sizeof(struct in6_pktinfo)); INSIST(msg->msg_controllen <= sock->sendcmsgbuflen); msg->msg_control = (void *)sock->sendcmsgbuf; cmsgp = (struct cmsghdr *)sock->sendcmsgbuf; cmsgp->cmsg_level = IPPROTO_IPV6; cmsgp->cmsg_type = IPV6_PKTINFO; cmsgp->cmsg_len = cmsg_len(sizeof(struct in6_pktinfo)); pktinfop = (struct in6_pktinfo *)CMSG_DATA(cmsgp); memcpy(pktinfop, &dev->pktinfo, sizeof(struct in6_pktinfo)); }#endif /* USE_CMSG && ISC_PLATFORM_HAVEIPV6 */#else /* ISC_NET_BSD44MSGHDR */ msg->msg_accrights = NULL; msg->msg_accrightslen = 0;#endif /* ISC_NET_BSD44MSGHDR */ if (write_countp != NULL) *write_countp = write_count;}/* * Construct an iov array and attach it to the msghdr passed in. This is * the RECV constructor, which will use the avialable region of the buffer * (if using a buffer list) or will use the internal region (if a single * buffer I/O is requested). * * Nothing can be NULL, and the done event must list at least one buffer * on the buffer linked list for this function to be meaningful. * * If read_countp != NULL, *read_countp will hold the number of bytes * this transaction can receive. */static voidbuild_msghdr_recv(isc_socket_t *sock, isc_socketevent_t *dev, struct msghdr *msg, struct iovec *iov, size_t *read_countp){ unsigned int iovcount; isc_buffer_t *buffer; isc_region_t available; size_t read_count; memset(msg, 0, sizeof(struct msghdr)); if (sock->type == isc_sockettype_udp) { memset(&dev->address, 0, sizeof(dev->address)); msg->msg_name = (void *)&dev->address.type.sa; msg->msg_namelen = sizeof(dev->address.type);#ifdef ISC_NET_RECVOVERFLOW /* If needed, steal one iovec for overflow detection. */ maxiov--;#endif } else { /* TCP */ msg->msg_name = NULL; msg->msg_namelen = 0; dev->address = sock->address; } buffer = ISC_LIST_HEAD(dev->bufferlist); read_count = 0; /* * Single buffer I/O? Skip what we've done so far in this region. */ if (buffer == NULL) { read_count = dev->region.length - dev->n; iov[0].iov_base = (void *)(dev->region.base + dev->n); iov[0].iov_len = read_count; iovcount = 1; goto config; } /* * Multibuffer I/O. * Skip empty buffers. */ while (buffer != NULL) { REQUIRE(ISC_BUFFER_VALID(buffer)); if (isc_buffer_availablelength(buffer) != 0) break; buffer = ISC_LIST_NEXT(buffer, link); } iovcount = 0; while (buffer != NULL) { INSIST(iovcount < MAXSCATTERGATHER_RECV); isc_buffer_availableregion(buffer, &available); if (available.length > 0) { iov[iovcount].iov_base = (void *)(available.base); iov[iovcount].iov_len = available.length; read_count += available.length; iovcount++; } buffer = ISC_LIST_NEXT(buffer, link); } config: /* * If needed, set up to receive that one extra byte. Note that * we know there is at least one iov left, since we stole it * at the top of this function. */#ifdef ISC_NET_RECVOVERFLOW if (sock->type == isc_sockettype_udp) { iov[iovcount].iov_base = (void *)(&sock->overflow); iov[iovcount].iov_len = 1; iovcount++; }#endif msg->msg_iov = iov; msg->msg_iovlen = iovcount;#ifdef ISC_NET_BSD44MSGHDR msg->msg_control = NULL; msg->msg_controllen = 0; msg->msg_flags = 0;#if defined(USE_CMSG) if (sock->type == isc_sockettype_udp) { msg->msg_control = sock->recvcmsgbuf; msg->msg_controllen = sock->recvcmsgbuflen; }#endif /* USE_CMSG */#else /* ISC_NET_BSD44MSGHDR */ msg->msg_accrights = NULL; msg->msg_accrightslen = 0;#endif /* ISC_NET_BSD44MSGHDR */ if (read_countp != NULL) *read_countp = read_count;}static voidset_dev_address(isc_sockaddr_t *address, isc_socket_t *sock, isc_socketevent_t *dev){ if (sock->type == isc_sockettype_udp) { if (address != NULL) dev->address = *address; else dev->address = sock->address; } else if (sock->type == isc_sockettype_tcp) { INSIST(address == NULL); dev->address = sock->address; }}static isc_socketevent_t *allocate_socketevent(isc_socket_t *sock, isc_eventtype_t eventtype, isc_taskaction_t action, const void *arg){ isc_socketevent_t *ev; ev = (isc_socketevent_t *)isc_event_allocate(sock->manager->mctx, sock, eventtype, action, arg, sizeof(*ev)); if (ev == NULL) return (NULL); ev->result = ISC_R_UNEXPECTED; ISC_LINK_INIT(ev, ev_link); ISC_LIST_INIT(ev->bufferlist); ev->region.base = NULL; ev->n = 0; ev->offset = 0; ev->attributes = 0; return (ev);}#if defined(ISC_SOCKET_DEBUG)static voiddump_msg(struct msghdr *msg) { unsigned int i; printf("MSGHDR %p\n", msg); printf("\tname %p, namelen %d\n", msg->msg_name, msg->msg_namelen); printf("\tiov %p, iovlen %d\n", msg->msg_iov, msg->msg_iovlen); for (i = 0; i < (unsigned int)msg->msg_iovlen; i++) printf("\t\t%d\tbase %p, len %d\n", i, msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len);#ifdef ISC_NET_BSD44MSGHDR printf("\tcontrol %p, controllen %d\n", msg->msg_control, msg->msg_controllen);#endif}#endif#define DOIO_SUCCESS 0 /* i/o ok, event sent */#define DOIO_SOFT 1 /* i/o ok, soft error, no event sent */#define DOIO_HARD 2 /* i/o error, event sent */#define DOIO_EOF 3 /* EOF, no event sent */static intdoio_recv(isc_socket_t *sock, isc_socketevent_t *dev) { int cc; struct iovec iov[MAXSCATTERGATHER_RECV]; size_t read_count; size_t actual_count; struct msghdr msghdr; isc_buffer_t *buffer; int recv_errno; char strbuf[ISC_STRERRORSIZE]; build_msghdr_recv(sock, dev, &msghdr, iov, &read_count);#if defined(ISC_SOCKET_DEBUG) dump_msg(&msghdr);#endif cc = recvmsg(sock->fd, &msghdr, 0); recv_errno = errno; if (cc < 0) { if (SOFT_ERROR(recv_errno)) return (DOIO_SOFT); 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, "doio_recv: recvmsg(%d) %d bytes, err %d/%s", sock->fd, cc, recv_errno, strbuf); }#define SOFT_OR_HARD(_system, _isc) \ if (recv_errno == _system) { \ if (sock->connected) { \ dev->result = _isc; \ return (DOIO_HARD); \ } \ return (DOIO_SOFT); \ }#define ALWAYS_HARD(_system, _isc) \ if (recv_errno == _system) { \ dev->result = _isc; \ return (DOIO_HARD); \ } SOFT_OR_HARD(ECONNREFUSED, ISC_R_CONNREFUSED); SOFT_OR_HARD(ENETUNREACH, ISC_R_NETUNREACH); SOFT_OR_HARD(EHOSTUNREACH, ISC_R_HOSTUNREACH); SOFT_OR_HARD(EHOSTDOWN, ISC_R_HOSTDOWN); /* HPUX 11.11 can return EADDRNOTAVAIL. */ SOFT_OR_HARD(EADDRNOTAVAIL, ISC_R_ADDRNOTAVAIL); ALWAYS_HARD(ENOBUFS, ISC_R_NORESOURCES);#undef SOFT_OR_HARD#undef ALWAYS_HARD dev->result = isc__errno2result(recv_errno); return (DOIO_HARD); } /* * On TCP, zero length reads indicate EOF, while on * UDP, zero length reads are perfectly valid, although * strange. */ if ((sock->type == isc_sockettype_tcp) && (cc == 0)) return (DOIO_EOF); if (sock->type == isc_sockettype_udp) { dev->address.length = msghdr.msg_namelen; if (isc_sockaddr_getport(&dev->address) == 0) { if (isc_log_wouldlog(isc_lctx, IOEVENT_LEVEL)) { socket_log(sock, &dev->address, IOEVENT, isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ZEROPORT, "dropping source port zero packet"); } return (DOIO_SOFT); } } socket_log(sock, &dev->address, IOEVENT, isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_PKTRECV, "packet received correctly"); /* * Overflow bit detection. If we received MORE bytes than we should, * this indicates an overflow situation. Set the flag in the * dev entry and adjust how much we read by one. */#ifdef ISC_NET_RECVOVERFLOW if ((sock->type == isc_sockettype_udp) && ((size_t)cc > read_count)) { dev->attributes |= ISC_SOCKEVENTATTR_TRUNC; cc--; }#endif /* * If there are control messages attached, run through them and pull * out the interesting bits. */ if (sock->type == isc_sockettype_udp) process_cmsg(sock, &msghdr, dev); /* * update the buffers (if any) and the i/o count */ dev->n += cc; actual_count = cc; buffer = ISC_LIST_HEAD(dev->bufferlist); while (buffer != NULL && actual_count > 0U) { REQUIRE(ISC_BUFFER_VALID(buffer)); if (isc_buffer_availablelength(buffer) <= actual_count) { actual_count -= isc_buffer_availablelength(buffer); isc_buffer_add(buffer, isc_buffer_availablelength(buffer)); } else { isc_buffer_add(buffer, actual_count); actual_count = 0; break; } buffer = ISC_LIST_NEXT(buffer, link); if (buffer == NULL) { INSIST(actual_count == 0U); } } /* * If we read less than we expected, update counters, * and let the upper layer poke the descriptor. */ if (((size_t)cc != read_count) && (dev->n < dev->minimum)) return (DOIO_SOFT); /* * Full reads are posted, or partials if partials are ok. */ dev->result = ISC_R_SUCCESS; return (DOIO_SUCCESS);}/* * 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.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -