Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 1 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 1 /*****************************************************************************/ 2 /* 3 Net.c 4 5 The networking essentials are based on DEC TCP/IP Services for OpenVMS (aka 6 UCX). The QIO interface was obviously chosen because of its asynchronous, 7 non-blocking capabilities. Although some functionalilty could have been 8 implemented using the BSD sockets abstraction and only the asynchronous I/O 9 done using the QIO I opted for working out the QIOs. It wasn't too difficult 10 and avoids the (slight) extra overhead of the sockets layer. 11 12 With resource wait explicitly enabled all sys$qio()s should wait until 13 resources become available. The only execption is ASTLM, a fundamental 14 requirement for this server. If SS$_EXQUOTA is returned from a sys$qio() (i.e. 15 without wait for completion, and therefore depending on AST delivery) then 16 EXIT THE SERVER with error status! 17 18 The 'ServiceStruct' structure has two groups of fields and performs two basic 19 roles. First, it provides a linked list which can be traversed to determine 20 from the destination IP address of a request which host was specified in a 21 (multi-homed) request. Second, for each unique port specified for the same 22 server the client components of the structure are used for the accept()ing of 23 requests. Note that there may be more 'service' structures in the list than 24 actual sockets created (and client components used) because only one is 25 allocated against a given port even though the services may specify multiple 26 host names using that port. 27 28 The server identity is derived from the 'ServerHostName' (gethostname()) name 29 and the 'ServerPort' (which is the first port specified as a service, or the 30 port specified in the configuration or /PORT= qualifier). 31 32 33 WASD_NET_TEST_BREAK 34 ------------------- 35 See logical name WASD_NET_TEST_BREAK and NetTestSupervisor() for assistance 36 with testing server behaviour under less-than ideal circumstances. 37 38 39 VERSION HISTORY 40 --------------- 41 29-APR-2026 MGD NetAcceptProcess() too busy disconnect 20% idle connections 42 14-SEP-2025 MGD bugfix; do not suppress output for HTTP/0.9 (especially HEAD) 43 09-OCT-2022 MGD NetListFor() include client IP port, rework truncation 44 15-AUG-2022 MGD bugfix; NetAbortSocket() deliver any outstanding read and/or 45 write ASTs (especially for HTTP/2 streams) 46 06-MAR-2022 MGD NetWrite() drop any and all HTTP status 418 (e.g. DCL script) 47 11-SEP-2021 MGD NetControl() CONTROL_NET_PURGE_HTTP1 and .._HTTP2 48 27-APR-2021 MGD BSD 4.4 sockaddr.. IO$M_EXTEND to $QIO 49 20-NOV-2020 MGD NetWriteChunked() 65kB limit removed 50 30-JAN-2020 MGD NetIoWriteStatus() when request terminated by timeout 51 19-DEC-2019 MGD bugfix; NetCreateService() only SesolaInitService() once 52 bugfix; use NetIoWriteStatus() to maintain NETIO ASTs 53 07-APR-2018 MGD NetWriteBuffered() now writes before reset if necessary 54 NetWriteStrDsc() can now write synchronously 55 14-NOV-2017 MGD NetResponseHeaderAst() fudge status as necessary 56 19-MAY-2016 MGD bugfix; NetWrite() response header write error handling 57 11-AUG-2015 MGD restructure of network I/O abstractions Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 2 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 58 09-JUN-2014 MGD accounting for network blocks 59 07-JUN-2014 MGD NetCreateService() check bind address string instead of 60 address to allow binding primary to 0.0.0.0 (INADDR_ANY) 61 15-OCT-2011 MGD NetPurge() becomes NetControl() with expanded capability 62 12-FEB-2011 MGD NetCloseSocket() using WatchFilterClientService() so 63 that final close can be noted if required 64 30-OCT-2010 MGD NetCreateService() set primary service after address 65 23-JAN-2010 MGD NetPeek() now requires buffer arguments 66 14-NOV-2009 MGD NetPeek() non-consuming read 67 bugfix; NetHostNameLookup() IP address zeroed 68 13-OCT-2009 MGD NetHostNameLookup() now 'resolves' IP address 'host names' 69 23-SEP-2009 MGD bugfix; NetWriteStrDsc() flush all full descriptors 70 12-SEP-2009 MGD bugfix; NetWriteGzip() ensure buffer size <= 65535 71 31-JUL-2009 MGD NetCreateService() use primary if service IP addr reset 72 26-MAY-2009 MGD NetHostNameLookup() retry attempts from zero to two 73 26-APR-2008 MGD bugfix; NetRead() redact into DataPtr *not* into 74 rqNet.ReadBufferPtr (which works until subsequent read :-) 75 25-NOV-2007 MGD NetRead() redact buffer processing 76 04-OCT-2007 MGD call TcpIpSocketBufferSize() 77 10-JUN-2007 MGD use STR_DSC 78 26-OCT-2006 MGD bugfix; NetAcceptProcess() and NetDirectResponse() 79 should issue 503 for 'too busy', not 502 80 12-SEP-2006 MGD bugfix; NetAccept(), NetAcceptAst(), NetAcceptProcess() 81 nasty problem where multihomed servers 'svptr' confusion 82 (due to the multihome pointer manipulation) could result 83 in an attempted re-queue of an accept on a service that 84 did not correspond to the original accept AST delivery 85 with the result that no accept ended up being queued 86 22-AUG-2006 MGD maintenance; there seem to have been some changes in the 87 underlying TCP/IP Services handling of shared sockets 88 NetAcceptAst() if [DclGatewayBg] set socket share on client 89 NetClientSocketCcl() to control BG device carriage-control 90 (to parallel the APACHE$SET_CCL.EXE functionality) 91 08-AUG-2006 MGD NetWrite() accomodate 304 (not modified) 92 15-JUL-2006 MGD NetSuspend() and NetResume() to allow halt and resume 93 request processing 94 NetPassive() and NetActive() to allow non-supervisor 95 instances to be made quiescent 96 NetPurge() to break idle (and in-progress) connections 97 01-APR-2006 MGD no kidding; NetRead() cast AST routine and RequestGet 98 using (char*) to prevent %CC-E-NOEQUALITY compile-time 99 error under VAX VMS V7.3 and DECC V6.4 100 30-AUG-2005 JPP bugfix; raw proxy tunnelling requires a contrived connect 101 request in NetRead() to initiate an AST to RequestGet() 102 10-JUN-2005 MGD make EXQUOTA (particularly ASTLM) a little more obvious, 103 handle NetAccept() EXQUOTA via NetAcceptSupervisor() 104 26-MAY-2005 MGD bugfix; multi-instance socket device name handling 105 19-APR-2005 MGD revised multihoming so that the client specified IP address 106 of a accept()ed connection is used to identify the service 107 (this allows easier isolation of SSL certificates, etc.) 108 16-MAR-2005 JPP allow client-side GZIPing of proxied responses 109 28-JAN-2005 MGD bugfix; aarghh! NetWriteGzip()/NetWriteGzipAst() 110 20-JAN-2005 MGD bugfix; NetWriteChunked() ensure an empty body is 111 terminated with a chunk of zero 112 13-JAN-2005 MGD bugfix; NetWrite() distinguish between "empty" data and 113 end-of-stream (inducing occasional ZLIB buffer errors) 114 10-JAN-2005 MGD NetWriteGzip() abandon using argument counts to determine Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 3 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 115 AST usage or direct call, use NetWriteGzipAst() instead 116 08-JAN-2005 MGD minor mod to handle GZIP buffer flush 117 21-DEC-2004 MGD bugfix; NetWriteGzip() AST no remaining data length 118 16-DEC-2004 MGD NetWriteChunked() and NetWriteRawP5() 119 15-NOV-2004 MGD bugfix; handling of GZIP encoding (with GZIP.C) 120 (thanks to jpp@esme.fr for isolating this during BETA) 121 16-OCT-2004 MGD network write changes for GZIP encoding 122 10-APR-2004 MGD significant modifications to support IPv6 123 18-FEB-2004 MGD NetWriteBufferedSizeInit() 124 30-DEC-2003 MGD NetTcpIpAgentInfo() mods for IA64 125 07-JUL-2003 MGD support response header none/append mappings, 126 cache loading from network output 127 26-FEB-2003 MGD disable 'NetMultiHome' (should not be required 128 for modern virtual service processing) 129 15-JUL-2002 MGD all 'xray' functionality now performed in RequestScript() 130 02-JUN-2002 MGD rework NetCreateService() to allow SS$_IVADDR (invalid 131 media address) service to be supported by using INADDR_ANY 132 25-APR-2002 MGD NetAcceptSupervisor() and associated NOIOCHAN redress 133 31-MAR-2002 MGD integrate client connection data into request structure, 134 make client host name lookup asynchronous 135 22-JAN-2002 MGD bugfix; NetAcceptAst() deassign channel when connection 136 dropped during accept processing (jpp@esme.fr) 137 18-JAN-2002 MGD allow ->BindIpAddressString to specify 0.0.0.0 (INADDR_ANY) 138 29-SEP-2001 MGD service creation now supports multiple channels to the 139 one listening socket device for multiple per-node instances 140 04-AUG-2001 MGD support module WATCHing, 141 CONNECT method connection cancellation is normal behaviour 142 04-JUL-2001 MGD bugfix; (completed from 02-JUN, this time for SSL services), 143 also change behaviour, if a bind to INADDR_ANY fails attempt 144 to bind to the resolved host name address 145 02-JUN-2001 MGD bugfix; port check when IP address explicitly supplied 146 18-APR-2001 MGD rqNet.WriteErrorCount and rqNet.ReadErrorCount, 147 introduce NetTcpIpAgentInfo() (adapted from WATCH.C), 148 bugfix; NetThisVirtualService() 149 13-FEB-2001 MGD ntohs() on client port 150 22-NOV-2000 MGD rework service creation 151 17-OCT-2000 MGD modify SSL initialization so that "sharing" conditions 152 (same port on same IP address) are more easily identified 153 08-AUG-2000 MGD client sockets C_SHARE for direct script output to BG: 154 17-JUN-2000 MGD modifications for SERVICE.C requirements 155 10-MAY-2000 MGD per-service session tracking, 156 per-service listen queue backlog (for Compaq TCP/IP 5.0ff) 157 29-APR-2000 MGD proxy authorization 158 10-NOV-1999 MGD add IO$_NOWAIT to NetWriteDirect() 159 25-OCT-1999 MGD remove NETLIB support 160 10-OCT-1999 MGD allow virtual services more latitude, 161 check for request supervisor request timeout, 162 add FULL_DUPLEX_CLOSE, 163 workaround TCPWARE 5.3-3 behaviour (Laishev@SMTP.DeltaTel.RU) 164 18-AUG-1999 MGD bugfix; parsing certificate/key from service 165 11-JUN-1999 MGD bugfix; NetTooBusy() sys$fao() charset, 166 bugfix; NetDummyReadAst() UCX IOsb by reference 167 26-MAY-1999 MGD bugfix; NetShutdownSocket() AST handling 168 04-APR-1999 MGD provide HTTP/0.9 header absorbtion (finally!) 169 15-JAN-1999 MGD changed AST delivery algorithm 170 07-NOV-1998 MGD WATCH facility 171 24-OCT-1998 MGD allow SSL certificate to be specified per-service Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 4 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 172 08-APR-1998 MGD allow legitimate connects to be CANCELed in NetAcceptAst() 173 19-JAN-1998 MGD redesigned NetWriteBuffered() 174 27-NOV-1997 MGD hmmm, rationalized AST processing by making network 175 writes always deliver an AST (implicit or explicit) 176 (causing ACCVIOs for the last couple of versions) 177 25-OCT-1997 MGD changes to MsgFor() function 178 06-SEP-1997 MGD multi-homed hosts and multi-port services 179 30-AUG-1997 MGD bugfix; get server host name before starting logging 180 (woops, problem introduced with NETLIB) 181 09-AUG-1997 MGD message database 182 23-JUL-1997 MGD HTTPD v4.3, MultiNet dropped, using the NETLIB Library 183 01-FEB-1997 MGD HTTPd version 4 184 27-SEP-1996 MGD add dummy read for early error reporting 185 12-APR-1996 MGD observed Multinet disconnection/zero-byte behaviour 186 (request now aborts if Multinet returns zero bytes) 187 03-JAN-1996 MGD support for both DEC TCP/IP Services and TGV MultiNet 188 01-DEC-1995 MGD NetWriteBuffered() for improving network I/O 189 20-DEC-1994 MGD multi-threaded version 190 20-JUN-1994 MGD single-threaded version 191 */ 192 /*****************************************************************************/ 193 X 194 #ifdef WASD_VMS_V7 X 195 #undef _VMS__V6__SOURCE X 196 #define _VMS__V6__SOURCE X 197 #undef __VMS_VER X 198 #define __VMS_VER 70000000 X 199 #undef __CRTL_VER X 200 #define __CRTL_VER 70000000 X 201 #endif 202 203 /* standard C header files */ 204 #include 1112 #include 1319 #include 1491 #include 2589 #include 3060 3061 /* VMS related header files */ 3062 #include 3178 #include 4235 #include 4772 #include 6654 #include 6799 #include 7143 #include 7267 #include 9470 #include 9669 #include 10529 10530 /* application-related header files */ 10531 #include "wasd.h" 63379 63380 #define WASD_MODULE "NET" 63381 63382 #define NET_TEST 0 63383 Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 5 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 63384 /******************/ 63385 /* global storage */ 63386 /******************/ 63387 63388 BOOL NetAcceptAgent, 63389 NetAcceptExQuota, 63390 NetAcceptFailure, 63391 NetAcceptNoIoChan, 63392 NetConnectSuspend, 63393 NetInstancePassive, 63394 NetMultiHome; 63395 63396 int ConnectCountTotal, 63397 NetAcceptBytLmRequired, 63398 NetConcurrentMax, 63399 NetConcurrentProcessMax, 63400 NetCurrentHttp1Persistent, 63401 NetListenBytLmRequired, 63402 NetReadBufferSize, 63403 NetRequestMax, 63404 OutputBufferSize, 63405 OutputFileBufferSize, 63406 ServerHostNameLength; 63407 63408 ulong NetCurrentConnected [HTTPN], 63409 NetCurrentProcessing [HTTPN]; 63410 63411 char ServerHostName [TCPIP_HOSTNAME_MAX+1], 63412 ServerHostPort [TCPIP_HOSTNAME_MAX+1+8]; 63413 int ServerHostPortSize = sizeof(ServerHostPort); 63414 63415 static char NetAcceptAgentScript [] = "/cgiplus-bin/accagent"; 63416 63417 static char ProblemAcceptAgent [] = "Problem initiating accept agent"; 63418 63419 #define NET_AGENT_ACTIVE_MAX 8 63420 #define NET_AGENT_BUSY_MAX 100 63421 static int NetAgentActiveCount, 63422 NetAgentActiveMax = NET_AGENT_ACTIVE_MAX, 63423 NetAgentBusyMax = NET_AGENT_BUSY_MAX, 63424 NetAgentBusyCount, 63425 NetAgentBusyLimit; 63426 63427 /********************/ 63428 /* external storage */ 63429 /********************/ 63430 X 63431 #ifdef DBUG X 63432 extern BOOL Debug; X 63433 #else 63434 #define Debug 0 63435 #endif 63436 63437 extern BOOL ControlExitRequested, 63438 HttpdServerStartup, 63439 InstanceNodeSupervisor, 63440 ProtocolHttpsAvailable, Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 6 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 63441 ProtocolHttpsConfigured, 63442 TcpIpv6Configured; 63443 63444 extern int ConfigDnsLookupRetryCount, 63445 EfnWait, 63446 EfnNoWait, 63447 HttpdTickSecond, 63448 InstanceNodeConfig, 63449 InstanceNodeCurrent, 63450 InstanceNumber, 63451 InstanceStatusRequestCount, 63452 OpcomMessages, 63453 ServerPort, 63454 TcpIpSendBufferSize, 63455 TcpIpSocketKeepAlive, 63456 TcpIpReceiveBufferSize, 63457 WebSockCurrent; 63458 63459 extern const int64 Delta05Sec, 63460 Delta100mSec; 63461 63462 extern char CliLogFileName[], 63463 ControlBuffer[], 63464 ErrorSanityCheck[], 63465 HttpdName[], 63466 HttpdVersion[]; 63467 63468 extern struct dsc$descriptor TcpIpDeviceDsc; 63469 63470 extern ACCOUNTING_STRUCT *AccountingPtr; 63471 extern CONFIG_STRUCT Config; 63472 extern HTTPD_GBLSEC *HttpdGblSecPtr; 63473 extern MSG_STRUCT Msgs; 63474 extern LIST_HEAD Http2List, 63475 RequestList, 63476 ServiceList; 63477 extern TCP_SOCKET_ITEM TcpIpSocket4, 63478 TcpIpSocket6; 63479 extern VMS_ITEM_LIST2 TcpIpFullDuplexCloseOption; 63480 extern VMS_ITEM_LIST2 TcpIpSocketCclOptionOn; 63481 extern VMS_ITEM_LIST2 TcpIpSocketCclOptionOff; 63482 extern VMS_ITEM_LIST2 TcpIpSocketKeepAliveOption; 63483 extern VMS_ITEM_LIST2 TcpIpSocketReuseAddrOption; 63484 extern VMS_ITEM_LIST2 TcpIpSocketShareOption; 63485 extern WATCH_STRUCT Watch; 63486 63487 /*****************************************************************************/ 63488 /* 63489 Get local host (server) name. 63490 */ 63491 63492 NetGetServerHostName () 63493 1 63494 { 1 63495 int status; 1 63496 unsigned short Length; 1 63497 char *cptr; Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 7 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 1 63498 1 63499 /*********/ 1 63500 /* begin */ 1 63501 /*********/ 1 63502 1 63503 if (WATCH_MODULE(WATCH_MOD_NET)) 1 63504 WatchThis (WATCHALL, WATCH_MOD_NET, "NetGetServerHostName()"); 1 63505 1 63506 if (gethostname (ServerHostName, sizeof(ServerHostName)) != 0) 1 63507 ErrorExitVmsStatus (vaxc$errno, "resolving server hostname", FI_LI); 1 63508 1 63509 /* looks better if its all in lower case (host name is sometimes upper) */ 1 63510 for (cptr = ServerHostName; *cptr; cptr++) *cptr = to_lower(*cptr); 1 63511 ServerHostNameLength = cptr - ServerHostName; 1 63512 1 63513 if (!ServerHostNameLength) 1 63514 ErrorExitVmsStatus (SS$_BUGCHECK, "could not determine local host name", 1 63515 FI_LI); 1 63516 } 63517 63518 /*****************************************************************************/ 63519 /* 63520 It is only necessary to create one socket for each port port on the same 63521 server, even if that port is specified against a different (multi-home) host 63522 name because the accept()ing socket can be interrogated to determine which 63523 host had been specified. Then in a infinite loop accept connections from 63524 clients. 63525 63526 Binding services to sockets and allied topics ... 63527 63528 A service (host name and IP address) binds to INADDR_ANY and a port (say 80). 63529 This allows the socket to accept connections for any address supported by the 63530 interface, and on that port. 63531 63532 Subsequent services (different host name but same IP address, an alias, CNAME 63533 records?) using the same port does not (indeed could not) bind again (to 63534 INADDR_ANY). It just becomes part of the the existing bound socket's 63535 environment inside the server. Using the HTTP "Host:" field virtual services 63536 are supported (once the HTTP request header is parsed). Different ports are of 63537 course bound to different sockets. 63538 63539 Some further subsequent service, this time with a different IP address (i.e. 63540 implying there is a multi-homed system) wishes to establish a service on a 63541 previously used port (say 80). First it attempts a bind to INADDR_ANY, which 63542 fails because the port is already bound to that (mind you it may not be, in 63543 which case it won't fail). So the server then retries the bind with it's IP 63544 address, which we'll presume is OK. 63545 63546 Another service, with a third IP address tries to bind to INADDR_ANY on port 63547 80, which fails, but it then successfully is bound using it's (so far) unique 63548 address. 63549 63550 So far, no real site admin intervention. It seems to simply and easily support 63551 the potential requirements of SSL services, as well as multi-homed standard 63552 services. All "real" multi-homed services (with autonomous IP addresses) are 63553 always bind against their unqiue address. "Virtual" services using those 63554 addresses only are ever bound once for each port, subsequent services being Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 8 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 63555 software contrivances. The [ServiceIpAddress] is still available to 63556 "hard-wire" a service name to a particular IP address, but the above "cascade" 63557 of binds tends to mean it should be far less important. 63558 63559 Only when a service with an IP address that is not supported by the interface 63560 is attempted to be bound does it fail (with an invalid media address IIRC). 63561 */ 63562 63563 NetCreateService () 63564 1 63565 { 1 63566 int cnt, qiofun, status, 1 63567 BytLmAfter, 1 63568 BytLmBefore; 1 63569 ushort IpPort, 1 63570 Length, 1 63571 ServerChannel; 1 63572 char *cptr, 1 63573 *ProtocolPtr, 1 63574 *SocketDevNamePtr; 1 63575 IPADDRESS IpAddress, 1 63576 PrimaryIpAddress; 1 63577 SOCKADDRIN *sin4ptr; 1 63578 SOCKADDRIN6 *sin6ptr; 1 63579 SERVICE_STRUCT *svptr, *tsvptr; 1 63580 TCP_SOCKET_ITEM *TcpSocketPtr; 1 63581 VMS_ITEM_LIST2 SocketNameItem; 1 63582 VMS_ITEM_LIST2 *il2ptr; 1 63583 $DESCRIPTOR (BgDevNameDsc, ""); 1 63584 1 63585 /*********/ 1 63586 /* begin */ 1 63587 /*********/ 1 63588 1 63589 if (WATCH_MODULE(WATCH_MOD_NET)) 1 63590 WatchThis (WATCHALL, WATCH_MOD_NET, 1 63591 "NetCreateService() !UL", ServiceList.EntryCount); 1 63592 1 63593 InstanceMutexLock (INSTANCE_MUTEX_HTTPD); 1 63594 NetConnectSuspend = HttpdGblSecPtr->ConnectSuspend; 1 63595 NetInstancePassive = HttpdGblSecPtr->InstancePassive; 1 63596 InstanceMutexUnLock (INSTANCE_MUTEX_HTTPD); 1 63597 1 63598 IPADDRESS_ZERO (&PrimaryIpAddress); 1 63599 1 63600 /********************************/ 1 63601 /* process the list of services */ 1 63602 /********************************/ 1 63603 1 63604 /* block other instances from concurrently attempting to create services */ 1 63605 if (VMSnok (status = InstanceLock (INSTANCE_NODE_SOCKET))) 1 63606 ErrorExitVmsStatus (status, "InstanceLock()", FI_LI); 1 63607 1 63608 LIST_ITERATE (svptr, &ServiceList) 2 63609 { 2 63610 FaoToStdout ("%HTTPD-I-SERVICE, !AZ//!AZ\n", 2 63611 svptr->RequestSchemeNamePtr, svptr->ServerHostPort); Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 9 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 2 63612 2 63613 /* if the service has been given a a specific IP address to bind to */ 2 63614 if (svptr->BindIpAddressString[0]) 3 63615 { 3 63616 IPADDRESS_COPY (&IpAddress, &svptr->BindIpAddress) 3 63617 IPADDRESS_COPY (&svptr->MultiHomeIpAddress, &svptr->BindIpAddress) 2 63618 } 2 63619 else 2 63620 if (IPADDRESS_IS_SAME (&svptr->ServerIpAddress, &PrimaryIpAddress)) 3 63621 { 3 63622 /* zeroing these is the equivalent of setting INADDR_ANY */ 3 63623 if (IPADDRESS_IS_V4 (&PrimaryIpAddress)) 3 63624 IPADDRESS_ZERO4 (&IpAddress) 3 63625 else 3 63626 if (IPADDRESS_IS_V6 (&PrimaryIpAddress)) 3 63627 IPADDRESS_ZERO6 (&IpAddress) 3 63628 else 3 63629 ErrorExitVmsStatus (SS$_BUGCHECK, ErrorSanityCheck, FI_LI); 3 63630 IPADDRESS_COPY (&svptr->MultiHomeIpAddress, &PrimaryIpAddress) 2 63631 } 2 63632 else 2 63633 if (IPADDRESS_IS_RESET (&svptr->ServerIpAddress)) 3 63634 { 3 63635 IPADDRESS_COPY (&IpAddress, &svptr->ServerIpAddress) 3 63636 if (IPADDRESS_IS_RESET (&PrimaryIpAddress)) 4 63637 { 4 63638 IPADDRESS_COPY (&svptr->MultiHomeIpAddress, &IpAddress) 4 63639 strzcpy (&svptr->ServerIpAddressString, 4 63640 TcpIpAddressToString (&IpAddress, 0), 4 63641 sizeof(svptr->ServerIpAddressString)); 3 63642 } 3 63643 else 4 63644 { 4 63645 if (IPADDRESS_IS_V4 (&PrimaryIpAddress)) 4 63646 IPADDRESS_ZERO4 (&IpAddress) 4 63647 else 4 63648 if (IPADDRESS_IS_V6 (&PrimaryIpAddress)) 4 63649 IPADDRESS_ZERO6 (&IpAddress) 4 63650 else 4 63651 ErrorExitVmsStatus (SS$_BUGCHECK, ErrorSanityCheck, FI_LI); 4 63652 IPADDRESS_COPY (&svptr->MultiHomeIpAddress, &PrimaryIpAddress) 4 63653 strzcpy (&svptr->ServerIpAddressString, 4 63654 TcpIpAddressToString (&PrimaryIpAddress, 0), 4 63655 sizeof(svptr->ServerIpAddressString)); 3 63656 } 2 63657 } 2 63658 else 3 63659 { 3 63660 IPADDRESS_COPY (&IpAddress, &svptr->ServerIpAddress) 3 63661 IPADDRESS_COPY (&svptr->MultiHomeIpAddress, &svptr->ServerIpAddress) 2 63662 } 2 63663 IpPort = svptr->ServerPort; 2 63664 2 63665 /* get the address of the primary (first) service */ 2 63666 if (IPADDRESS_IS_RESET (&PrimaryIpAddress)) 2 63667 IPADDRESS_COPY (&PrimaryIpAddress, &IpAddress); 2 63668 Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 10 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 2 63669 if (!IPADDRESS_IS_SAME (&svptr->MultiHomeIpAddress, &PrimaryIpAddress)) 2 63670 NetMultiHome = true; 2 63671 2 63672 /**********************************/ 2 63673 /* we may need to try this twice */ 2 63674 /**********************************/ 2 63675 2 63676 /* 2 63677 Once to try an bind to any non-primary or supplied IP address. 2 63678 If this fails then a second attempt against address INADDR_ANY. 2 63679 */ 2 63680 2 63681 svptr->ServerBindStatus = SS$_NORMAL; 2 63682 2 63683 for (cnt = 0; cnt <= 1; cnt++) 3 63684 { 3 63685 /* status explicitly set to zero (is checked for at end of loop!) */ 3 63686 ServerChannel = status = 0; 3 63687 3 63688 /* check if this instance has a channel to the socket */ 3 63689 SocketDevNamePtr = InstanceSocket (&IpAddress, IpPort, NULL); 3 63690 if (SocketDevNamePtr && SocketDevNamePtr[0] == '_') 4 63691 { 4 63692 /********************/ 4 63693 /* existing channel */ 4 63694 /********************/ 4 63695 4 63696 /* find it by device name */ 4 63697 LIST_ITERATE (tsvptr, &ServiceList) 4 63698 if (strsame (SocketDevNamePtr+1, tsvptr->BgDevName, -1)) break; 4 63699 if (!tsvptr) 5 63700 { 5 63701 char String [256]; 5 63702 FaoToBuffer (String, sizeof(String), NULL, "!&I,!UL !AZ", 5 63703 &IpAddress, IpPort, SocketDevNamePtr+1); 5 63704 ErrorExitVmsStatus (SS$_BUGCHECK, String, FI_LI); 4 63705 } 4 63706 4 63707 if (svptr->RequestScheme != tsvptr->RequestScheme) 5 63708 { 5 63709 FaoToStdout ( 5 63710 "-SERVICE-W-INUSE, IP address and port already in use for \ 5 63711 !&?SSL\rHTTP\r service\n", 5 63712 svptr->RequestScheme == SCHEME_HTTP); 5 63713 break; 4 63714 } 4 63715 4 63716 /* reuse the existing socket's data */ 4 63717 svptr->ServerBindStatus = 0; 4 63718 IPADDRESS_COPY (&svptr->ServerIpAddress, &tsvptr->ServerIpAddress); 4 63719 svptr->ServerChannel = tsvptr->ServerChannel; 4 63720 strzcpy (svptr->BgDevName, tsvptr->BgDevName, 4 63721 sizeof(svptr->BgDevName)); 3 63722 } 3 63723 3 63724 if (svptr->RequestScheme == SCHEME_HTTPS) 4 63725 { Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 11 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 4 63726 /* SSL service, initialize */ 4 63727 if (!cnt) 5 63728 { 5 63729 /* but only the first time through */ 5 63730 if (!SesolaInitService (svptr)) 6 63731 { 6 63732 FaoToStdout ("-SERVICE-W-SSL, service not configured\n"); 6 63733 break; 5 63734 } 4 63735 } 4 63736 LIST_ITERATE (tsvptr, &ServiceList) 5 63737 { 5 63738 if (tsvptr == svptr) continue; 5 63739 if (tsvptr->RequestScheme != SCHEME_HTTPS) continue; 5 63740 if (!IPADDRESS_IS_SAME (&tsvptr->MultiHomeIpAddress, 5 63741 &svptr->MultiHomeIpAddress)) continue; 5 63742 if (tsvptr->ServerPort != svptr->ServerPort) continue; 5 63743 FaoToStdout ("-SERVICE-W-SSL, shares address/port with !AZ\n", 5 63744 tsvptr->ServerHostPort); 4 63745 } 3 63746 } 3 63747 3 63748 if (svptr->SSLclientEnabled) 4 63749 { 4 63750 /* if HTTP->SSL capable proxy service, initialize */ 4 63751 if (!SesolaInitClientService (svptr)) 5 63752 { 5 63753 FaoToStdout ("-SERVICE-W-SSL, client not configured\n"); 5 63754 break; 4 63755 } 3 63756 } 3 63757 3 63758 /* if there is an existing channel to a socket */ 3 63759 if (SocketDevNamePtr && SocketDevNamePtr[0] == '_') 4 63760 { 4 63761 svptr->SharedSocket = true; 4 63762 break; 3 63763 } 3 63764 3 63765 /******************************************/ 3 63766 /* create and/or assign channel to socket */ 3 63767 /******************************************/ 3 63768 3 63769 if (!NetListenBytLmRequired) BytLmBefore = GetJpiBytLm (); 3 63770 3 63771 if (!SocketDevNamePtr) 4 63772 { 4 63773 /*****************/ 4 63774 /* create socket */ 4 63775 /*****************/ 4 63776 4 63777 /* create it now then */ 4 63778 status = sys$assign (&TcpIpDeviceDsc, &ServerChannel, 0, 0); 4 63779 if (VMSnok (status)) 4 63780 ErrorExitVmsStatus (status, "sys$assign()", FI_LI); 4 63781 4 63782 /* prepare to bind the server socket to the IP address and port */ Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 12 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 4 63783 if (IPADDRESS_IS_V4 (&IpAddress)) 5 63784 { 5 63785 SOCKADDRESS_ZERO4 (&svptr->ServerSocketName) 5 63786 sin4ptr = &svptr->ServerSocketName.sa.v4; 5 63787 sin4ptr->SIN$B_FAMILY = TCPIP$C_AF_INET; 5 63788 sin4ptr->SIN$W_PORT = htons(IpPort); 5 63789 IPADDRESS_SET4 (&sin4ptr->SIN$L_ADDR, &IpAddress) 5 63790 5 63791 il2ptr = &SocketNameItem; 5 63792 il2ptr->buf_len = sizeof(SOCKADDRIN); 5 63793 il2ptr->item = 0; 5 63794 il2ptr->buf_addr = sin4ptr; 5 63795 5 63796 TcpSocketPtr = &TcpIpSocket4; 5 63797 5 63798 qiofun = IO$_SETMODE; 4 63799 } 4 63800 else 4 63801 if (IPADDRESS_IS_V6 (&IpAddress)) 5 63802 { 5 63803 SOCKADDRESS_ZERO6 (&svptr->ServerSocketName) 5 63804 sin6ptr = &svptr->ServerSocketName.sa.v6; 5 63805 sin6ptr->SIN6$B_FAMILY = TCPIP$C_AF_INET6; 5 63806 sin6ptr->SIN6$W_PORT = htons(IpPort); 5 63807 IPADDRESS_SET6 (&sin6ptr->SIN6$R_ADDR_OVERLAY.SIN6$T_ADDR, 5 63808 &IpAddress) 5 63809 5 63810 il2ptr = &SocketNameItem; 5 63811 il2ptr->buf_len = sizeof(SOCKADDRIN6); 5 63812 il2ptr->item = 0; 5 63813 il2ptr->buf_addr = sin6ptr; 5 63814 5 63815 TcpSocketPtr = &TcpIpSocket6; 5 63816 5 63817 qiofun = IO$_SETMODE | IO$M_EXTEND; 4 63818 } 4 63819 else 4 63820 ErrorExitVmsStatus (SS$_BUGCHECK, ErrorSanityCheck, FI_LI); 4 63821 4 63822 /* make the channel a TCP, connection-oriented socket */ 4 63823 status = sys$qiow (EfnWait, ServerChannel, qiofun, 4 63824 &svptr->ServerIOsb, 0, 0, TcpSocketPtr, 0, 0, 0, 4 63825 &TcpIpSocketReuseAddrOption, 0); 4 63826 if (VMSok (status)) status = svptr->ServerIOsb.Status; 4 63827 if (VMSnok (status)) 4 63828 ErrorExitVmsStatus (status, NULL, FI_LI); 4 63829 4 63830 if (VMSok (status) && svptr->AdminService) 5 63831 { 5 63832 /* admin service chooses the first available of a range */ 5 63833 while (IpPort < 65535) 6 63834 { 6 63835 status = sys$qiow (EfnWait, ServerChannel, 6 63836 qiofun, &svptr->ServerIOsb, 0, 0, 6 63837 0, 0, &SocketNameItem, 6 63838 svptr->ListenBacklog, 0, 0); 6 63839 if (VMSok (status)) status = svptr->ServerIOsb.Status; Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 13 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 6 63840 if (status != SS$_DUPLNAM) break; 6 63841 IpPort++; 6 63842 if (IPADDRESS_IS_V4 (&IpAddress)) 6 63843 sin4ptr->SIN$W_PORT = htons(IpPort); 6 63844 else 6 63845 sin6ptr->SIN6$W_PORT = htons(IpPort); 5 63846 } 4 63847 } 4 63848 else 4 63849 if (VMSok (status)) 5 63850 { 5 63851 /* no existing device bound to this address and port */ 5 63852 status = sys$qiow (EfnWait, ServerChannel, 5 63853 qiofun, &svptr->ServerIOsb, 0, 0, 5 63854 0, 0, &SocketNameItem, 5 63855 svptr->ListenBacklog, 0, 0); 5 63856 if (VMSok (status)) status = svptr->ServerIOsb.Status; 4 63857 } 4 63858 if (VMSok (status)) 4 63859 SocketDevNamePtr = NetGetBgDevice(ServerChannel, NULL, 0); 3 63860 } 3 63861 else 4 63862 { 4 63863 /* socket already exists */ 4 63864 status = SS$_NORMAL; 3 63865 } 3 63866 3 63867 if (VMSok (status)) 4 63868 { 4 63869 /*********************************************/ 4 63870 /* assign channel to existing/created socket */ 4 63871 /*********************************************/ 4 63872 4 63873 strzcpy (svptr->BgDevName, SocketDevNamePtr, 4 63874 sizeof(svptr->BgDevName)); 4 63875 BgDevNameDsc.dsc$a_pointer = svptr->BgDevName; 4 63876 BgDevNameDsc.dsc$w_length = strlen(svptr->BgDevName); 4 63877 status = sys$assign (&BgDevNameDsc, &svptr->ServerChannel, 0, 0); 4 63878 if (VMSnok (status)) 5 63879 { 5 63880 FaoToStdout ( 5 63881 "-SERVICE-W-ASSIGN, error assigning channel to !AZ \ 5 63882 (!&I!&?(INADDR_ANY)\r\r!UL)\n-!&M\n", 5 63883 SocketDevNamePtr, 5 63884 &IpAddress, IPADDRESS_IS_ANY(&IpAddress), 5 63885 IpPort, status); 4 63886 } 3 63887 } 3 63888 else 4 63889 { 4 63890 FaoToStdout ( 4 63891 "-SERVICE-W-BIND, error binding to !&I!&?(INADDR_ANY)\r\r:!UL\n-\!&M\n", 4 63892 &IpAddress, IPADDRESS_IS_ANY(&IpAddress), IpPort, status); 3 63893 } 3 63894 3 63895 if (VMSok(status) || IPADDRESS_IS_ANY(&IpAddress)) break; 3 63896 Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 14 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 3 63897 /* this time try to bind to 'any' address it can! */ 3 63898 if (ServerChannel) sys$dassgn (ServerChannel); 3 63899 svptr->ServerBindStatus = status; 3 63900 IPADDRESS_SET_ANY (&IpAddress) 3 63901 FaoToStdout ("-SERVICE-W-RETRY, try again using INADDR_ANY\n"); 3 63902 3 63903 /*************/ 3 63904 /* try again */ 3 63905 /*************/ 2 63906 } 2 63907 2 63908 /* status explicitly set to zero, just continue with next service */ 2 63909 if (!status) continue; 2 63910 2 63911 IPADDRESS_COPY (&svptr->ServerIpAddress, &IpAddress) 2 63912 2 63913 if (VMSok (status) && InstanceNodeConfig > 1) 3 63914 { 3 63915 /* make the socket shareable (seems to work only if done here) */ 3 63916 status = sys$qiow (EfnWait, svptr->ServerChannel, IO$_SETMODE, 3 63917 &svptr->ServerIOsb, 0, 0, 3 63918 0, 0, 0, 32, &TcpIpSocketShareOption, 0); 3 63919 if (VMSok (status)) status = svptr->ServerIOsb.Status; 3 63920 if (VMSnok (status)) ErrorExitVmsStatus (status, NULL, FI_LI); 2 63921 } 2 63922 else 2 63923 if (VMSok (status)) 3 63924 { 3 63925 status = sys$qiow (EfnWait, svptr->ServerChannel, IO$_SETMODE, 3 63926 &svptr->ServerIOsb, 0, 0, 3 63927 0, 0, 0, 32, 0, 0); 3 63928 if (VMSok (status)) status = svptr->ServerIOsb.Status; 3 63929 if (VMSnok (status)) ErrorExitVmsStatus (status, NULL, FI_LI); 2 63930 } 2 63931 2 63932 if (VMSnok (status)) 3 63933 { 3 63934 /***********/ 3 63935 /* problem */ 3 63936 /***********/ 3 63937 3 63938 if (ServerChannel) sys$dassgn (ServerChannel); 3 63939 svptr->ServerBindStatus = status; 3 63940 svptr->ServerChannel = svptr->AdminPort = 0; 3 63941 svptr->BgDevName[0] = '\0'; 3 63942 continue; 2 63943 } 2 63944 2 63945 /***********/ 2 63946 /* success */ 2 63947 /***********/ 2 63948 2 63949 if (WATCH_MODULE(WATCH_MOD_NET)) 2 63950 WatchThis (WATCHALL, WATCH_MOD_NET, 2 63951 "LISTEN !AZ !&I!&?(INADDR_ANY)\r\r,!UL (!UL)", 2 63952 svptr->BgDevName, &IpAddress, IPADDRESS_IS_ANY(&IpAddress), 2 63953 IpPort, svptr->ListenBacklog); Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 15 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 2 63954 2 63955 if (svptr->AdminService) 3 63956 { 3 63957 /* set the IP address and port of this instance's admin service */ 3 63958 InstanceSocketAdmin (IpPort); 3 63959 svptr->AdminPort = IpPort; 2 63960 } 2 63961 else 2 63962 if (ServerChannel) 3 63963 { 3 63964 /* inform the instance socket lock and table of the new device name */ 3 63965 InstanceSocket (NULL, 0, svptr->BgDevName); 2 63966 } 2 63967 if (ServerChannel) sys$dassgn (ServerChannel); 2 63968 2 63969 if (!NetListenBytLmRequired) 3 63970 { 3 63971 BytLmAfter = GetJpiBytLm (); 3 63972 NetListenBytLmRequired = BytLmBefore - BytLmAfter; 2 63973 } 2 63974 2 63975 if (IPADDRESS_IS_V6 (&IpAddress)) TcpIpv6Configured = true; 1 63976 } 1 63977 1 63978 /* finished with service creation */ 1 63979 if (VMSnok (status = InstanceUnLock (INSTANCE_NODE_SOCKET))) 1 63980 ErrorExitVmsStatus (status, "InstanceUnLock()", FI_LI); 1 63981 1 63982 if (WATCH_MODULE(WATCH_MOD_NET)) 1 63983 WatchThis (WATCHALL, WATCH_MOD_NET, 1 63984 "NetMultiHome: !&B", NetMultiHome); 1 63985 1 63986 return (SS$_NORMAL); 1 63987 } 63988 63989 /*****************************************************************************/ 63990 /* 63991 Queue the first accept for every service channel. 63992 Call as an AST so that it's not interrupted during processing. 63993 */ 63994 63995 void NetAcceptBegin () 63996 1 63997 { 1 63998 SERVICE_STRUCT *svptr; 1 63999 1 64000 /*********/ 1 64001 /* begin */ 1 64002 /*********/ 1 64003 1 64004 if (WATCH_MODULE(WATCH_MOD_NET)) 1 64005 WatchThis (WATCHALL, WATCH_MOD_NET, "NetAcceptBegin()"); 1 64006 1 64007 LIST_ITERATE (svptr, &ServiceList) NetAccept (svptr); 1 64008 } 64009 64010 /*****************************************************************************/ Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 16 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 64011 /* 64012 Just get the "BGnnn:" device name associated with the channel, returning it in 64013 the storage supplied. If the storage pointer is NULL internal, static storage 64014 is used ... good for one call per whatever. If an error occurs the message 64015 string is returned instead. 64016 */ 64017 64018 char* NetGetBgDevice 64019 ( 64020 unsigned short Channel, 64021 char *DevName, 64022 int SizeOfDevName 64023 ) 1 64024 { 1 64025 static char StaticDevName [64]; 1 64026 static unsigned short Length; 1 64027 static VMS_ITEM_LIST3 DevNamItemList [] = 1 64028 { 1 64029 { 0, DVI$_DEVNAM, 0, &Length }, 1 64030 { 0, 0, 0, 0 } 1 64031 }; 1 64032 1 64033 int status; 1 64034 IO_SB IOsb; 1 64035 1 64036 /*********/ 1 64037 /* begin */ 1 64038 /*********/ 1 64039 1 64040 if (WATCH_MODULE(WATCH_MOD_NET)) 1 64041 WatchThis (WATCHALL, WATCH_MOD_NET, "NetGetBgDevice()"); 1 64042 1 64043 if (!DevName) 2 64044 { 2 64045 DevName = StaticDevName; 2 64046 SizeOfDevName = sizeof(StaticDevName); 1 64047 } 1 64048 1 64049 if (!Channel) 2 64050 { 2 64051 /* multiple successive nulls */ 2 64052 *(ULONGPTR)DevName = 0; 2 64053 return (DevName); 1 64054 } 1 64055 1 64056 DevNamItemList[0].buf_addr = DevName; 1 64057 DevNamItemList[0].buf_len = SizeOfDevName-1; 1 64058 1 64059 status = sys$getdviw (EfnWait, Channel, 0, &DevNamItemList, &IOsb, 0, 0, 0); 1 64060 if (VMSok (status)) status = IOsb.Status; 1 64061 if (VMSok (status)) 1 64062 DevName[Length] = '\0'; 1 64063 else 1 64064 FaoToBuffer (DevName, SizeOfDevName, NULL, "%!&M", status); 1 64065 1 64066 if (WATCH_MODULE(WATCH_MOD_NET)) 1 64067 WatchThis (WATCHALL, WATCH_MOD_NET, "!AZ", DevName); Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 17 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 1 64068 1 64069 if (DevName[0] == '_') return (DevName+1); 1 64070 return (DevName); 1 64071 } 64072 64073 /*****************************************************************************/ 64074 /* 64075 Get the device reference count of the supplied channel. 64076 */ 64077 64078 int NetGetRefCnt (unsigned short Channel) 64079 1 64080 { 1 64081 static int DviRefCnt; 1 64082 static VMS_ITEM_LIST3 DevNamItemList [] = 1 64083 { 1 64084 { sizeof(DviRefCnt), DVI$_REFCNT, &DviRefCnt, 0 }, 1 64085 { 0, 0, 0, 0 } 1 64086 }; 1 64087 1 64088 int status; 1 64089 IO_SB IOsb; 1 64090 1 64091 /*********/ 1 64092 /* begin */ 1 64093 /*********/ 1 64094 1 64095 if (WATCH_MODULE(WATCH_MOD_NET)) 1 64096 WatchThis (WATCHALL, WATCH_MOD_NET, "NetGetRefCnt()"); 1 64097 1 64098 status = sys$getdviw (EfnWait, Channel, 0, &DevNamItemList, &IOsb, 0, 0, 0); 1 64099 if (VMSok (status)) status = IOsb.Status; 1 64100 if (VMSok (status)) return (DviRefCnt); 1 64101 return (0); 1 64102 } 64103 64104 /*****************************************************************************/ 64105 /* 64106 Zero the per-service accounting counters. 64107 */ 64108 64109 NetServiceZeroAccounting () 64110 1 64111 { 1 64112 SERVICE_STRUCT *svptr; 1 64113 1 64114 /*********/ 1 64115 /* begin */ 1 64116 /*********/ 1 64117 1 64118 if (WATCH_MODULE(WATCH_MOD_NET)) 1 64119 WatchThis (WATCHALL, WATCH_MOD_NET, "NetServiceZeroAccounting()"); 1 64120 1 64121 LIST_ITERATE (svptr, &ServiceList) 2 64122 { 2 64123 svptr->ConnectCount = svptr->ReadErrorCount = svptr->WriteErrorCount = 0; 2 64124 svptr->BytesRawRx64 = 0; Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 18 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 2 64125 svptr->BytesRawTx64 = 0; 1 64126 } 1 64127 } 64128 64129 /*****************************************************************************/ 64130 /* 64131 Output service statistics (called from AdminReportServerStats()). 64132 */ 64133 64134 int NetServiceReportStats (REQUEST_STRUCT *rqptr) 64135 1 64136 { 1 64137 static char ServicesFao [] = 1 64138 "

