SOCKETS 22-SEP-1995 18:31:35 VAX C V3.2-044 Page 1 V1.0 25-MAY-1995 14:07:25 [GOPHER.G2.VMS2_13.OBJECT]SOCKETS.C;5 (1) 1 /******************************************************************** 2 * wilkinson 3 * 3.19VMS 4 * 1995/05/25 14:00 5 * gopher_root1:[gopher.g2.vms2_13.object]Sockets.c,v 6 * Exp 7 * 8 * Paul Lindner, University of Minnesota CIS. 9 * 10 * Copyright 1991, 1992 by the Regents of the University of Minnesota 11 * see the file "Copyright" in the distribution for conditions of use. 12 ********************************************************************* 13 * MODULE: Sockets.c 14 * Socket functions 15 ********************************************************************* 16 * Revision History: 17 * Sockets.c,v 18 * Revision 3.19VMS 1995/05/25 14:00 wilkinson 19 * Consolodate VMS/Unix source code for server as well as client 20 * 21 * Revision 3.19 1994/07/31 05:09:47 lindner 22 * Add option to log only IP 23 * 24 * Revision 3.18 1994/04/25 03:46:03 lindner 25 * Fix for NETLIB and CMUIP 26 * 27 * Revision 3.17 1994/04/25 03:36:59 lindner 28 * Modifications for Debug() and mismatched NULL arguments, added Debugmsg 29 * 30 * Revision 3.16 1994/04/08 20:05:53 lindner 31 * gcc -Wall fixes 32 * 33 * Revision 3.15 1994/03/31 21:03:35 lindner 34 * Use better, more descriptive return codes for socket routines 35 * 36 * Revision 3.14 1994/03/17 04:45:39 lindner 37 * Add needed stdio.h 38 * 39 * Revision 3.13 1994/03/17 04:44:39 lindner 40 * Add needed stdio.h 41 * 42 * Revision 3.12 1994/03/17 04:36:01 lindner 43 * Move socket specific server code here, rearrange include files 44 * 45 * Revision 3.11 1994/03/08 15:56:20 lindner 46 * gcc -Wall fixes 47 * 48 * Revision 3.10 1994/01/12 22:23:50 lindner 49 * Fixes for Data General 50 * 51 * Revision 3.9 1993/12/27 16:16:03 lindner 52 * Fix for sign on integer.. 53 * 54 * Revision 3.8 1993/10/19 20:49:02 lindner 55 * Fix for NETLIB SOCKETS 22-SEP-1995 18:31:35 VAX C V3.2-044 Page 2 V1.0 25-MAY-1995 14:07:25 [GOPHER.G2.VMS2_13.OBJECT]SOCKETS.C;5 (1) 56 * 57 * Revision 3.7 1993/10/11 17:26:01 lindner 58 * Fix for cmuip/netlib 59 * 60 * Revision 3.6 1993/09/21 01:51:34 lindner 61 * Moved netnames fcn.. 62 * 63 * Revision 3.5 1993/08/09 20:17:10 lindner 64 * Fixes for CMULIB and NETLIB for VMS 65 * 66 * Revision 3.4 1993/08/05 03:23:37 lindner 67 * Changes for CMUIP and NETLIB 68 * 69 * Revision 3.3 1993/07/29 20:01:02 lindner 70 * Removed dead variables 71 * 72 * Revision 3.2 1993/07/27 05:30:27 lindner 73 * Mondo Debug overhaul from Mitra 74 * 75 * Revision 3.1 1993/07/07 19:27:25 lindner 76 * Socket functions 77 * 78 * 79 * 80 *********************************************************************/ 81 82 /* Generic stuff */ 83 84 #include "boolean.h" 129 #include "compatible.h" 877 #include "Debug.h" 1192 1193 #ifdef unix 1194 X # include 1195 #endif 1196 1197 #include "Sockets.h" 3118 #include "Malloc.h" 3776 #include 4025 4026 #ifdef VMS_SERVER 4027 X char * vms_errno_string(); 4028 #endif 4029 4030 /* 4031 * This turns the linger output off 4032 */ 4033 4034 void 4035 SOCKlinger(sockfd, onoff) 4036 int sockfd; 4037 boolean onoff; 4038 { 4039 1 #if defined(SO_LINGER) && !defined(NO_LINGER) 4040 1 struct linger linger; 4041 1 4042 1 linger.l_onoff = onoff; SOCKETS 22-SEP-1995 18:31:35 VAX C V3.2-044 Page 3 V1.0 25-MAY-1995 14:07:25 [GOPHER.G2.VMS2_13.OBJECT]SOCKETS.C;5 (1) 4043 1 linger.l_linger = 0; 4044 1 if (setsockopt(sockfd, SOL_SOCKET, SO_LINGER, (char *)&linger, 4045 1 sizeof (linger)) < 0) 4046 1 #ifndef VMS_SERVER 4047 1 perror("server: can't turn off linger sockopt"),exit(-1); 4048 1 #else 4049 X LOGGopher(-99,"fatal: can't turn off linger sockopt, %s", 4050 X vms_errno_string()); 4051 1 #endif 4052 1 #endif 4053 1 } 4054 4055 4056 4057 /* 4058 * This function returns a socket file descriptor bound to the given port 4059 */ 4060 4061 #if !defined(CMUIP) && !defined(NETLIB) 4062 int 4063 SOCKbind_to_port(port) 4064 int port; 4065 { 4066 1 struct sockaddr_in serv_addr; 4067 1 int reuseaddr = 1; 4068 1 int sockfd; 4069 1 4070 1 4071 1 if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) 4072 1 #ifndef VMS_SERVER 4073 1 perror("server: can't open stream socket"), exit(-1); 4074 1 #else 4075 X LOGGopher(-99,"fatal: can't open stream socket, %s", 4076 X vms_errno_string()); 4077 1 #endif 4078 1 4079 1 /** Bind our local address so that the client can send to us **/ 4080 1 4081 1 bzero((char *) &serv_addr, sizeof(serv_addr)); 4082 1 serv_addr.sin_family = AF_INET; 4083 1 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); 4084 1 serv_addr.sin_port = htons(port); 4085 1 4086 1 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuseaddr, 4087 1 sizeof(reuseaddr)) < 0) 4088 1 #ifndef VMS_SERVER 4089 1 perror("server: can't set REUSEADDR!"),exit(-1); 4090 1 #else 4091 X LOGGopher(-99,"fatal: can't set socket REUSEADDR, %s", 4092 X vms_errno_string()); 4093 1 #endif 4094 1 4095 1 if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) <0) 4096 1 #ifndef VMS_SERVER 4097 1 perror("server: can't bind local address"),exit(-1); 4098 1 #else 4099 X LOGGopher(-99, "fatal: can't bind local address, %s", SOCKETS 22-SEP-1995 18:31:35 VAX C V3.2-044 Page 4 V1.0 25-MAY-1995 14:07:25 [GOPHER.G2.VMS2_13.OBJECT]SOCKETS.C;5 (1) 4100 X vms_errno_string()); 4101 1 #endif 4102 1 4103 1 SOCKlinger(sockfd, FALSE); 4104 1 return(sockfd); 4105 1 } 4106 4107 4108 4109 /* 4110 * This routine finds out the hostname of the server machine. 4111 * It uses a couple of methods to find the fully qualified 4112 * Domain name 4113 * 4114 * If gdchost is non NULL then use that paramater instead of 4115 * the code in here. 4116 */ 4117 4118 char * 4119 SOCKgetDNSname(backupdomain, gdchost) 4120 char *backupdomain; 4121 char *gdchost; 4122 { 4123 1 static char DNSname[MAXHOSTNAMELEN]; 4124 1 struct hostent *hp; 4125 1 4126 1 if (*gdchost != '\0') 4127 1 return(gdchost); 4128 1 4129 1 DNSname[0] = '\0'; 4130 1 /* Work out our fully-qualified name, for later use */ 4131 1 4132 1 if (gethostname(DNSname, MAXHOSTNAMELEN) != 0) { 4133 2 #ifndef VMS_SERVER 4134 2 fprintf(stderr, "Cannot determine the name of this host\n"); 4135 2 exit(-1); 4136 2 #else 4137 X LOGGopher(-99,"fatal: Cannot determine the name of this host"); 4138 2 #endif 4139 2 } 4140 1 4141 1 /* Now, use gethostbyname to (hopefully) do a nameserver lookup */ 4142 1 hp = gethostbyname( DNSname); 4143 1 4144 1 /* 4145 1 ** If we got something, and the name is longer than hostname, then 4146 1 ** assume that it must the the fully-qualified hostname 4147 1 */ 4148 1 if ( hp!=NULL && strlen(hp->h_name) > strlen(DNSname) ) 4149 1 strncpy( DNSname, hp->h_name, MAXHOSTNAMELEN ); 4150 1 else 4151 1 strcat(DNSname, backupdomain); 4152 1 4153 1 return(DNSname); 4154 1 } 4155 4156 SOCKETS 22-SEP-1995 18:31:35 VAX C V3.2-044 Page 5 V1.0 25-MAY-1995 14:07:25 [GOPHER.G2.VMS2_13.OBJECT]SOCKETS.C;5 (1) 4157 /* 4158 * Tries to figure out what the currently connected port is. 4159 * 4160 * If it's a socket then it will return the port of the socket, 4161 * if it isn't a socket then it returns -1. 4162 */ 4163 4164 int 4165 SOCKgetPort(fd) 4166 int fd; 4167 { 4168 1 struct sockaddr_in serv_addr; 4169 1 4170 1 int length = sizeof(serv_addr); 4171 1 4172 1 /** Try to figure out the port we're running on. **/ 4173 1 4174 1 if (getsockname(fd, (struct sockaddr *) &serv_addr,&length) == 0) 4175 1 return(ntohs(serv_addr.sin_port)); 4176 1 else 4177 1 return(-1); 4178 1 4179 1 } 4180 4181 #endif /* not CMUIP nor NETLIB */ 4182 4183 4184 4185 /* SOCKconnect performs a connection to socket 'service' on host 4186 * 'host'. Host can be a hostname or ip-address. If 'host' is null, the 4187 * local host is assumed. The parameter full_hostname will, on return, 4188 * contain the expanded hostname (if possible). Note that full_hostname is a 4189 * pointer to a char *, and is allocated by connect_to_gopher() 4190 * 4191 * Errors: ErrSocket* defined in Sockets.h 4192 * 4193 */ 4194 4195 int 4196 SOCKconnect(hostname, port) 4197 char *hostname; 4198 int port; 4199 { 4200 1 #if !defined(CMUIP) && !defined(NETLIB) 4201 1 struct sockaddr_in Server; 4202 1 struct hostent *HostPtr; 4203 1 int sockfd = 0; 4204 1 unsigned int ERRinet = -1; 4205 1 4206 1 #ifdef _CRAY 4207 X ERRinet = 0xFFFFFFFF; /* -1 doesn't sign extend on 64 bit machines */ 4208 1 #endif 4209 1 4210 1 /*** Find the hostname address ***/ 4211 1 4212 1 if (hostname == NULL || *hostname == '\0') 4213 1 return(ErrSocketNullHost); SOCKETS 22-SEP-1995 18:31:35 VAX C V3.2-044 Page 6 V1.0 25-MAY-1995 14:07:25 [GOPHER.G2.VMS2_13.OBJECT]SOCKETS.C;5 (1) 4214 1 4215 1 #ifdef DGUX 4216 X Server.sin_addr = inet_addr(hostname); 4217 X if (Server.sin_addr.s_addr == ERRinet) 4218 1 #else 4219 1 if ((Server.sin_addr.s_addr = inet_addr(hostname)) == ERRinet) 4220 1 #endif 4221 1 { 4222 2 if ((HostPtr = gethostbyname(hostname)) != NULL) { 4223 3 bzero((char *) &Server, sizeof(Server)); 4224 3 bcopy(HostPtr->h_addr, (char *) &Server.sin_addr, HostPtr->h_length); 4225 3 Server.sin_family = HostPtr->h_addrtype; 4226 3 } else 4227 2 return (ErrSocketGetHost); 4228 2 } else 4229 1 Server.sin_family = AF_INET; 4230 1 4231 1 Server.sin_port = (unsigned short) htons(port); 4232 1 4233 1 /*** Open the socket ***/ 4234 1 4235 1 if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) 4236 1 return (ErrSocketCall); 4237 1 4238 1 #ifndef UCX 4239 1 setsockopt(sockfd, SOL_SOCKET, ~SO_LINGER, 0, 0); 4240 1 #endif 4241 1 4242 1 setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, 0, 0); 4243 1 setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, 0, 0); 4244 1 4245 1 /*** Connect ***/ 4246 1 4247 1 if (connect(sockfd, (struct sockaddr *) &Server, sizeof(Server)) < 0) { 4248 2 closenet(sockfd); 4249 2 return (ErrSocketConnect); 4250 2 } 4251 1 4252 1 return(sockfd); 4253 1 4254 1 #else /* !NETLIB && !CMUIP */ 4255 X #ifdef NETLIB 4256 X int status; 4257 X static int iSock = 0; 4258 X struct { 4259 X long len; 4260 X char *adr; 4261 X } host_desc; 4262 X 4263 X #define NET_K_TCP 1 4264 X status = NET_ASSIGN (&iSock); 4265 X if ((status & 1) == 0) 4266 X return (ErrSocketCall); 4267 X status = NET_BIND (&iSock, NET_K_TCP); 4268 X if ((status & 1) == 0) 4269 X return (ErrSocketCall); 4270 X host_desc.adr = hostname; SOCKETS 22-SEP-1995 18:31:35 VAX C V3.2-044 Page 7 V1.0 25-MAY-1995 14:07:25 [GOPHER.G2.VMS2_13.OBJECT]SOCKETS.C;5 (1) 4271 X host_desc.len = strlen (host_desc.adr); 4272 X status = TCP_CONNECT (&iSock, &host_desc, port); 4273 X if ((status & 1) == 0) { 4274 X NET_DEASSIGN (&iSock); 4275 X if (status == SS$_REJECT || status == SS$_TIMEOUT) { 4276 X if (status == SS$_REJECT) 4277 X errno = ECONNREFUSED; 4278 X else 4279 X errno = ETIMEDOUT; 4280 X 4281 X return (ErrSocketConnect); 4282 X } 4283 X if (status == SS$_ENDOFFILE) 4284 X return (ErrSocketGetHost); 4285 X return (ErrSocketGetService); 4286 X } 4287 X return (iSock); 4288 X #else /* ifdef NETLIB: assume CMUIP */ 4289 X short channel; 4290 X int status; 4291 X struct { 4292 X short status; 4293 X short size; 4294 X long xxx; 4295 X } cmu_iosb; 4296 X static struct {long l; char *a;} ip_dev = {12, "INET$DEVICE:"}; 4297 X globalvalue NET$_CREF; /* Connection refused */ 4298 X globalvalue NET$_FTO; /* Function timedout */ 4299 X globalvalue NET$_DSNAMERR; /* Domain server name error */ 4300 X status = SYS$ASSIGN (&ip_dev, &channel, 0, 0); 4301 X if ((status & 1) == 0) 4302 X return (ErrSocketCall); 4303 X status = SYS$QIOW (0, channel, IO$_CREATE, &cmu_iosb, 0, 0, 4304 X hostname, port, 0, 1, 0, 0); 4305 X if ((status & 1) == 0 || (cmu_iosb.status & 1) == 0) { 4306 X SYS$DASSGN (channel); 4307 X if (cmu_iosb.status == SS$_ABORT || cmu_iosb.xxx == NET$_FTO) { 4308 X if (cmu_iosb.xxx == NET$_CREF) 4309 X errno = ECONNREFUSED; 4310 X else 4311 X errno = ETIMEDOUT; 4312 X 4313 X return(ErrSocketConnect); 4314 X } 4315 X if (cmu_iosb.xxx == NET$_DSNAMERR) 4316 X return (ErrSocketGetHost); 4317 X } 4318 X return (channel); 4319 X #endif 4320 1 #endif 4321 1 4322 1 } 4323 4324 4325 4326 4327 /* SOCKETS 22-SEP-1995 18:31:35 VAX C V3.2-044 Page 8 V1.0 25-MAY-1995 14:07:25 [GOPHER.G2.VMS2_13.OBJECT]SOCKETS.C;5 (1) 4328 * 4329 */ 4330 4331 #if !defined(CMUIP) && !defined(NETLIB) /* temp - MLH */ 4332 int 4333 SOCKlisten(We) 4334 struct sockaddr_in * We; 4335 { 4336 1 int sockfd = 0; 4337 1 struct hostent *HostPtr; 4338 1 int len = sizeof(struct sockaddr); 4339 1 char name[100]; 4340 1 4341 1 4342 1 sockfd = SOCKbind_to_port(sockfd); 4343 1 if (listen(sockfd, 5) || getsockname(sockfd, (struct sockaddr *) We, &len)) { 4344 2 closenet(sockfd); 4345 2 return(ErrSocketGetHost); 4346 2 } 4347 1 4348 1 gethostname(name, 100); 4349 1 if ((HostPtr = gethostbyname(name))) 4350 1 bcopy(HostPtr->h_addr, (char *) &We->sin_addr, HostPtr->h_length); 4351 1 return(sockfd); 4352 1 } 4353 4354 4355 /* SOCKaccept accepts a connection form some socket. * 4356 * Errors: ErrSocket* defined in Sockets.h 4357 */ 4358 4359 int 4360 SOCKaccept(s, we) 4361 int s; 4362 struct sockaddr_in we; 4363 { 4364 1 int sockfd = 0; 4365 1 int len = sizeof(struct sockaddr); 4366 1 unsigned short tem; 4367 1 4368 1 tem = ntohs(we.sin_port); 4369 1 4370 1 Debugmsg("Here we go...\n"); 4371 1 4372 1 if ((sockfd = accept(s, (struct sockaddr *) &we, &len)) < 0) { 4373 2 return ErrSocketConnect; 4374 2 } 4375 1 close(s); /* Der Mohr hat seine Schuldigkeit getan */ 4376 1 4377 1 return(sockfd); 4378 1 } 4379 4380 4381 4382 /* 4383 * SOCKnetnames -- return the network, subnet, and host names of 4384 * our peer process for the Internet domain. SOCKETS 22-SEP-1995 18:31:35 VAX C V3.2-044 Page 9 V1.0 25-MAY-1995 14:07:25 [GOPHER.G2.VMS2_13.OBJECT]SOCKETS.C;5 (1) 4385 * 4386 * Parameters: "sock" is our socket 4387 * "host_name" 4388 * is filled in by this routine with the 4389 * corresponding ASCII names of our peer. 4390 * 4391 * if there doesn't exist a hostname in DNS etal, 4392 * the IP# will be inserted for the host_name 4393 * 4394 * "ipnum" is filled in with the ascii IP# 4395 */ 4396 4397 void 4398 SOCKnetnames(sockfd, host_name, ipnum) 4399 int sockfd; 4400 char *host_name; 4401 char *ipnum; 4402 { 4403 1 struct sockaddr_in sa; 4404 1 int length; 4405 1 struct hostent *hp; 4406 1 4407 1 length = sizeof(sa); 4408 1 if (getpeername(sockfd, (struct sockaddr *)&sa, &length)) 4409 1 /** May fail if sockfd has been closed **/ 4410 1 #ifdef VMS_SERVER 4411 X { 4412 X LOGGopher(-2, "getpeername() failure: %s", vms_errno_string()); 4413 X if (ipnum != NULL) 4414 X strcpy(ipnum,"Unknown"); 4415 X if (host_name != NULL) 4416 X strcpy(host_name,"Unknown"); 4417 X return; 4418 X } 4419 X 4420 1 #else 4421 1 return; 4422 1 #endif 4423 1 4424 1 if (ipnum != NULL) 4425 1 strcpy(ipnum, inet_ntoa(sa.sin_addr)); 4426 1 4427 1 if (host_name != NULL) 4428 1 strcpy(host_name, inet_ntoa(sa.sin_addr)); 4429 1 4430 1 #ifdef LOG_IP_ONLY 4431 X hp = NULL; 4432 1 #else 4433 1 hp = gethostbyaddr((char *) &sa.sin_addr,sizeof (sa.sin_addr), AF_INET); 4434 1 #endif 4435 1 4436 1 if (hp != NULL && host_name != NULL) 4437 1 (void) strcpy(host_name, hp->h_name); 4438 1 4439 1 } 4440 4441 #endif /** CMUIP etal **/ SOCKETS 22-SEP-1995 18:31:35 VAX C V3.2-044 Page 10 V1.0 25-MAY-1995 14:07:25 [GOPHER.G2.VMS2_13.OBJECT]SOCKETS.C;5 (1) Command Line ------------ CC/INCL=([-],[-.OBJECT])/DEFINE=(MULTINET=1,DEBUGGING,__VMS)/DEBUG/NOOPT/OBJ=[.VAX.DBG]/LIS=[.VAX.LIS] SOCKETS.C .