Annotation of libwww/Library/src/HTTCP.c, revision 2.94.2.1
2.31 frystyk 1: /* HTTCP.c
2.83 frystyk 2: ** TCP SPECIFIC CODE
2.31 frystyk 3: **
2.42 frystyk 4: ** (c) COPYRIGHT MIT 1995.
2.31 frystyk 5: ** Please first read the full copyright statement in the file COPYRIGH.
2.94.2.1! eric 6: ** @(#) $Id: HTTCP.c,v 2.94 1996/10/07 02:05:19 frystyk Exp $
1.1 timbl 7: **
8: ** This code is in common between client and server sides.
9: **
10: ** 16 Jan 92 TBL Fix strtol() undefined on CMU Mach.
11: ** 25 Jun 92 JFG Added DECNET option through TCP socket emulation.
2.7 duns 12: ** 13 Sep 93 MD Added correct return of vmserrorno for HTInetStatus.
13: ** Added decoding of vms error message for MULTINET.
2.13 frystyk 14: ** 31 May 94 HF Added cache on host id's; now use inet_ntoa() to
15: ** HTInetString and some other fixes. Added HTDoConnect
16: ** and HTDoAccept
1.1 timbl 17: */
18:
2.36 frystyk 19: /* Library include files */
2.79 frystyk 20: #include "sysdep.h"
2.83 frystyk 21: #include "WWWUtil.h"
22: #include "WWWCore.h"
23:
2.58 frystyk 24: #include "HTReqMan.h"
2.54 frystyk 25: #include "HTNetMan.h"
2.36 frystyk 26: #include "HTTCP.h" /* Implemented here */
2.29 frystyk 27:
2.94.2.1! eric 28: #include "HTWatch.h"
! 29: #include "HTHstMan.h"
! 30:
2.36 frystyk 31: /* VMS stuff */
32: #ifdef VMS
33: #ifndef MULTINET
34: #define FD_SETSIZE 32
35: #else /* Multinet */
36: #define FD_SETSIZE 256
37: #endif /* Multinet */
38: #endif /* VMS */
39:
2.13 frystyk 40: /* Macros and other defines */
2.24 frystyk 41: /* x seconds penalty on a multi-homed host if IP-address is down */
42: #define TCP_PENALTY 1200
43:
44: /* x seconds penalty on a multi-homed host if IP-address is timed out */
45: #define TCP_DELAY 600
46:
2.93 eric 47: /* imperical study in socket call error codes
48: */
49: #ifdef _WINSOCKAPI_ /* windows */
50: #define NETCALL_ERROR(ret) (ret == SOCKET_ERROR)
51: #define NETCALL_DEADSOCKET(err) (err == WSAEBADF)
52: #define NETCALL_WOULDBLOCK(err) (err == WSAEWOULDBLOCK)
53: #else /* _WINSOCKAPI_ unix */
54: #define NETCALL_ERROR(ret) (ret < 0)
55: #define NETCALL_DEADSOCKET(err) (err == EBADF)
56: #if defined(EAGAIN) && defined(EALREADY)
57: #define NETCALL_WOULDBLOCK(err) (err == EINPROGRESS || \
58: err == EALREADY || \
59: err == EAGAIN)
60: #else /* (EAGAIN && EALREADY) */
61: #ifdef EALREADY
62: #define NETCALL_WOULDBLOCK(err) (err == EINPROGRESS || err == EALREADY)
63: #else /* EALREADY */
64: #ifdef EAGAIN
65: #define NETCALL_WOULDBLOCK(err) (err == EINPROGRESS || err == EAGAIN)
66: #else /* EAGAIN */
67: #define NETCALL_WOULDBLOCK(err) (err == EINPROGRESS)
68: #endif /* !EAGAIN */
69: #endif /* !EALREADY */
70: #endif /* !(EAGAIN && EALREADY) */
71: #endif /* !_WINSOCKAPI_ done */
2.13 frystyk 72: /* ------------------------------------------------------------------------- */
2.19 frystyk 73: /* CONNECTION ESTABLISHMENT MANAGEMENT */
74: /* ------------------------------------------------------------------------- */
2.13 frystyk 75:
2.94.2.1! eric 76: /* _makeSocket - create a socket, if !preemptive, set FIONBIO
2.93 eric 77: * returns 1: blocking
78: * 0: non-blocking
79: * -1: creation error
80: */
2.94.2.1! eric 81: PRIVATE int _makeSocket(HTHost * host, HTRequest * request, int preemptive, HTTransport * transport)
2.93 eric 82: {
83: int status;
2.94.2.1! eric 84: SOCKET sockfd;
2.93 eric 85: #ifdef DECNET
2.94.2.1! eric 86: if ((sockfd=socket(AF_DECnet, SOCK_STREAM, 0))==INVSOC)
2.93 eric 87: #else
2.94.2.1! eric 88: if ((sockfd=socket(AF_INET, SOCK_STREAM,IPPROTO_TCP))==INVSOC)
2.93 eric 89: #endif
90: {
2.94.2.1! eric 91: HTRequest_addSystemError(request, ERR_FATAL, socerrno,
2.93 eric 92: NO, "socket");
2.94.2.1! eric 93: host->tcpstate = TCP_ERROR;
2.93 eric 94: return -1;
95: }
2.94.2.1! eric 96: HTWATCH(PROT_TRACE, host, HTHIDE("Socket...... Created %d\n"), sockfd);
2.93 eric 97:
98: /* Increase the number of sockets by one */
99: HTNet_increaseSocket();
100:
101: /* If non-blocking protocol then change socket status
102: ** I use fcntl() so that I can ask the status before I set it.
103: ** See W. Richard Stevens (Advan. Prog. in UNIX environment, p.364)
104: ** Be CAREFULL with the old `O_NDELAY' - it will not work as read()
105: ** returns 0 when blocking and NOT -1. FNDELAY is ONLY for BSD and
106: ** does NOT work on SVR4 systems. O_NONBLOCK is POSIX.
107: */
2.94.2.1! eric 108: if (!preemptive) {
2.93 eric 109: #ifdef _WINSOCKAPI_
110: { /* begin windows scope */
111: long levents = FD_READ | FD_WRITE | FD_ACCEPT |
112: FD_CONNECT | FD_CLOSE ;
113: int rv = 0 ;
114: u_long one = 1;
115:
2.94.2.1! eric 116: status = ioctlsocket(sockfd, FIONBIO, &one) ==
2.93 eric 117: SOCKET_ERROR ? -1 : 0;
118: } /* end scope */
119: #else /* _WINSOCKAPI_ */
120: #if defined(VMS)
121: {
122: int enable = 1;
2.94.2.1! eric 123: status = IOCTL(sockfd, FIONBIO, &enable);
2.93 eric 124: }
125: #else /* VMS */
2.94.2.1! eric 126: if((status = fcntl(sockfd, F_GETFL, 0)) != -1) {
2.93 eric 127: #ifdef O_NONBLOCK
128: status |= O_NONBLOCK; /* POSIX */
129: #else /* O_NONBLOCK */
130: #ifdef F_NDELAY
131: status |= F_NDELAY; /* BSD */
132: #endif /* F_NDELAY */
133: #endif /* !O_NONBLOCK */
2.94.2.1! eric 134: status = fcntl(sockfd, F_SETFL, status);
2.93 eric 135: }
136: #endif /* !VMS */
137: #endif /* !_WINSOCKAPI_ */
2.94.2.1! eric 138: HTWATCH(PROT_TRACE, host, HTHIDE("Socket...... %slocking socket\n"), status == -1 ? "B" : "Non-b");
! 139: } else
! 140: HTWATCH(PROT_TRACE, host, HTHIDE("Socket...... Blocking socket\n"));
! 141:
! 142: /* Create a channel for this socket */
! 143: HTHost_setChannel(host, HTChannel_new(sockfd, YES));
! 144: HTHost_getInput(host, transport, NULL, 0);
2.93 eric 145:
146: return status == -1 ? 1 : 0;
147: }
148:
2.13 frystyk 149: /* HTDoConnect()
150: **
151: ** Note: Any port indication in URL, e.g., as `host:port' overwrites
2.54 frystyk 152: ** the default port value.
2.13 frystyk 153: **
2.40 frystyk 154: ** returns HT_ERROR Error has occured or interrupted
155: ** HT_OK if connected
156: ** HT_WOULD_BLOCK if operation would have blocked
2.13 frystyk 157: */
2.54 frystyk 158: PUBLIC int HTDoConnect (HTNet * net, char * url, u_short default_port)
2.13 frystyk 159: {
2.94.2.1! eric 160: HTHost * me = net->host;
2.88 frystyk 161: HTRequest * request = HTNet_request(net);
2.94.2.1! eric 162: int preemptive = net->preemptive;
! 163: int retry = net->retry;
! 164:
! 165: int status = HT_OK;
! 166: char * hostname = HTHost_name(me);
2.13 frystyk 167:
2.55 frystyk 168: /* Jump into the state machine */
2.94.2.1! eric 169: if (!me)
! 170: goto tcp_begin;
2.55 frystyk 171: while (1) {
2.94.2.1! eric 172: switch (me->tcpstate) {
! 173: tcp_begin:
2.55 frystyk 174: case TCP_BEGIN:
2.91 frystyk 175: {
176: char * proxy = HTRequest_proxy(request);
2.94.2.1! eric 177: char * physical = HTAnchor_physical(HTRequest_anchor(request));
2.91 frystyk 178:
179: /* Check to see whether we connect directly or via a proxy */
2.94.2.1! eric 180: if ((net->host = HTHost_newWParse(request, proxy ? proxy : physical,
! 181: HTProtocol_port(net->protocol))) == NULL)
! 182: return NO;
! 183: me = net->host;
2.91 frystyk 184:
185: /*
186: ** Add the net object to the host object found above. If the
187: ** host is idle then we can start the request right away,
188: ** otherwise we must wait until it is free.
189: */
2.94.2.1! eric 190: if (HTHost_addNet(net->host, net) == HT_PENDING)
2.91 frystyk 191: if (PROT_TRACE) HTTrace("HTDoConnect. Pending...\n");
192:
193: /*
2.94.2.1! eric 194: ** If we are pending then return here, otherwise go to next state
2.91 frystyk 195: ** which is setting up a channel
196: */
2.94.2.1! eric 197: me->tcpstate = TCP_CHANNEL;
! 198: HTWATCH(HTWatch_TCP, me, HTHIDE("HTHost %p going to state TCP_CHANNEL.\n"), me);
2.91 frystyk 199: if (status == HT_PENDING) return HT_PENDING;
200: }
201: break;
2.83 frystyk 202:
2.91 frystyk 203: case TCP_CHANNEL:
2.83 frystyk 204: /*
2.91 frystyk 205: ** The next state depends on whether we have a connection
206: ** or not - if so then we can jump directly to connect() to
207: ** test it - otherwise we must around DNS to get the name
2.93 eric 208: ** Resolved
2.83 frystyk 209: */
2.94.2.1! eric 210: if (HTHost_channel(me) == NULL) {
! 211: me->tcpstate = TCP_DNS;
! 212: HTWATCH(HTWatch_TCP, me, HTHIDE("HTHost %p going to state TCP_DNS.\n"), me);
! 213: } else {
! 214: HTChannel_upSemaphore(me->channel);
! 215: me->tcpstate = TCP_CONNECTED;
! 216: HTWATCH(HTWatch_TCP, me, HTHIDE("HTHost %p going to state TCP_CONNECTED.\n"), me);
! 217: }
! 218: hostname = HTHost_name(me);
2.55 frystyk 219: break;
220:
2.91 frystyk 221: case TCP_DNS:
2.94.2.1! eric 222: if ((status = HTParseInet(me, hostname, request)) < 0) {
! 223: HTWATCH(PROT_TRACE, me, HTHIDE("HTDoConnect. Can't locate `%s\'\n"), hostname);
2.91 frystyk 224: HTRequest_addError(request, ERR_FATAL, NO,
225: HTERR_NO_REMOTE_HOST,
226: (void *) hostname, strlen(hostname),
227: "HTDoConnect");
2.94.2.1! eric 228: me->tcpstate = TCP_ERROR;
! 229: HTWATCH(HTWatch_TCP, me, HTHIDE("HTHost %p going to state TCP_ERROR.\n"), me);
2.27 frystyk 230: break;
2.55 frystyk 231: }
2.94.2.1! eric 232: if (!retry && status > 1) /* If multiple homes */
! 233: retry = status;
! 234: me->tcpstate = TCP_NEED_SOCKET;
! 235: HTWATCH(HTWatch_TCP, me, HTHIDE("HTHost %p going to state TCP_NEED_SOCKET.\n"), me);
2.55 frystyk 236: break;
237:
238: case TCP_NEED_SOCKET:
2.94.2.1! eric 239: if (_makeSocket(me, request, preemptive, net->transport) == -1)
2.27 frystyk 240: break;
2.83 frystyk 241:
2.27 frystyk 242: /* If multi-homed host then start timer on connection */
2.94.2.1! eric 243: if (retry) me->connecttime = time(NULL);
2.65 frystyk 244:
245: /* Progress */
246: {
247: HTAlertCallback *cbf = HTAlert_find(HT_PROG_CONNECT);
2.94.2.1! eric 248: if (cbf) (*cbf)(request, HT_PROG_CONNECT, HT_MSG_NULL,
2.91 frystyk 249: NULL, hostname, NULL);
2.65 frystyk 250: }
2.94.2.1! eric 251: me->tcpstate = TCP_NEED_CONNECT;
! 252: HTWATCH(HTWatch_TCP, me, HTHIDE("HTHost %p going to state TCP_NEED_CONNECT.\n"), me);
2.55 frystyk 253: break;
2.56 frystyk 254: case TCP_NEED_CONNECT:
2.94.2.1! eric 255: status = connect(HTChannel_socket(me->channel), (struct sockaddr *) &me->sock_addr,
! 256: sizeof(me->sock_addr));
2.55 frystyk 257: /*
258: * According to the Sun man page for connect:
259: * EINPROGRESS The socket is non-blocking and the con-
260: * nection cannot be completed immediately.
261: * It is possible to select(2) for comple-
262: * tion by selecting the socket for writ-
263: * ing.
264: * According to the Motorola SVR4 man page for connect:
265: * EAGAIN The socket is non-blocking and the con-
266: * nection cannot be completed immediately.
267: * It is possible to select for completion
268: * by selecting the socket for writing.
269: * However, this is only possible if the
270: * socket STREAMS module is the topmost
271: * module on the protocol stack with a
272: * write service procedure. This will be
273: * the normal case.
274: */
2.93 eric 275: if (NETCALL_ERROR(status))
2.55 frystyk 276: {
2.93 eric 277: if (NETCALL_WOULDBLOCK(socerrno))
2.55 frystyk 278: {
2.94.2.1! eric 279: HTWATCH(PROT_TRACE, me, HTHIDE("HTDoConnect. WOULD BLOCK `%s'\n"), hostname);
! 280: HTHost_register(me, net, HTEvent_CONNECT);
2.55 frystyk 281: return HT_WOULD_BLOCK;
282: }
283: if (socerrno == EISCONN) {
2.94.2.1! eric 284: me->tcpstate = TCP_CONNECTED;
! 285: HTWATCH(HTWatch_TCP, me, HTHIDE("HTHost %p going to state TCP_CONNECTED.\n"), me);
2.55 frystyk 286: break;
287: }
2.93 eric 288: if (NETCALL_DEADSOCKET(socerrno)) /* We lost the socket */
2.58 frystyk 289: {
2.94.2.1! eric 290: me->tcpstate = TCP_NEED_SOCKET;
! 291: HTWATCH(HTWatch_TCP, me, HTHIDE("HTHost %p going to state TCP_NEED_SOCKET.\n"), me);
2.55 frystyk 292: break;
2.27 frystyk 293: }
2.94.2.1! eric 294: if (retry) {
! 295: me->connecttime -= time(NULL);
2.54 frystyk 296: /* Added EINVAL `invalid argument' as this is what I
297: get back from a non-blocking connect where I should
298: get `connection refused' on BSD. SVR4 gives SIG_PIPE */
2.94 frystyk 299: #if defined(__svr4__) || defined (_WINSOCKAPI_)
2.55 frystyk 300: if (socerrno==ECONNREFUSED || socerrno==ETIMEDOUT ||
301: socerrno==ENETUNREACH || socerrno==EHOSTUNREACH ||
302: socerrno==EHOSTDOWN)
303: #else
2.54 frystyk 304: if (socerrno==ECONNREFUSED || socerrno==ETIMEDOUT ||
305: socerrno==ENETUNREACH || socerrno==EHOSTUNREACH ||
306: socerrno==EHOSTDOWN || socerrno==EINVAL)
2.35 roeber 307: #endif
2.94.2.1! eric 308: me->connecttime += TCP_DELAY;
2.54 frystyk 309: else
2.94.2.1! eric 310: me->connecttime += TCP_PENALTY;
! 311: HTDNS_updateWeigths(me->dns, me->home, me->connecttime);
2.55 frystyk 312: }
2.94.2.1! eric 313: me->tcpstate = TCP_ERROR;
! 314: HTWATCH(HTWatch_TCP, me, HTHIDE("HTHost %p going to state TCP_ERROR.\n"), me);
! 315: } else {
! 316: me->tcpstate = TCP_CONNECTED;
! 317: HTWATCH(HTWatch_TCP, me, HTHIDE("HTHost %p going to state TCP_CONNECTED.\n"), me);
! 318: }
2.55 frystyk 319: break;
320:
321: case TCP_CONNECTED:
2.94.2.1! eric 322: HTHost_unregister(me, net, HTEvent_CONNECT);
! 323: if (retry) {
! 324: me->connecttime -= time(NULL);
! 325: HTDNS_updateWeigths(me->dns, me->home, me->connecttime);
2.27 frystyk 326: }
2.94.2.1! eric 327: retry = 0;
! 328: me->tcpstate = TCP_BEGIN;
! 329: HTWATCH(HTWatch_TCP, me, HTHIDE("HTHost %p connected.\n"), me);
2.55 frystyk 330: return HT_OK;
331: break;
332:
2.56 frystyk 333: case TCP_NEED_BIND:
334: case TCP_NEED_LISTEN:
2.55 frystyk 335: case TCP_ERROR:
2.94.2.1! eric 336: HTWATCH(PROT_TRACE, me, HTHIDE("HTDoConnect. Connect failed %d\n"), socerrno);
! 337: if (HTChannel_socket(me->channel) != INVSOC) {
! 338: /* HTEvent_unregister(HTChannel_socket(me->channel), (SockOps) FD_ALL); */
! 339: NETCLOSE(HTChannel_socket(me->channel));
! 340: HTChannel_setSocket(me->channel, INVSOC);
! 341: #if 1 /* @@@ */
! 342: if (HTHost_isPersistent(me)) { /* Inherited socket */
! 343: HTHost_setPersistent(me, NO, HT_TP_SINGLE);
! 344: me->tcpstate = TCP_NEED_SOCKET;
! 345: HTWATCH(HTWatch_TCP, me, HTHIDE("HTHost %p going to state TCP_NEED_SOCKET.\n"), me);
2.55 frystyk 346: break;
347: }
2.94.2.1! eric 348: #endif
2.55 frystyk 349: }
350:
351: /* Do we have more homes to try? */
2.94.2.1! eric 352: if (--retry > 0) {
2.65 frystyk 353: HTRequest_addSystemError(request, ERR_NON_FATAL, socerrno, NO,
2.55 frystyk 354: "connect");
2.94.2.1! eric 355: me->tcpstate = TCP_DNS;
! 356: HTWATCH(HTWatch_TCP, me, HTHIDE("HTHost %p going to state TCP_DNS.\n"), me);
2.24 frystyk 357: break;
358: }
2.65 frystyk 359: HTRequest_addSystemError(request, ERR_FATAL,socerrno,NO,"connect");
2.91 frystyk 360: HTDNS_delete(hostname);
2.94.2.1! eric 361: retry = 0;
! 362: me->tcpstate = TCP_BEGIN;
! 363: HTWATCH(HTWatch_TCP, me, HTHIDE("HTHost %p going to state TCP_BEGIN.\n"), me);
2.55 frystyk 364: return HT_ERROR;
365: break;
2.24 frystyk 366: }
2.55 frystyk 367: }
2.13 frystyk 368: }
369:
2.56 frystyk 370: /* HTDoAccept()
371: ** ------------
372: ** This function makes a non-blocking accept which will turn up as ready
373: ** read in the select.
374: ** Returns
375: ** HT_ERROR Error has occured or interrupted
376: ** HT_OK if connected
377: ** HT_WOULD_BLOCK if operation would have blocked
2.13 frystyk 378: */
2.94.2.1! eric 379:
2.88 frystyk 380: PUBLIC int HTDoAccept (HTNet * net, HTNet ** accepted)
2.13 frystyk 381: {
382: int status;
2.94.2.1! eric 383: int size = sizeof(net->host->sock_addr);
2.88 frystyk 384: HTRequest * request = HTNet_request(net);
2.94.2.1! eric 385: if (!request || HTNet_socket(net)==INVSOC) {
2.77 eric 386: if (PROT_TRACE) HTTrace("HTDoAccept.. Invalid socket\n");
2.56 frystyk 387: return HT_ERROR;
2.13 frystyk 388: }
2.65 frystyk 389:
390: /* Progress report */
391: {
392: HTAlertCallback *cbf = HTAlert_find(HT_PROG_ACCEPT);
393: if (cbf) (*cbf)(request, HT_PROG_ACCEPT, HT_MSG_NULL,NULL, NULL, NULL);
394: }
2.94.2.1! eric 395: status = accept(HTNet_socket(net), (struct sockaddr *) &net->host->sock_addr, &size);
2.93 eric 396: if (NETCALL_ERROR(status))
2.23 duns 397: {
2.93 eric 398: if (NETCALL_WOULDBLOCK(socerrno))
2.56 frystyk 399: {
400: if (PROT_TRACE)
2.94.2.1! eric 401: HTTrace("HTDoAccept.. WOULD BLOCK %d\n", HTNet_socket(net));
! 402: HTEvent_register(HTNet_socket(net), HTEvent_ACCEPT, &net->event);
2.56 frystyk 403: return HT_WOULD_BLOCK;
404: }
2.65 frystyk 405: HTRequest_addSystemError(request, ERR_WARN, socerrno, YES, "accept");
2.77 eric 406: if (PROT_TRACE) HTTrace("HTDoAccept.. Accept failed\n");
2.56 frystyk 407: return HT_ERROR;
2.23 duns 408: }
2.71 frystyk 409:
2.88 frystyk 410: if (PROT_TRACE) HTTrace("Accepted.... socket %d\n", status);
411:
412: /*
413: ** If accepted is the same as the net obejct then reuse it, else create
414: ** a new object and leave the original alone
415: */
416: if (*accepted == net)
417: HTDoClose(net);
418: else
419: *accepted = HTNet_dup(net);
2.94.2.1! eric 420: HTNet_setSocket(*accepted, status);
2.83 frystyk 421:
422: /* Create a channel for the new socket */
2.94.2.1! eric 423: HTHost_setChannel((*accepted)->host, HTChannel_new(HTNet_socket(*accepted), NO));
2.83 frystyk 424:
2.56 frystyk 425: return HT_OK;
426: }
427:
428:
429: /* HTDoListen
430: ** ----------
431: ** Listens on the specified port. 0 means that we chose it here
432: ** If master==INVSOC then we listen on all local interfaces (using a
433: ** wildcard). If !INVSOC then use this as the local interface
434: ** returns HT_ERROR Error has occured or interrupted
435: ** HT_OK if connected
436: */
2.67 frystyk 437: PUBLIC int HTDoListen (HTNet * net, u_short port, SOCKET master, int backlog)
2.56 frystyk 438: {
439: int status;
440:
441: /* Jump into the state machine */
442: while (1) {
2.94.2.1! eric 443: switch (net->host->tcpstate) {
2.56 frystyk 444: case TCP_BEGIN:
445: {
2.94.2.1! eric 446: SockA *sin = &net->host->sock_addr;
2.56 frystyk 447: memset((void *) sin, '\0', sizeof(SockA));
448: #ifdef DECNET
449: sin->sdn_family = AF_DECnet;
450: sin->sdn_objnum = port;
2.36 frystyk 451: #else
2.56 frystyk 452: sin->sin_family = AF_INET;
453: if (master != INVSOC) {
454: int len = sizeof(SockA);
455: if (getsockname(master, (struct sockaddr *) sin, &len)<0) {
2.65 frystyk 456: HTRequest_addSystemError(net->request, ERR_FATAL,
457: socerrno, NO, "getsockname");
2.94.2.1! eric 458: net->host->tcpstate = TCP_ERROR;
2.56 frystyk 459: break;
460: }
461: } else
462: sin->sin_addr.s_addr = INADDR_ANY;
463: sin->sin_port = htons(port);
464: #endif
465: }
466: if (PROT_TRACE)
2.83 frystyk 467: HTTrace("Socket...... Listen on port %d\n", port);
2.94.2.1! eric 468: net->host->tcpstate = TCP_NEED_SOCKET;
2.56 frystyk 469: break;
470:
471: case TCP_NEED_SOCKET:
2.94.2.1! eric 472: if (_makeSocket(net->host, net->request, net->preemptive, net->transport) == -1)
2.93 eric 473: break;
2.94.2.1! eric 474: net->host->tcpstate = TCP_NEED_BIND;
2.56 frystyk 475: break;
476:
477: case TCP_NEED_BIND:
2.94.2.1! eric 478: status = bind(HTNet_socket(net), (struct sockaddr *) &net->host->sock_addr,
! 479: sizeof(net->host->sock_addr));
2.93 eric 480: if (NETCALL_ERROR(status))
2.56 frystyk 481: {
482: if (PROT_TRACE)
2.83 frystyk 483: HTTrace("Socket...... Bind failed %d\n", socerrno);
2.94.2.1! eric 484: net->host->tcpstate = TCP_ERROR;
2.56 frystyk 485: } else
2.94.2.1! eric 486: net->host->tcpstate = TCP_NEED_LISTEN;
2.56 frystyk 487: break;
488:
489: case TCP_NEED_LISTEN:
2.94.2.1! eric 490: status = listen(HTNet_socket(net), backlog);
2.93 eric 491: if (NETCALL_ERROR(status))
2.94.2.1! eric 492: net->host->tcpstate = TCP_ERROR;
2.56 frystyk 493: else
2.94.2.1! eric 494: net->host->tcpstate = TCP_CONNECTED;
2.56 frystyk 495: break;
496:
497: case TCP_CONNECTED:
2.94.2.1! eric 498: net->host->tcpstate = TCP_BEGIN;
2.56 frystyk 499: if (PROT_TRACE)
2.83 frystyk 500: HTTrace("Socket...... Bind and listen on port %d %s\n",
2.94.2.1! eric 501: (int) ntohs(net->host->sock_addr.sin_port),
! 502: HTInetString(&net->host->sock_addr));
2.56 frystyk 503: return HT_OK;
504: break;
2.13 frystyk 505:
2.91 frystyk 506: case TCP_CHANNEL:
2.56 frystyk 507: case TCP_NEED_CONNECT:
508: case TCP_DNS:
509: case TCP_ERROR:
2.83 frystyk 510: if (PROT_TRACE) HTTrace("Socket...... Listen failed\n");
2.62 frystyk 511: HTRequest_addSystemError(net->request, ERR_FATAL, socerrno, NO, "HTDoListen");
2.94.2.1! eric 512: net->host->tcpstate = TCP_BEGIN;
2.56 frystyk 513: return HT_ERROR;
514: break;
515: }
2.38 frystyk 516: }
1.1 timbl 517: }
518:
2.83 frystyk 519: /* HTDoClose
520: ** ---------
521: ** Closes a file descriptor whatever means are available on the current
522: ** platform. If we have unix file descriptors then use this otherwise use
523: ** the ANSI C file descriptors
524: **
525: ** returns HT_ERROR Error has occured or interrupted
526: ** HT_OK if connected
527: ** HT_WOULD_BLOCK if operation would have blocked
528: */
2.87 frystyk 529: PUBLIC int HTDoClose (HTNet * net)
2.83 frystyk 530: {
531: int status = -1;
2.94.2.1! eric 532: if (net && HTNet_socket(net) != INVSOC) {
! 533: if (PROT_TRACE) HTTrace("HTDoClose... Close %d\n", HTNet_socket(net));
! 534: status = NETCLOSE(HTNet_socket(net));
! 535: /* HTEvent_unregister(HTNet_socket(net), (SockOps) FD_ALL); */
2.91 frystyk 536: HTNet_decreaseSocket();
2.94.2.1! eric 537: HTNet_setSocket(net, INVSOC);
2.91 frystyk 538:
539: /*
540: ** As we have a socket available we check for whether
541: ** we can start any pending requests. We do this by asking for
542: ** pending Host objects. If none then use the current object
543: */
544: HTHost_launchPending(net->host);
545:
546: } else
547: if (PROT_TRACE) HTTrace("HTDoClose... No pending requests\n");
2.83 frystyk 548: return status < 0 ? HT_ERROR : HT_OK;
549: }
2.91 frystyk 550:
2.83 frystyk 551:
Webmaster