\n\ 1 64139 \n\ 1 64140 \n\ 1 64179
!&?\rInstance \rServices
\n\ 1 64141 \n\ 1 64142 \ 1 64143 \ 1 64144 \ 1 64145 \ 1 64146 \ 1 64147 \ 1 64148 \ 1 64149 \ 1 64150 \ 1 64151 \n"; 1 64152 1 64153 static char OneServiceFao [] = 1 64154 "\ 1 64155 \ 1 64156 \ 1 64157 \ 1 64158 \ 1 64159 \ 1 64160 \ 1 64161 \ 1 64162 \ 1 64163 \ 1 64164 \n"; 1 64165 1 64166 static char TotalFao [] = 1 64167 "\ 1 64168 \ 1 64169 \ 1 64170 \ 1 64171 \ 1 64172 \ 1 64173 \ 1 64174 \n\ 1 64175 \n\ 1 64177
IPHTTPCountbytes Rxerrbytes Txerr
!UL.!AZ//!AZ!&?v4\rv6\r!&?2+1\r1\r!&L!UL%!&,@UQ!&L!&,@UQ!&L!UL%
total:!&L!&,@UQ!&L!&,@UQ!&L
\ 1 64176 *counts are per-startup only
\n\ 1 64178
\n"; 1 64180 1 64181 int status, Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 19 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 1 64182 ServiceListCount, 1 64183 ServiceTotalCount; 1 64184 unsigned short Length; 1 64185 unsigned long *vecptr; 1 64186 unsigned long NetReadErrorTotal, 1 64187 NetWriteErrorTotal; 1 64188 unsigned long FaoVector [32]; 1 64189 int64 BytesRawRx64, 1 64190 BytesRawTx64, 1 64191 BytesRxTx64, 1 64192 BytesTotal64; 1 64193 SERVICE_STRUCT *svptr; 1 64194 1 64195 /*********/ 1 64196 /* begin */ 1 64197 /*********/ 1 64198 1 64199 if (WATCH_MODULE(WATCH_MOD_NET)) 1 64200 WatchThis (WATCHALL, WATCH_MOD_NET, "NetServiceReportStats()"); 1 64201 1 64202 NetReadErrorTotal = NetWriteErrorTotal = ServiceTotalCount = 0; 1 64203 BytesRawRx64 = BytesRawTx64 = BytesTotal64 = 0; 1 64204 1 64205 /* accumulate the raw (network) bytes for the services */ 1 64206 LIST_ITERATE (svptr, &ServiceList) 2 64207 { 2 64208 ServiceTotalCount += svptr->ConnectCount; 2 64209 BytesRawRx64 += svptr->BytesRawRx64; 2 64210 BytesRawTx64 += svptr->BytesRawTx64; 1 64211 } 1 64212 BytesTotal64 += BytesRawRx64; 1 64213 BytesTotal64 += BytesRawTx64; 1 64214 1 64215 vecptr = FaoVector; 1 64216 *vecptr++ = (InstanceNodeConfig <= 1); 1 64217 status = FaolToNet (rqptr, ServicesFao, &FaoVector); 1 64218 if (VMSnok (status)) ErrorNoticed (rqptr, status, NULL, FI_LI); 1 64219 1 64220 ServiceListCount = 1; 1 64221 LIST_ITERATE (svptr, &ServiceList) 2 64222 { 2 64223 NetReadErrorTotal += svptr->ReadErrorCount; 2 64224 NetWriteErrorTotal += svptr->WriteErrorCount; 2 64225 2 64226 vecptr = FaoVector; 2 64227 *vecptr++ = ServiceListCount++; 2 64228 *vecptr++ = svptr->RequestSchemeNamePtr; 2 64229 *vecptr++ = svptr->ServerHostPort; 2 64230 *vecptr++ = IPADDRESS_IS_V4(&svptr->ServerIpAddress); 2 64231 *vecptr++ = svptr->Http2Enabled; 2 64232 *vecptr++ = svptr->ConnectCount; 2 64233 *vecptr++ = PercentOf32 (svptr->ConnectCount, ServiceTotalCount); 2 64234 *vecptr++ = &svptr->BytesRawRx64; 2 64235 *vecptr++ = svptr->ReadErrorCount; 2 64236 *vecptr++ = &svptr->BytesRawTx64; 2 64237 *vecptr++ = svptr->WriteErrorCount; 2 64238 Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 20 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 2 64239 BytesRxTx64 = svptr->BytesRawRx64 + svptr->BytesRawTx64; 2 64240 *vecptr++ = PercentOf64 (&BytesRxTx64, &BytesTotal64); 2 64241 2 64242 status = FaolToNet (rqptr, OneServiceFao, &FaoVector); 2 64243 if (VMSnok (status)) ErrorNoticed (rqptr, status, NULL, FI_LI); 1 64244 } 1 64245 1 64246 vecptr = FaoVector; 1 64247 1 64248 *vecptr++ = ServiceTotalCount; 1 64249 *vecptr++ = &BytesRawRx64; 1 64250 *vecptr++ = NetReadErrorTotal; 1 64251 *vecptr++ = &BytesRawTx64; 1 64252 *vecptr++ = NetWriteErrorTotal; 1 64253 1 64254 status = FaolToNet (rqptr, TotalFao, &FaoVector); 1 64255 if (VMSnok (status)) ErrorNoticed (rqptr, status, NULL, FI_LI); 1 64256 1 64257 return (SS$_NORMAL); 1 64258 } 64259 64260 /*****************************************************************************/ 64261 /* 64262 Disconnect network connections. If no criteria supplied then disconnects all 64263 persistent connects leaving requests in-progress. If ConnectNumber is positive 64264 then disconnect that number, or if -1 all HTTP/1.n connections, -2 all HTTP/2 64265 connections, negative (not -1 or -2) then *all* connections. Otherwise, 64266 disconnect matching requests in-progress. Least recent before more recent. 64267 /BusyOr/ will be true for BUSY or false (CONTROL.C $SETIMR(...0) for NET. 64268 */ 64269 64270 NetControl 64271 ( 64272 int ConnectNumber, 64273 char *RequestUri, 64274 BOOL BusyOr 64275 ) 1 64276 { 1 64277 int PurgeCount = 0; 1 64278 LIST_ENTRY *leptr; 1 64279 REQUEST_STRUCT *rqeptr; 1 64280 1 64281 /*********/ 1 64282 /* begin */ 1 64283 /*********/ 1 64284 1 64285 if (WATCH_MODULE(WATCH_MOD_NET)) 1 64286 WatchThis (WATCHALL, WATCH_MOD_NET, "NetControl() !SL !&Z !&B", 1 64287 ConnectNumber, RequestUri, BusyOr); 1 64288 1 64289 /* least recent purged before more recent */ 1 64290 for (leptr = RequestList.TailPtr; leptr; leptr = leptr->PrevPtr) 2 64291 { 2 64292 rqeptr = (REQUEST_STRUCT*)leptr; 2 64293 2 64294 /* do NOT disconnect any WATCHing client (might be me :-) */ 2 64295 if (rqeptr == Watch.RequestPtr) continue; Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 21 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 2 64296 2 64297 if (rqeptr->rqTmr.TerminateSecond) 3 64298 { 3 64299 /* request has already been terminated */ 3 64300 PurgeCount++; 3 64301 continue; 2 64302 } 2 64303 2 64304 if (ConnectNumber < -2) 3 64305 { 3 64306 /* purge all */ 3 64307 HttpdTimerSet (rqeptr, TIMER_TERMINATE, 0); 3 64308 PurgeCount++; 2 64309 } 2 64310 else 2 64311 if (ConnectNumber == -2 && rqeptr->Http2Ptr) 3 64312 { 3 64313 /* purge all HTTP/2 */ 3 64314 HttpdTimerSet (rqeptr, TIMER_TERMINATE, 0); 3 64315 PurgeCount++; 2 64316 } 2 64317 else 2 64318 if (ConnectNumber == -1 && !rqeptr->Http2Ptr) 3 64319 { 3 64320 /* purge all HTTP/1.n */ 3 64321 HttpdTimerSet (rqeptr, TIMER_TERMINATE, 0); 3 64322 PurgeCount++; 2 64323 } 2 64324 else 2 64325 if (ConnectNumber > 0 && 2 64326 ConnectNumber == rqeptr->ConnectNumber) 3 64327 { 3 64328 /* purge matching number */ 3 64329 HttpdTimerSet (rqeptr, TIMER_TERMINATE, 0); 3 64330 PurgeCount++; 2 64331 } 2 64332 else 2 64333 if (ConnectNumber >= 0 && 2 64334 RequestUri && RequestUri[0]) 3 64335 { 3 64336 char *uptr = rqeptr->rqHeader.RequestUriPtr; 3 64337 if ((RequestUri[0] == '!' && StringMatch (NULL, uptr, RequestUri+1)) || 3 64338 StringMatch (NULL, uptr, RequestUri)) 4 64339 { 4 64340 HttpdTimerSet (rqeptr, TIMER_TERMINATE, 0); 4 64341 PurgeCount++; 3 64342 } 2 64343 } 2 64344 else 2 64345 if (rqeptr->rqNet.PersistentCount && 2 64346 !rqeptr->BytesRx64 && 2 64347 !rqeptr->BytesTx64) 3 64348 { 3 64349 /* purge idle (only HTTP/1.n persistent) */ 3 64350 if (!ConnectNumber) HttpdTimerSet (rqeptr, TIMER_TERMINATE, 0); 3 64351 PurgeCount++; 2 64352 } Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 22 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 1 64353 } 1 64354 1 64355 if (ConnectNumber > 0 && 1 64356 (!RequestUri || !RequestUri[0])) 2 64357 { 2 64358 /* the equivalent for HTTP/2 connections if not purged enough */ 2 64359 ConnectNumber -= PurgeCount; 2 64360 if (ConnectNumber > 0) PurgeCount += Http2NetControl (ConnectNumber); 1 64361 } 1 64362 else 2 64363 { 2 64364 /* and the equivalent for HTTP/2 connections */ 2 64365 PurgeCount += Http2NetControl (ConnectNumber); 1 64366 } 1 64367 1 64368 if (BusyOr) 1 64369 FaoToStdout ("%HTTPD-W-BUSY, !20%D, !UL connection!%s purged\n", 1 64370 0, PurgeCount); 1 64371 else 1 64372 FaoToStdout ("%HTTPD-I-NET, !UL connection!%s purged\n", 1 64373 PurgeCount); 1 64374 1 64375 if (OpcomMessages) 1 64376 FaoToOpcom ("%HTTPD-!AZ, !UL connection!%s purged", 1 64377 BusyOr ? "W-BUSY" : "I-NET", PurgeCount); 1 64378 } 64379 64380 /*****************************************************************************/ 64381 /* 64382 Suspend request processing by cancelling all queued net-accept socket I/O. 64383 The boolean just aborts any network I/O (request) in-progress. 64384 */ 64385 64386 NetSuspend (BOOL RightNow) 64387 1 64388 { 1 64389 LIST_ENTRY *leptr; 1 64390 REQUEST_STRUCT *rqeptr; 1 64391 SERVICE_STRUCT *svptr; 1 64392 1 64393 /*********/ 1 64394 /* begin */ 1 64395 /*********/ 1 64396 1 64397 if (WATCH_MODULE(WATCH_MOD_NET)) 1 64398 WatchThis (WATCHALL, WATCH_MOD_NET, "NetSuspend()"); 1 64399 1 64400 InstanceMutexLock (INSTANCE_MUTEX_HTTPD); 1 64401 HttpdGblSecPtr->ConnectSuspend = true; 1 64402 InstanceMutexUnLock (INSTANCE_MUTEX_HTTPD); 1 64403 1 64404 if (NetConnectSuspend) return; 1 64405 NetConnectSuspend = true; 1 64406 1 64407 LIST_ITERATE (svptr, &ServiceList) sys$cancel (svptr->ServerChannel); 1 64408 1 64409 /* process the request list looking for persistent connections to break */ Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 23 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 1 64410 for (leptr = RequestList.HeadPtr; leptr; leptr = leptr->NextPtr) 2 64411 { 2 64412 rqeptr = (REQUEST_STRUCT*)leptr; 2 64413 if (RightNow) 2 64414 sys$cancel (rqeptr->NetIoPtr->Channel); 2 64415 else 2 64416 if (rqeptr->rqNet.PersistentCount && !rqeptr->BytesRx64) 2 64417 sys$cancel (rqeptr->NetIoPtr->Channel); 1 64418 } 1 64419 1 64420 FaoToStdout ("%HTTPD-I-NET, request processing suspended\n"); 1 64421 if (OpcomMessages) 1 64422 FaoToOpcom ("%HTTPD-I-NET, request processing suspended"); 1 64423 } 64424 64425 /*****************************************************************************/ 64426 /* 64427 Resume request processing by requeueing net-accept I/O to all sockets. 64428 */ 64429 64430 NetResume () 64431 1 64432 { 1 64433 SERVICE_STRUCT *svptr; 1 64434 1 64435 /*********/ 1 64436 /* begin */ 1 64437 /*********/ 1 64438 1 64439 if (WATCH_MODULE(WATCH_MOD_NET)) 1 64440 WatchThis (WATCHALL, WATCH_MOD_NET, "NetResume()"); 1 64441 1 64442 InstanceMutexLock (INSTANCE_MUTEX_HTTPD); 1 64443 HttpdGblSecPtr->ConnectSuspend = false; 1 64444 InstanceMutexUnLock (INSTANCE_MUTEX_HTTPD); 1 64445 1 64446 if (!NetConnectSuspend) return; 1 64447 NetConnectSuspend = false; 1 64448 1 64449 LIST_ITERATE (svptr, &ServiceList) NetAccept (svptr); 1 64450 1 64451 FaoToStdout ("%HTTPD-I-NET, request processing resumed\n"); 1 64452 if (OpcomMessages) 1 64453 FaoToOpcom ("%HTTPD-I-NET, request processing resumed"); 1 64454 } 64455 64456 /*****************************************************************************/ 64457 /* 64458 Cancel all the queued net-accept socket I/O. 64459 Also see description on active/passive modes in INSTANCE.C module. 64460 */ 64461 64462 NetPassive () 64463 1 64464 { 1 64465 LIST_ENTRY *leptr; 1 64466 REQUEST_STRUCT *rqeptr; Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 24 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 1 64467 SERVICE_STRUCT *svptr; 1 64468 1 64469 /*********/ 1 64470 /* begin */ 1 64471 /*********/ 1 64472 1 64473 if (WATCH_MODULE(WATCH_MOD_NET)) 1 64474 WatchThis (WATCHALL, WATCH_MOD_NET, "NetPassive()"); 1 64475 1 64476 if (NetInstancePassive) return; 1 64477 1 64478 InstanceMutexLock (INSTANCE_MUTEX_HTTPD); 1 64479 NetInstancePassive = HttpdGblSecPtr->InstancePassive = true; 1 64480 InstanceMutexUnLock (INSTANCE_MUTEX_HTTPD); 1 64481 1 64482 if (InstanceNodeSupervisor) 2 64483 { 2 64484 /* adjust to provide greater capacity in this one instance */ 2 64485 NetConcurrentMax *= 2; 2 64486 NetConcurrentProcessMax *= 2; 2 64487 2 64488 /* of course the supervisor is the only one left processing requests! */ 2 64489 return; 1 64490 } 1 64491 1 64492 if (InstanceNodeCurrent == 1 || NetConnectSuspend) return; 1 64493 1 64494 LIST_ITERATE (svptr, &ServiceList) sys$cancel (svptr->ServerChannel); 1 64495 1 64496 /* process the request list looking for persistent connections to break */ 1 64497 for (leptr = RequestList.HeadPtr; leptr; leptr = leptr->NextPtr) 2 64498 { 2 64499 rqeptr = (REQUEST_STRUCT*)leptr; 2 64500 if (rqeptr->rqNet.PersistentCount && !rqeptr->BytesRx64) 2 64501 sys$cancel (rqeptr->NetIoPtr->Channel); 1 64502 } 1 64503 1 64504 FaoToStdout ("%HTTPD-I-NET, instance to passive mode\n"); 1 64505 if (OpcomMessages) 1 64506 FaoToOpcom ("%HTTPD-I-NET, instance to passive mode"); 1 64507 } 64508 64509 /*****************************************************************************/ 64510 /* 64511 Requeue the net-accept I/O to all sockets. 64512 Also see description on active/passive modes in INSTANCE.C module. 64513 */ 64514 64515 NetActive (BOOL NowSupervisor) 64516 1 64517 { 1 64518 BOOL InstancePassive; 1 64519 SERVICE_STRUCT *svptr; 1 64520 1 64521 /*********/ 1 64522 /* begin */ 1 64523 /*********/ Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 25 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 1 64524 1 64525 if (WATCH_MODULE(WATCH_MOD_NET)) 1 64526 WatchThis (WATCHALL, WATCH_MOD_NET, "NetActive()"); 1 64527 1 64528 if (!NetInstancePassive) return; 1 64529 1 64530 if (NowSupervisor) 2 64531 { 2 64532 /* adjust to provide greater capacity in this one instance */ 2 64533 NetConcurrentMax *= 2; 2 64534 NetConcurrentProcessMax *= 2; 2 64535 2 64536 if (NetConnectSuspend) return; 2 64537 2 64538 LIST_ITERATE (svptr, &ServiceList) NetAccept (svptr); 1 64539 } 1 64540 else 2 64541 { 2 64542 InstanceMutexLock (INSTANCE_MUTEX_HTTPD); 2 64543 NetInstancePassive = HttpdGblSecPtr->InstancePassive = false; 2 64544 InstanceMutexUnLock (INSTANCE_MUTEX_HTTPD); 2 64545 2 64546 if (InstanceNodeSupervisor) 3 64547 { 3 64548 /* restore the original values */ 3 64549 NetConcurrentMax /= 2; 3 64550 NetConcurrentProcessMax /= 2; 3 64551 3 64552 /* the supervisor is already processing requests! */ 3 64553 return; 2 64554 } 2 64555 2 64556 if (InstanceNodeCurrent == 1 || NetConnectSuspend) return; 2 64557 2 64558 LIST_ITERATE (svptr, &ServiceList) NetAccept (svptr); 2 64559 2 64560 FaoToStdout ("%HTTPD-I-NET, instance to active mode\n"); 2 64561 if (OpcomMessages) 2 64562 FaoToOpcom ("%HTTPD-I-NET, instance to active mode"); 1 64563 } 1 64564 } 64565 64566 /*****************************************************************************/ 64567 /* 64568 A little convoluted. Will constrain to 80 or 132 wide terminal. 64569 64570 This function runs in the executing server to generate a listing of network 64571 connections on behalf of a /DO=NET=LIST CLI command. The solution chosen to 64572 ensure atomicity was to perform the reporting in the active server at AST 64573 delivery level, written to an allocated buffer, and this then $BRKTHRU()ed 64574 directly to the terminal of the process doing the /DO=NET=LIST. 64575 64576 Use of the $BRKTHRU service requires OPER privilege. No OPER, no list (but an 64577 error -W-NOTICED). The $BRKTHRU buffer size is also constrained so busy sites 64578 may eventually truncate. 64579 */ 64580 Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 26 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 64581 void NetListFor (char *terminal) 64582 1 64583 { 1 64584 static ulong OperMask [2] = { PRV$M_OPER, 0 }; 1 64585 static $DESCRIPTOR (TermDsc, ""); 1 64586 1 64587 static ulong SyiMaxBuf; 1 64588 static VMS_ITEM_LIST3 SyiItem [] = 1 64589 { 1 64590 { sizeof(SyiMaxBuf), SYI$_MAXBUF, &SyiMaxBuf, 0 }, 1 64591 { 0,0,0,0 } 1 64592 }; 1 64593 1 64594 int blen, brem, cnt1, cnt2, cntvia2, mlen, status, 1 64595 width1, width2, width3, width4; 1 64596 int64 dura64, time64; 1 64597 ushort slen; 1 64598 char *bptr, *dptr, *eptr, *mptr, *uptr; 1 64599 char BytBuf [64], 1 64600 CliBuf [126], 1 64601 ConBuf [64], 1 64602 MsgBuf [16350], 1 64603 PerBuf [64], 1 64604 SerBuf [126], 1 64605 TruBuf [64]; 1 64606 $DESCRIPTOR (MsgBufDsc, MsgBuf); 1 64607 IO_SB IOsb; 1 64608 HTTP2_STRUCT *h2ptr; 1 64609 LIST_ENTRY *leptr; 1 64610 REQUEST_STRUCT *rqeptr; 1 64611 1 64612 /*********/ 1 64613 /* begin */ 1 64614 /*********/ 1 64615 1 64616 if (WATCH_MODULE(WATCH_MOD_NET)) 1 64617 WatchThis (WATCHALL, WATCH_MOD_NET, "NetListFor() !AZ", terminal); 1 64618 1 64619 sys$gettim (&time64); 1 64620 1 64621 SyiMaxBuf = sizeof(MsgBuf); 1 64622 status = sys$getsyiw (EfnWait, 0, 0, &SyiItem, &IOsb, 0, 0); 1 64623 if (VMSok (status)) status = IOsb.Status; 1 64624 if (VMSnok (status)) ErrorNoticed (NULL, status, "sys$getsyiw()", FI_LI); 1 64625 1 64626 /********************/ 1 64627 /* calculate widths */ 1 64628 /********************/ 1 64629 1 64630 cnt1 = cnt2 = width1 = width2 = width3 = 0; 1 64631 for (leptr = RequestList.HeadPtr; leptr; leptr = leptr->NextPtr) 2 64632 { 2 64633 cnt1++; 2 64634 rqeptr = (REQUEST_STRUCT*)leptr; 2 64635 if (rqeptr->Http2Ptr) 2 64636 FaoToBuffer (ConBuf, sizeof(ConBuf), &slen, "!UL->!UL", 2 64637 rqeptr->ConnectNumber, Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 27 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 2 64638 rqeptr->Http2Ptr->ConnectNumber); 2 64639 else 2 64640 FaoToBuffer (ConBuf, sizeof(ConBuf), &slen, "!UL", 2 64641 rqeptr->ConnectNumber); 2 64642 if (slen > width1) width1 = slen; 2 64643 slen = strlen(rqeptr->ServicePtr->RequestSchemeNamePtr) + 2 64644 strlen(rqeptr->ServicePtr->ServerHostPort); 2 64645 if (slen > width2) width2 = slen; 2 64646 slen = strlen(rqeptr->ClientPtr->Lookup.HostName); 2 64647 slen += sprintf (CliBuf, ",%u", rqeptr->ClientPtr->IpPort); 2 64648 if (slen > width3) width3 = slen; 1 64649 } 1 64650 1 64651 for (leptr = Http2List.HeadPtr; leptr; leptr = leptr->NextPtr) 2 64652 { 2 64653 cnt2++; 2 64654 h2ptr = (HTTP2_STRUCT*)leptr; 2 64655 FaoToBuffer (ConBuf, sizeof(ConBuf), &slen, "->!UL", 2 64656 h2ptr->ConnectNumber); 2 64657 if (slen > width1) width1 = slen; 2 64658 slen = strlen(h2ptr->ServicePtr->RequestSchemeNamePtr) + 2 64659 strlen(h2ptr->ServicePtr->ServerHostPort); 2 64660 if (slen > width2) width2 = slen; 2 64661 slen = strlen(h2ptr->ClientPtr->Lookup.HostName); 2 64662 slen += sprintf (CliBuf, ",%u", h2ptr->ClientPtr->IpPort); 2 64663 if (slen > width3) width3 = slen; 1 64664 } 1 64665 1 64666 if (width1 < 7) width1 = 7; 1 64667 if (width2 < 17) width2 = 17; 1 64668 if (width3 < 10) width3 = 10; 1 64669 1 64670 /* calculate the width of the URI to fit into 80 or 132 */ 1 64671 width4 = width1 + 2 + width2 + 2 + width3 + 2 + 8 + 2 + 8; 1 64672 if (width4 >= 132) 1 64673 width4 = 132; 1 64674 else 1 64675 if (width4 <= 80) 1 64676 width4 = 80; 1 64677 width4 -= width1 + 2; 1 64678 1 64679 /*******************/ 1 64680 /* generate report */ 1 64681 /*******************/ 1 64682 1 64683 bptr = MsgBuf; 1 64684 blen = 0; 1 64685 1 64686 if (SyiMaxBuf > sizeof(MsgBuf)) 1 64687 brem = sizeof(MsgBuf); 1 64688 else 1 64689 brem = SyiMaxBuf; 1 64690 brem -= 128; 1 64691 1 64692 *(USHORTPTR)bptr = '\r\n'; 1 64693 bptr += 2; 1 64694 blen += 2; Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 28 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 1 64695 brem -= 2; 1 64696 1 64697 if (cnt1 || cnt2) 2 64698 { 2 64699 FaoToBuffer (bptr, brem, &slen, 2 64700 "\r\n\ 2 64701 !#AZ !#AZ !#AZ !8AZ !10AZ\r\n\ 2 64702 !#*- !#*- !#*- !8*- !8*-\r\n", 2 64703 width1, "Connect", width2, "Service / Request", width3, "Client", 2 64704 "Time", "Duration", 2 64705 width1, width2, width3); 2 64706 bptr += slen; 2 64707 blen += slen; 2 64708 brem -= slen; 1 64709 } 1 64710 1 64711 cnt1 = cnt2 = cntvia2 = 0; 1 64712 1 64713 for (leptr = RequestList.HeadPtr; leptr; leptr = leptr->NextPtr) 2 64714 { 2 64715 if (brem <= 1) break; 2 64716 rqeptr = (REQUEST_STRUCT*)leptr; 2 64717 2 64718 if (rqeptr->Http2Ptr) 3 64719 { 3 64720 cntvia2++; 3 64721 FaoToBuffer (ConBuf, sizeof(ConBuf), 0, "!UL->!UL", 3 64722 rqeptr->ConnectNumber, 3 64723 rqeptr->Http2Ptr->ConnectNumber); 2 64724 } 2 64725 else 3 64726 { 3 64727 cnt1++; 3 64728 FaoToBuffer (ConBuf, sizeof(ConBuf), 0, "!UL", rqeptr->ConnectNumber); 2 64729 } 2 64730 2 64731 FaoToBuffer (SerBuf, sizeof(SerBuf), 0, "!AZ!AZ", 2 64732 rqeptr->ServicePtr->RequestSchemeNamePtr, 2 64733 rqeptr->ServicePtr->ServerHostPort); 2 64734 2 64735 FaoToBuffer (CliBuf, sizeof(CliBuf), 0, "!AZ,!UL", 2 64736 rqeptr->ClientPtr->Lookup.HostName, 2 64737 rqeptr->ClientPtr->IpPort); 2 64738 2 64739 dura64 = rqeptr->rqTime.BeginTime64 - time64; 2 64740 dptr = DurationString (NULL, &dura64); 2 64741 2 64742 FaoToBuffer (bptr, brem, &slen, 2 64743 "!#AZ !#AZ !#AZ !8%T !10AZ\r\n", 2 64744 width1, ConBuf, 2 64745 width2, SerBuf, 2 64746 width3, CliBuf, 2 64747 &rqeptr->rqTime.BeginTime64, 2 64748 dptr); 2 64749 bptr += slen; 2 64750 blen += slen; 2 64751 brem -= slen; Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 29 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 2 64752 2 64753 if (!(uptr = rqeptr->rqHeader.RequestUriPtr)) 3 64754 { 3 64755 if (rqeptr->rqNet.PersistentCount) 3 64756 FaoToBuffer (uptr = PerBuf, sizeof(PerBuf), NULL, 3 64757 "[persistent:!UL]", rqeptr->rqNet.PersistentCount); 3 64758 else 3 64759 uptr = "[connected]"; 3 64760 mptr = eptr = ""; 3 64761 mlen = 0; 2 64762 } 2 64763 else 3 64764 { 3 64765 mlen = strlen(mptr = rqeptr->rqHeader.MethodName); 3 64766 if (mlen) mlen++; 3 64767 eptr = ""; 3 64768 if (strlen(uptr) > width4) 4 64769 { 4 64770 mlen += 3; 4 64771 eptr = "..."; 3 64772 } 2 64773 } 2 64774 2 64775 FaoToBuffer (bptr, brem, &slen, 2 64776 "!#* !AZ!AZ!#AZ!AZ\r\n", 2 64777 width1+2, mptr, *mptr ? " " : "", 2 64778 width4 - mlen, uptr, eptr); 2 64779 bptr += slen; 2 64780 blen += slen; 2 64781 brem -= slen; 1 64782 } 1 64783 1 64784 for (leptr = Http2List.HeadPtr; leptr; leptr = leptr->NextPtr) 2 64785 { 2 64786 if (brem <= 1) break; 2 64787 h2ptr = (HTTP2_STRUCT*)leptr; 2 64788 2 64789 cnt2++; 2 64790 2 64791 FaoToBuffer (ConBuf, sizeof(ConBuf), 0, "->!UL", h2ptr->ConnectNumber); 2 64792 2 64793 FaoToBuffer (SerBuf, sizeof(SerBuf), 0, "!AZ!AZ", 2 64794 h2ptr->ServicePtr->RequestSchemeNamePtr, 2 64795 h2ptr->ServicePtr->ServerHostPort); 2 64796 2 64797 FaoToBuffer (CliBuf, sizeof(CliBuf), 0, "!AZ,!UL", 2 64798 h2ptr->ClientPtr->Lookup.HostName, 2 64799 h2ptr->ClientPtr->IpPort); 2 64800 2 64801 dura64 = h2ptr->ConnectTime64 - time64; 2 64802 dptr = DurationString (NULL, &dura64); 2 64803 2 64804 FaoToBuffer (bptr, brem, &slen, 2 64805 "!#AZ !#AZ !#AZ !8%T !10AZ\r\n", 2 64806 width1, ConBuf, 2 64807 width2, SerBuf, 2 64808 width3, CliBuf, Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 30 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 2 64809 &h2ptr->ConnectTime64, 2 64810 dptr); 2 64811 bptr += slen; 2 64812 blen += slen; 2 64813 brem -= slen; 2 64814 2 64815 FaoToBuffer (bptr, brem, &slen, 2 64816 "!#* current:!UL peak:!UL count:!UL\r\n", 2 64817 width1+2, 2 64818 h2ptr->RequestCurrent, 2 64819 h2ptr->RequestPeak, 2 64820 h2ptr->RequestCount); 2 64821 bptr += slen; 2 64822 blen += slen; 2 64823 brem -= slen; 1 64824 } 1 64825 1 64826 #if WATCH_MOD 1 64827 sprintf (BytBuf, " (%d bytes)", blen); 1X 64828 #else 1X 64829 BytBuf[0] = '\0'; 1X 64830 #endif 1 64831 1 64832 if (brem <= 1) 2 64833 { 2 64834 if (SyiMaxBuf > sizeof(MsgBuf)) 2 64835 sprintf (TruBuf, "\r\n*** TRUNCATED! *** (sizeof(MsgBuf))\r\n"); 2 64836 else 2 64837 sprintf (TruBuf, "\r\n*** TRUNCATED! *** (MAXBUF)\r\n"); 1 64838 } 1 64839 else 1 64840 TruBuf[0] = '\0'; 1 64841 1 64842 /* always space for these (the -128) */ 1 64843 FaoToBuffer (bptr, brem+128, &slen, 1 64844 "!AZ\r\n!UL HTTP/1.n, !UL via HTTP/2, !UL HTTP/2, !20%D!AZ\r\n", 1 64845 TruBuf, cnt1, cntvia2, cnt2, 0, BytBuf); 1 64846 blen += slen; 1 64847 1 64848 TermDsc.dsc$a_pointer = terminal; 1 64849 TermDsc.dsc$w_length = strlen(terminal); 1 64850 1 64851 MsgBufDsc.dsc$w_length = blen; 1 64852 1 64853 sys$setprv (1, &OperMask, 0, 0); 1 64854 status = sys$brkthru (EfnNoWait, &MsgBufDsc, &TermDsc, BRK$C_DEVICE, 1 64855 0, 0, 0, BRK$C_GENERAL, 5, 0, 0); 1 64856 sys$setprv (0, &OperMask, 0, 0); 1 64857 if (VMSnok (status)) ErrorNoticed (NULL, status, "sys$brkthru()", FI_LI); 1 64858 } 64859 64860 /*****************************************************************************/ 64861 /* 64862 Called every second by HttpdTick(). 64863 Handles accept queue failures due to lack of BYTCNT and deferred too busys. 64864 Any service that does not have an accept already queued calls NetAccept(). 64865 Should that again fail to queue, loop breaks, function exits and the next time Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 31 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 64866 called starts again at the failed service, ensuring equitable distribution. 64867 */ 64868 64869 BOOL NetAcceptSupervisor () 64870 1 64871 { 1 64872 static LIST_ENTRY *leptr, 1 64873 *nleptr; 1 64874 1 64875 SERVICE_STRUCT *svptr; 1 64876 1 64877 /*********/ 1 64878 /* begin */ 1 64879 /*********/ 1 64880 1 64881 if (WATCH_MODULE(WATCH_MOD_NET) && WATCH_MODULE(WATCH_MOD__DETAIL)) 1 64882 WatchThis (NULL, FI_LI, WATCH_MOD_NET, "NetAcceptSupervisor()"); 1 64883 1 64884 if (!leptr) nleptr = leptr = ServiceList.HeadPtr; 1 64885 1 64886 while (leptr) 2 64887 { 2 64888 svptr = (SERVICE_STRUCT*)leptr->DataPtr; 2 64889 if (!svptr->AcceptQueued) 3 64890 { 3 64891 NetAccept (svptr); 3 64892 if (!svptr->AcceptQueued) break; 2 64893 } 2 64894 if (leptr = leptr->NextPtr) continue; 2 64895 if (!nleptr) break; 2 64896 nleptr = NULL; 2 64897 leptr = ServiceList.HeadPtr; 1 64898 } 1 64899 1 64900 return (leptr != NULL); 1 64901 } 64902 64903 /*****************************************************************************/ 64904 /* 64905 Queue an accept() to the listening server socket. 64906 This is also called every second by NetAcceptSupervisor(). 64907 */ 64908 64909 NetAccept (SERVICE_STRUCT *svptr) 64910 1 64911 { 1 64912 int qiofun, status, 1 64913 BytLmBefore; 1 64914 CLIENT_STRUCT *clptr; 1 64915 NETIO_STRUCT *ioptr; 1 64916 VMS_ITEM_LIST3 *il3ptr; 1 64917 1 64918 /*********/ 1 64919 /* begin */ 1 64920 /*********/ 1 64921 1 64922 if (WATCH_MODULE(WATCH_MOD_NET)) Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 32 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 1 64923 WatchThis (WATCHALL, WATCH_MOD_NET, 1 64924 "NetAccept() !UL", svptr->AcceptQueued); 1 64925 1 64926 /* do the obvious */ 1 64927 if (NetConnectSuspend) return; 1 64928 1 64929 /* if instances are passive and not the instance supervisor */ 1 64930 if (NetInstancePassive && !InstanceNodeSupervisor) return; 1 64931 1 64932 /* server channel has been shutdown, most probably restart/exit underway */ 1 64933 if (!svptr->ServerChannel) return; 1 64934 1 64935 /* do not queue a second time on a shared socket */ 1 64936 if (svptr->SharedSocket) return; 1 64937 1 64938 /* only need the one queued at a time */ 1 64939 if (svptr->AcceptQueued) return; 1 64940 1 64941 /* if (still) busy then do not accept just yet */ 1 64942 if (NetCurrentConnected[HTTP12] > NetConcurrentMax) return; 1 64943 1 64944 if (!NetAcceptBytLmRequired) BytLmBefore = GetJpiBytLm (); 1 64945 1 64946 if (!(ioptr = NetIoBegin ())) 2 64947 { 2 64948 NetAcceptFailure = true; 2 64949 NetAcceptBytLmRequired = BytLmBefore - GetJpiBytLm(); 2 64950 return; 1 64951 } 1 64952 1 64953 ioptr->ServicePtr = svptr; 1 64954 ioptr->ClientPtr = clptr = &ioptr->ClientIp; 1 64955 1 64956 if (IPADDRESS_IS_V4 (&svptr->ServerIpAddress)) 2 64957 { 2 64958 SOCKADDRESS_ZERO4 (&clptr->SocketName) 2 64959 il3ptr = &clptr->SocketNameItem; 2 64960 il3ptr->buf_len = sizeof(SOCKADDRIN); 2 64961 il3ptr->item = 0; 2 64962 il3ptr->buf_addr = &clptr->SocketName.sa.v4; 2 64963 il3ptr->ret_len = &clptr->SocketNameLength; 2 64964 2 64965 qiofun = IO$_ACCESS | IO$M_ACCEPT; 1 64966 } 1 64967 else 1 64968 if (IPADDRESS_IS_V6 (&svptr->ServerIpAddress)) 2 64969 { 2 64970 SOCKADDRESS_ZERO6 (&clptr->SocketName) 2 64971 il3ptr = &clptr->SocketNameItem; 2 64972 il3ptr->buf_len = sizeof(SOCKADDRIN6); 2 64973 il3ptr->item = 0; 2 64974 il3ptr->buf_addr = &clptr->SocketName.sa.v6; 2 64975 il3ptr->ret_len = &clptr->SocketNameLength; 2 64976 2 64977 qiofun = IO$_ACCESS | IO$M_ACCEPT | IO$M_EXTEND; 1 64978 } 1 64979 else Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 33 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 1 64980 ErrorExitVmsStatus (SS$_BUGCHECK, ErrorSanityCheck, FI_LI); 1 64981 1 64982 status = sys$qio (EfnNoWait, svptr->ServerChannel, 1 64983 qiofun, &ioptr->AcceptIOsb, &NetAcceptAst, ioptr, 1 64984 0, 0, &clptr->SocketNameItem, 1 64985 &ioptr->Channel, &TcpIpFullDuplexCloseOption, 0); 1 64986 if (VMSnok (status)) ErrorExitVmsStatus (status, NULL, FI_LI); 1 64987 1 64988 svptr->AcceptQueued++; 1 64989 1 64990 if (WATCH_CATEGORY(WATCH_NETWORK) && WATCH_NOT_ONE_SHOT(Watch.Category)) 1 64991 WatchThis (WATCHALL, WATCH_NETWORK, 1 64992 "ACCEPT !AZ !&I!&?(INADDR_ANY)\r\r,!AZ", 1 64993 NetGetBgDevice(svptr->ServerChannel, NULL, 0), 1 64994 &svptr->ServerIpAddress, 1 64995 IPADDRESS_IS_ANY(&svptr->ServerIpAddress), 1 64996 svptr->ServerPortString); 1 64997 } 64998 64999 /*****************************************************************************/ 65000 /* 65001 A connection has been accept()ed on the specified server socket. 65002 */ 65003 65004 NetAcceptAst (NETIO_STRUCT *ioptr) 65005 1 65006 { 1 65007 int status; 1 65008 IO_SB IOsb; 1 65009 CLIENT_STRUCT *clptr; 1 65010 SERVICE_STRUCT *svptr; 1 65011 1 65012 /*********/ 1 65013 /* begin */ 1 65014 /*********/ 1 65015 1 65016 if (Watch.Category || Watch.Module) 1 65017 if (WATCH_NOT_ONE_SHOT(Watch.Category)) 1 65018 if (!Watch.FilterSet && !Watch.TriggerRxCount && !Watch.TriggerTxCount) 1 65019 ioptr->WatchItem = WatchSetWatch (NULL, WATCH_NEW_ITEM); 1 65020 1 65021 if (WATCH_MODULE(WATCH_MOD_NET)) 1 65022 WatchThis (WATCHALL, WATCH_MOD_NET, 1 65023 "NetAcceptAst() !&F !UL !&S !&X", 1 65024 &NetAcceptAst, ioptr->ServicePtr->AcceptQueued, 1 65025 ioptr->AcceptIOsb.Status, ioptr->AcceptIOsb.Unused); 1 65026 1 65027 clptr = ioptr->ClientPtr; 1 65028 svptr = ioptr->ServicePtr; 1 65029 1 65030 if (svptr->AcceptQueued) svptr->AcceptQueued--; 1 65031 1 65032 if (VMSnok (status = ioptr->AcceptIOsb.Status)) 2 65033 { 2 65034 if (ControlExitRequested) 3 65035 { 3 65036 /* server exiting or restarting, no new accepts, just return */ Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 34 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 3 65037 return; 2 65038 } 2 65039 2 65040 /* if connect dropped, forget it, ready for next connection */ 2 65041 if (status == SS$_CANCEL || 2 65042 status == SS$_ABORT || 2 65043 status == SS$_CONNECFAIL || 2 65044 status == SS$_LINKABORT || 2 65045 status == SS$_REJECT || 2 65046 status == SS$_TIMEOUT || 2 65047 status == SS$_INSFMEM) 3 65048 { 3 65049 /* if server channel zero most probably restart/exit underway */ 3 65050 if (!svptr->ServerChannel) return; 3 65051 3 65052 if (status != SS$_CANCEL && 3 65053 status != SS$_CONNECFAIL) 3 65054 ErrorNoticed (NULL, status, NULL, FI_LI); 3 65055 3 65056 NetIoEnd (ioptr); 3 65057 3 65058 /* queue up the next request acceptance */ 3 65059 NetAccept (svptr); 3 65060 return; 2 65061 } 2 65062 2 65063 /* most often network/system shutting down ... SS$_SHUT */ 2 65064 ErrorExitVmsStatus (status, "accept()", FI_LI); 1 65065 } 1 65066 1X 65067 #if NET_TEST 1X 65068 1X 65069 NetTestRequest (ioptr->Channel); 1X 65070 NetAccept (svptr); 1X 65071 return; 1X 65072 1X 65073 #endif /* NET_TEST */ 1 65074 1 65075 if (Config.cfScript.GatewayBg) 2 65076 { 2 65077 if (svptr->RequestScheme == SCHEME_HTTP) 3 65078 { 3 65079 /* make the socket shareable */ 3 65080 status = sys$qiow (EfnWait, ioptr->Channel, IO$_SETMODE, 3 65081 &ioptr->AcceptIOsb, 0, 0, 3 65082 0, 0, 0, 0, &TcpIpSocketShareOption, 0); 3 65083 if (VMSok (status)) status = ioptr->AcceptIOsb.Status; 3 65084 if (VMSnok (status)) 4 65085 { 4 65086 ErrorNoticed (NULL, status, NULL, FI_LI); 4 65087 NetIoEnd (ioptr); 4 65088 /* queue another accept */ 4 65089 NetAccept (svptr); 4 65090 return; 3 65091 } 2 65092 } 1 65093 } Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 35 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 1 65094 1 65095 if (TcpIpSocketKeepAlive) 2 65096 { 2 65097 /* set keep alive option on socket */ 2 65098 status = sys$qiow (EfnWait, ioptr->Channel, IO$_SETMODE, 2 65099 &IOsb, 0, 0, 2 65100 0, 0, 0, 0, &TcpIpSocketKeepAliveOption, 0); 2 65101 if (VMSok (status)) status = IOsb.Status; 1 65102 } 1 65103 1 65104 if (svptr->RequestScheme == SCHEME_HTTPS) 1 65105 InstanceGblSecIncrLong (&AccountingPtr->ConnectSSLCount); 1 65106 1 65107 if (IPADDRESS_IS_V4 (&svptr->ServerIpAddress)) 2 65108 { 2 65109 InstanceGblSecIncrLong (&AccountingPtr->ConnectIpv4Count); 2 65110 clptr->IpPort = ntohs(clptr->SocketName.sa.v4.SIN$W_PORT); 2 65111 IPADDRESS_GET4 (&clptr->IpAddress, 2 65112 &clptr->SocketName.sa.v4.SIN$L_ADDR); 2 65113 strzcpy (clptr->IpAddressString, 2 65114 TcpIpAddressToString (&clptr->IpAddress, 0), 2 65115 sizeof(clptr->IpAddressString)); 1 65116 } 1 65117 else 1 65118 if (IPADDRESS_IS_V6 (&svptr->ServerIpAddress)) 2 65119 { 2 65120 InstanceGblSecIncrLong (&AccountingPtr->ConnectIpv6Count); 2 65121 clptr->IpPort = ntohs(clptr->SocketName.sa.v6.SIN6$W_PORT); 2 65122 IPADDRESS_GET6 (&clptr->IpAddress, 2 65123 clptr->SocketName.sa.v6.SIN6$R_ADDR_OVERLAY.SIN6$T_ADDR) 2 65124 strzcpy (clptr->IpAddressString, 2 65125 TcpIpAddressToString (&clptr->IpAddress, 0), 2 65126 sizeof(clptr->IpAddressString)); 1 65127 } 1 65128 else 1 65129 ErrorExitVmsStatus (SS$_BUGCHECK, ErrorSanityCheck, FI_LI); 1 65130 1 65131 /* meanwhile queue another accept */ 1 65132 NetAccept (svptr); 1 65133 1 65134 if (Config.cfMisc.DnsLookupClient) 2 65135 { 2 65136 if (WATCH_CATEGORY(WATCH_NETWORK)) 2 65137 WatchThis (WATCHALL, WATCH_NETWORK, 2 65138 "RESOLVE !&I", &clptr->IpAddress); 2 65139 2 65140 /* asynchronous DNS lookup */ 2 65141 TcpIpAddressToName (&clptr->Lookup, &clptr->IpAddress, 2 65142 ConfigDnsLookupRetryCount, 2 65143 &NetAcceptProcess, ioptr); 1 65144 } 1 65145 else 2 65146 { 2 65147 /* not using client DNS lookup, carry on synchronously */ 2 65148 NetAcceptProcess (ioptr); 1 65149 } 1 65150 } Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 36 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 65151 65152 /*****************************************************************************/ 65153 /* 65154 This function can be called either as an AST by TcpIpAdddressToName() if DNS 65155 host name lookup is enabled, or directly from NetAccept() if it's disabled. 65156 Either way just continue to process the connection accept. 65157 */ 65158 65159 NetAcceptProcess (NETIO_STRUCT *ioptr) 65160 1 65161 { 1 65162 static int PrevPurgeTickSecond, 1 65163 StillBusyTickSecond; 1 65164 1 65165 int idx, qiofun, status, 1 65166 SocketNameLength, 1 65167 ServerSocketNameLength; 1 65168 char ServerIpAddressString [32]; 1 65169 CLIENT_STRUCT *clptr; 1 65170 REQUEST_STRUCT *rqptr; 1 65171 SERVICE_STRUCT *asvptr, 1 65172 *svptr, 1 65173 *tsvptr; 1 65174 IO_SB IOsb; 1 65175 SOCKADDRESS SocketName; 1 65176 VMS_ITEM_LIST3 SocketNameItem; 1 65177 VMS_ITEM_LIST3 *il3ptr; 1 65178 1 65179 /*********/ 1 65180 /* begin */ 1 65181 /*********/ 1 65182 1 65183 if (WATCH_MODULE(WATCH_MOD_NET)) 1 65184 WatchThis (WATCHALL, WATCH_MOD_NET, 1 65185 "NetAcceptProcess() !&F !&S !UL", 1 65186 &NetAcceptProcess, ioptr->AcceptIOsb.Status, 1 65187 ioptr->ClientPtr->Lookup.HostNameLength); 1 65188 1 65189 clptr = ioptr->ClientPtr; 1 65190 svptr = ioptr->ServicePtr; 1 65191 1 65192 if (NetAcceptAgent) 2 65193 { 2 65194 /*************/ 2 65195 /* net agent */ 2 65196 /*************/ 2 65197 2 65198 if (clptr->AgentRequestPtr) 3 65199 { 3 65200 /* post-process the agent response */ 3 65201 if (MATCH3 (clptr->AgentResponsePtr, "418")) 3 65202 status = SS$_ABORT; 3 65203 else 3 65204 status = SS$_NORMAL; 3 65205 3 65206 if (clptr->AgentRequestPtr) VmFree (clptr->AgentRequestPtr, FI_LI); 3 65207 if (clptr->AgentResponsePtr) VmFree (clptr->AgentResponsePtr, FI_LI); Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 37 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 3 65208 clptr->AgentRequestPtr = clptr->AgentResponsePtr = NULL; 3 65209 3 65210 if (VMSnok (status)) 4 65211 { 4 65212 /* 418 so drop the connection */ 4 65213 if (WATCH_CATEGORY(WATCH_NETWORK)) 4 65214 WatchThis (WATCHALL, WATCH_NETWORK, "DROP"); 4 65215 sys$dassgn (ioptr->Channel); 4 65216 VmFree (ioptr, FI_LI); 4 65217 return; 3 65218 } 2 65219 } 2 65220 else 3 65221 { 3 65222 NetAgentBegin (ioptr); 3 65223 return; 2 65224 } 1 65225 } 1 65226 1 65227 if (clptr->Lookup.DropConnect) 2 65228 { 2 65229 /* drop the connection (from a lookup agent) */ 2 65230 if (WATCH_CATEGORY(WATCH_NETWORK)) 2 65231 WatchThis (WATCHALL, WATCH_NETWORK, "DROP"); 2 65232 sys$dassgn (ioptr->Channel); 2 65233 VmFree (ioptr, FI_LI); 2 65234 return; 1 65235 } 1 65236 1 65237 if (VMSnok (clptr->Lookup.LookupIOsb.Status)) 2 65238 { 2 65239 /* lookup not done or failed, substitute the IP address for the name */ 2 65240 strzcpy (clptr->Lookup.HostName, clptr->IpAddressString, 2 65241 sizeof(clptr->Lookup.HostName)); 2 65242 clptr->Lookup.HostNameLength = strlen(clptr->Lookup.HostName); 1 65243 } 1 65244 1 65245 if (WATCH_MODULE(WATCH_MOD_NET)) 1 65246 WatchDataFormatted ("!&Z !&Z\n", clptr->IpAddressString, 1 65247 clptr->Lookup.HostName); 1 65248 1 65249 if (NetMultiHome) 2 65250 { 2 65251 /***********************/ 2 65252 /* multihomed services */ 2 65253 /***********************/ 2 65254 2 65255 /* get actual IP address and port specified by the client */ 2 65256 il3ptr = &SocketNameItem; 2 65257 il3ptr->item = 0; 2 65258 if (IPADDRESS_IS_V4 (&svptr->ServerIpAddress)) 3 65259 { 3 65260 il3ptr->buf_len = sizeof(SOCKADDRIN); 3 65261 il3ptr->buf_addr = &SocketName.sa.v4; 3 65262 qiofun = IO$_SENSEMODE; 2 65263 } 2 65264 else Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 38 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 2 65265 if (IPADDRESS_IS_V6 (&svptr->ServerIpAddress)) 3 65266 { 3 65267 il3ptr->buf_len = sizeof(SOCKADDRIN6); 3 65268 il3ptr->buf_addr = &SocketName.sa.v6; 3 65269 qiofun = IO$_SENSEMODE | IO$M_EXTEND; 2 65270 } 2 65271 else 2 65272 ErrorExitVmsStatus (SS$_BUGCHECK, ErrorSanityCheck, FI_LI); 2 65273 il3ptr->ret_len = &SocketNameLength; 2 65274 2 65275 status = sys$qiow (EfnWait, ioptr->Channel, qiofun, &IOsb, 0, 0, 2 65276 0, 0, &SocketNameItem, 0, 0, 0); 2 65277 2 65278 if (WATCH_MODULE(WATCH_MOD_NET)) 2 65279 WatchThis (WATCHALL, WATCH_MOD_NET, 2 65280 "$QIOW() !&S !&S", status, IOsb.Status); 2 65281 2 65282 if (VMSok (status)) status = IOsb.Status; 2 65283 if (VMSnok (status)) 3 65284 { 3 65285 /* hmmm, forget it, ready for next connection */ 3 65286 sys$dassgn (ioptr->Channel); 3 65287 VmFree (ioptr, FI_LI); 3 65288 return; 2 65289 } 2 65290 2 65291 if (IPADDRESS_IS_V4 (&svptr->ServerIpAddress)) 2 65292 IPADDRESS_GET4 (&clptr->MultiHomeIpAddress, 2 65293 &SocketName.sa.v4.SIN$L_ADDR) 2 65294 else 2 65295 if (IPADDRESS_IS_V6 (&svptr->ServerIpAddress)) 2 65296 IPADDRESS_GET6 (&clptr->MultiHomeIpAddress, 2 65297 &SocketName.sa.v6.SIN6$R_ADDR_OVERLAY.SIN6$T_ADDR) 2 65298 else 2 65299 ErrorExitVmsStatus (SS$_BUGCHECK, ErrorSanityCheck, FI_LI); 2 65300 2 65301 if (WATCH_MODULE(WATCH_MOD_NET)) 2 65302 WatchThis (WATCHALL, WATCH_MOD_NET, "!&I,!UL !&I,!UL", 2 65303 &clptr->MultiHomeIpAddress, svptr->ServerPort, 2 65304 &svptr->MultiHomeIpAddress, svptr->ServerPort); 2 65305 2 65306 /* first check against the service it arrived at (port is implicit) */ 2 65307 asvptr = svptr; 2 65308 if (IPADDRESS_IS_SAME(&clptr->MultiHomeIpAddress, 2 65309 &asvptr->MultiHomeIpAddress)) 2 65310 tsvptr = asvptr; 2 65311 else 2 65312 /* then if necessary scan through the list of services */ 2 65313 LIST_ITERATE (tsvptr, &ServiceList) 3 65314 { 3 65315 if (WATCH_CATEGORY(WATCH_NETWORK)) 3 65316 WatchThis (WATCHALL, WATCH_NETWORK, 3 65317 "MULTIHOME !&I,!UL !&I,!UL", 3 65318 &clptr->MultiHomeIpAddress, asvptr->ServerPort, 3 65319 &tsvptr->MultiHomeIpAddress, tsvptr->ServerPort); 3 65320 3 65321 if (IPADDRESS_IS_SAME(&clptr->MultiHomeIpAddress, Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 39 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 3 65322 &tsvptr->MultiHomeIpAddress) && 3 65323 (asvptr->ServerPort == tsvptr->ServerPort || 3 65324 asvptr->ServerPort == tsvptr->AdminPort)) break; 2 65325 } 2 65326 2 65327 if (tsvptr) 3 65328 { 3 65329 /* matched, change to the resolved (multihomed) service */ 3 65330 ioptr->ServicePtr = svptr = tsvptr; 2 65331 } 2 65332 else 3 65333 { 3 65334 /* the presence of this value indicates a multi-home mismatch */ 3 65335 strzcpy (clptr->MultiHomeIpAddressString, 3 65336 TcpIpAddressToString(&clptr->MultiHomeIpAddress,0), 3 65337 sizeof(clptr->MultiHomeIpAddressString)); 2 65338 } 1 65339 } 1 65340 else 1 65341 tsvptr = NULL; 1 65342 1 65343 if (WATCH_MODULE(WATCH_MOD_NET)) 1 65344 WatchThis (WATCHALL, WATCH_MOD_NET, "!AZ !AZ:!UL", 1 65345 svptr->ServerIpAddressString, 1 65346 svptr->ServerHostName, svptr->ServerPort); 1 65347 1 65348 if (NetCurrentConnected[HTTP12] > NetConcurrentMax) 2 65349 { 2 65350 /************/ 2 65351 /* too busy */ 2 65352 /************/ 2 65353 2 65354 if (WATCHING (ioptr, WATCH_CONNECT)) 2 65355 WatchThis (WATCHALL, WATCH_CONNECT, 2 65356 "ACCEPTED !UL too-busy !AZ,!UL on !AZ//!AZ,!AZ !AZ", 2 65357 NetConcurrentMax, 2 65358 clptr->Lookup.HostName, clptr->IpPort, 2 65359 svptr->RequestSchemeNamePtr, 2 65360 svptr->ServerIpAddressString, 2 65361 svptr->ServerPortString, 2 65362 NetGetBgDevice(ioptr->Channel, NULL, 0)); 2 65363 2 65364 if (PrevPurgeTickSecond < HttpdTickSecond) 3 65365 { 3 65366 /* every couple of seconds disconnect 20% of idle connections */ 3 65367 /* two seconds gives TIMER_TERMINATE a chance to take action */ 3 65368 PrevPurgeTickSecond = HttpdTickSecond + 2; 3 65369 NetControl (NetConcurrentMax / 5, NULL, "BUSY"); 2 65370 } 2 65371 2 65372 svptr->ConnectCount++; 2 65373 InstanceMutexLock (INSTANCE_MUTEX_HTTPD); 2 65374 AccountingPtr->ConnectTooBusyCount++; 2 65375 AccountingPtr->ResponseStatusCodeGroup[5]++; 2 65376 AccountingPtr->ResponseStatusCodeCount[RequestHttpStatusIndex(503)]++; 2 65377 InstanceMutexUnLock (INSTANCE_MUTEX_HTTPD); 2 65378 /* just drop (as yet unnegotiated) TLS/SSL connection if too busy */ Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 40 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 2 65379 if (svptr->RequestScheme == SCHEME_HTTPS) 2 65380 NetIoEnd (ioptr); 2 65381 else 2 65382 NetDirectResponse (ioptr, MSG_GENERAL_TOO_BUSY); 2 65383 2 65384 if (StillBusyTickSecond) 3 65385 { 3 65386 if (StillBusyTickSecond < HttpdTickSecond) 4 65387 { 4 65388 char buf [64]; 4 65389 FaoToBuffer (buf, sizeof(buf), NULL, 4 65390 "BUSY continuously for !UL seconds", 4 65391 STILL_BUSY_SECONDS); 4 65392 ErrorExitVmsStatus (SS$_BUGCHECK, buf, FI_LI); 3 65393 } 2 65394 } 2 65395 else 2 65396 StillBusyTickSecond = HttpdTickSecond + STILL_BUSY_SECONDS; 2 65397 2 65398 return; 1 65399 } 1 65400 1 65401 StillBusyTickSecond = 0; 1 65402 1 65403 1 65404 if (rqptr = ioptr->RequestPtr) 1 65405 if (rqptr->rqNet.PersistentCount) 1 65406 rqptr = NULL; 1 65407 1 65408 if (!rqptr && NetRejectConnect (clptr, svptr)) 2 65409 { 2 65410 /************/ 2 65411 /* rejected */ 2 65412 /************/ 2 65413 2 65414 if (WATCHING (ioptr, WATCH_CONNECT)) 2 65415 WatchThis (WATCHALL, WATCH_CONNECT, 2 65416 "REJECT !AZ,!UL on !AZ//!AZ,!AZ !AZ", 2 65417 clptr->Lookup.HostName, clptr->IpPort, 2 65418 svptr->RequestSchemeNamePtr, 2 65419 svptr->ServerIpAddressString, 2 65420 svptr->ServerPortString, 2 65421 NetGetBgDevice(ioptr->Channel, NULL, 0)); 2 65422 2 65423 svptr->ConnectCount++; 2 65424 InstanceMutexLock (INSTANCE_MUTEX_HTTPD); 2 65425 AccountingPtr->ResponseStatusCodeGroup[4]++; 2 65426 AccountingPtr->ResponseStatusCodeCount[RequestHttpStatusIndex(418)]++; 2 65427 InstanceMutexUnLock (INSTANCE_MUTEX_HTTPD); 2 65428 /* just drop (as yet unnegotiated) TLS/SSL connection if rejected */ 2 65429 NetIoEnd (ioptr); 2 65430 return; 1 65431 } 1 65432 1 65433 /************/ 1 65434 /* accepted */ 1 65435 /************/ Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 41 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 1 65436 1 65437 TcpIpSocketMaxSeg (ioptr); 1 65438 1 65439 if (ioptr->WatchItem && 1 65440 WATCH_CATEGORY(WATCH_CONNECT)) 2 65441 { 2 65442 if (NetMultiHome) 2 65443 WatchThis (WATCHITM(ioptr), WATCH_CONNECT, 2 65444 "MULTIHOME !&?match\rno match\r for !&I,!UL arrived at !&I,!UL", 2 65445 tsvptr, 2 65446 &clptr->MultiHomeIpAddress, svptr->ServerPort, 2 65447 &asvptr->ServerIpAddress, asvptr->ServerPort); 2 65448 WatchThis (WATCHITM(ioptr), WATCH_CONNECT, 2 65449 "ACCEPTED !AZ,!UL on !AZ//!AZ,!UL (!&I) !AZ", 2 65450 clptr->Lookup.HostName, clptr->IpPort, 2 65451 svptr->RequestSchemeNamePtr, 2 65452 svptr->ServerHostName, 2 65453 svptr->ServerPort, 2 65454 &svptr->ServerIpAddress, 2 65455 NetGetBgDevice(ioptr->Channel, NULL, 0)); 1 65456 } 1 65457 1 65458 RequestAccept (ioptr); 1 65459 } 65460 65461 /*****************************************************************************/ 65462 /* 65463 Change the socket BG devices implied carriage-control bit; 0 forces the CCL bit 65464 off, 1 forces it on(, and -1 one toggles it [perhaps one day]). 65465 */ 65466 65467 int NetClientSocketCcl 65468 ( 65469 NETIO_STRUCT *ioptr, 65470 int CclOption 65471 ) 1 65472 { 1 65473 int status; 1 65474 IO_SB IOsb; 1 65475 1 65476 /*********/ 1 65477 /* begin */ 1 65478 /*********/ 1 65479 1 65480 if (WATCHMOD (ioptr, WATCH_MOD_NET)) 1 65481 WatchThis (WATCHITM(ioptr), WATCH_MOD_NET, 1 65482 "NetClientSocketCcl() !SL !&A !UL", 1 65483 CclOption, ioptr->Stream2Ptr, ioptr->Channel); 1 65484 1 65485 if (ioptr->Stream2Ptr) 1 65486 status = SS$_BADPARAM; 1 65487 else 1 65488 if (ioptr->ServicePtr->RequestScheme == SCHEME_HTTP) 2 65489 { 2 65490 if (ioptr->Channel) 3 65491 { 3 65492 if (CclOption == 1) Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 42 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 3 65493 status = sys$qiow (EfnWait, ioptr->Channel, IO$_SETMODE, 3 65494 &IOsb, 0, 0, 3 65495 0, 0, 0, 0, &TcpIpSocketCclOptionOn, 0); 3 65496 else 3 65497 if (CclOption == 0) 3 65498 status = sys$qiow (EfnWait, ioptr->Channel, IO$_SETMODE, 3 65499 &IOsb, 0, 0, 3 65500 0, 0, 0, 0, &TcpIpSocketCclOptionOff, 0); 3 65501 else 3 65502 status = SS$_BADPARAM; 3 65503 if (VMSok (status)) status = IOsb.Status; 3 65504 3 65505 if (WATCHING (ioptr, WATCH_NETWORK)) 3 65506 WatchThis (WATCHITM(ioptr), WATCH_NETWORK, 3 65507 "SOCKET CCL !SL !&S", CclOption, status); 2 65508 } 2 65509 else 2 65510 status = SS$_BADPARAM; 1 65511 } 1 65512 else 1 65513 status = SS$_BADPARAM; 1 65514 1 65515 return (status); 1 65516 } 65517 65518 /*****************************************************************************/ 65519 /* 65520 'HostNamePort' can contain a "host.name:port" or just a "host.name" if the port 65521 is supplied via 'PortNumber'. Using the supplied or parsed host name get the 65522 lookup host name into 'HostNamePtr', the decimal-dot-notation IP address string 65523 into 'IpAddressStringPtr' and the IP address into 'IpAddressPtr', the IP port 65524 number (particularly if parsed from 'HostNamePort' in to 'IpPortPtr'. Any of 65525 the '...Ptr' parameters can be NULL and won't have the respective information 65526 returned. 65527 */ 65528 65529 int NetHostNameLookup 65530 ( 65531 char *HostNamePort, 65532 int PortNumber, 65533 char *HostNamePtr, 65534 char *HostPortPtr, 65535 char *IpAddressStringPtr, 65536 IPADDRESS *IpAddressPtr, 65537 ushort *IpPortPtr 65538 ) 1 65539 { 1 65540 static $DESCRIPTOR (HostPortFaoDsc, "!AZ:!UL\0"); 1 65541 static $DESCRIPTOR (StringDsc, ""); 1 65542 static int RetryAttempts = -1; 1 65543 1 65544 BOOL AddressOnly, 1 65545 FullyQualified; 1 65546 int idx, 1 65547 status; 1 65548 char *cptr, *sptr, *zptr; 1 65549 char HostNameScratch [128]; Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 43 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 1 65550 IPADDRESS IpAddress; 1 65551 TCPIP_HOST_LOOKUP HostLookup; 1 65552 1 65553 /*********/ 1 65554 /* begin */ 1 65555 /*********/ 1 65556 1 65557 if (WATCH_MODULE(WATCH_MOD_NET)) 1 65558 WatchThis (WATCHALL, WATCH_MOD_NET, 1 65559 "NetHostNameLookup() !AZ", HostNamePort); 1 65560 1 65561 AddressOnly = true; 1 65562 FullyQualified = false; 1 65563 1 65564 zptr = (sptr = HostNameScratch) + sizeof(HostNameScratch)-1; 1 65565 if (HostNamePort[0] == '[') 2 65566 { 2 65567 /* IPv6 address */ 2 65568 for (cptr = HostNamePort; 2 65569 *cptr && *cptr != ']' && sptr < zptr; 2 65570 *sptr++ = *cptr++); 2 65571 if (*cptr == ']' && sptr < zptr) *sptr++ = *cptr++; 2 65572 *sptr = '\0'; 1 65573 } 1 65574 else 2 65575 { 2 65576 for (cptr = HostNamePort; 2 65577 *cptr && *cptr != ':' && sptr < zptr; 2 65578 *sptr++ = to_lower(*cptr++)) 2 65579 if (isalpha(*cptr)) AddressOnly = false; 2 65580 *sptr = '\0'; 1 65581 } 1 65582 if (*cptr == ':' && !PortNumber) PortNumber = atoi(cptr+1); 1 65583 1 65584 /*************************/ 1 65585 /* UCX resolve host name */ 1 65586 /*************************/ 1 65587 1 65588 IPADDRESS_ZERO (&IpAddress); 1 65589 1 65590 if (AddressOnly) 1 65591 status = SS$_NORMAL; 1 65592 else 2 65593 { 2 65594 if (RetryAttempts < 0) 3 65595 { 3 65596 if (cptr = SysTrnLnm (WASD_NET_LOOKUP_RETRY)) 3 65597 RetryAttempts = atoi(cptr); 3 65598 else 3 65599 RetryAttempts = NET_LOOKUP_RETRY; 2 65600 } 2 65601 2 65602 memset (&HostLookup, 0, sizeof(HostLookup)); 2 65603 status = TcpIpNameToAddress (&HostLookup, HostNameScratch, 2 65604 RetryAttempts, NULL, 0); 2 65605 if (VMSok (status)) 3 65606 { Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 44 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 3 65607 /* use the resolved name */ 3 65608 zptr = (sptr = HostNameScratch) + 127; 3 65609 for (cptr = HostLookup.HostName; 3 65610 *cptr && sptr < zptr; 3 65611 *sptr++ = to_lower(*cptr++)); 3 65612 *sptr = '\0'; 3 65613 IPADDRESS_COPY (&IpAddress, &HostLookup.IpAddress) 2 65614 } 1 65615 } 1 65616 1 65617 /*****************************/ 1 65618 /* return values as required */ 1 65619 /*****************************/ 1 65620 1 65621 if (HostNamePtr) 2 65622 { 2 65623 strzcpy (HostNamePtr, HostNameScratch, 127); 2 65624 if (WATCH_MODULE(WATCH_MOD_NET)) 2 65625 WatchThis (WATCHALL, WATCH_MOD_NET, "!AZ", HostNamePtr); 1 65626 } 1 65627 1 65628 if (HostPortPtr) 2 65629 { 2 65630 StringDsc.dsc$a_pointer = HostPortPtr; 2 65631 StringDsc.dsc$w_length = 128+16; 2 65632 sys$fao (&HostPortFaoDsc, 0, &StringDsc, HostNameScratch, PortNumber); 2 65633 if (WATCH_MODULE(WATCH_MOD_NET)) 2 65634 WatchThis (WATCHALL, WATCH_MOD_NET, "!AZ", HostPortPtr); 1 65635 } 1 65636 1 65637 if (IpAddressStringPtr) 2 65638 { 2 65639 /* convert the binary address into a string */ 2 65640 strzcpy (IpAddressStringPtr, TcpIpAddressToString (&IpAddress, 0), 128); 2 65641 if (WATCH_MODULE(WATCH_MOD_NET)) 2 65642 WatchThis (WATCHALL, WATCH_MOD_NET, "!AZ", IpAddressStringPtr); 1 65643 } 1 65644 1 65645 if (IpAddressPtr) IPADDRESS_COPY (IpAddressPtr, &IpAddress) 1 65646 if (IpPortPtr) *IpPortPtr = PortNumber; 1 65647 1 65648 return (status); 1 65649 } 65650 65651 /****************************************************************************/ 65652 /* 65653 Just close the socket, bang! 65654 */ 65655 65656 void NetCloseSocket (REQUEST_STRUCT *rqptr) 65657 1 65658 { 1 65659 /*********/ 1 65660 /* begin */ 1 65661 /*********/ 1 65662 1 65663 if (WATCHMOD (rqptr, WATCH_MOD_NET)) Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 45 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 1 65664 WatchThis (WATCHITM(rqptr), WATCH_MOD_NET, "NetCloseSocket()"); 1 65665 1 65666 NetIoCloseSocket (rqptr->NetIoPtr); 1 65667 } 65668 65669 /****************************************************************************/ 65670 /* 65671 After checking for and explicitly delivering any outstanding read and/or write 65672 ASTs, deassign the request's underlying network connection regardless of 65673 whether it is a directly connected socket or HTTP/2 connected socket. 65674 */ 65675 65676 void NetAbortSocket (REQUEST_STRUCT *rqptr) 65677 1 65678 { 1 65679 int status; 1 65680 NETIO_STRUCT *ioptr; 1 65681 1 65682 /*********/ 1 65683 /* begin */ 1 65684 /*********/ 1 65685 1 65686 if (WATCHMOD (rqptr, WATCH_MOD_NET)) 1 65687 WatchThis (WATCHITM(rqptr), WATCH_MOD_NET, "NetAbortSocket()"); 1 65688 1 65689 ioptr = rqptr->NetIoPtr; 1 65690 if (ioptr->WriteAstFunction) 2 65691 { 2 65692 ioptr->WriteIOsb.Status = SS$_ABORT; 2 65693 SysDclAst (ioptr->WriteAstFunction, ioptr->WriteAstParam); 2 65694 ioptr->WriteAstFunction = ioptr->WriteAstParam = 0; 1 65695 } 1 65696 if (ioptr->ReadAstFunction) 2 65697 { 2 65698 ioptr->ReadIOsb.Status = SS$_ABORT; 2 65699 SysDclAst (ioptr->ReadAstFunction, ioptr->ReadAstParam); 2 65700 ioptr->ReadAstFunction = ioptr->ReadAstParam = 0; 1 65701 } 1 65702 1 65703 if (HTTP2_REQUEST(rqptr)) 1 65704 NetIoCloseSocket (rqptr->Http2Ptr->NetIoPtr); 1 65705 else 1 65706 NetIoCloseSocket (rqptr->NetIoPtr); 1 65707 } 65708 65709 /****************************************************************************/ 65710 /* 65711 Stop the server from receiving incoming requests. 65712 */ 65713 65714 NetShutdownServerSocket () 65715 1 65716 { 1 65717 SERVICE_STRUCT *svptr; 1 65718 1 65719 /*********/ 1 65720 /* begin */ Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 46 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 1 65721 /*********/ 1 65722 1 65723 if (WATCH_MODULE(WATCH_MOD_NET)) 1 65724 WatchThis (WATCHALL, WATCH_MOD_NET, "NetShutdownServerSocket()"); 1 65725 1 65726 LIST_ITERATE (svptr, &ServiceList) 2 65727 { 2 65728 sys$dassgn (svptr->ServerChannel); 2 65729 svptr->ServerChannel = 0; 1 65730 } 1 65731 } 65732 65733 /*****************************************************************************/ 65734 /* 65735 Called from NetWrite() if a response header needs to be sent before any data. 65736 Response header has now been sent, send the data using the buffered 65737 information about it. 65738 */ 65739 65740 NetResponseHeaderAst (REQUEST_STRUCT *rqptr) 65741 1 65742 { 1 65743 int status; 1 65744 1 65745 /*********/ 1 65746 /* begin */ 1 65747 /*********/ 1 65748 1 65749 if (WATCHMOD (rqptr, WATCH_MOD_NET)) 1 65750 WatchThis (WATCHITM(rqptr), WATCH_MOD_NET, 1 65751 "NetResponseHeaderAst() !&F !&A !&X !UL", 1 65752 &NetResponseHeaderAst, 1 65753 rqptr->rqResponse.HeaderAstFunction, 1 65754 rqptr->rqResponse.HeaderDataPtr, 1 65755 rqptr->rqResponse.HeaderDataLength); 1 65756 1 65757 if (rqptr->rqResponse.HeaderDataPtr && 1 65758 rqptr->rqResponse.HeaderDataLength) 1 65759 NetWrite (rqptr, 1 65760 rqptr->rqResponse.HeaderAstFunction, 1 65761 rqptr->rqResponse.HeaderDataPtr, 1 65762 rqptr->rqResponse.HeaderDataLength); 1 65763 else 1 65764 /* without a real network write just fudge the status */ 1 65765 NetIoWriteStatus (rqptr->NetIoPtr, rqptr->rqResponse.HeaderAstFunction, 1 65766 rqptr, SS$_NORMAL, 0); 1 65767 } 65768 65769 /*****************************************************************************/ 65770 /* 65771 Write 'DataLength' bytes located at 'DataPtr' to the client either using either 65772 the "raw" network or via the Secure Sockets Layer. 65773 65774 If 'AstFunction' zero then use sys$qiow(), waiting for completion. If 65775 an AST completion address is supplied then use sys$qio(). If empty data 65776 buffer is supplied (zero length) then declare an AST to service any AST 65777 routine supplied. If none then just return. Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 47 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 65778 65779 For responses generated by the server the HTTP header is a separate structure 65780 which can be sent separately. If the HTTP method is "HEAD" only allow bytes in 65781 the header to be sent, absorb any other, explicitly calling the AST completion 65782 routine as necessary (this, in particular, is for scripts that don't recognise 65783 this method). 65784 65785 Explicitly declares any AST routine if an error occurs. The calling function 65786 must not do any error recovery if an AST routine has been supplied but the 65787 associated AST routine must! If an AST was not supplied then the return 65788 status can be checked. 65789 */ 65790 65791 int NetWrite 65792 ( 65793 REQUEST_STRUCT *rqptr, 65794 REQUEST_AST AstFunction, 65795 char *DataPtr, 65796 int DataLength 65797 ) 1 65798 { 1 65799 int cnt, length, nlcnt, status; 1 65800 BOOL WritingProxyResponseHeader; 1 65801 char *cptr, *sptr; 1 65802 DICT_ENTRY_STRUCT *denptr; 1 65803 NETIO_STRUCT *ioptr; 1 65804 1 65805 /*********/ 1 65806 /* begin */ 1 65807 /*********/ 1 65808 1 65809 if (WATCHMOD (rqptr, WATCH_MOD_NET)) 1 65810 WatchThis (WATCHITM(rqptr), WATCH_MOD_NET, 1 65811 "NetWrite() ast:!&A data:!&X len:!UL gen:!&B sent:!&B cnt:!UL", 1 65812 AstFunction, DataPtr, DataLength, 1 65813 rqptr->rqResponse.HeaderGenerated, 1 65814 rqptr->rqResponse.HeaderSent, 1 65815 rqptr->rqResponse.HeaderNewlineCount); 1 65816 1 65817 ioptr = rqptr->NetIoPtr; 1 65818 ioptr->WatchItem = rqptr->WatchItem; 1 65819 1 65820 /* intermediate update to data transfer stats */ 1 65821 rqptr->NetIoPtr->BlocksRawTx64 = ioptr->BlocksRawTx64; 1 65822 rqptr->NetIoPtr->BytesRawTx64 = ioptr->BytesRawTx64; 1 65823 1 65824 status = SS$_NORMAL; 1 65825 1 65826 /* initiate cache load if .. */ 1 65827 if (rqptr->rqPathSet.CacheNet && /* the path indicates it */ 1 65828 !rqptr->rqCache.LoadCheck && /* not been checked already */ 1 65829 !rqptr->rqCache.EntryPtr) /* output is not from the cache! */ 2 65830 { 2 65831 /* request output to be cached */ 2 65832 rqptr->rqCache.LoadFromNet = 2 65833 CacheLoadBegin (rqptr, (int)rqptr->rqResponse.ContentLength64, 2 65834 rqptr->rqResponse.ContentTypePtr); Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 48 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 1 65835 } 1 65836 1 65837 if (rqptr->rqResponse.HeaderGenerated && 1 65838 !rqptr->rqResponse.HeaderSent) 2 65839 { 2 65840 /*******************************************/ 2 65841 /* nothing of response sent to client yet! */ 2 65842 /*******************************************/ 2 65843 2 65844 rqptr->rqResponse.HeaderSent = true; 2 65845 2 65846 if (rqptr->rqResponse.HttpStatus == 418) 3 65847 { 3 65848 if (WATCHING (rqptr, WATCH_RESPONSE)) 3 65849 WatchThis (WATCHITM(ioptr), WATCH_RESPONSE, 3 65850 "HTTP status 418 drop"); 3 65851 3 65852 if (AstFunction) 3 65853 SysDclAst (AstFunction, rqptr); 3 65854 else 3 65855 SysDclAst (RequestEnd, rqptr); 3 65856 3 65857 return (SS$_NORMAL); 2 65858 } 2 65859 2 65860 if (rqptr->rqPathSet.ResponseHeaderNone && 2 65861 rqptr->rqResponse.HttpStatus / 100 == 2) 3 65862 { 3 65863 /*********************/ 3 65864 /* header suppressed */ 3 65865 /*********************/ 3 65866 3 65867 if (WATCHING (rqptr, WATCH_RESPONSE_HEADER)) 4 65868 { 4 65869 if (denptr = ResponseDictHeader (rqptr)) 4 65870 length = DICT_GET_VALUE_LEN(denptr); 4 65871 else 4 65872 length = 0; 4 65873 WatchThis (WATCHITM(rqptr), WATCH_RESPONSE_HEADER, 4 65874 "HEADER !UL bytes (NONE)", length); 3 65875 } 2 65876 } 2 65877 else 2 65878 if (rqptr->rqResponse.HttpVersion != HTTP_VERSION_0_9) 3 65879 { 3 65880 /************************/ 3 65881 /* send response header */ 3 65882 /************************/ 3 65883 3 65884 if (rqptr != Watch.RequestPtr && 3 65885 WATCHPNT(rqptr) && WATCH_CATEGORY(WATCH_RESPONSE_HEADER)) 4 65886 { 4 65887 WatchThis (WATCHITM(rqptr), WATCH_RESPONSE_HEADER, "DATA"); 4 65888 DictWatchEntry (NULL); 4 65889 DictWatch (rqptr->rqDictPtr, DICT_TYPE_INTERNAL, "response_status"); 4 65890 DictWatch (rqptr->rqDictPtr, DICT_TYPE_RESPONSE, "*"); 3 65891 } Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 49 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 3 65892 3 65893 if (AstFunction) 4 65894 { 4 65895 rqptr->rqResponse.HeaderAstFunction = AstFunction; 4 65896 rqptr->rqResponse.HeaderDataPtr = DataPtr; 4 65897 rqptr->rqResponse.HeaderDataLength = DataLength; 4 65898 AstFunction = &NetResponseHeaderAst; 3 65899 } 3 65900 3 65901 /* only need header via the network if it's not already generated */ 3 65902 if (rqptr->rqCache.LoadFromNet && 3 65903 !rqptr->rqResponse.ContentTypePtr) 4 65904 { 4 65905 if (denptr = ResponseDictHeader (rqptr)) 5 65906 { 5 65907 cptr = DICT_GET_VALUE(denptr); 5 65908 length = DICT_GET_VALUE_LEN(denptr); 5 65909 CacheLoadData (rqptr, cptr, length); 4 65910 } 3 65911 } 3 65912 else 3 65913 denptr = NULL; 3 65914 3 65915 if (HTTP2_REQUEST(rqptr)) 4 65916 { 4 65917 /* function will return SS$_ABORT if header not generated */ 4 65918 if (VMSnok (status = Http2ResponseDictHeader (rqptr, AstFunction))) 4 65919 NetIoWriteStatus (ioptr, AstFunction, rqptr, status, 0); 3 65920 } 3 65921 else 4 65922 { 4 65923 if (denptr == NULL) denptr = ResponseDictHeader (rqptr); 4 65924 /* it is possible that a header has not been generated */ 4 65925 if (denptr) 5 65926 { 5 65927 cptr = DICT_GET_VALUE(denptr); 5 65928 length = DICT_GET_VALUE_LEN(denptr); 5 65929 if (rqptr->rqPathSet.ResponseHeaderBegin && 5 65930 rqptr->rqResponse.HttpStatus / 100 == 2) length -= 2; 5 65931 5 65932 if (rqptr != Watch.RequestPtr && 5 65933 WATCHPNT(rqptr) && WATCH_CATEGORY(WATCH_RESPONSE_HEADER)) 6 65934 { 6 65935 WatchThis (WATCHITM(rqptr), WATCH_RESPONSE_HEADER, 6 65936 "HEADER !UL bytes", length); 6 65937 WatchData (cptr, length); 5 65938 } 5 65939 5 65940 status = NetIoWrite (ioptr, AstFunction, rqptr, cptr, length); 5 65941 if (VMSok (status)) rqptr->BytesTx64 += length; 4 65942 } 4 65943 else 4 65944 NetIoWriteStatus (ioptr, AstFunction, rqptr, 4 65945 status = SS$_ABORT, 0); 3 65946 } 3 65947 3 65948 if (AstFunction) return (status); Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 50 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 3 65949 /* a blocking write will continue on to write the data */ 2 65950 } 1 65951 } 1 65952 1 65953 if (DataLength) 2 65954 { 2 65955 /********/ 2 65956 /* data */ 2 65957 /********/ 2 65958 2 65959 rqptr->BytesTx64 += DataLength; 2 65960 2 65961 if ((rqptr->rqHeader.Method == HTTP_METHOD_HEAD || 2 65962 rqptr->rqResponse.HttpStatus == 304) && 2 65963 rqptr->rqHeader.HttpVersion != HTTP_VERSION_0_9 && 2 65964 !rqptr->ProxyTaskPtr) 3 65965 { 3 65966 /*****************************/ 3 65967 /* send only response header */ 3 65968 /*****************************/ 3 65969 3 65970 if (!rqptr->rqResponse.HeaderSent && 3 65971 rqptr->rqResponse.HeaderNewlineCount <= 1) 4 65972 { 4 65973 /**********************/ 4 65974 /* header from script */ 4 65975 /**********************/ 4 65976 4 65977 nlcnt = rqptr->rqResponse.HeaderNewlineCount; 4 65978 cptr = DataPtr; 4 65979 cnt = DataLength; 4 65980 while (cnt--) 5 65981 { 5 65982 if (*cptr == '\n' && ++nlcnt == 2) 6 65983 { 6 65984 /* two successive end-of-lines, therefore end of header */ 6 65985 cptr++; 6 65986 break; 5 65987 } 5 65988 else 5 65989 if (*cptr != '\r' && *cptr != '\n') 5 65990 nlcnt = 0; 5 65991 cptr++; 4 65992 } 4 65993 4 65994 if ((rqptr->rqResponse.HeaderNewlineCount = nlcnt) == 2) 5 65995 { 5 65996 /* finally found those two consecutive newlines! */ 5 65997 rqptr->rqResponse.HeaderSent = true; 5 65998 if (DataLength = cptr - DataPtr) 6 65999 { 6 66000 /* adjust data length to include only the HTTP header */ 6 66001 DataLength = cptr - DataPtr; 5 66002 } 5 66003 else 6 66004 { 6 66005 /* no data in HTTP header left at all */ Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 51 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 6 66006 NetIoWriteStatus (ioptr, AstFunction, rqptr, SS$_NORMAL, 0); 6 66007 return (SS$_NORMAL); 5 66008 } 4 66009 } 3 66010 } 3 66011 else 4 66012 { 4 66013 /* HTTP header has been completely sent, absorb anything else */ 4 66014 NetIoWriteStatus (ioptr, AstFunction, rqptr, SS$_NORMAL, 0); 4 66015 return (SS$_NORMAL); 3 66016 } 3 66017 3 66018 if (WATCHMOD (rqptr, WATCH_MOD_NET)) 3 66019 WatchThis (WATCHITM(rqptr), WATCH_MOD_NET, 3 66020 "HEAD !&X !UL", DataPtr, DataLength); 2 66021 } 2 66022 2 66023 if (rqptr->rqResponse.HttpVersion == HTTP_VERSION_0_9 && 2 66024 !rqptr->rqResponse.HeaderSent && 2 66025 rqptr->rqResponse.HeaderNewlineCount <= 1 && 2 66026 !rqptr->ProxyTaskPtr) 3 66027 { 3 66028 /*********************************/ 3 66029 /* absorb any header from script */ 3 66030 /*********************************/ 3 66031 3 66032 int cnt, nlcnt; 3 66033 char *cptr; 3 66034 3 66035 nlcnt = rqptr->rqResponse.HeaderNewlineCount; 3 66036 cptr = DataPtr; 3 66037 cnt = DataLength; 3 66038 while (cnt--) 4 66039 { 4 66040 if (*cptr == '\n' && ++nlcnt == 2) 5 66041 { 5 66042 /* two successive end-of-lines, therefore end of header */ 5 66043 cptr++; 5 66044 break; 4 66045 } 4 66046 else 4 66047 if (*cptr != '\r' && *cptr != '\n') 4 66048 nlcnt = 0; 4 66049 cptr++; 3 66050 } 3 66051 3 66052 if ((rqptr->rqResponse.HeaderNewlineCount = nlcnt) == 2) 4 66053 { 4 66054 /* adjust data pointer and length to exclude header */ 4 66055 rqptr->rqResponse.HeaderSent = true; 4 66056 DataLength = cptr - DataPtr; 4 66057 DataPtr = cptr; 3 66058 } 3 66059 else 4 66060 { 4 66061 /* no data in HTTP header left at all */ 4 66062 NetIoWriteStatus (ioptr, AstFunction, rqptr, SS$_NORMAL, 0); Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 52 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 4 66063 return (SS$_NORMAL); 3 66064 } 3 66065 3 66066 /* HTTP header has been completely absorbed, send everything else */ 3 66067 if (WATCHMOD (rqptr, WATCH_MOD_NET)) 3 66068 WatchThis (WATCHITM(rqptr), WATCH_MOD_NET, 3 66069 "HTTP/0.9 !&X !UL", DataPtr, DataLength); 2 66070 } 2 66071 2 66072 /*************/ 2 66073 /* send data */ 2 66074 /*************/ 2 66075 2 66076 if (WATCHING (rqptr, WATCH_RESPONSE_BODY)) 3 66077 { 3 66078 if (rqptr->rqResponse.HeaderSent) 3 66079 WatchThis (WATCHITM(rqptr), WATCH_RESPONSE_BODY, 3 66080 "BODY !UL bytes", DataLength); 3 66081 else 3 66082 WatchThis (WATCHITM(rqptr), WATCH_RESPONSE_BODY, 3 66083 "STREAM !UL bytes", DataLength); 3 66084 WatchDataDump (DataPtr, DataLength); 3 66085 3 66086 #if WATCH_MOD 3 66087 if (rqptr->rqResponse.ContentTypePtr && 3 66088 !strncmp (rqptr->rqResponse.ContentTypePtr, "text/", 5)) 4 66089 { 4 66090 if (DataLength && DataPtr[DataLength-1] == '\n') 4 66091 WatchDataFormatted ("!#AZ", DataLength, DataPtr); 4 66092 else 4 66093 WatchDataFormatted ("!#AZ\n", DataLength, DataPtr); 3 66094 } 3 66095 #endif /* WATCH_MOD */ 2 66096 } 2 66097 2 66098 if (rqptr->rqCache.LoadFromNet) 2 66099 CacheLoadData (rqptr, DataPtr, DataLength); 2 66100 2 66101 if (rqptr->rqResponse.CharsetNcsCf) 3 66102 { 3 66103 status = ResponseCharsetConvert (rqptr, &DataPtr, &DataLength); 3 66104 if (VMSnok (status)) 4 66105 { 4 66106 /* fudge the status */ 4 66107 NetIoWriteStatus (ioptr, AstFunction, rqptr, status, 0); 4 66108 return (status); 3 66109 } 2 66110 } 1 66111 } 1 66112 else 1 66113 if (DataPtr) 2 66114 { 2 66115 /****************/ 2 66116 /* "empty" data */ 2 66117 /****************/ 2 66118 2 66119 /* without a real network write just fudge the status */ Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 53 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 2 66120 NetIoWriteStatus (ioptr, AstFunction, rqptr, SS$_NORMAL, 0); 2 66121 return (SS$_NORMAL); 1 66122 } 1 66123 else 2 66124 { 2 66125 /*****************/ 2 66126 /* end-of-stream */ 2 66127 /*****************/ 2 66128 2 66129 if (rqptr->GzipCompress.DeflateStartStream && 2 66130 !rqptr->GzipCompress.DeflateEndOfStream) 3 66131 { 3 66132 /* indicates to GZIP to flush then close the deflate stream */ 3 66133 status = NetWriteGzip (rqptr, AstFunction, NULL, 0); 2 66134 } 2 66135 else 2 66136 if (rqptr->rqResponse.TransferEncodingChunked) 3 66137 { 3 66138 /* writes the end-of-content empty chunk */ 3 66139 status = NetWriteChunked (rqptr, AstFunction, NULL, 0); 2 66140 } 2 66141 else 3 66142 { 3 66143 /* without a real network write just fudge the status */ 3 66144 NetIoWriteStatus (ioptr, AstFunction, rqptr, status = SS$_NORMAL, 0); 2 66145 } 2 66146 return (status); 1 66147 } 1 66148 1 66149 /******************/ 1 66150 /* write the data */ 1 66151 /******************/ 1 66152 1 66153 WritingProxyResponseHeader = rqptr->ProxyTaskPtr && 1 66154 rqptr->ProxyTaskPtr->ResponseHeaderPtr && 1 66155 !rqptr->rqResponse.HeaderSent; 1 66156 if (rqptr->rqResponse.ContentEncodeAsGzip && !WritingProxyResponseHeader) 1 66157 status = NetWriteGzip (rqptr, AstFunction, DataPtr, DataLength); 1 66158 else 1 66159 if (rqptr->rqResponse.TransferEncodingChunked && !WritingProxyResponseHeader) 1 66160 status = NetWriteChunked (rqptr, AstFunction, DataPtr, DataLength); 1 66161 else 1 66162 if (!DataLength) 1 66163 NetIoWriteStatus (ioptr, AstFunction, rqptr, status = SS$_NORMAL, 0); 1 66164 else 1 66165 status = NetIoWrite (ioptr, AstFunction, rqptr, DataPtr, DataLength); 1 66166 1 66167 return (status); 1 66168 } 66169 66170 /*****************************************************************************/ 66171 /* 66172 The response content is being "Content-Encoding: gzip"ed. Due to the way the 66173 ZLIB compressed multiple consecutive input buffers before providing multiple 66174 consecutive output buffers this routine must be able to handle both independent 66175 of any other processing in the response. It may AST to NetWriteGzipAst() 66176 multiple times when outputing compressed data. It ASTs to 'AstFunction' Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 54 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 66177 (usually for more raw data) when any output ceases. 66178 */ 66179 66180 NetWriteGzip 66181 ( 66182 REQUEST_STRUCT *rqptr, 66183 REQUEST_AST AstFunction, 66184 char *DataPtr, 66185 int DataLength 66186 ) 1 66187 { 1 66188 int status, 1 66189 BufferSize, 1 66190 OutDataLength, 1 66191 SanityCount; 1 66192 char *OutDataPtr; 1 66193 GZIP_COMPRESS *gzptr; 1 66194 NETIO_STRUCT *ioptr; 1 66195 1 66196 /*********/ 1 66197 /* begin */ 1 66198 /*********/ 1 66199 1 66200 if (WATCHMOD (rqptr, WATCH_MOD_NET)) 1 66201 WatchThis (WATCHITM(rqptr), WATCH_MOD_NET, 1 66202 "NetWriteGzip() !&X !UL !&A", 1 66203 DataPtr, DataLength, AstFunction); 1 66204 1 66205 gzptr = &rqptr->GzipCompress; 1 66206 1 66207 ioptr = rqptr->NetIoPtr; 1 66208 ioptr->WatchItem = rqptr->WatchItem; 1 66209 1 66210 /* intermediate update to data transfer stats */ 1 66211 rqptr->NetIoPtr->BlocksRawTx64 = ioptr->BlocksRawTx64; 1 66212 rqptr->NetIoPtr->BytesRawTx64 = ioptr->BytesRawTx64; 1 66213 1 66214 if (!gzptr->DeflateStartStream) 2 66215 { 2 66216 if (DataLength <= OutputBufferSize) 2 66217 BufferSize = OutputBufferSize; 2 66218 else 2 66219 BufferSize = DataLength + (DataLength / 100) + 32; 2 66220 BufferSize &= 0x0000ffff; 2 66221 GzipDeflateBegin (rqptr, gzptr, BufferSize); 1 66222 } 1 66223 1 66224 /* blocking I/O may require multiple writes */ 1 66225 SanityCount = 0; 1 66226 for (;;) 2 66227 { 2 66228 /* if we didn't have or somehow have lost the zlib stream */ 2 66229 if (!gzptr->DeflateZstreamPtr) break; 2 66230 2 66231 if (!GzipDeflate (rqptr, gzptr, 2 66232 &DataPtr, &DataLength, 2 66233 &OutDataPtr, &OutDataLength)) break; Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 55 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 2 66234 2 66235 if (OutDataLength) 3 66236 { 3 66237 /* if non-blocking I/O then AST back here (eventually) for any more */ 3 66238 if (AstFunction) 4 66239 { 4 66240 rqptr->rqNet.GzipDataPtr = DataPtr; 4 66241 rqptr->rqNet.GzipDataLength = DataLength; 4 66242 rqptr->rqNet.GzipAstFunction = AstFunction; 4 66243 AstFunction = NetWriteGzipAst; 3 66244 } 3 66245 3 66246 if (rqptr->rqResponse.TransferEncodingChunked) 3 66247 status = NetWriteChunked (rqptr, AstFunction, 3 66248 OutDataPtr, OutDataLength); 3 66249 else 3 66250 status = NetIoWrite (ioptr, AstFunction, rqptr, 3 66251 OutDataPtr, OutDataLength); 3 66252 3 66253 if (AstFunction) return (status); 2 66254 } 2 66255 else 2 66256 if (!DataLength) 3 66257 { 3 66258 /* nothing still to input, nothing to write, fudge it */ 3 66259 NetIoWriteStatus (ioptr, AstFunction, rqptr, SS$_WASECC, 0); 3 66260 return (SS$_NORMAL); 2 66261 } 2 66262 if (SanityCount++ > 100) 3 66263 { 3 66264 /* don't quite trust my logic! */ 3 66265 ErrorNoticed (rqptr, SS$_BUGCHECK, ErrorSanityCheck, FI_LI); 3 66266 break; 2 66267 } 1 66268 } 1 66269 1 66270 /* only ever breaks from the loop on an error */ 1 66271 NetIoWriteStatus (ioptr, AstFunction, rqptr, SS$_ABORT, 0); 1 66272 return (SS$_ABORT); 1 66273 } 66274 66275 /*****************************************************************************/ 66276 /* 66277 AST delivered by asynchronous I/O initiated by NetWriteGzip(). Checks the 66278 status of the network write and if OK reassembles the parameters required when 66279 calling NetWriteGzip(). 66280 */ 66281 66282 NetWriteGzipAst (REQUEST_STRUCT *rqptr) 66283 1 66284 { 1 66285 int DataLength; 1 66286 char *DataPtr; 1 66287 NETIO_STRUCT *ioptr; 1 66288 REQUEST_AST AstFunction; 1 66289 1 66290 /*********/ Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 56 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 1 66291 /* begin */ 1 66292 /*********/ 1 66293 1 66294 ioptr = rqptr->NetIoPtr; 1 66295 ioptr->WatchItem = rqptr->WatchItem; 1 66296 1 66297 if (WATCHMOD (rqptr, WATCH_MOD_NET)) 1 66298 WatchThis (WATCHITM(rqptr), WATCH_MOD_NET, 1 66299 "NetWriteGzipAst() !&F !&S !&X !UL !&A", NetWriteGzipAst, 1 66300 ioptr->WriteStatus, 1 66301 rqptr->rqNet.GzipDataPtr, 1 66302 rqptr->rqNet.GzipDataLength, 1 66303 rqptr->rqNet.GzipAstFunction); 1 66304 1 66305 DataPtr = rqptr->rqNet.GzipDataPtr; 1 66306 DataLength = rqptr->rqNet.GzipDataLength; 1 66307 AstFunction = rqptr->rqNet.GzipAstFunction; 1 66308 rqptr->rqNet.GzipDataPtr = 1 66309 rqptr->rqNet.GzipDataLength = 1 66310 rqptr->rqNet.GzipAstFunction = 0; 1 66311 1 66312 if (VMSok (ioptr->WriteStatus)) 1 66313 NetWriteGzip (rqptr, AstFunction, DataPtr, DataLength); 1 66314 else 1 66315 NetIoWriteStatus (ioptr, AstFunction, rqptr, ioptr->WriteStatus, 0); 1 66316 } 66317 66318 /*****************************************************************************/ 66319 /* 66320 The response is being "Transfer-Encoding: chunked". 66321 66322 This is a little more complicated than it might have been in order improve the 66323 efficiency of non-encrypted (non-SSL) network I/O. 66324 66325 In the case of encrypted data a separate chunk buffer is allocated. In this 66326 buffer the chunk size string is placed, followed by a copy of the data, and 66327 then the required trailing arriage control. This involves the expensive 66328 copying of often large quantities of data, the reason why for non-encrypted 66329 data the buffer list is used, avoiding this processing overhead. 66330 */ 66331 66332 NetWriteChunked 66333 ( 66334 REQUEST_STRUCT *rqptr, 66335 REQUEST_AST AstFunction, 66336 char *DataPtr, 66337 int DataLength 66338 ) 1 66339 { 1 66340 static char ChunkBuf [32]; 1 66341 static $DESCRIPTOR (ChunkBufDsc, ChunkBuf); 1 66342 static $DESCRIPTOR (ChunkFaoDsc, "!XL\r\n\0"); 1 66343 1 66344 int size, status; 1 66345 char *cptr, *sptr; 1 66346 NETIO_STRUCT *ioptr; 1 66347 VMS_ITEM_LIST2 *p5ptr; Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 57 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 1 66348 1 66349 /*********/ 1 66350 /* begin */ 1 66351 /*********/ 1 66352 1 66353 if (WATCHMOD (rqptr, WATCH_MOD_NET)) 1 66354 WatchThis (WATCHITM(rqptr), WATCH_MOD_NET, "NetWriteChunked()"); 1 66355 1 66356 ioptr = rqptr->NetIoPtr; 1 66357 ioptr->WatchItem = rqptr->WatchItem; 1 66358 1 66359 /* intermediate update to data transfer stats */ 1 66360 rqptr->NetIoPtr->BlocksRawTx64 = ioptr->BlocksRawTx64; 1 66361 rqptr->NetIoPtr->BytesRawTx64 = ioptr->BytesRawTx64; 1 66362 1 66363 if (WATCHING (rqptr, WATCH_NETWORK_OCTETS)) 1 66364 WatchThis (WATCHITM(rqptr), WATCH_NETWORK, 1 66365 "CHUNK !UL bytes", DataLength); 1 66366 1 66367 /* if it's the zero-length chunk (end-of-stream) then it is no longer */ 1 66368 if (!DataLength) rqptr->rqResponse.TransferEncodingChunked = false; 1 66369 1 66370 size = rqptr->rqResponse.ChunkedBufferSize; 1 66371 sptr = rqptr->rqResponse.ChunkedBufferPtr; 1 66372 if (DataLength > size || !sptr) 2 66373 { 2 66374 while (DataLength > size) size += OutputBufferSize; 2 66375 if (sptr) VmFreeFromHeap (rqptr, sptr, FI_LI); 2 66376 sptr = VmGetHeap (rqptr, size + sizeof(ChunkBuf)); 2 66377 rqptr->rqResponse.ChunkedBufferPtr = sptr; 2 66378 rqptr->rqResponse.ChunkedBufferSize = size; 1 66379 } 1 66380 1 66381 sys$fao (&ChunkFaoDsc, 0, &ChunkBufDsc, DataLength); 1 66382 for (cptr = ChunkBuf; *cptr; *sptr++ = *cptr++); 1 66383 for (cptr = DataPtr; DataLength--; *sptr++ = *cptr++); 1 66384 *sptr++ = '\r'; 1 66385 *sptr++ = '\n'; 1 66386 1 66387 DataPtr = rqptr->rqResponse.ChunkedBufferPtr; 1 66388 DataLength = sptr - rqptr->rqResponse.ChunkedBufferPtr; 1 66389 1 66390 status = NetIoWrite (rqptr->NetIoPtr, AstFunction, rqptr, 1 66391 DataPtr, DataLength); 1 66392 return (status); 1 66393 } 66394 66395 /*****************************************************************************/ 66396 /* 66397 Write data directly to the network. No fancy stuff. 66398 */ 66399 66400 int NetWriteRaw 66401 ( 66402 REQUEST_STRUCT *rqptr, 66403 REQUEST_AST AstFunction, 66404 char *DataPtr, Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 58 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 66405 int DataLength 66406 ) 66407 1 66408 { 1 66409 int status; 1 66410 NETIO_STRUCT *ioptr; 1 66411 1 66412 /*********/ 1 66413 /* begin */ 1 66414 /*********/ 1 66415 1 66416 if (WATCHMOD (rqptr, WATCH_MOD_NET)) 1 66417 WatchThis (WATCHITM(rqptr), WATCH_MOD_NET, 1 66418 "NetWriteRaw() !&A !&X !UL", AstFunction, DataPtr, DataLength); 1 66419 1 66420 ioptr = rqptr->NetIoPtr; 1 66421 ioptr->WatchItem = rqptr->WatchItem; 1 66422 1 66423 status = NetIoWrite (ioptr, AstFunction, rqptr, DataPtr, DataLength); 1 66424 1 66425 return (status); 1 66426 } 66427 66428 /*****************************************************************************/ 66429 /* 66430 */ 66431 66432 int NetRead 66433 ( 66434 REQUEST_STRUCT *rqptr, 66435 REQUEST_AST AstFunction, 66436 char *DataPtr, 66437 int DataSize 66438 ) 1 66439 { 1 66440 int status; 1 66441 NETIO_STRUCT *ioptr; 1 66442 1 66443 /*********/ 1 66444 /* begin */ 1 66445 /*********/ 1 66446 1 66447 if (WATCHMOD (rqptr, WATCH_MOD_NET)) 1 66448 WatchThis (WATCHITM(rqptr), WATCH_MOD_NET, "NetRead() !&A !&X !UL", 1 66449 AstFunction, DataPtr, DataSize); 1 66450 1 66451 ioptr = rqptr->NetIoPtr; 1 66452 ioptr->WatchItem = rqptr->WatchItem; 1 66453 1 66454 /* intermediate update to data transfer stats */ 1 66455 rqptr->NetIoPtr->BlocksRawRx64 = ioptr->BlocksRawRx64; 1 66456 rqptr->NetIoPtr->BytesRawRx64 = ioptr->BytesRawRx64; 1 66457 1 66458 if (rqptr->rqNet.RedactBufferPtr) 2 66459 { 2 66460 int ReadCount = rqptr->rqNet.RedactBufferSize - 2 66461 rqptr->rqNet.RedactBufferCount; Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 59 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 2 66462 char *RedactBufferPtr = rqptr->rqNet.RedactBufferPtr + 2 66463 rqptr->rqNet.RedactBufferCount; 2 66464 2 66465 if (WATCHMOD (rqptr, WATCH_MOD_NET)) 2 66466 WatchThis (WATCHITM(rqptr), WATCH_MOD_NET, "REDACT !UL-!UL=!UL", 2 66467 rqptr->rqNet.RedactBufferSize, 2 66468 rqptr->rqNet.RedactBufferCount, 2 66469 ReadCount); 2 66470 2 66471 if (ReadCount >= DataSize) 3 66472 { 3 66473 /* redact buffer (still) contains more than a network buffer */ 3 66474 status = SS$_NORMAL; 3 66475 ReadCount = DataSize; 3 66476 memcpy (DataPtr, RedactBufferPtr, ReadCount); 3 66477 rqptr->rqNet.RedactBufferCount += ReadCount; 2 66478 } 2 66479 else 2 66480 if (ReadCount) 3 66481 { 3 66482 /* whatever is remaining */ 3 66483 status = SS$_NORMAL; 3 66484 memcpy (DataPtr, RedactBufferPtr, ReadCount); 3 66485 rqptr->rqNet.RedactBufferCount += ReadCount; 2 66486 } 2 66487 else 3 66488 { 3 66489 /* redact buffer has been completely read */ 3 66490 status = SS$_ENDOFFILE; 3 66491 ReadCount = 0; 2 66492 } 2 66493 2 66494 NetIoReadStatus (ioptr, AstFunction, rqptr, status, ReadCount); 2 66495 return (status); 1 66496 } 1 66497 1 66498 if (rqptr->ServicePtr->ProxyTunnel == PROXY_TUNNEL_RAW && 1 66499 /* prevent %CC-E-NOEQUALITY under VAX VMS V7.3 and DECC V6.4 */ 1 66500 (void*)AstFunction == (void*)RequestGet) 2 66501 { 2 66502 /* 2 66503 For raw proxy tunneling, we need to send a connect request to 2 66504 the origin server immediately since the client will wait until it 2 66505 receives the server welcome message. This should be done only once 2 66506 upon SSL handshake completion. 2 66507 */ 2 66508 /* fudge these as if it came from the network */ 2 66509 NetIoReadStatus (ioptr, RequestGet, rqptr, SS$_NORMAL, 0); 2 66510 return (SS$_NORMAL); 1 66511 } 1 66512 1 66513 status = NetIoRead (ioptr, AstFunction, rqptr, DataPtr, DataSize); 1 66514 1 66515 return (status); 1 66516 } 66517 66518 /*****************************************************************************/ Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 60 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 66519 /* 66520 This function buffers output without actually sending it to the client until 66521 ready, either when the first buffer fills or when all output is completely 66522 buffered. It will store any amount of output in a linked list of separately 66523 allocated descriptors. This is useful when a function that must not be 66524 interrupted can rapidly store all required output without being slowed by 66525 actually transfering it on the network, then flush it all asynchronously (e.g. 66526 the server administration reports, for instance CacheReport(), which are 66527 blocking). 66528 66529 If the data pointer is not NULL and the data length is -1 then the data is 66530 assumed to be a null-terminated string. 66531 66532 Providing an AST parameter and a data parameter implies that after the first 66533 buffer fills (and usually overflows into a second) the current buffered output 66534 should be written to the client. 66535 66536 Providing an AST parameter and setting the data parameter to NULL and 66537 the data length to 0 indicates all the currently buffered contents should be 66538 written to the client. 66539 66540 Providing an AST parameter and setting the data parameter to NULL and the data 66541 length parameter to -1 indicates all the currently buffered contents should be 66542 written to the client if more than buffer-full has been written, otherwise just 66543 declare the AST. 66544 66545 Providing all parameters as NULL and zero, (except 'rqptr') as appropriate, 66546 results in the data buffer initialized (if it didn't exist) or reset (if it 66547 did). 66548 */ 66549 66550 void NetWriteBuffered 66551 ( 66552 REQUEST_STRUCT *rqptr, 66553 REQUEST_AST AstFunction, 66554 char *DataPtr, 66555 int DataLength 66556 ) 1 66557 { 1 66558 int status; 1 66559 char *BufferPtr; 1 66560 STR_DSC *sdptr; 1 66561 STR_DSC_AUTO (DataDsc); 1 66562 1 66563 /*********/ 1 66564 /* begin */ 1 66565 /*********/ 1 66566 1 66567 if (WATCHMOD (rqptr, WATCH_MOD_NET)) 2 66568 { 2 66569 WatchThis (WATCHITM(rqptr), WATCH_MOD_NET, 2 66570 "NetWriteBuffered() !&A !&X !SL", 2 66571 AstFunction, DataPtr, DataLength); 2 66572 WatchDataDump (DataPtr, DataLength); 1 66573 } 1 66574 1 66575 /* if all parameters empty */ Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 61 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 1 66576 if (!AstFunction && !DataPtr && !DataLength) 2 66577 { 2 66578 /* reset the descriptor */ 2 66579 if (STR_DSC_SANITY(&rqptr->NetWriteBufferDsc)) 3 66580 { 3 66581 /* if there is data in the descriptor write it blocking */ 3 66582 if (STR_DSC_LEN (&rqptr->NetWriteBufferDsc)) 3 66583 NetWriteStrDsc (rqptr, NULL); 3 66584 StrDscNoContent (&rqptr->NetWriteBufferDsc); 2 66585 } 2 66586 else 2 66587 StrDscBegin (rqptr, &rqptr->NetWriteBufferDsc, 2 66588 rqptr->NetIoPtr->TcpMaxSeg); 2 66589 return; 1 66590 } 1 66591 1 66592 if (DataPtr && DataLength) 2 66593 { 2 66594 /**********************/ 2 66595 /* buffer this output */ 2 66596 /**********************/ 2 66597 2 66598 if (!STR_DSC_SANITY(&rqptr->NetWriteBufferDsc)) 2 66599 StrDscBegin (rqptr, &rqptr->NetWriteBufferDsc, 2 66600 rqptr->NetIoPtr->TcpMaxSeg); 2 66601 2 66602 if (rqptr->NetWriteEscapeHtml) 3 66603 { 3 66604 if (DataLength == -1) 3 66605 StrDscBuildHtmlEscape (&rqptr->NetWriteBufferDsc, NULL, DataPtr); 3 66606 else 4 66607 { 4 66608 StrDscThis (NULL, &DataDsc, DataPtr, DataLength); 4 66609 StrDscBuildHtmlEscape (&rqptr->NetWriteBufferDsc, &DataDsc, NULL); 3 66610 } 2 66611 } 2 66612 else 3 66613 { 3 66614 if (DataLength == -1) 3 66615 StrDscBuild (&rqptr->NetWriteBufferDsc, NULL, DataPtr); 3 66616 else 4 66617 { 4 66618 StrDscThis (NULL, &DataDsc, DataPtr, DataLength); 4 66619 StrDscBuild (&rqptr->NetWriteBufferDsc, &DataDsc, NULL); 3 66620 } 2 66621 } 1 66622 } 1 66623 1 66624 /* if an AST routine supplied then we can think about buffer flushing */ 1 66625 if (!AstFunction) return; 1 66626 1 66627 if (!DataPtr && DataLength != -1) 2 66628 { 2 66629 /*************************/ 2 66630 /* flush is being forced */ 2 66631 /*************************/ 2 66632 Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 62 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 2 66633 NetWriteStrDsc (rqptr, AstFunction); 2 66634 return; 1 66635 } 1 66636 1 66637 if (STR_DSC_LEN(&rqptr->NetWriteBufferDsc) >= 1 66638 STR_DSC_SIZE(&rqptr->NetWriteBufferDsc)) 2 66639 { 2 66640 /************************/ 2 66641 /* first buffer is full */ 2 66642 /************************/ 2 66643 2 66644 rqptr->NetWriteFlushOnly = true; 2 66645 NetWriteStrDsc (rqptr, AstFunction); 2 66646 return; 1 66647 } 1 66648 1 66649 /************************/ 1 66650 /* just declare the AST */ 1 66651 /************************/ 1 66652 1 66653 /* fudge this status for the AST routine check */ 1 66654 NetIoWriteStatus (rqptr->NetIoPtr, AstFunction, rqptr, SS$_NORMAL, 0); 1 66655 } 66656 66657 /*****************************************************************************/ 66658 /* 66659 Synchronous (no AST function supplied) or asynchronous write of a WASD string 66660 descriptor or linked list of string descriptors. Where multiple writes are 66661 required this function will be delivered to as an AST (and then the 66662 'AstFunction' parameter is ignored). 66663 */ 66664 66665 void NetWriteStrDsc 66666 ( 66667 REQUEST_STRUCT *rqptr, 66668 REQUEST_AST AstFunction 66669 ) 1 66670 { 1 66671 BOOL BlockingWrite; 1 66672 int DataLength; 1 66673 char *DataPtr, 1 66674 *EndPtr; 1 66675 NETIO_STRUCT *ioptr; 1 66676 STR_DSC *sdptr; 1 66677 1 66678 /*********/ 1 66679 /* begin */ 1 66680 /*********/ 1 66681 1 66682 if (WATCHMOD (rqptr, WATCH_MOD_NET)) 1 66683 WatchThis (WATCHITM(rqptr), WATCH_MOD_NET, 1 66684 "NetWriteStrDsc() !&F !&A", &NetWriteStrDsc, 1 66685 rqptr->NetWriteAstFunction); 1 66686 1 66687 ioptr = rqptr->NetIoPtr; 1 66688 ioptr->WatchItem = rqptr->WatchItem; 1 66689 Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 63 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 1 66690 /* loop for (possible) blocking write */ 1 66691 BlockingWrite = false; 1 66692 for (;;) 2 66693 { 2 66694 if (BlockingWrite || rqptr->NetWriteAstFunction) 3 66695 { 3 66696 /* blocking write loop or AST delivery */ 3 66697 if (VMSnok (ioptr->WriteStatus)) 4 66698 { 4 66699 /* network write has failed, bail out now */ 4 66700 NetIoWriteStatus (ioptr, rqptr->NetWriteAstFunction, rqptr, 4 66701 ioptr->WriteStatus, 0); 4 66702 rqptr->NetWriteAstFunction = NULL; 4 66703 StrDscNoContent (&rqptr->NetWriteBufferDsc); 4 66704 return; 3 66705 } 3 66706 3 66707 /* find the descriptor having content */ 3 66708 STR_DSC_ITERATE (sdptr, &rqptr->NetWriteBufferDsc) 3 66709 if (STR_DSC_LEN(sdptr)) break; 3 66710 3 66711 if (!sdptr) ErrorExitVmsStatus (SS$_BUGCHECK, ErrorSanityCheck, FI_LI); 2 66712 } 2 66713 else 3 66714 { 3 66715 /* initial call */ 3 66716 if (!rqptr) ErrorExitVmsStatus (SS$_BUGCHECK, ErrorSanityCheck, FI_LI); 3 66717 BlockingWrite = !(rqptr->NetWriteAstFunction = AstFunction); 3 66718 rqptr->NetWriteBufferCount = 0; 3 66719 sdptr = &rqptr->NetWriteBufferDsc; 2 66720 } 2 66721 2 66722 EndPtr = STR_DSC_PTR(sdptr) + STR_DSC_LEN(sdptr); 2 66723 DataPtr = STR_DSC_PTR(sdptr) + rqptr->NetWriteBufferCount; 2 66724 DataLength = EndPtr - DataPtr; 2 66725 rqptr->NetWriteBufferCount += DataLength; 2 66726 2 66727 if (!BlockingWrite) AstFunction = &NetWriteStrDsc; 2 66728 2 66729 if (rqptr->NetWriteBufferCount >= STR_DSC_LEN(sdptr)) 3 66730 { 3 66731 /* this is the final write for this descriptor */ 3 66732 rqptr->NetWriteBufferCount = STR_DSC_LEN(sdptr) = 0; 3 66733 3 66734 if (rqptr->NetWriteFlushOnly) 4 66735 { 4 66736 /* output all (if multiple) leading full descriptors */ 4 66737 if (!STR_DSC_NEXT(sdptr) || 4 66738 STR_DSC_LEN(STR_DSC_NEXT(sdptr)) < 4 66739 STR_DSC_SIZE(STR_DSC_NEXT(sdptr))) 5 66740 { 5 66741 /* less than full (or none at all) */ 5 66742 rqptr->NetWriteFlushOnly = false; 5 66743 if (STR_DSC_NEXT(sdptr)) 6 66744 { 6 66745 /* swap the now-emptied and partially filled storage */ 6 66746 StrDscStorageSwap (&rqptr->NetWriteBufferDsc, Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 64 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 6 66747 STR_DSC_NEXT(sdptr)); 5 66748 } 5 66749 sdptr = NULL; 4 66750 } 3 66751 } 3 66752 else 4 66753 { 4 66754 /* find the next (if any) descriptor having content */ 4 66755 for (sdptr = STR_DSC_NEXT(sdptr); sdptr; sdptr = STR_DSC_NEXT(sdptr)) 4 66756 if (STR_DSC_LEN(sdptr)) break; 3 66757 } 3 66758 3 66759 if (!sdptr) 4 66760 { 4 66761 /* final write entirely */ 4 66762 AstFunction = rqptr->NetWriteAstFunction; 4 66763 rqptr->NetWriteAstFunction = NULL; 4 66764 BlockingWrite = false; 3 66765 } 2 66766 } 2 66767 2 66768 NetWrite (rqptr, AstFunction, DataPtr, DataLength); 2 66769 2 66770 if (!BlockingWrite || AstFunction) return; 1 66771 } 1 66772 } 66773 66774 /*****************************************************************************/ 66775 /* 66776 This function MUST be called with the global section ALREADY locked. 66777 Increment or decrement the counters of current network connections. Account 66778 for HTTP/2 and HTTP/1.n connections separately. Global storage represents data 66779 of the running image and process (i.e. this instance) and accounting data 66780 the server overall (where multiple instances are deployed). 66781 */ 66782 66783 void NetUpdateConnected 66784 ( 66785 void *DataPtr, 66786 int MoreOrLess 66787 ) 1 66788 { 1 66789 int idx, tot1, tot2; 1 66790 ACCOUNTING_STRUCT *accptr; 1 66791 HTTP2_STRUCT *h2ptr = NULL; 1 66792 REQUEST_STRUCT *rqptr = NULL; 1 66793 1 66794 /*********/ 1 66795 /* begin */ 1 66796 /*********/ 1 66797 1 66798 accptr = AccountingPtr; 1 66799 1 66800 if (!DataPtr) 1 66801 h2ptr = rqptr = NULL; 1 66802 else 1 66803 if (((LIST_ENTRY*)DataPtr)->DataType == LIST_ENTRY_TYPE_HTTP2) Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 65 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 1 66804 h2ptr = (HTTP2_STRUCT*)DataPtr; 1 66805 else 1 66806 if (((LIST_ENTRY*)DataPtr)->DataType == LIST_ENTRY_TYPE_REQUEST) 1 66807 rqptr = (REQUEST_STRUCT*)DataPtr; 1 66808 /* else an accepted connection is not a "request" until RequestBegin() */ 1 66809 1 66810 if (WATCH_MODULE(WATCH_MOD_NET)) 1 66811 WatchThis (WATCHALL, WATCH_MOD_NET, 1 66812 "NetUpdateConnected() !SL !AZ !UL+!UL=!UL", 1 66813 MoreOrLess, h2ptr ? "HTTP/2" : "HTTP/1.n", 1 66814 NetCurrentConnected[HTTP1], NetCurrentConnected[HTTP2], 1 66815 NetCurrentConnected[HTTP12]); 1 66816 1 66817 if (MoreOrLess > 0) 2 66818 { 2 66819 /************/ 2 66820 /* one more */ 2 66821 /************/ 2 66822 2 66823 if (rqptr) 3 66824 { 3 66825 NetCurrentConnected[HTTP1]++; 3 66826 accptr->CurrentInstanceConnected[HTTP1][InstanceNumber] = 3 66827 NetCurrentConnected[HTTP1]; 3 66828 /* total connections only increase with HTTP/1.n */ 3 66829 accptr->ConnectCount[HTTP12]++; 2 66830 } 2 66831 else 2 66832 if (h2ptr) 3 66833 { 3 66834 NetCurrentConnected[HTTP2]++; 3 66835 accptr->CurrentInstanceConnected[HTTP2][InstanceNumber] = 3 66836 NetCurrentConnected[HTTP2]; 2 66837 } 2 66838 else 2 66839 ErrorNoticed (NULL, SS$_BUGCHECK, NULL, FI_LI); 1 66840 } 1 66841 else 1 66842 if (MoreOrLess < 0) 2 66843 { 2 66844 /************/ 2 66845 /* one less */ 2 66846 /************/ 2 66847 2 66848 if (rqptr) 3 66849 { 3 66850 if (NetCurrentConnected[HTTP1]) NetCurrentConnected[HTTP1]--; 3 66851 accptr->CurrentInstanceConnected[HTTP1][InstanceNumber] = 3 66852 NetCurrentConnected[HTTP1]; 3 66853 3 66854 if (rqptr->WebSocketRequest) 4 66855 { 4 66856 if (WebSockCurrent) WebSockCurrent--; 4 66857 accptr->CurrentWebSockets[InstanceNumber] = WebSockCurrent; 3 66858 } 2 66859 } 2 66860 else Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 66 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 2 66861 if (h2ptr) 3 66862 { 3 66863 if (NetCurrentConnected[HTTP2]) NetCurrentConnected[HTTP2]--; 3 66864 accptr->CurrentInstanceConnected[HTTP2][InstanceNumber] = 3 66865 NetCurrentConnected[HTTP2]; 2 66866 } 2 66867 else 2 66868 ErrorNoticed (NULL, SS$_BUGCHECK, NULL, FI_LI); 1 66869 } 1 66870 /* else if zero then just drop through to re-accumulate accounting */ 1 66871 1 66872 /**************/ 1 66873 /* accumulate */ 1 66874 /**************/ 1 66875 1 66876 NetCurrentConnected[HTTP12] = NetCurrentConnected[HTTP1] + 1 66877 NetCurrentConnected[HTTP2]; 1 66878 1 66879 for (tot1 = tot2 = idx = 0; idx <= InstanceNodeCurrent; idx++) 2 66880 { 2 66881 tot1 += accptr->CurrentInstanceConnected[HTTP1][idx]; 2 66882 tot2 += accptr->CurrentInstanceConnected[HTTP2][idx]; 1 66883 } 1 66884 1 66885 if (NetCurrentConnected[HTTP1] > accptr->ConnectPeak[HTTP1]) 1 66886 accptr->ConnectPeak[HTTP1] = NetCurrentConnected[HTTP1]; 1 66887 accptr->CurrentConnected[HTTP1] = tot1; 1 66888 if (tot1 > accptr->ConnectPeak[HTTP1]) accptr->ConnectPeak[HTTP1] = tot1; 1 66889 1 66890 if (NetCurrentConnected[HTTP2] > accptr->ConnectPeak[HTTP2]) 1 66891 accptr->ConnectPeak[HTTP2] = NetCurrentConnected[HTTP2]; 1 66892 accptr->CurrentConnected[HTTP2] = tot2; 1 66893 if (tot2 > accptr->ConnectPeak[HTTP2]) accptr->ConnectPeak[HTTP2] = tot2; 1 66894 1 66895 accptr->CurrentConnected[HTTP12] = tot1 + tot2; 1 66896 if (accptr->CurrentConnected[HTTP12] > accptr->ConnectPeak[HTTP12]) 1 66897 accptr->ConnectPeak[HTTP12] = accptr->CurrentConnected[HTTP12]; 1 66898 1 66899 if (WATCH_MODULE(WATCH_MOD_NET)) 1 66900 WatchThis (WATCHALL, WATCH_MOD_NET, "!AZ!AZ!UL+!UL=!UL !UL+!UL=!UL", 1 66901 h2ptr ? "HTTP/2 " : "", 1 66902 rqptr ? "HTTP/1.n " : "", 1 66903 NetCurrentConnected[HTTP1], NetCurrentConnected[HTTP2], 1 66904 NetCurrentConnected[HTTP12], tot1, tot2, 1 66905 accptr->CurrentConnected[HTTP12]); 1 66906 } 66907 66908 /*****************************************************************************/ 66909 /* 66910 This function MUST be called with the global section ALREADY locked. 66911 Increment or decrement the counters of currently processing requests. Account 66912 for HTTP/2 and HTTP/1.n requests separately. Global storage represents data of 66913 the running image and process (i.e. this instance) and accounting data the 66914 server overall (where multiple instances are deployed). 66915 */ 66916 66917 void NetUpdateProcessing Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 67 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 66918 ( 66919 void *DataPtr, 66920 int MoreOrLess 66921 ) 1 66922 { 1 66923 int idx, tot1, tot2; 1 66924 ACCOUNTING_STRUCT *accptr; 1 66925 HTTP2_STRUCT *h2ptr = NULL; 1 66926 REQUEST_STRUCT *rqptr = NULL; 1 66927 1 66928 /*********/ 1 66929 /* begin */ 1 66930 /*********/ 1 66931 1 66932 accptr = AccountingPtr; 1 66933 1 66934 if (!DataPtr) 1 66935 h2ptr = rqptr = NULL; 1 66936 else 1 66937 if (((LIST_ENTRY*)DataPtr)->DataType == LIST_ENTRY_TYPE_REQUEST) 2 66938 { 2 66939 rqptr = (REQUEST_STRUCT*)DataPtr; 2 66940 if (HTTP2_REQUEST(rqptr) && 2 66941 (h2ptr = rqptr->Http2Ptr)) rqptr = NULL; 1 66942 } 1 66943 else 1 66944 ErrorExitVmsStatus (SS$_BUGCHECK, ErrorSanityCheck, FI_LI); 1 66945 1 66946 if (WATCH_MODULE(WATCH_MOD_NET)) 1 66947 WatchThis (WATCHALL, WATCH_MOD_NET, 1 66948 "NetUpdateProcessing() !SL !AZ !UL+!UL=!UL", 1 66949 MoreOrLess, h2ptr ? "HTTP/2" : "HTTP/1.n", 1 66950 NetCurrentProcessing[HTTP1], NetCurrentProcessing[HTTP2], 1 66951 NetCurrentProcessing[HTTP12]); 1 66952 1 66953 if (MoreOrLess > 0) 2 66954 { 2 66955 /************/ 2 66956 /* one more */ 2 66957 /************/ 2 66958 2 66959 InstanceStatusRequestCount++; 2 66960 accptr->ProcessingTotalCount[HTTP12]++; 2 66961 2 66962 if (rqptr) 3 66963 { 3 66964 NetCurrentProcessing[HTTP1]++; 3 66965 accptr->CurrentInstanceProcessing[HTTP1][InstanceNumber] = 3 66966 NetCurrentProcessing[HTTP1]; 3 66967 accptr->ProcessingTotalCount[HTTP1]++; 3 66968 3 66969 if (rqptr->ServicePtr->RequestScheme == SCHEME_HTTPS) 3 66970 AccountingPtr->RequestSSLCount++; 2 66971 } 2 66972 else 2 66973 if (h2ptr) 3 66974 { Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 68 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 3 66975 NetCurrentProcessing[HTTP2]++; 3 66976 accptr->CurrentInstanceProcessing[HTTP2][InstanceNumber] = 3 66977 NetCurrentProcessing[HTTP2]; 3 66978 accptr->ProcessingTotalCount[HTTP2]++; 3 66979 3 66980 if (h2ptr->ServicePtr->RequestScheme == SCHEME_HTTPS) 3 66981 AccountingPtr->RequestSSLCount++; 2 66982 } 2 66983 else 2 66984 ErrorNoticed (NULL, SS$_BUGCHECK, NULL, FI_LI); 1 66985 } 1 66986 else 1 66987 if (MoreOrLess < 0) 2 66988 { 2 66989 /************/ 2 66990 /* one less */ 2 66991 /************/ 2 66992 2 66993 if (rqptr) 3 66994 { 3 66995 if (NetCurrentProcessing[HTTP1]) NetCurrentProcessing[HTTP1]--; 3 66996 accptr->CurrentInstanceProcessing[HTTP1][InstanceNumber] = 3 66997 NetCurrentProcessing[HTTP1]; 3 66998 3 66999 if (rqptr->WebSocketRequest) 4 67000 { 4 67001 if (WebSockCurrent) WebSockCurrent--; 4 67002 accptr->CurrentWebSockets[InstanceNumber] = WebSockCurrent; 3 67003 } 2 67004 } 2 67005 else 2 67006 if (h2ptr) 3 67007 { 3 67008 if (NetCurrentProcessing[HTTP2]) NetCurrentProcessing[HTTP2]--; 3 67009 accptr->CurrentInstanceProcessing[HTTP2][InstanceNumber] = 3 67010 NetCurrentProcessing[HTTP2]; 2 67011 } 2 67012 else 2 67013 ErrorNoticed (NULL, SS$_BUGCHECK, NULL, FI_LI); 1 67014 } 1 67015 /* else if zero then just drop through to re-accumulate accounting */ 1 67016 1 67017 /**************/ 1 67018 /* accumulate */ 1 67019 /**************/ 1 67020 1 67021 NetCurrentProcessing[HTTP12] = NetCurrentProcessing[HTTP1] + 1 67022 NetCurrentProcessing[HTTP2]; 1 67023 1 67024 for (tot1 = tot2 = idx = 0; idx <= InstanceNodeCurrent; idx++) 2 67025 { 2 67026 tot1 += accptr->CurrentInstanceProcessing[HTTP1][idx]; 2 67027 tot2 += accptr->CurrentInstanceProcessing[HTTP2][idx]; 1 67028 } 1 67029 1 67030 accptr->CurrentProcessing[HTTP1] = tot1; 1 67031 if (tot1 > accptr->ProcessingPeak[HTTP1]) Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 69 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 1 67032 accptr->ProcessingPeak[HTTP1] = tot1; 1 67033 accptr->CurrentProcessing[HTTP2] = tot2; 1 67034 if (tot2 > accptr->ProcessingPeak[HTTP2]) 1 67035 accptr->ProcessingPeak[HTTP2] = tot2; 1 67036 accptr->CurrentProcessing[HTTP12] = tot1 + tot2; 1 67037 if (accptr->CurrentProcessing[HTTP12] > accptr->ProcessingPeak[HTTP12]) 1 67038 accptr->ProcessingPeak[HTTP12] = accptr->CurrentProcessing[HTTP12]; 1 67039 1 67040 if (WATCH_MODULE(WATCH_MOD_NET)) 1 67041 WatchThis (WATCHALL, WATCH_MOD_NET, "!UL+!UL=!UL !UL+!UL=!UL", 1 67042 NetCurrentProcessing[HTTP1], NetCurrentProcessing[HTTP2], 1 67043 NetCurrentProcessing[HTTP12], tot1, tot2, 1 67044 accptr->CurrentProcessing[HTTP12]); 1 67045 } 67046 67047 /*****************************************************************************/ 67048 /* 67049 This function MUST be called with the global section ALREADY locked. 67050 Increment or decrement the current count of persistent connections. 67051 */ 67052 67053 void NetUpdatePersistent (int MoreOrLess) 67054 1 67055 { 1 67056 int idx, tot1; 1 67057 ACCOUNTING_STRUCT *accptr; 1 67058 1 67059 /*********/ 1 67060 /* begin */ 1 67061 /*********/ 1 67062 1 67063 if (WATCH_MODULE(WATCH_MOD_NET)) 1 67064 WatchThis (WATCHALL, WATCH_MOD_NET, "NetUpdatePersistent() !SL !UL", 1 67065 MoreOrLess, NetCurrentHttp1Persistent); 1 67066 1 67067 accptr = AccountingPtr; 1 67068 1 67069 if (MoreOrLess > 0) 2 67070 { 2 67071 NetCurrentHttp1Persistent++; 2 67072 accptr->CurrentPersistentHttp1[InstanceNumber] = 2 67073 NetCurrentHttp1Persistent; 1 67074 } 1 67075 else 1 67076 if (MoreOrLess < 0) 2 67077 { 2 67078 if (NetCurrentHttp1Persistent) NetCurrentHttp1Persistent--; 2 67079 accptr->CurrentPersistentHttp1[InstanceNumber] = 2 67080 NetCurrentHttp1Persistent; 1 67081 } 1 67082 /* else if zero then just drop through to re-accumulate accounting */ 1 67083 1 67084 for (tot1 = idx = 0; idx <= InstanceNodeCurrent; idx++) 1 67085 tot1 += accptr->CurrentPersistentHttp1[idx]; 1 67086 accptr->CurrentHttp1Persistent = tot1; 1 67087 if (accptr->CurrentHttp1Persistent > accptr->ConnectPeakPersistent) 1 67088 accptr->ConnectPeakPersistent = accptr->CurrentHttp1Persistent; Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 70 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 1 67089 1 67090 if (WATCH_MODULE(WATCH_MOD_NET)) 1 67091 WatchThis (WATCHALL, WATCH_MOD_NET, "!UL !UL", 1 67092 NetCurrentHttp1Persistent, tot1); 1 67093 } 67094 67095 /*****************************************************************************/ 67096 /* 67097 Respond direct to the client without beginning request processing. Read 67098 something from the client, they seem to enjoy (need) that! These responses 67099 are completely independent of the main request processing life-cycle. These 67100 functions should only be used from NetAcceptProcess()!! 67101 */ 67102 67103 NetDirectResponse 67104 ( 67105 NETIO_STRUCT *ioptr, 67106 int Message 67107 ) 1 67108 { 1 67109 static $DESCRIPTOR (BufferDsc, ""); 1 67110 1 67111 static $DESCRIPTOR (TooBusyFaoDsc, 1 67112 "HTTP/1.1 503 Too busy!!\r\n\ 1 67113 Content-Type: text/html!AZ!AZ\r\n\ 1 67114 Connection: close\r\n\ 1 67115 \r\n\ 1 67116 !AZ\ 1 67117 \n\ 1 67118 \n\ 1 67119 !AZ 503\n\ 1 67120 \n\ 1 67121 !AZ\n\ 1 67122 !AZ\n\ 1 67123 \n\ 1 67124 \n"); 1 67125 1 67126 static $DESCRIPTOR (ForbiddenFaoDsc, 1 67127 "HTTP/1.1 403 Forbidden\r\n\ 1 67128 Content-Type: text/html!AZ!AZ\r\n\ 1 67129 Connection: close\r\n\ 1 67130 \r\n\ 1 67131 !AZ\ 1 67132 \n\ 1 67133 \n\ 1 67134 !AZ 403\n\ 1 67135 \n\ 1 67136 !AZ\n\ 1 67137 !AZ\n\ 1 67138 \n\ 1 67139 \n"); 1 67140 1 67141 int status; 1 67142 short slen; 1 67143 IO_SB IOsb; 1 67144 1 67145 /*********/ Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 71 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 1 67146 /* begin */ 1 67147 /*********/ 1 67148 1 67149 if (WATCH_MODULE(WATCH_MOD_NET)) 1 67150 WatchThis (WATCHALL, WATCH_MOD_NET, 1 67151 "NetDirectResponse() !UL", Message); 1 67152 1 67153 status = sys$setimr (0, &Delta05Sec, 1 67154 &NetDirectResponseTimeoutAst, ioptr, 0); 1 67155 if (VMSnok (status)) 2 67156 { 2 67157 ErrorNoticed (NULL, status, NULL, FI_LI); 2 67158 sys$dassgn (ioptr->Channel); 2 67159 VmFree (ioptr, FI_LI); 2 67160 return; 1 67161 } 1 67162 1 67163 ioptr->ReadPtr = VmGet (NetReadBufferSize); 1 67164 1 67165 BufferDsc.dsc$a_pointer = ioptr->ReadPtr; 1 67166 BufferDsc.dsc$w_length = NetReadBufferSize; 1 67167 1 67168 if (Message == MSG_GENERAL_ACCESS_DENIED) 1 67169 sys$fao (&ForbiddenFaoDsc, &slen, &BufferDsc, 1 67170 Config.cfContent.CharsetDefault[0] ? "; charset=" : "", 1 67171 Config.cfContent.CharsetDefault, 1 67172 WASD_DOCTYPE, 1 67173 MsgFor (NULL, MSG_STATUS_ERROR), 1 67174 REPORT_BODY_TAG, 1 67175 MsgFor (NULL, MSG_GENERAL_ACCESS_DENIED)); 1 67176 else 1 67177 if (Message == MSG_GENERAL_TOO_BUSY) 1 67178 sys$fao (&TooBusyFaoDsc, &slen, &BufferDsc, 1 67179 Config.cfContent.CharsetDefault[0] ? "; charset=" : "", 1 67180 Config.cfContent.CharsetDefault, 1 67181 WASD_DOCTYPE, 1 67182 MsgFor (NULL, MSG_STATUS_ERROR), 1 67183 REPORT_BODY_TAG, 1 67184 MsgFor (NULL, MSG_GENERAL_TOO_BUSY)); 1 67185 else 1 67186 ErrorExitVmsStatus (SS$_BUGCHECK, ErrorSanityCheck, FI_LI); 1 67187 1 67188 status = sys$qiow (EfnWait, ioptr->Channel, 1 67189 IO$_WRITEVBLK | IO$M_NOWAIT, 1 67190 &IOsb, 0, 0, ioptr->ReadPtr, slen, 1 67191 0, 0, 0, 0); 1 67192 if (VMSok (status)) status = IOsb.Status; 1 67193 if (VMSok (status)) 2 67194 { 2 67195 status = sys$qio (EfnNoWait, ioptr->Channel, 2 67196 IO$_READVBLK, &ioptr->WriteIOsb, 2 67197 &NetDirectResponseAst, ioptr, 2 67198 ioptr->ReadPtr, NetReadBufferSize, 2 67199 0, 0, 0, 0); 2 67200 if (VMSnok (status)) ErrorNoticed (NULL, status, NULL, FI_LI); 1 67201 } 1 67202 else Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 72 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 1 67203 ErrorNoticed (NULL, status, NULL, FI_LI); 1 67204 1 67205 if (VMSnok (status)) 2 67206 { 2 67207 VmFree (ioptr->ReadPtr, FI_LI); 2 67208 NetIoEnd (ioptr); 1 67209 } 1 67210 } 67211 67212 /*****************************************************************************/ 67213 /* 67214 See commentary in NetDirectResponse(). 67215 */ 67216 67217 NetDirectResponseAst (NETIO_STRUCT *ioptr) 67218 1 67219 { 1 67220 /*********/ 1 67221 /* begin */ 1 67222 /*********/ 1 67223 1 67224 if (WATCH_MODULE(WATCH_MOD_NET)) 1 67225 WatchThis (WATCHALL, WATCH_MOD_NET, "NetDirectResponseAst()"); 1 67226 1 67227 sys$cantim (ioptr, 0); 1 67228 VmFree (ioptr->ReadPtr, FI_LI); 1 67229 NetIoEnd (ioptr); 1 67230 } 67231 67232 /*****************************************************************************/ 67233 /* 67234 See commentary in NetDirectResponse(). 67235 */ 67236 67237 NetDirectResponseTimeoutAst (NETIO_STRUCT *ioptr) 67238 1 67239 { 1 67240 /*********/ 1 67241 /* begin */ 1 67242 /*********/ 1 67243 1 67244 if (WATCH_MODULE(WATCH_MOD_NET)) 1 67245 WatchThis (WATCHALL, WATCH_MOD_NET, "NetDirectResponseTimeoutAst()"); 1 67246 1 67247 sys$cancel (ioptr->Channel); 1 67248 } 67249 67250 /*****************************************************************************/ 67251 /* 67252 Activate a network agent (DCL script) to perform a function. ASYNCHRONOUS! 67253 A network agent is primarily to allow an assessment of a connection and whether 67254 that should be dropped. A network agent, like a lookup agent, is way to early 67255 to have an associated request. 67256 */ 67257 67258 void NetAgentBegin (NETIO_STRUCT *ioptr) 67259 Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 73 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 1 67260 { 1 67261 int size, status; 1 67262 char *sptr; 1 67263 CLIENT_STRUCT *clptr; 1 67264 REQUEST_STRUCT *rqptr; 1 67265 SERVICE_STRUCT *svptr; 1 67266 1 67267 /*********/ 1 67268 /* begin */ 1 67269 /*********/ 1 67270 1 67271 if (WATCH_MODULE(WATCH_MOD_NET)) 1 67272 WatchThis (WATCHALL, WATCH_MOD_NET, "NetAgentBegin()"); 1 67273 1 67274 clptr = ioptr->ClientPtr; 1 67275 1 67276 if (NetAgentActiveCount >= NetAgentActiveMax) 2 67277 { 2 67278 /* busy, busy, busy ... requeue for a delayed subsequent attempt */ 2 67279 if (clptr->AgentBusyCount++ <= NetAgentBusyMax) 3 67280 { 3 67281 if (clptr->AgentBusyCount <= NetAgentBusyMax / 4) 3 67282 SysDclAst (NetAgentBegin, ioptr); 3 67283 else 3 67284 sys$setimr (0, &Delta100mSec, &NetAgentBegin, ioptr, 0); 3 67285 return; 2 67286 } 2 67287 else 3 67288 { 3 67289 ErrorNoticed (NULL, SS$_TOOMANYREDS, "!UL exceeded (!UL)", 3 67290 FI_LI, NetAgentBusyMax, NetAgentBusyLimit); 3 67291 NetAgentBusyCount++; 3 67292 clptr->AgentResponsePtr = sptr = VmGet (size = 64); 3 67293 strzcpy (sptr, "500 ", size); 3 67294 strzcat (sptr, ProblemAcceptAgent, size); 3 67295 SysDclAst (NetAcceptProcess, ioptr); 3 67296 return; 2 67297 } 1 67298 } 1 67299 if (clptr->AgentBusyCount) 2 67300 { 2 67301 if (clptr->AgentBusyCount > NetAgentBusyLimit) 2 67302 NetAgentBusyLimit = clptr->AgentBusyCount; 2 67303 clptr->AgentBusyCount = 0; 1 67304 } 1 67305 1 67306 /************/ 1 67307 /* continue */ 1 67308 /************/ 1 67309 1 67310 svptr = ioptr->ServicePtr; 1 67311 1 67312 rqptr = DclFauxRequest (NULL, NULL, NULL); 1 67313 1 67314 /* use these rather than the stubs created by DclFauxRequest() */ 1 67315 rqptr->ClientPtr = clptr; 1 67316 rqptr->ServicePtr = svptr; Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 74 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 1 67317 1 67318 rqptr->AgentAstParam = ioptr; 1 67319 1 67320 clptr->AgentRequestPtr = VmGet(size = 64); 1 67321 strzcpy (clptr->AgentRequestPtr, "*", size); 1 67322 rqptr->AgentRequestPtr = 1 67323 VmGetHeap (rqptr, size = strlen(clptr->AgentRequestPtr)+1); 1 67324 strzcpy (rqptr->AgentRequestPtr, clptr->AgentRequestPtr, size); 1 67325 1 67326 rqptr = DclFauxRequest (rqptr, NetAcceptAgentScript, &NetAgentEnd); 1 67327 1 67328 if (!rqptr) 2 67329 { 2 67330 if (WATCH_MODULE(WATCH_MOD_NET)) 2 67331 WatchThis (WATCHALL, WATCH_NETWORK, "AGENT !AZ", NetAcceptAgentScript); 2 67332 ErrorNoticed (NULL, SS$_ABORT, ProblemAcceptAgent, FI_LI); 2 67333 clptr->AgentResponsePtr = sptr = VmGet (size = 64); 2 67334 strzcpy (sptr, "500 ", size); 2 67335 strzcat (sptr, ProblemAcceptAgent, size); 2 67336 SysDclAst (NetAcceptProcess, ioptr); 2 67337 return; 1 67338 } 1 67339 1 67340 NetAgentActiveCount++; 1 67341 1 67342 rqptr->AgentRequestPtr = clptr->AgentRequestPtr; 1 67343 } 67344 67345 /*****************************************************************************/ 67346 /* 67347 The agent (DCL script) has completed. 67348 */ 67349 67350 void NetAgentEnd (REQUEST_STRUCT *rqptr) 67351 1 67352 { 1 67353 int count, size, status; 1 67354 char *cptr, *sptr, *zptr; 1 67355 CLIENT_STRUCT *clptr; 1 67356 NETIO_STRUCT *ioptr; 1 67357 1 67358 /*********/ 1 67359 /* begin */ 1 67360 /*********/ 1 67361 1 67362 if (WATCH_MODULE(WATCH_MOD_NET)) 1 67363 WatchThis (WATCHALL, WATCH_MOD_NET, "NetAgentEnd()"); 1 67364 1 67365 ioptr = (NETIO_STRUCT*)rqptr->AgentAstParam; 1 67366 clptr = ioptr->ClientPtr; 1 67367 1 67368 if (cptr = rqptr->AgentResponsePtr) 2 67369 { 2 67370 for (sptr = cptr; *sptr; sptr++); 2 67371 clptr->AgentResponsePtr = sptr = VmGet (sptr - cptr); 2 67372 while (*cptr) *sptr++ = *cptr++; 1 67373 } Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 75 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 1 67374 else 2 67375 { 2 67376 clptr->AgentResponsePtr = sptr = VmGet (size = 64); 2 67377 strzcpy (sptr, "500 ", size); 2 67378 strzcat (sptr, ProblemAcceptAgent, size); 2 67379 ErrorNoticed (NULL, SS$_ABORT, ProblemAcceptAgent, FI_LI); 1 67380 } 1 67381 1 67382 SysDclAst (NetAcceptProcess, ioptr); 1 67383 1 67384 if (NetAgentActiveCount) NetAgentActiveCount--; 1 67385 1 67386 VmFreeRequest (rqptr, FI_LI); 1 67387 } 67388 67389 /*****************************************************************************/ 67390 /* 67391 Called by HttpdTick() every minute to continuously break network connections 67392 using NetTestBreak(). The logical name WASD_NET_TEST_BREAK contains one or 67393 more single-digit integers used to call NetTestBreak() every five seconds after 67394 the minute. 67395 */ 67396 67397 #if WATCH_MOD 67398 67399 void NetTestSupervisor () 67400 1 67401 { 1 67402 static char *nptr = ""; 1 67403 1 67404 int status; 1 67405 ulong number, seconds; 1 67406 char *cptr; 1 67407 1 67408 /*********/ 1 67409 /* begin */ 1 67410 /*********/ 1 67411 1 67412 if (WATCH_MODULE(WATCH_MOD_NET)) 1 67413 WatchThis (WATCHALL, WATCH_MOD_NET, "NetTestSupervisor()"); 1 67414 1 67415 if (!(cptr = SysTrnLnm (WASD_NET_TEST_BREAK))) return; 1 67416 if (!*nptr) nptr = cptr; 1 67417 while (*nptr && !isdigit(*nptr)) nptr++; 1 67418 number = atoi(nptr); 1 67419 while (isdigit(*nptr)) nptr++; 1 67420 1 67421 status = sys$setimr (0, &Delta05Sec, NetTestBreak, number, 0); 1 67422 if (VMSnok (status)) ErrorNoticed (NULL, status, NULL, FI_LI); 1 67423 } 67424 67425 #endif /* WATCH_MOD */ 67426 67427 /*****************************************************************************/ 67428 /* 67429 This function is used to break every /nth/ network connection simply by 67430 deassigning the network channel. Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 76 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 67431 67432 It is used on the development/test bench to see how the server behaves when 67433 network connections are abruptly broken. Any HTTP/2 request in progress has 67434 the underlying HTTP/2 connection broken (and so may take-out multiple requests). 67435 A selective sledgehammer! 67436 */ 67437 67438 #if WATCH_MOD 67439 67440 #include "sesola.h" 68048 void NetTestBreak (int every) 68049 1 68050 { 1 68051 int count, total; 1 68052 HTTP2_STRUCT *h2ptr; 1 68053 LIST_ENTRY *leptr; 1 68054 NETIO_STRUCT *ioptr; 1 68055 REQUEST_STRUCT *rqeptr; 1 68056 1 68057 /*********/ 1 68058 /* begin */ 1 68059 /*********/ 1 68060 1 68061 if (WATCH_MODULE(WATCH_MOD_NET)) 1 68062 WatchThis (WATCHALL, WATCH_MOD_NET, "NetTestBreak()"); 1 68063 1 68064 if (every <= 0) every = 1; 1 68065 count = total = 0; 1 68066 for (leptr = RequestList.HeadPtr; leptr; leptr = leptr->NextPtr) 2 68067 { 2 68068 if (++count % every) continue; 2 68069 rqeptr = (REQUEST_STRUCT*)leptr; 2 68070 /* do not kill WATCHing request */ 2 68071 if (rqeptr == Watch.RequestPtr) continue; 2 68072 ioptr = rqeptr->NetIoPtr; 2 68073 if (ioptr->Stream2Ptr) continue; 2 68074 if (rqeptr->rqHeader.RequestUriPtr) 2 68075 WatchThis (WATCHITM(rqeptr), WATCH_NETWORK, "BREAK1 !AZ !AZ !AZ", 2 68076 rqeptr->ServicePtr->ServerHostPort, 2 68077 rqeptr->rqHeader.MethodName, 2 68078 rqeptr->rqHeader.RequestUriPtr); 2 68079 else 2 68080 WatchThis (WATCHITM(rqeptr), WATCH_NETWORK, "BREAK1 !AZ !UL", 2 68081 rqeptr->ServicePtr->ServerHostPort, 2 68082 rqeptr->rqNet.PersistentCount); 2 68083 sys$dassgn (ioptr->Channel); 2 68084 ioptr->Channel = 0; 2 68085 total++; 1 68086 } 1 68087 FaoToStdout ("%HTTPD-I-NET, !%T, !UL/!UL/!UL broken\n", 1 68088 0, every, total, count); 1 68089 Http2TestBreak (every); 1 68090 } 68091 68092 #endif /* WATCH_MOD */ 68093 68094 /*****************************************************************************/ Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 77 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 68095 /* 68096 Needed a rig to test/experiment with multiple-instance network device (socket) 68097 handling. 68098 */ 68099 X 68100 #if NET_TEST X 68101 X 68102 NetTestRequest (unsigned short Channel) X 68103 X 68104 { X 68105 int status; X 68106 struct NetTestStruct *ntptr; X 68107 X 68108 /*********/ X 68109 /* begin */ X 68110 /*********/ X 68111 X 68112 if (WATCH_MODULE(WATCH_MOD_NET)) X 68113 WatchThis (WATCHALL, WATCH_MOD_NET, "NetTestRequest() !UL", Channel); X 68114 X 68115 ntptr = VmGet (sizeof(struct NetTestStruct)); X 68116 X 68117 ntptr->Channel = Channel; X 68118 X 68119 status = sys$qio (EfnNoWait, ntptr->Channel, IO$_READVBLK, X 68120 &ntptr->IOsb, &NetTestReadAst, ntptr, X 68121 ntptr->Buffer, sizeof(ntptr->Buffer), 0, 0, 0, 0); X 68122 if (VMSnok (status)) ErrorNoticed (rqptr, status, NULL, FI_LI); X 68123 } X 68124 X 68125 /*****************************************************************************/ X 68126 /* X 68127 See comments in NetTestRequest(). X 68128 */ X 68129 X 68130 NetTestReadAst (struct NetTestStruct *ntptr) X 68131 X 68132 { X 68133 static char ResponseHeader [] = X 68134 "HTTP/1.0 200 OK\r\n\ X 68135 Server: WASD/Test\r\n\ X 68136 Content-Type: text/plain\r\n\ X 68137 \r\n"; X 68138 static char ResponseBody [] = X 68139 "abcdefghijklnmopqrstuvwxyzABCDEFGHIJKLNMOPQRSTUVWXYZ0123456789\n"; X 68140 X 68141 int status; X 68142 char *cptr, *sptr, *zptr; X 68143 X 68144 /*********/ X 68145 /* begin */ X 68146 /*********/ X 68147 X 68148 if (WATCH_MODULE(WATCH_MOD_NET)) X 68149 WatchThis (WATCHALL, WATCH_MOD_NET, X 68150 "NetTestReadAst() !UL !&S !UL", X 68151 ntptr->Channel, ntptr->IOsb.Status, ntptr->IOsb.Count); Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 78 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 X 68152 X 68153 if (VMSnok (ntptr->IOsb.Status)) X 68154 { X 68155 ErrorNoticed (rqptr, ntptr->IOsb.Status, NULL, FI_LI); X 68156 status = sys$dassgn (ntptr->Channel); X 68157 if (VMSnok (status)) ErrorNoticed (rqptr, status, NULL, FI_LI); X 68158 VmFree (ntptr, FI_LI); X 68159 return; X 68160 } X 68161 X 68162 memcpy (ntptr->Buffer, ResponseHeader, sizeof(ResponseHeader)); X 68163 sptr = ntptr->Buffer + sizeof(ResponseHeader); X 68164 zptr = ntptr->Buffer + sizeof(ntptr->Buffer); X 68165 cptr = ResponseBody; X 68166 while (sptr < zptr) X 68167 { X 68168 if (!*cptr) cptr = ResponseBody; X 68169 *sptr++ = *cptr++; X 68170 } X 68171 X 68172 status = sys$qio (EfnNoWait, ntptr->Channel, IO$_WRITEVBLK, &ntptr->IOsb, X 68173 &NetTestWriteAst, ntptr, X 68174 ntptr->Buffer, sizeof(ntptr->Buffer), 0, 0, 0, 0); X 68175 if (VMSnok (status)) ErrorNoticed (rqptr, status, NULL, FI_LI); X 68176 } X 68177 X 68178 /*****************************************************************************/ X 68179 /* X 68180 See comments in NetTestRequest(). X 68181 */ X 68182 X 68183 NetTestWriteAst (struct NetTestStruct *ntptr) X 68184 X 68185 { X 68186 int status; X 68187 X 68188 /*********/ X 68189 /* begin */ X 68190 /*********/ X 68191 X 68192 if (WATCH_MODULE(WATCH_MOD_NET)) X 68193 WatchThis (WATCHALL, WATCH_MOD_NET, X 68194 "NetTestWriteAst() !UL !&S", X 68195 ntptr->Channel, ntptr->IOsb.Status); X 68196 X 68197 status = sys$dassgn (ntptr->Channel); X 68198 if (VMSnok (status)) ErrorNoticed (rqptr, status, NULL, FI_LI); X 68199 VmFree (ntptr, FI_LI); X 68200 } X 68201 X 68202 #endif /* NET_TEST */ 68203 68204 /****************************************************************************/ 68205 Source Listing 7-MAY-2026 15:51:10 VSI C x86-64 V7.7-003-50Z9T Page 79 7-MAY-2026 15:49:07 WASD_ROOT:[src.httpd]net.c;118 Command Line ------- ---- CC/DECC/STAND=RELAXED_ANSI/PREFIX=ALL/NAMES=AS_IS/OPTIMIZE=(INLINE=AUTO,LEVEL=4 ,UNROLL=0,TUNE=HOST)/LIST/MACHINE/NODEBUG/WARNING=(NOINFORM,DISABLE=(PREOPTW,CX XPRAGMANA))/FLOAT=IEEE/IEEE=DENORM/DEFINE=(SESOLA,WATCH_CAT=1,WATCH_MOD=1,WASD_ GETSPI=1)/OBJ=[.obj_X86_64]Net Net.c These macros are in effect at the start of the compilation. ----- ------ --- -- ------ -- --- ----- -- --- ------------ __G_FLOAT=0 __DECC=1 vms=1 VMS=1 __32BITS=1 __PRAGMA_ENVIRONMENT=1 WATCH_CAT=1 __CRTL_VER=90230000 __vms_version="V9.2-3 " CC$gfloat=0 __X_FLOAT=1 WASD_GETSPI=1 vms_version="V9.2-3 " __DATE__="May 7 2026" __STDC_VERSION__=199901L __DECC_MODE_RELAXED=1 __DECC_VER=70790003 __VMS=1 VMS_VERSION="V9.2-3 " __IEEE_FLOAT=1 __VMS_VERSION="V9.2-3 " SESOLA=1 __TIME__="15:51:10" __x86_64=1 __VMS_VER=90230022 __BIASED_FLT_ROUNDS=2 __INITIAL_POINTER_SIZE=0 WATCH_MOD=1 __STDC__=2 _IEEE_FP=1 __LANGUAGE_C__=1 __vms=1 __x86_64__=1 __D_FLOAT=0