Annotation of libwww/Library/src/HTTCP.c, revision 2.91
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.91 ! frystyk 6: ** @(#) $Id: HTTCP.c,v 2.90 1996/08/09 14:10:58 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.36 frystyk 28: /* VMS stuff */
29: #ifdef VMS
30: #ifndef MULTINET
31: #define FD_SETSIZE 32
32: #else /* Multinet */
33: #define FD_SETSIZE 256
34: #endif /* Multinet */
35: #endif /* VMS */
36:
2.13 frystyk 37: /* Macros and other defines */
2.24 frystyk 38: /* x seconds penalty on a multi-homed host if IP-address is down */
39: #define TCP_PENALTY 1200
40:
41: /* x seconds penalty on a multi-homed host if IP-address is timed out */
42: #define TCP_DELAY 600
43:
2.13 frystyk 44: /* ------------------------------------------------------------------------- */
2.19 frystyk 45: /* CONNECTION ESTABLISHMENT MANAGEMENT */
46: /* ------------------------------------------------------------------------- */
2.13 frystyk 47:
48: /* HTDoConnect()
49: **
50: ** Note: Any port indication in URL, e.g., as `host:port' overwrites
2.54 frystyk 51: ** the default port value.
2.13 frystyk 52: **
2.40 frystyk 53: ** returns HT_ERROR Error has occured or interrupted
54: ** HT_OK if connected
55: ** HT_WOULD_BLOCK if operation would have blocked
2.13 frystyk 56: */
2.54 frystyk 57: PUBLIC int HTDoConnect (HTNet * net, char * url, u_short default_port)
2.13 frystyk 58: {
59: int status;
2.88 frystyk 60: HTRequest * request = HTNet_request(net);
2.91 ! frystyk 61: char * hostname = HTHost_name(HTNet_host(net));
2.13 frystyk 62:
2.55 frystyk 63: /* Jump into the state machine */
64: while (1) {
65: switch (net->tcpstate) {
66: case TCP_BEGIN:
2.91 ! frystyk 67: {
! 68: char * proxy = HTRequest_proxy(request);
! 69: char * fullhost = NULL;
! 70: char * host = NULL;
! 71:
! 72: /* Check to see whether we connect directly or via a proxy */
! 73: fullhost = HTParse(proxy ? proxy : url, "", PARSE_HOST);
! 74:
! 75: /* If there's an @ then use the stuff after it as a hostname */
! 76: if (fullhost) {
! 77: char * at_sign;
! 78: if ((at_sign = strchr(fullhost, '@')) != NULL)
! 79: host = at_sign+1;
! 80: else
! 81: host = fullhost;
! 82: }
! 83: if (!host || !*host) {
! 84: HTRequest_addError(request, ERR_FATAL, NO, HTERR_NO_HOST,
! 85: NULL, 0, "HTDoConnect");
! 86: HT_FREE(fullhost);
! 87: return HT_ERROR;
! 88: } else {
! 89: char *port = strchr(host, ':');
! 90: SockA *sin = &net->sock_addr;
! 91: memset((void *) sin, '\0', sizeof(SockA));
! 92: if (PROT_TRACE)
! 93: HTTrace("HTDoConnect. Looking up `%s\'\n", host);
! 94: if (port) {
! 95: *port++ = '\0';
! 96: if (*port && isdigit(*port)) {
2.54 frystyk 97: #ifdef DECNET
2.91 ! frystyk 98: sin->sdn_family = AF_DECnet;
! 99: sin->sdn_objnum =
! 100: (unsigned char)(strtol(port, (char **) 0, 10));
2.55 frystyk 101: #else
2.91 ! frystyk 102: sin->sin_family = AF_INET;
! 103: sin->sin_port = htons(atol(port));
2.54 frystyk 104: #endif
2.91 ! frystyk 105: }
! 106: } else {
2.13 frystyk 107: #ifdef DECNET
2.91 ! frystyk 108: sin->sdn_family = AF_DECnet;
! 109: net->sock_addr.sdn_objnum = DNP_OBJ;
2.13 frystyk 110: #else /* Internet */
2.91 ! frystyk 111: sin->sin_family = AF_INET;
! 112: sin->sin_port = htons(default_port);
2.13 frystyk 113: #endif
2.91 ! frystyk 114: }
! 115: }
2.83 frystyk 116:
2.91 ! frystyk 117: /* Find information about this host */
! 118: if ((net->host = HTHost_new(host)) == NULL) {
! 119: if (PROT_TRACE)HTTrace("HTDoConnect. Can't get host info\n");
! 120: net->tcpstate = TCP_ERROR;
! 121: break;
! 122: }
! 123:
! 124: /*
! 125: ** Add the net object to the host object found above. If the
! 126: ** host is idle then we can start the request right away,
! 127: ** otherwise we must wait until it is free.
! 128: */
! 129: if ((status = HTHost_addNet(net->host, net)) == HT_PENDING)
! 130: if (PROT_TRACE) HTTrace("HTDoConnect. Pending...\n");
! 131: HT_FREE(fullhost);
! 132:
! 133: /*
! 134: ** If we are pending hen return here, otherwise go to next state
! 135: ** which is setting up a channel
! 136: */
! 137: net->tcpstate = TCP_CHANNEL;
! 138: if (status == HT_PENDING) return HT_PENDING;
! 139: }
! 140: break;
2.83 frystyk 141:
2.91 ! frystyk 142: case TCP_CHANNEL:
2.83 frystyk 143: /*
2.91 ! frystyk 144: ** The next state depends on whether we have a connection
! 145: ** or not - if so then we can jump directly to connect() to
! 146: ** test it - otherwise we must around DNS to get the name
! 147: ** resolved
2.83 frystyk 148: */
149: if ((net->channel = HTHost_channel(net->host)) != NULL) {
150: net->sockfd = HTChannel_socket(net->channel);
2.91 ! frystyk 151: HTChannel_upSemaphore(net->channel);
! 152: net->tcpstate = TCP_CONNECTED;
! 153: } else
! 154: net->tcpstate = TCP_DNS;
! 155: hostname = HTHost_name(HTNet_host(net));
2.55 frystyk 156: break;
157:
2.91 ! frystyk 158: case TCP_DNS:
! 159: if ((status = HTParseInet(net, hostname)) < 0) {
2.27 frystyk 160: if (PROT_TRACE)
2.91 ! frystyk 161: HTTrace("HTDoConnect. Can't locate `%s\'\n", hostname);
! 162: HTRequest_addError(request, ERR_FATAL, NO,
! 163: HTERR_NO_REMOTE_HOST,
! 164: (void *) hostname, strlen(hostname),
! 165: "HTDoConnect");
2.55 frystyk 166: net->tcpstate = TCP_ERROR;
2.27 frystyk 167: break;
2.55 frystyk 168: }
169: if (!net->retry && status > 1) /* If multiple homes */
170: net->retry = status;
2.83 frystyk 171: net->tcpstate = TCP_NEED_SOCKET;
2.55 frystyk 172: break;
173:
174: case TCP_NEED_SOCKET:
2.27 frystyk 175: #ifdef DECNET
2.36 frystyk 176: if ((net->sockfd=socket(AF_DECnet, SOCK_STREAM, 0))==INVSOC)
2.27 frystyk 177: #else
2.55 frystyk 178: if ((net->sockfd=socket(AF_INET, SOCK_STREAM,IPPROTO_TCP))==INVSOC)
2.27 frystyk 179: #endif
180: {
2.65 frystyk 181: HTRequest_addSystemError(request, ERR_FATAL, socerrno, NO, "socket");
2.55 frystyk 182: net->tcpstate = TCP_ERROR;
2.27 frystyk 183: break;
184: }
185: if (PROT_TRACE)
2.77 eric 186: HTTrace("HTDoConnect. Created socket %d\n",net->sockfd);
2.27 frystyk 187:
2.91 ! frystyk 188: /* Increase the number of sockets by one */
! 189: HTNet_increaseSocket();
! 190:
2.28 frystyk 191: /* If non-blocking protocol then change socket status
2.82 frystyk 192: ** I use fcntl() so that I can ask the status before I set it.
2.50 frystyk 193: ** See W. Richard Stevens (Advan. Prog. in UNIX environment, p.364)
194: ** Be CAREFULL with the old `O_NDELAY' - it will not work as read()
195: ** returns 0 when blocking and NOT -1. FNDELAY is ONLY for BSD and
196: ** does NOT work on SVR4 systems. O_NONBLOCK is POSIX.
197: */
2.74 frystyk 198: if (!net->preemptive) {
2.73 frystyk 199: #ifdef _WINSOCKAPI_
2.41 frystyk 200: { /* begin windows scope */
2.65 frystyk 201: HTRequest * rq = request;
2.41 frystyk 202: long levents = FD_READ | FD_WRITE | FD_ACCEPT |
203: FD_CONNECT | FD_CLOSE ;
204: int rv = 0 ;
205:
2.64 frystyk 206: #ifdef WWW_WIN_ASYNC
2.41 frystyk 207: /* N.B WSAAsyncSelect() turns on non-blocking I/O */
2.64 frystyk 208: rv = WSAAsyncSelect( net->sockfd, rq->hwnd,
209: rq->winMsg, levents);
210: if (rv == SOCKET_ERROR) {
211: status = -1 ;
212: if (PROT_TRACE)
2.77 eric 213: HTTrace("HTDoConnect. WSAAsyncSelect() fails: %d\n",
2.64 frystyk 214: WSAGetLastError());
215: } /* error returns */
216: #else
217: int enable = 1;
218: status = IOCTL(net->sockfd, FIONBIO, &enable);
219: #endif
2.41 frystyk 220: } /* end scope */
221: #else
222: #if defined(VMS)
2.36 frystyk 223: {
224: int enable = 1;
225: status = IOCTL(net->sockfd, FIONBIO, &enable);
226: }
227: #else
2.82 frystyk 228: if((status = fcntl(net->sockfd, F_GETFL, 0)) != -1) {
2.81 frystyk 229: #ifdef O_NONBLOCK
230: status |= O_NONBLOCK; /* POSIX */
231: #else
232: #ifdef F_NDELAY
233: status |= F_NDELAY; /* BSD */
234: #endif /* F_NDELAY */
235: #endif /* O_NONBLOCK */
2.82 frystyk 236: status = fcntl(net->sockfd, F_SETFL, status);
2.27 frystyk 237: }
2.41 frystyk 238: #endif /* VMS */
239: #endif /* WINDOW */
2.43 frystyk 240: if (PROT_TRACE) {
241: if (status == -1)
2.77 eric 242: HTTrace("HTDoConnect. Only blocking works\n");
2.43 frystyk 243: else
2.77 eric 244: HTTrace("HTDoConnect. Non-blocking socket\n");
2.43 frystyk 245: }
2.57 frystyk 246: } else if (PROT_TRACE)
2.77 eric 247: HTTrace("HTDoConnect. Blocking socket\n");
2.56 frystyk 248:
2.83 frystyk 249: /* Create a channel for this socket */
250: net->channel = HTChannel_new(net, YES);
251:
2.27 frystyk 252: /* If multi-homed host then start timer on connection */
2.55 frystyk 253: if (net->retry) net->connecttime = time(NULL);
2.65 frystyk 254:
255: /* Progress */
256: {
257: HTAlertCallback *cbf = HTAlert_find(HT_PROG_CONNECT);
2.91 ! frystyk 258: if (cbf) (*cbf)(request, HT_PROG_CONNECT, HT_MSG_NULL,
! 259: NULL, hostname, NULL);
2.65 frystyk 260: }
2.56 frystyk 261: net->tcpstate = TCP_NEED_CONNECT;
2.55 frystyk 262: break;
2.54 frystyk 263:
2.56 frystyk 264: case TCP_NEED_CONNECT:
2.55 frystyk 265: status = connect(net->sockfd, (struct sockaddr *) &net->sock_addr,
266: sizeof(net->sock_addr));
267: /*
268: * According to the Sun man page for connect:
269: * EINPROGRESS The socket is non-blocking and the con-
270: * nection cannot be completed immediately.
271: * It is possible to select(2) for comple-
272: * tion by selecting the socket for writ-
273: * ing.
274: * According to the Motorola SVR4 man page for connect:
275: * EAGAIN The socket is non-blocking and the con-
276: * nection cannot be completed immediately.
277: * It is possible to select for completion
278: * by selecting the socket for writing.
279: * However, this is only possible if the
280: * socket STREAMS module is the topmost
281: * module on the protocol stack with a
282: * write service procedure. This will be
283: * the normal case.
284: */
285: #ifdef _WINSOCKAPI_
286: if (status == SOCKET_ERROR)
287: #else
288: if (status < 0)
289: #endif
290: {
2.91 ! frystyk 291: #if defined(EAGAIN) && defined(EALREADY)
! 292: if (socerrno==EINPROGRESS ||
! 293: socerrno==EALREADY || socerrno==EAGAIN)
! 294: #else
2.89 frystyk 295: #ifdef EALREADY
296: if (socerrno==EINPROGRESS || socerrno==EALREADY)
297: #else
2.27 frystyk 298: #ifdef EAGAIN
2.55 frystyk 299: if (socerrno==EINPROGRESS || socerrno==EAGAIN)
2.89 frystyk 300: #else
2.55 frystyk 301: #ifdef _WINSOCKAPI_
302: if (socerrno==WSAEWOULDBLOCK)
2.40 frystyk 303: #else
2.55 frystyk 304: if (socerrno==EINPROGRESS)
305: #endif /* _WINSOCKAPI_ */
2.27 frystyk 306: #endif /* EAGAIN */
2.89 frystyk 307: #endif /* EALREADY */
2.91 ! frystyk 308: #endif /* EAGAIN && EALREADY */
2.55 frystyk 309: {
310: if (PROT_TRACE)
2.91 ! frystyk 311: HTTrace("HTDoConnect. WOULD BLOCK `%s'\n", hostname);
2.86 eric 312: HTEvent_register(net->sockfd, request, (SockOps)FD_CONNECT,
2.55 frystyk 313: net->cbf, net->priority);
314: return HT_WOULD_BLOCK;
315: }
316: if (socerrno == EISCONN) {
317: net->tcpstate = TCP_CONNECTED;
318: break;
319: }
2.58 frystyk 320: #ifdef _WINSOCKAPI_
2.59 frystyk 321: if (socerrno == WSAEBADF) /* We lost the socket */
2.58 frystyk 322: #else
323: if (socerrno == EBADF) /* We lost the socket */
324: #endif
325: {
2.55 frystyk 326: net->tcpstate = TCP_NEED_SOCKET;
327: break;
2.27 frystyk 328: }
2.55 frystyk 329: if (net->retry) {
330: net->connecttime -= time(NULL);
2.54 frystyk 331: /* Added EINVAL `invalid argument' as this is what I
332: get back from a non-blocking connect where I should
333: get `connection refused' on BSD. SVR4 gives SIG_PIPE */
2.58 frystyk 334: #if defined(__srv4__) || defined (_WINSOCKAPI_)
2.55 frystyk 335: if (socerrno==ECONNREFUSED || socerrno==ETIMEDOUT ||
336: socerrno==ENETUNREACH || socerrno==EHOSTUNREACH ||
337: socerrno==EHOSTDOWN)
338: #else
2.54 frystyk 339: if (socerrno==ECONNREFUSED || socerrno==ETIMEDOUT ||
340: socerrno==ENETUNREACH || socerrno==EHOSTUNREACH ||
341: socerrno==EHOSTDOWN || socerrno==EINVAL)
2.35 roeber 342: #endif
2.54 frystyk 343: net->connecttime += TCP_DELAY;
344: else
345: net->connecttime += TCP_PENALTY;
2.55 frystyk 346: HTDNS_updateWeigths(net->dns, net->home, net->connecttime);
347: }
348: net->tcpstate = TCP_ERROR;
349: } else
350: net->tcpstate = TCP_CONNECTED;
351: break;
352:
353: case TCP_CONNECTED:
2.86 eric 354: HTEvent_unregister(net->sockfd, (SockOps) FD_CONNECT);
2.55 frystyk 355: if (net->retry) {
356: net->connecttime -= time(NULL);
2.54 frystyk 357: HTDNS_updateWeigths(net->dns, net->home, net->connecttime);
2.27 frystyk 358: }
2.55 frystyk 359: net->retry = 0;
360: net->tcpstate = TCP_BEGIN;
361: return HT_OK;
362: break;
363:
2.56 frystyk 364: case TCP_NEED_BIND:
365: case TCP_NEED_LISTEN:
2.55 frystyk 366: case TCP_ERROR:
2.89 frystyk 367: if (PROT_TRACE)
368: HTTrace("HTDoConnect. Connect failed %d\n", socerrno);
2.55 frystyk 369: if (net->sockfd != INVSOC) {
2.86 eric 370: HTEvent_unregister(net->sockfd, (SockOps) FD_ALL);
2.55 frystyk 371: NETCLOSE(net->sockfd);
372: net->sockfd = INVSOC;
2.83 frystyk 373: if (HTHost_isPersistent(net->host)) { /* Inherited socket */
2.91 ! frystyk 374: HTHost_clearChannel(net->host, HT_ERROR);
2.55 frystyk 375: net->tcpstate = TCP_NEED_SOCKET;
376: break;
377: }
378: }
379:
380: /* Do we have more homes to try? */
381: if (--net->retry > 0) {
2.65 frystyk 382: HTRequest_addSystemError(request, ERR_NON_FATAL, socerrno, NO,
2.55 frystyk 383: "connect");
384: net->tcpstate = TCP_DNS;
2.24 frystyk 385: break;
386: }
2.65 frystyk 387: HTRequest_addSystemError(request, ERR_FATAL,socerrno,NO,"connect");
2.91 ! frystyk 388: HTDNS_delete(hostname);
2.54 frystyk 389: net->retry = 0;
2.55 frystyk 390: net->tcpstate = TCP_BEGIN;
391: return HT_ERROR;
392: break;
2.24 frystyk 393: }
2.55 frystyk 394: }
2.13 frystyk 395: }
396:
2.56 frystyk 397: /* HTDoAccept()
398: ** ------------
399: ** This function makes a non-blocking accept which will turn up as ready
400: ** read in the select.
401: ** Returns
402: ** HT_ERROR Error has occured or interrupted
403: ** HT_OK if connected
404: ** HT_WOULD_BLOCK if operation would have blocked
2.13 frystyk 405: */
2.88 frystyk 406: PUBLIC int HTDoAccept (HTNet * net, HTNet ** accepted)
2.13 frystyk 407: {
408: int status;
2.56 frystyk 409: int size = sizeof(net->sock_addr);
2.88 frystyk 410: HTRequest * request = HTNet_request(net);
411: if (!request || net->sockfd==INVSOC) {
2.77 eric 412: if (PROT_TRACE) HTTrace("HTDoAccept.. Invalid socket\n");
2.56 frystyk 413: return HT_ERROR;
2.13 frystyk 414: }
2.65 frystyk 415:
416: /* Progress report */
417: {
418: HTAlertCallback *cbf = HTAlert_find(HT_PROG_ACCEPT);
419: if (cbf) (*cbf)(request, HT_PROG_ACCEPT, HT_MSG_NULL,NULL, NULL, NULL);
420: }
2.56 frystyk 421: status = accept(net->sockfd, (struct sockaddr *) &net->sock_addr, &size);
422: #ifdef _WINSOCKAPI_
423: if (status == SOCKET_ERROR)
424: #else
425: if (status < 0)
426: #endif
2.23 duns 427: {
2.89 frystyk 428: #ifdef EALREADY
429: if (socerrno==EINPROGRESS || socerrno==EALREADY)
430: #else
2.56 frystyk 431: #ifdef EAGAIN
2.89 frystyk 432: if (socerrno==EINPROGRESS || socerrno==EAGAIN)
433: #else
2.56 frystyk 434: #ifdef _WINSOCKAPI_
2.89 frystyk 435: if (socerrno==WSAEWOULDBLOCK)
2.56 frystyk 436: #else
2.89 frystyk 437: if (socerrno==EINPROGRESS)
2.56 frystyk 438: #endif /* _WINSOCKAPI_ */
439: #endif /* EAGAIN */
2.89 frystyk 440: #endif /* EALREADY */
2.56 frystyk 441: {
442: if (PROT_TRACE)
2.77 eric 443: HTTrace("HTDoAccept.. WOULD BLOCK %d\n", net->sockfd);
2.86 eric 444: HTEvent_register(net->sockfd, request, (SockOps) FD_ACCEPT,
2.56 frystyk 445: net->cbf, net->priority);
446: return HT_WOULD_BLOCK;
447: }
2.65 frystyk 448: HTRequest_addSystemError(request, ERR_WARN, socerrno, YES, "accept");
2.77 eric 449: if (PROT_TRACE) HTTrace("HTDoAccept.. Accept failed\n");
2.56 frystyk 450: return HT_ERROR;
2.23 duns 451: }
2.71 frystyk 452:
2.88 frystyk 453: if (PROT_TRACE) HTTrace("Accepted.... socket %d\n", status);
454:
455: /*
456: ** If accepted is the same as the net obejct then reuse it, else create
457: ** a new object and leave the original alone
458: */
459: if (*accepted == net)
460: HTDoClose(net);
461: else
462: *accepted = HTNet_dup(net);
463: (*accepted)->sockfd = status;
2.83 frystyk 464:
465: /* Create a channel for the new socket */
2.88 frystyk 466: (*accepted)->channel = HTChannel_new(*accepted, NO);
2.83 frystyk 467:
2.56 frystyk 468: return HT_OK;
469: }
470:
471:
472: /* HTDoListen
473: ** ----------
474: ** Listens on the specified port. 0 means that we chose it here
475: ** If master==INVSOC then we listen on all local interfaces (using a
476: ** wildcard). If !INVSOC then use this as the local interface
477: ** returns HT_ERROR Error has occured or interrupted
478: ** HT_OK if connected
479: */
2.67 frystyk 480: PUBLIC int HTDoListen (HTNet * net, u_short port, SOCKET master, int backlog)
2.56 frystyk 481: {
482: int status;
483:
484: /* Jump into the state machine */
485: while (1) {
486: switch (net->tcpstate) {
487: case TCP_BEGIN:
488: {
489: SockA *sin = &net->sock_addr;
490: memset((void *) sin, '\0', sizeof(SockA));
491: #ifdef DECNET
492: sin->sdn_family = AF_DECnet;
493: sin->sdn_objnum = port;
2.36 frystyk 494: #else
2.56 frystyk 495: sin->sin_family = AF_INET;
496: if (master != INVSOC) {
497: int len = sizeof(SockA);
498: if (getsockname(master, (struct sockaddr *) sin, &len)<0) {
2.65 frystyk 499: HTRequest_addSystemError(net->request, ERR_FATAL,
500: socerrno, NO, "getsockname");
2.56 frystyk 501: net->tcpstate = TCP_ERROR;
502: break;
503: }
504: } else
505: sin->sin_addr.s_addr = INADDR_ANY;
506: sin->sin_port = htons(port);
507: #endif
508: }
509: if (PROT_TRACE)
2.83 frystyk 510: HTTrace("Socket...... Listen on port %d\n", port);
2.56 frystyk 511: net->tcpstate = TCP_NEED_SOCKET;
512: break;
513:
514: case TCP_NEED_SOCKET:
515: #ifdef DECNET
516: if ((net->sockfd=socket(AF_DECnet, SOCK_STREAM, 0))==INVSOC)
517: #else
518: if ((net->sockfd=socket(AF_INET, SOCK_STREAM,IPPROTO_TCP))==INVSOC)
519: #endif
520: {
2.65 frystyk 521: HTRequest_addSystemError(net->request, ERR_FATAL, socerrno,
522: NO, "socket");
2.56 frystyk 523: net->tcpstate = TCP_ERROR;
524: break;
525: }
526: if (PROT_TRACE)
2.83 frystyk 527: HTTrace("Socket...... Created %d\n", net->sockfd);
2.56 frystyk 528:
2.91 ! frystyk 529: /* Increase the number of sockets by one */
! 530: HTNet_increaseSocket();
! 531:
2.56 frystyk 532: /* If non-blocking protocol then change socket status
2.82 frystyk 533: ** I use fcntl() so that I can ask the status before I set it.
2.56 frystyk 534: ** See W. Richard Stevens (Advan. Prog. in UNIX environment, p.364)
535: ** Be CAREFULL with the old `O_NDELAY' - it will not work as read()
536: ** returns 0 when blocking and NOT -1. FNDELAY is ONLY for BSD and
537: ** does NOT work on SVR4 systems. O_NONBLOCK is POSIX.
538: */
2.74 frystyk 539: if (!net->preemptive) {
2.73 frystyk 540: #ifdef _WINSOCKAPI_
2.56 frystyk 541: { /* begin windows scope */
542: long levents = FD_READ | FD_WRITE | FD_ACCEPT |
543: FD_CONNECT | FD_CLOSE ;
544: int rv = 0 ;
545:
2.64 frystyk 546: #ifdef WWW_WIN_ASYNC
2.56 frystyk 547: /* N.B WSAAsyncSelect() turns on non-blocking I/O */
2.69 frystyk 548: rv = WSAAsyncSelect(net->sockfd, net->request->hwnd,
2.66 frystyk 549: net->request->winMsg, levents);
2.64 frystyk 550: if (rv == SOCKET_ERROR) {
551: status = -1 ;
552: if (PROT_TRACE)
2.83 frystyk 553: HTTrace("Socket...... WSAAsyncSelect() fails: %d\n",
2.64 frystyk 554: WSAGetLastError());
2.56 frystyk 555: } /* error returns */
2.64 frystyk 556: #else
557: int enable = 1 ;
558: status = IOCTL(net->sockfd, FIONBIO, &enable);
559: #endif
2.56 frystyk 560: } /* end scope */
561: #else
562: #if defined(VMS)
563: {
564: int enable = 1;
565: status = IOCTL(net->sockfd, FIONBIO, &enable);
566: }
567: #else
2.82 frystyk 568: if((status = fcntl(net->sockfd, F_GETFL, 0)) != -1) {
2.81 frystyk 569: #ifdef O_NONBLOCK
2.56 frystyk 570: status |= O_NONBLOCK; /* POSIX */
2.81 frystyk 571: #else
572: #ifdef F_NDELAY
573: status |= F_NDELAY; /* BSD */
574: #endif /* F_NDELAY */
575: #endif /* O_NONBLOCK */
2.82 frystyk 576: status = fcntl(net->sockfd, F_SETFL, status);
2.56 frystyk 577: }
578: #endif /* VMS */
579: #endif /* WINDOW */
580: if (PROT_TRACE) {
581: if (status == -1)
2.83 frystyk 582: HTTrace("Sockrt...... Blocking socket\n");
2.56 frystyk 583: else
2.83 frystyk 584: HTTrace("Socket...... Non-blocking socket\n");
2.56 frystyk 585: }
586: }
587: net->tcpstate = TCP_NEED_BIND;
588: break;
589:
590: case TCP_NEED_BIND:
591: status = bind(net->sockfd, (struct sockaddr *) &net->sock_addr,
592: sizeof(net->sock_addr));
593: #ifdef _WINSOCKAPI_
594: if (status == SOCKET_ERROR)
595: #else
596: if (status < 0)
597: #endif
598: {
599: if (PROT_TRACE)
2.83 frystyk 600: HTTrace("Socket...... Bind failed %d\n", socerrno);
2.56 frystyk 601: net->tcpstate = TCP_ERROR;
602: } else
603: net->tcpstate = TCP_NEED_LISTEN;
604: break;
605:
606: case TCP_NEED_LISTEN:
2.67 frystyk 607: status = listen(net->sockfd, backlog);
2.56 frystyk 608: #ifdef _WINSOCKAPI_
609: if (status == SOCKET_ERROR)
610: #else
611: if (status < 0)
2.36 frystyk 612: #endif
2.56 frystyk 613: net->tcpstate = TCP_ERROR;
614: else
615: net->tcpstate = TCP_CONNECTED;
616: break;
617:
618: case TCP_CONNECTED:
619: net->tcpstate = TCP_BEGIN;
620: if (PROT_TRACE)
2.83 frystyk 621: HTTrace("Socket...... Bind and listen on port %d %s\n",
2.56 frystyk 622: (int) ntohs(net->sock_addr.sin_port),
623: HTInetString(&net->sock_addr));
624: return HT_OK;
625: break;
2.13 frystyk 626:
2.91 ! frystyk 627: case TCP_CHANNEL:
2.56 frystyk 628: case TCP_NEED_CONNECT:
629: case TCP_DNS:
630: case TCP_ERROR:
2.83 frystyk 631: if (PROT_TRACE) HTTrace("Socket...... Listen failed\n");
2.62 frystyk 632: HTRequest_addSystemError(net->request, ERR_FATAL, socerrno, NO, "HTDoListen");
2.56 frystyk 633: net->tcpstate = TCP_BEGIN;
634: return HT_ERROR;
635: break;
636: }
2.38 frystyk 637: }
1.1 timbl 638: }
639:
2.83 frystyk 640: /* HTDoClose
641: ** ---------
642: ** Closes a file descriptor whatever means are available on the current
643: ** platform. If we have unix file descriptors then use this otherwise use
644: ** the ANSI C file descriptors
645: **
646: ** returns HT_ERROR Error has occured or interrupted
647: ** HT_OK if connected
648: ** HT_WOULD_BLOCK if operation would have blocked
649: */
2.87 frystyk 650: PUBLIC int HTDoClose (HTNet * net)
2.83 frystyk 651: {
652: int status = -1;
653: if (net && net->sockfd != INVSOC) {
2.91 ! frystyk 654: if (PROT_TRACE) HTTrace("HTDoClose... Close %d\n", net->sockfd);
2.83 frystyk 655: status = NETCLOSE(net->sockfd);
2.86 eric 656: HTEvent_unregister(net->sockfd, (SockOps) FD_ALL);
2.91 ! frystyk 657: HTNet_decreaseSocket();
2.83 frystyk 658: net->sockfd = INVSOC;
2.91 ! frystyk 659:
! 660: /*
! 661: ** As we have a socket available we check for whether
! 662: ** we can start any pending requests. We do this by asking for
! 663: ** pending Host objects. If none then use the current object
! 664: */
! 665: HTHost_launchPending(net->host);
! 666:
! 667: } else
! 668: if (PROT_TRACE) HTTrace("HTDoClose... No pending requests\n");
2.83 frystyk 669: return status < 0 ? HT_ERROR : HT_OK;
670: }
2.91 ! frystyk 671:
2.83 frystyk 672:
Webmaster