1 #ifdef sun 2 #define uint uxuint 3 #define ulong uxulong 4 #define ushort uxushort 5 #endif 6 #include <sys/types.h> 7 #include <sys/time.h> 8 #include <sys/socket.h> 9 #include <net/if.h> 10 #include <net/if_arp.h> 11 #include <netinet/in.h> 12 #include <netinet/tcp.h> 13 #include <netdb.h> 14 #include <sys/ioctl.h> 15 #undef ulong 16 #undef ushort 17 #undef uint 18 19 #include "dat.h" 20 #include "fns.h" 21 #include "ip.h" 22 #include "error.h" 23 24 int 25 so_socket(int type) 26 { 27 int fd, one; 28 29 switch(type) { 30 default: 31 error("bad protocol type"); 32 case S_TCP: 33 type = SOCK_STREAM; 34 break; 35 case S_UDP: 36 type = SOCK_DGRAM; 37 break; 38 } 39 40 fd = socket(AF_INET, type, 0); 41 if(fd < 0) 42 oserror(); 43 if(type == SOCK_DGRAM){ 44 one = 1; 45 setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char*)&one, sizeof (one)); 46 }else{ 47 one = 1; 48 setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof(one)); 49 } 50 return fd; 51 } 52 53 int 54 so_send(int sock, void *va, int len, void *hdr, int hdrlen) 55 { 56 int r; 57 struct sockaddr sa; 58 struct sockaddr_in *sin; 59 char *h = hdr; 60 61 62 osenter(); 63 if(hdr == 0) 64 r = write(sock, va, len); 65 else { 66 memset(&sa, 0, sizeof(sa)); 67 sin = (struct sockaddr_in*)&sa; 68 sin->sin_family = AF_INET; 69 switch(hdrlen){ 70 case OUdphdrlenv4: 71 memmove(&sin->sin_addr, h, 4); 72 memmove(&sin->sin_port, h+8, 2); 73 break; 74 case OUdphdrlen: 75 v6tov4((uchar*)&sin->sin_addr, h); 76 memmove(&sin->sin_port, h+2*IPaddrlen, 2); /* rport */ 77 break; 78 default: 79 v6tov4((uchar*)&sin->sin_addr, h); 80 memmove(&sin->sin_port, h+3*IPaddrlen, 2); 81 break; 82 } 83 r = sendto(sock, va, len, 0, &sa, sizeof(sa)); 84 } 85 osleave(); 86 return r; 87 } 88 89 int 90 so_recv(int sock, void *va, int len, void *hdr, int hdrlen) 91 { 92 int r, l; 93 struct sockaddr sa; 94 struct sockaddr_in *sin; 95 char h[Udphdrlen]; 96 97 98 osenter(); 99 if(hdr == 0) 100 r = read(sock, va, len); 101 else { 102 sin = (struct sockaddr_in*)&sa; 103 l = sizeof(sa); 104 r = recvfrom(sock, va, len, 0, &sa, &l); 105 if(r >= 0) { 106 memset(h, 0, sizeof(h)); 107 switch(hdrlen){ 108 case OUdphdrlenv4: 109 memmove(h, &sin->sin_addr, 4); 110 memmove(h+2*IPv4addrlen, &sin->sin_port, 2); 111 break; 112 case OUdphdrlen: 113 v4tov6(h, (uchar*)&sin->sin_addr); 114 memmove(h+2*IPaddrlen, &sin->sin_port, 2); 115 break; 116 default: 117 v4tov6(h, (uchar*)&sin->sin_addr); 118 memmove(h+3*IPaddrlen, &sin->sin_port, 2); 119 break; 120 } 121 122 /* alas there's no way to get the local addr/port correctly. Pretend. */ 123 getsockname(sock, &sa, &l); 124 switch(hdrlen){ 125 case OUdphdrlenv4: 126 memmove(h+IPv4addrlen, &sin->sin_addr, IPv4addrlen); 127 memmove(h+2*IPv4addrlen+2, &sin->sin_port, 2); 128 break; 129 case OUdphdrlen: 130 v4tov6(h+IPaddrlen, (uchar*)&sin->sin_addr); 131 memmove(h+2*IPaddrlen+2, &sin->sin_port, 2); 132 break; 133 default: 134 v4tov6(h+IPaddrlen, (uchar*)&sin->sin_addr); 135 v4tov6(h+2*IPaddrlen, (uchar*)&sin->sin_addr); /* ifcaddr */ 136 memmove(h+3*IPaddrlen+2, &sin->sin_port, 2); 137 break; 138 } 139 memmove(hdr, h, hdrlen); 140 } 141 } 142 osleave(); 143 return r; 144 } 145 146 void 147 so_close(int sock) 148 { 149 close(sock); 150 } 151 152 void 153 so_connect(int fd, unsigned long raddr, unsigned short rport) 154 { 155 int r; 156 struct sockaddr sa; 157 struct sockaddr_in *sin; 158 159 memset(&sa, 0, sizeof(sa)); 160 sin = (struct sockaddr_in*)&sa; 161 sin->sin_family = AF_INET; 162 hnputs(&sin->sin_port, rport); 163 hnputl(&sin->sin_addr.s_addr, raddr); 164 165 osenter(); 166 r = connect(fd, &sa, sizeof(sa)); 167 osleave(); 168 if(r < 0) 169 oserror(); 170 } 171 172 void 173 so_getsockname(int fd, unsigned long *laddr, unsigned short *lport) 174 { 175 int len; 176 struct sockaddr sa; 177 struct sockaddr_in *sin; 178 179 len = sizeof(sa); 180 if(getsockname(fd, &sa, &len) < 0) 181 oserror(); 182 183 sin = (struct sockaddr_in*)&sa; 184 if(sin->sin_family != AF_INET || len != sizeof(*sin)) 185 error("not AF_INET"); 186 187 *laddr = nhgetl(&sin->sin_addr.s_addr); 188 *lport = nhgets(&sin->sin_port); 189 } 190 191 void 192 so_listen(int fd) 193 { 194 int r; 195 196 osenter(); 197 r = listen(fd, 256); 198 osleave(); 199 if(r < 0) 200 oserror(); 201 } 202 203 int 204 so_accept(int fd, unsigned long *raddr, unsigned short *rport) 205 { 206 int nfd, len; 207 struct sockaddr sa; 208 struct sockaddr_in *sin; 209 210 sin = (struct sockaddr_in*)&sa; 211 212 len = sizeof(sa); 213 osenter(); 214 nfd = accept(fd, &sa, &len); 215 osleave(); 216 if(nfd < 0) 217 oserror(); 218 219 if(sin->sin_family != AF_INET || len != sizeof(*sin)) 220 error("not AF_INET"); 221 222 *raddr = nhgetl(&sin->sin_addr.s_addr); 223 *rport = nhgets(&sin->sin_port); 224 return nfd; 225 } 226 227 void 228 so_bind(int fd, int su, unsigned long addr, unsigned short port) 229 { 230 int i, one; 231 struct sockaddr sa; 232 struct sockaddr_in *sin; 233 234 sin = (struct sockaddr_in*)&sa; 235 236 one = 1; 237 if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(one)) < 0) { 238 oserrstr(up->genbuf, sizeof(up->genbuf)); 239 print("setsockopt: %s", up->genbuf); 240 } 241 242 if(su) { 243 for(i = 600; i < 1024; i++) { 244 memset(&sa, 0, sizeof(sa)); 245 sin->sin_family = AF_INET; 246 hnputl(&sin->sin_addr.s_addr, addr); 247 hnputs(&sin->sin_port, i); 248 249 if(bind(fd, &sa, sizeof(sa)) >= 0) 250 return; 251 } 252 oserror(); 253 } 254 255 memset(&sa, 0, sizeof(sa)); 256 sin->sin_family = AF_INET; 257 hnputl(&sin->sin_addr.s_addr, addr); 258 hnputs(&sin->sin_port, port); 259 260 if(bind(fd, &sa, sizeof(sa)) < 0) 261 oserror(); 262 } 263 264 int 265 so_gethostbyname(char *host, char**hostv, int n) 266 { 267 int i; 268 unsigned char buf[32], *p; 269 struct hostent *hp; 270 271 hp = gethostbyname(host); 272 if(hp == 0) 273 return 0; 274 275 for(i = 0; hp->h_addr_list[i] && i < n; i++) { 276 p = hp->h_addr_list[i]; 277 sprint(buf, "%ud.%ud.%ud.%ud", p[0], p[1], p[2], p[3]); 278 hostv[i] = strdup(buf); 279 if(hostv[i] == 0) 280 break; 281 } 282 return i; 283 } 284 285 int 286 so_gethostbyaddr(char *addr, char **hostv, int n) 287 { 288 int i; 289 struct hostent *hp; 290 unsigned long straddr; 291 292 straddr = inet_addr(addr); 293 if(straddr == -1) 294 return 0; 295 296 hp = gethostbyaddr((char *)&straddr, sizeof(straddr), AF_INET); 297 if(hp == 0) 298 return 0; 299 300 hostv[0] = strdup(hp->h_name); 301 if(hostv[0] == 0) 302 return 0; 303 for(i = 1; hp->h_aliases[i-1] && i < n; i++) { 304 hostv[i] = strdup(hp->h_aliases[i-1]); 305 if(hostv[i] == 0) 306 break; 307 } 308 return i; 309 } 310 311 int 312 so_getservbyname(char *service, char *net, char *port) 313 { 314 ushort p; 315 struct servent *s; 316 317 s = getservbyname(service, net); 318 if(s == 0) 319 return -1; 320 p = s->s_port; 321 sprint(port, "%d", nhgets(&p)); 322 return 0; 323 } 324 325 int 326 so_hangup(int fd, int nolinger) 327 { 328 int r; 329 static struct linger l = {1, 0}; 330 331 osenter(); 332 if(nolinger) 333 setsockopt(fd, SOL_SOCKET, SO_LINGER, (char*)&l, sizeof(l)); 334 r = shutdown(fd, 2); 335 if(r >= 0) 336 r = close(fd); 337 osleave(); 338 return r; 339 } 340 341 void 342 arpadd(char *ipaddr, char *eaddr, int n) 343 { 344 #ifdef SIOCGARP 345 struct arpreq a; 346 struct sockaddr_in pa; 347 int s; 348 uchar addr[IPaddrlen]; 349 350 s = socket(AF_INET, SOCK_DGRAM, 0); 351 memset(&a, 0, sizeof(a)); 352 memset(&pa, 0, sizeof(pa)); 353 pa.sin_family = AF_INET; 354 pa.sin_port = 0; 355 parseip(addr, ipaddr); 356 if(!isv4(addr)){ 357 close(s); 358 error(Ebadarg); 359 } 360 memmove(&pa.sin_addr, ipaddr+IPv4off, IPv4addrlen); 361 memmove(&a.arp_pa, &pa, sizeof(pa)); 362 while(ioctl(s, SIOCGARP, &a) != -1) { 363 ioctl(s, SIOCDARP, &a); 364 memset(&a.arp_ha, 0, sizeof(a.arp_ha)); 365 } 366 a.arp_ha.sa_family = AF_UNSPEC; 367 parsemac((uchar*)a.arp_ha.sa_data, eaddr, 6); 368 a.arp_flags = ATF_PERM; 369 if(ioctl(s, SIOCSARP, &a) == -1) { 370 oserrstr(up->env->errstr, ERRMAX); 371 close(s); 372 error(up->env->errstr); 373 } 374 close(s); 375 #else 376 error("arp not implemented"); 377 #endif 378 } 379 380 int 381 so_mustbind(int restricted, int port) 382 { 383 return restricted || port != 0; 384 } 385 386 void 387 so_keepalive(int fd, int ms) 388 { 389 int on; 390 391 on = 1; 392 setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char*)&on, sizeof(on)); 393 #ifdef TCP_KEEPIDLE 394 if(ms <= 120000) 395 ms = 120000; 396 ms /= 1000; 397 setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, (char*)&ms, sizeof(ms)); 398 #endif 399 } 400