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