⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 socket.c

📁 bind-3.2.
💻 C
📖 第 1 页 / 共 5 页
字号:
	INSIST(dev != NULL && *dev != NULL);	task = (*dev)->ev_sender;	(*dev)->ev_sender = sock;	if (ISC_LINK_LINKED(*dev, ev_link)) {		ISC_LIST_DEQUEUE(sock->send_list, *dev, ev_link);	}	if (((*dev)->attributes & ISC_SOCKEVENTATTR_ATTACHED)	    == ISC_SOCKEVENTATTR_ATTACHED)		isc_task_sendanddetach(&task, (isc_event_t **)dev);	else		isc_task_send(task, (isc_event_t **)dev);}/* * Call accept() on a socket, to get the new file descriptor.  The listen * socket is used as a prototype to create a new isc_socket_t.  The new * socket has one outstanding reference.  The task receiving the event * will be detached from just after the event is delivered. * * On entry to this function, the event delivered is the internal * readable event, and the first item on the accept_list should be * the done event we want to send.  If the list is empty, this is a no-op, * so just unlock and return. */static voidinternal_accept(isc_socket_t *sock, int accept_errno) {	isc_socketmgr_t *manager;	isc_socket_newconnev_t *dev;	isc_task_t *task;	ISC_SOCKADDR_LEN_T addrlen;	SOCKET fd;	isc_result_t result = ISC_R_SUCCESS;	char strbuf[ISC_STRERRORSIZE];	INSIST(VALID_SOCKET(sock));	LOCK(&sock->lock);	socket_log(sock, NULL, TRACE,		   isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTLOCK,		   "internal_accept called, locked socket");	manager = sock->manager;	INSIST(VALID_MANAGER(manager));	INSIST(sock->listener);	INSIST(sock->hEvent != NULL);	INSIST(sock->pending_accept == 1);	sock->pending_accept = 0;	INSIST(sock->references > 0);	sock->references--;  /* the internal event is done with this socket */	if (sock->references == 0) {		UNLOCK(&sock->lock);		destroy_socket(&sock);		return;	}	/*	 * Get the first item off the accept list.	 * If it is empty, unlock the socket and return.	 */	dev = ISC_LIST_HEAD(sock->accept_list);	if (dev == NULL) {		UNLOCK(&sock->lock);		return;	}	/*	 * Try to accept the new connection.  If the accept fails with	 * EAGAIN or EINTR, the event wait will be notified again since	 * the event will be reset on return to caller.	 */	addrlen = sizeof dev->newsocket->address.type;	memset(&dev->newsocket->address.type.sa, 0, addrlen);	fd = accept(sock->fd, &dev->newsocket->address.type.sa,		    (void *)&addrlen);	if (fd == INVALID_SOCKET) {		accept_errno = WSAGetLastError();		if (SOFT_ERROR(accept_errno) || accept_errno == WSAECONNRESET) {			goto soft_error;		} else {			isc__strerror(accept_errno, strbuf, sizeof(strbuf));			UNEXPECTED_ERROR(__FILE__, __LINE__,					 "internal_accept: accept() %s: %s",					 isc_msgcat_get(isc_msgcat,							ISC_MSGSET_GENERAL,							ISC_MSG_FAILED,							"failed"),					 strbuf);			fd = INVALID_SOCKET;			result = ISC_R_UNEXPECTED;		}	} else {		if (addrlen == 0) {			UNEXPECTED_ERROR(__FILE__, __LINE__,					 "internal_accept(): "					 "accept() failed to return "					 "remote address");			(void)closesocket(fd);			goto soft_error;		} else if (dev->newsocket->address.type.sa.sa_family !=			   sock->pf)		{			UNEXPECTED_ERROR(__FILE__, __LINE__,					 "internal_accept(): "					 "accept() returned peer address "					 "family %u (expected %u)", 					 dev->newsocket->address.					 type.sa.sa_family,					 sock->pf);			(void)closesocket(fd);			goto soft_error;		}	}	if (fd != INVALID_SOCKET) {		dev->newsocket->address.length = addrlen;		dev->newsocket->pf = sock->pf;	}	/*	 * Pull off the done event.	 */	ISC_LIST_UNLINK(sock->accept_list, dev, ev_link);	UNLOCK(&sock->lock);	if (fd != INVALID_SOCKET && (make_nonblock(fd) != ISC_R_SUCCESS)) {		closesocket(fd);		fd = INVALID_SOCKET;		result = ISC_R_UNEXPECTED;	}	/*	 * INVALID_SOCKET means the new socket didn't happen.	 */	if (fd != INVALID_SOCKET) {		LOCK(&manager->lock);		ISC_LIST_APPEND(manager->socklist, dev->newsocket, link);		dev->newsocket->fd = fd;		dev->newsocket->bound = 1;		dev->newsocket->connected = 1;		/*		 * Save away the remote address		 */		dev->address = dev->newsocket->address;		socket_log(sock, &dev->newsocket->address, CREATION,			   isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTEDCXN,			   "accepted connection, new socket %p",			   dev->newsocket);		UNLOCK(&manager->lock);	} else {		dev->newsocket->references--;		free_socket(&dev->newsocket);	}	/*	 * Fill in the done event details and send it off.	 */	dev->result = result;	task = dev->ev_sender;	dev->ev_sender = sock;	isc_task_sendanddetach(&task, (isc_event_t **)&dev);	return; soft_error:	UNLOCK(&sock->lock);	return;}/* * Called when a socket with a pending connect() finishes. */static voidinternal_connect(isc_socket_t *sock, int connect_errno) {	isc_socket_connev_t *dev;	isc_task_t *task;	int cc;	ISC_SOCKADDR_LEN_T optlen;	char strbuf[ISC_STRERRORSIZE];	INSIST(VALID_SOCKET(sock));	LOCK(&sock->lock);	WSAResetEvent(sock->hEvent);	/*	 * When the internal event was sent the reference count was bumped	 * to keep the socket around for us.  Decrement the count here.	 */	INSIST(sock->references > 0);	sock->references--;	if (sock->references == 0) {		UNLOCK(&sock->lock);		destroy_socket(&sock);		return;	}	/*	 * Has this event been canceled?	 */	dev = sock->connect_ev;	if (dev == NULL) {		INSIST(!sock->connecting);		UNLOCK(&sock->lock);		return;	}	INSIST(sock->connecting);	sock->connecting = 0;	/*	 * Get any possible error status here.	 */	optlen = sizeof(cc);	if (getsockopt(sock->fd, SOL_SOCKET, SO_ERROR,		       (void *)&cc, (void *)&optlen) < 0)		connect_errno = WSAGetLastError();	else		connect_errno = 0;	if (connect_errno != 0) {		/*		 * If the error is EAGAIN, just try again on this		 * fd and pretend nothing strange happened.		 */		if (SOFT_ERROR(connect_errno) || connect_errno == WSAEINPROGRESS) {			sock->connecting = 1;			UNLOCK(&sock->lock);			return;		}		/*		 * Translate other errors into ISC_R_* flavors.		 */		switch (connect_errno) {#define ERROR_MATCH(a, b) case a: dev->result = b; break;			ERROR_MATCH(WSAEACCES, ISC_R_NOPERM);			ERROR_MATCH(WSAEADDRNOTAVAIL, ISC_R_ADDRNOTAVAIL);			ERROR_MATCH(WSAEAFNOSUPPORT, ISC_R_ADDRNOTAVAIL);			ERROR_MATCH(WSAECONNREFUSED, ISC_R_CONNREFUSED);			ERROR_MATCH(WSAEHOSTUNREACH, ISC_R_HOSTUNREACH);			ERROR_MATCH(WSAEHOSTDOWN, ISC_R_HOSTUNREACH);			ERROR_MATCH(WSAENETUNREACH, ISC_R_NETUNREACH);			ERROR_MATCH(WSAENOBUFS, ISC_R_NORESOURCES);			ERROR_MATCH(EPERM, ISC_R_HOSTUNREACH);			ERROR_MATCH(EPIPE, ISC_R_NOTCONNECTED);			ERROR_MATCH(WSAETIMEDOUT, ISC_R_TIMEDOUT);#undef ERROR_MATCH		default:			dev->result = ISC_R_UNEXPECTED;			isc__strerror(connect_errno, strbuf, sizeof(strbuf));			UNEXPECTED_ERROR(__FILE__, __LINE__,					 "internal_connect: connect() %s",					 strbuf);		}	} else {		dev->result = ISC_R_SUCCESS;		sock->connected = 1;		sock->bound = 1;	}	sock->connect_ev = NULL;	UNLOCK(&sock->lock);	task = dev->ev_sender;	dev->ev_sender = sock;	isc_task_sendanddetach(&task, (isc_event_t **)&dev);}static voidinternal_recv(isc_socket_t *sock, isc_socketevent_t *dev, struct msghdr *messagehdr, int nbytes, int recv_errno) {	isc_socketevent_t *ldev;	int io_state;	int cc;	INSIST(VALID_SOCKET(sock));	LOCK(&sock->lock);	socket_log(sock, NULL, IOEVENT,		   isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALRECV,		   "internal_recv: task got socket event %p", dev);	INSIST(sock->references > 0);	sock->references--;  /* the internal event is done with this socket */	if (sock->references == 0) {		UNLOCK(&sock->lock);		destroy_socket(&sock);		return;	}	/* If the event is no longer in the list we can just return */	ldev = ISC_LIST_HEAD(sock->recv_list);	while (ldev != NULL && ldev != dev) {		ldev = ISC_LIST_NEXT(ldev, ev_link);	}	if (ldev == NULL)		goto done;	/*	 * Try to do as much I/O as possible on this socket.  There are no	 * limits here, currently.	 */		switch (completeio_recv(sock, dev, messagehdr, nbytes, recv_errno)) {		case DOIO_SOFT:			cc = 0;			recv_errno = 0;			io_state = startio_recv(sock, dev, &cc, FALSE, &recv_errno);			goto done;		case DOIO_EOF:			/*			 * read of 0 means the remote end was closed.			 * Run through the event queue and dispatch all			 * the events with an EOF result code.			 */			dev->result = ISC_R_EOF;			send_recvdone_event(sock, &dev);			goto done;		case DOIO_SUCCESS:		case DOIO_HARD:			send_recvdone_event(sock, &dev);			break;		} done:	UNLOCK(&sock->lock);}static voidinternal_send(isc_socket_t *sock, isc_socketevent_t *dev, struct msghdr *messagehdr, int nbytes, int send_errno) {	isc_socketevent_t *ldev;	int io_state;	int cc;	/*	 * Find out what socket this is and lock it.	 */	INSIST(VALID_SOCKET(sock));	LOCK(&sock->lock);	socket_log(sock, NULL, IOEVENT,		   isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALSEND,		   "internal_send: task got socket event %p", dev);	INSIST(sock->references > 0);	sock->references--;  /* the internal event is done with this socket */	if (sock->references == 0) {		UNLOCK(&sock->lock);		destroy_socket(&sock);		return;	}	/* If the event is no longer in the list we can just return */	ldev = ISC_LIST_HEAD(sock->send_list);	while (ldev != NULL && ldev != dev) {		ldev = ISC_LIST_NEXT(ldev, ev_link);	}	if (ldev == NULL)		goto done;	/*	 * Try to do as much I/O as possible on this socket.  There are no	 * limits here, currently.	 */	switch (completeio_send(sock, dev, messagehdr, nbytes, send_errno)) {	case DOIO_SOFT:		cc = 0;		send_errno = 0;		io_state = startio_send(sock, dev, &cc, FALSE, &send_errno);		goto done;	case DOIO_HARD:	case DOIO_SUCCESS:		send_senddone_event(sock, &dev);		break;	} done:	UNLOCK(&sock->lock);}/* * This is the I/O Completion Port Worker Function. It loops forever * waiting for I/O to complete and then forwards them for further * processing. There are a number of these in separate threads. */static isc_threadresult_t WINAPISocketIoThread(LPVOID ThreadContext) {	isc_socketmgr_t *manager = ThreadContext;	BOOL bSuccess = FALSE;	DWORD nbytes;	DWORD tbytes;	DWORD tflags;	IoCompletionInfo *lpo = NULL;	isc_socket_t *sock = NULL;	int request;	isc_socketevent_t *dev = NULL;	struct msghdr *messagehdr = NULL;	int errval;	char strbuf[ISC_STRERRORSIZE];	int errstatus;	REQUIRE(VALID_MANAGER(manager));	/*	Set the thread priority high enough so I/O will	 *	preempt normal recv packet processing, but not	 * 	higher than the timer sync thread.	 */	if (!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL)) {		errval = GetLastError();		isc__strerror(errval, strbuf, sizeof(strbuf));		FATAL_ERROR(__FILE__, __LINE__,				isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,				ISC_MSG_FAILED,				"Can't set thread priority: %s"),				strbuf);	}	/*	 * Loop forever waiting on I/O Completions and then processing them	 */	while(TRUE) {		bSuccess = GetQueuedCompletionStatus (                                       manager->hIoCompletionPort,                                       &nbytes,                                       (LPDWORD) &sock,                                       (LPOVERLAPPED *)&lpo,                                       INFINITE					);		if(lpo == NULL ) {			/*			 * Received request to exit			 */			break;		}		errstatus = 0;		if(!bSuccess) {			/*			 * I/O Failure			 * Find out why			 */			WSAGetOverlappedResult(sock->fd, (LPWSAOVERLAPPED) &lpo,						&tbytes, FALSE, &tflags);			dev = lpo->dev;		}		request = lpo->request_type;		dev = lpo->dev;		messagehdr = &lpo->messagehdr;		switch (request) {		case SOCKET_CANCEL:			break;		case SOCKET_RECV:			internal_recv(sock, dev, messagehdr, nbytes, errstatus);			break;		case SOCKET_SEND:			internal_send(sock, dev, messagehdr, nbytes, errstatus);			break;		default:			break;	/* Unknown: Just ignore it */		}		if (lpo != NULL)			HeapFree(hHeapHandle, 0, lpo);	}	/*	 * Exit Completion Port Thread	 */	manager_log(manager, TRACE,		    isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,				   ISC_MSG_EXITING, "SocketIoThread exiting"));	return ((isc_threadresult_t)0);}/* * This is the thread that will loop forever, waiting for an event to * happen. * * When the wait returns something to do, find the signaled event * and issue the request for the given socket */static isc_threadresult_t WINAPIevent_wait(void *uap) {	events_thread_t *evthread = uap;	isc_socketmgr_t *manager = evthread->manager;	int

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -