?? httcp.c
字號:
HTTRACE(PROT_TRACE, "HTDoConnect. WOULD BLOCK `%s'\n" _ hostname);#ifndef _WINSOCKAPI_ HTHost_register(host, net, HTEvent_CONNECT);#endif /* _WINSOCKAPI_ */ return HT_WOULD_BLOCK; }#ifdef _WINSOCKAPI_ /* * yovavm@contact.com * * According to Microsoft docs, the error code WSAEALREADY is * described as: * "A nonblocking connect call is in progress on the specified * socket. Note In order to preserve backward compatibility, * this error is reported as WSAEINVAL to Windows Sockets 1.1 * applications that link to either Winsock.dll or * Wsock32.dll." */ if (NETCALL_INVAL(socerrno)) { host->tcpstate = TCP_CONNECTED; HTTRACE(PROT_TRACE, "Connection to HTHost %p is already in progress.\n" _ host); break; }#endif /* _WINSOCKAPI_ */ if (socerrno == EISCONN) { host->tcpstate = TCP_CONNECTED; HTTRACE(PROT_TRACE, "HTHost %p going to state TCP_CONNECTED.\n" _ host); break; } if (NETCALL_DEADSOCKET(socerrno)) /* We lost the socket */ { host->tcpstate = TCP_NEED_SOCKET; HTTRACE(PROT_TRACE, "HTHost %p going to state TCP_NEED_SOCKET.\n" _ host); break; } if (HTHost_retry(host)) { host->connecttime = HTGetTimeInMillis() - host->connecttime; /* Added EINVAL `invalid argument' as this is what I get back from a non-blocking connect where I should get `connection refused' on BSD. SVR4 gives SIG_PIPE */ if (HT_HOSTUNREACHABLE(socerrno)) host->connecttime += TCP_DELAY; else host->connecttime += TCP_PENALTY; HTDNS_updateWeigths(host->dns, HTHost_home(host), host->connecttime); } host->tcpstate = TCP_ERROR; HTTRACE(PROT_TRACE, "HTHost %p going to state TCP_ERROR.\n" _ host); } else { host->tcpstate = TCP_CONNECTED; HTTRACE(PROT_TRACE, "HTHost %p going to state TCP_CONNECTED.\n" _ host); } break; case TCP_CONNECTED: HTHost_unregister(host, net, HTEvent_CONNECT); if (HTHost_retry(host)) { host->connecttime = HTGetTimeInMillis() - host->connecttime; HTDNS_updateWeigths(host->dns, HTHost_home(host), host->connecttime); } HTHost_setRetry(host, 0); host->tcpstate = TCP_IN_USE; HTTRACE(PROT_TRACE, "HTHost %p connected.\n" _ host); return HT_OK; break; /* Once a host is connected, subsequent connections are immediately OK */ case TCP_IN_USE: if ((status = HTHost_addNet(host, net)) == HT_PENDING) { HTTRACE(PROT_TRACE, "HTDoConnect. Pending...\n"); return HT_PENDING; } HTChannel_upSemaphore(host->channel); return HT_OK; case TCP_DNS_ERROR: HTHost_setRetry(host, 0); host->tcpstate = TCP_BEGIN; HTTRACE(PROT_TRACE, "HTHost %p going to state TCP_BEGIN.\n" _ host); return HT_NO_HOST; break; case TCP_NEED_BIND: case TCP_NEED_LISTEN: case TCP_ERROR: if (HTChannel_socket(host->channel) != INVSOC) { NETCLOSE(HTChannel_socket(host->channel)); if (HTHost_isPersistent(host)) { /* Inherited socket */ HTHost_setPersistent(host, NO, HT_TP_SINGLE); host->tcpstate = TCP_NEED_SOCKET; HTTRACE(PROT_TRACE, "HTHost %p going to state TCP_NEED_SOCKET.\n" _ host); break; } } /* Do we have more homes to try? */ HTHost_decreaseRetry(host); if (HT_HOSTUNREACHABLE(socerrno) && HTHost_retry(host) > 0) { HTRequest_addSystemError(request, ERR_NON_FATAL, socerrno, NO,"connect"); host->tcpstate = TCP_DNS; HTTRACE(PROT_TRACE, "HTHost %p going to state TCP_DNS.\n" _ host); break; } HTRequest_addSystemError(request, ERR_FATAL, socerrno, NO, "connect"); HTDNS_delete(hostname); HTHost_setRetry(host, 0); host->tcpstate = TCP_BEGIN; HTTRACE(PROT_TRACE, "HTHost %p going to state TCP_BEGIN.\n" _ host); return HT_ERROR; break; } }}/* HTDoAccept()** ------------** This function makes a non-blocking accept which will turn up as ready** read in the select.** Returns** HT_ERROR Error has occured or interrupted** HT_OK if connected** HT_WOULD_BLOCK if operation would have blocked*/PUBLIC int HTDoAccept (HTNet * listening, HTNet * accepting){ HTHost * host = HTNet_host(listening); HTRequest * request = HTNet_request(accepting); int size = sizeof(host->sock_addr); int status; if (!request || HTNet_socket(listening)==INVSOC) { HTTRACE(PROT_TRACE, "HTDoAccept.. Invalid socket\n"); return HT_ERROR; } status = accept(HTNet_socket(listening), (struct sockaddr *) &host->sock_addr, &size); if (NETCALL_ERROR(status)) { if (NETCALL_WOULDBLOCK(socerrno)) { HTTRACE(PROT_TRACE, "HTDoAccept.. WOULD BLOCK %d\n" _ HTNet_socket(listening)); HTHost_register(host, listening, HTEvent_ACCEPT); return HT_WOULD_BLOCK; } HTRequest_addSystemError(request, ERR_WARN, socerrno, YES, "accept"); HTTRACE(PROT_TRACE, "HTDoAccept.. Accept failed\n"); return HT_ERROR; } HTTRACE(PROT_TRACE, "Accepted.... socket %d\n" _ status); /* Remember the new socket we got and close the old one */ NETCLOSE(HTNet_socket(accepting)); HTNet_setSocket(accepting, status); return HT_OK;}/* HTDoListen** ----------** Listens on the specified port. ** returns HT_ERROR Error has occured or interrupted** HT_OK if connected*/PUBLIC int HTDoListen (HTNet * listening, HTNet * accepting, int backlog){ HTHost * host = HTNet_host(listening); HTRequest * request = HTNet_request(listening); int preemptive = listening->preemptive; int status = HT_OK; char * hostname = HTHost_name(host); /* Jump into the state machine */ while (1) { switch (host->tcpstate) { case TCP_BEGIN: { /* ** Add the net object to the host object found above. If the ** host is idle then we can start the request right away, ** otherwise we must wait until it is free. */ if ((status = HTHost_addNet(host, accepting)) == HT_PENDING) HTTRACE(PROT_TRACE, "HTDoListen.. Pending...\n"); /* ** If we are pending then return here, otherwise go to next state ** which is setting up a channel */ host->tcpstate = TCP_CHANNEL; HTTRACE(PROT_TRACE, "HTHost %p going to state TCP_CHANNEL.\n" _ host); if (status == HT_PENDING) return HT_PENDING; } break; case TCP_CHANNEL: /* ** The next state depends on whether we have a connection or not. */ if (HTHost_channel(host) == NULL) { host->tcpstate = TCP_NEED_SOCKET; HTTRACE(PROT_TRACE, "HTHost %p going to state TCP_SOCKET.\n" _ host); } else { /* ** There is now one more using the channel */ HTChannel_upSemaphore(host->channel); /* ** We are now all set and can jump to connected mode */ host->tcpstate = TCP_CONNECTED; HTTRACE(PROT_TRACE, "HTHost %p going to state TCP_CONNECTED.\n" _ host); } hostname = HTHost_name(host); break; case TCP_NEED_SOCKET: { SOCKET sockfd; /* Create a new socket */ if ((sockfd = _makeSocket(host, request, preemptive)) == INVSOC) { host->tcpstate = TCP_ERROR; break; } /* Create channnel and streams */ createChannelAndTransportStreams (host, sockfd, accepting->transport); /* Progress nofitication */ { HTAlertCallback *cbf = HTAlert_find(HT_PROG_ACCEPT); if (cbf) (*cbf)(request, HT_PROG_ACCEPT, HT_MSG_NULL, NULL, hostname, NULL); } host->tcpstate = TCP_NEED_BIND; HTTRACE(PROT_TRACE, "HTHost %p going to state TCP_NEED_BIND\n" _ host); break; } case TCP_NEED_BIND: HTTRACE(PROT_TRACE, "Socket...... Binding socket %d\n" _ HTNet_socket(listening)); status = bind(HTNet_socket(listening), (struct sockaddr *) &host->sock_addr, sizeof(host->sock_addr)); if (NETCALL_ERROR(status)) { HTTRACE(PROT_TRACE, "Socket...... Bind failed %d\n" _ socerrno); host->tcpstate = TCP_ERROR; } else { HTTRACE(PROT_TRACE, "Socket...... Starting listening on socket %d\n" _ HTNet_socket(listening)); host->tcpstate = TCP_NEED_LISTEN; } break; case TCP_NEED_LISTEN: status = listen(HTNet_socket(listening), backlog); if (NETCALL_ERROR(status)) host->tcpstate = TCP_ERROR; else host->tcpstate = TCP_CONNECTED; break; case TCP_CONNECTED: HTHost_unregister(host, listening, HTEvent_ACCEPT); HTHost_setRetry(host, 0); host->tcpstate = TCP_IN_USE; HTTRACE(PROT_TRACE, "HTHost %p listening.\n" _ host); return HT_OK; break; /* once a host is connected, subsequent connections are immediately OK */ case TCP_IN_USE: if ((status = HTHost_addNet(host, accepting)) == HT_PENDING) { HTTRACE(PROT_TRACE, "HTDoListen.. Pending...\n"); return HT_PENDING; } HTChannel_upSemaphore(host->channel); return HT_OK; case TCP_NEED_CONNECT: case TCP_DNS: case TCP_DNS_ERROR: case TCP_ERROR: if (HTChannel_socket(host->channel) != INVSOC) { NETCLOSE(HTChannel_socket(host->channel)); if (HTHost_isPersistent(host)) { /* Inherited socket */ HTHost_setPersistent(host, NO, HT_TP_SINGLE); host->tcpstate = TCP_NEED_SOCKET; HTTRACE(PROT_TRACE, "HTHost %p going to state TCP_NEED_SOCKET.\n" _ host); break; } } HTRequest_addSystemError(request, ERR_FATAL, socerrno, NO, "accept"); HTHost_setRetry(host, 0); host->tcpstate = TCP_BEGIN; HTTRACE(PROT_TRACE, "HTHost %p going to state TCP_BEGIN.\n" _ host); return HT_ERROR; break; } }}/* HTDoClose** ---------** Closes a file descriptor whatever means are available on the current** platform. If we have unix file descriptors then use this otherwise use** the ANSI C file descriptors**** returns HT_ERROR Error has occured or interrupted** HT_OK if connected** HT_WOULD_BLOCK if operation would have blocked*/PUBLIC int HTDoClose (HTNet * net){ int status = -1; if (net && HTNet_socket(net) != INVSOC) { HTTRACE(PROT_TRACE, "HTDoClose... Close %d\n" _ HTNet_socket(net)); status = NETCLOSE(HTNet_socket(net)); /* HTEvent_unregister(HTNet_socket(net), (SockOps) FD_ALL); */ HTNet_decreaseSocket(); HTNet_setSocket(net, INVSOC); /* ** As we have a socket available we check for whether ** we can start any pending requests. We do this by asking for ** pending Host objects. If none then use the current object */ HTHost_launchPending(net->host); } else HTTRACE(PROT_TRACE, "HTDoClose... No pending requests\n"); return status < 0 ? HT_ERROR : HT_OK;}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -