Addresses are now stored as uchar[16] instead of ulong, with enough room for IPv6. Generic IP functions have been removed from devip.c and replaced by libip, imported from Plan 9. Names and addresses are resolved using either gethostbyname() or getaddrinfo() functions. On Windows, IPv6 name resolution is not enabled, because mingw32 doesn't provide inet_ntop(). R=rsc http://codereview.appspot.com/6408044
264 lines
4.7 KiB
C
264 lines
4.7 KiB
C
#include <windows.h>
|
|
#include <ws2tcpip.h>
|
|
#include "u.h"
|
|
#include "lib.h"
|
|
#include "dat.h"
|
|
#include "fns.h"
|
|
#include "error.h"
|
|
#include "ip.h"
|
|
|
|
#include "devip.h"
|
|
|
|
#ifdef MSVC
|
|
#pragma comment(lib, "wsock32.lib")
|
|
#endif
|
|
|
|
#undef listen
|
|
#undef accept
|
|
#undef bind
|
|
|
|
static int
|
|
family(unsigned char *addr)
|
|
{
|
|
if(isv4(addr))
|
|
return AF_INET;
|
|
return AF_INET6;
|
|
}
|
|
|
|
void
|
|
osipinit(void)
|
|
{
|
|
WSADATA wasdat;
|
|
char buf[1024];
|
|
|
|
if(WSAStartup(MAKEWORD(1, 1), &wasdat) != 0)
|
|
panic("no winsock.dll");
|
|
|
|
gethostname(buf, sizeof(buf));
|
|
kstrdup(&sysname, buf);
|
|
}
|
|
|
|
int
|
|
so_socket(int type, unsigned char *addr)
|
|
{
|
|
int fd, one;
|
|
|
|
switch(type) {
|
|
default:
|
|
error("bad protocol type");
|
|
case S_TCP:
|
|
type = SOCK_STREAM;
|
|
break;
|
|
case S_UDP:
|
|
type = SOCK_DGRAM;
|
|
break;
|
|
}
|
|
|
|
fd = socket(family(addr), type, 0);
|
|
if(fd < 0)
|
|
oserror();
|
|
|
|
one = 1;
|
|
if(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(one)) > 0){
|
|
oserrstr();
|
|
print("setsockopt: %s\n", up->errstr);
|
|
}
|
|
|
|
return fd;
|
|
}
|
|
|
|
|
|
void
|
|
so_connect(int fd, unsigned char *raddr, unsigned short rport)
|
|
{
|
|
struct sockaddr_storage ss;
|
|
|
|
memset(&ss, 0, sizeof(ss));
|
|
|
|
ss.ss_family = family(raddr);
|
|
|
|
switch(ss.ss_family){
|
|
case AF_INET:
|
|
hnputs(&((struct sockaddr_in*)&ss)->sin_port, rport);
|
|
v6tov4((unsigned char*)&((struct sockaddr_in*)&ss)->sin_addr.s_addr, raddr);
|
|
break;
|
|
case AF_INET6:
|
|
hnputs(&((struct sockaddr_in6*)&ss)->sin6_port, rport);
|
|
memcpy(&((struct sockaddr_in6*)&ss)->sin6_addr.s6_addr, raddr, sizeof(struct in6_addr));
|
|
break;
|
|
}
|
|
|
|
if(connect(fd, (struct sockaddr*)&ss, sizeof(ss)) < 0)
|
|
oserror();
|
|
}
|
|
|
|
void
|
|
so_getsockname(int fd, unsigned char *laddr, unsigned short *lport)
|
|
{
|
|
int len;
|
|
struct sockaddr_storage ss;
|
|
|
|
len = sizeof(ss);
|
|
if(getsockname(fd, (struct sockaddr*)&ss, &len) < 0)
|
|
oserror();
|
|
|
|
switch(ss.ss_family){
|
|
case AF_INET:
|
|
v4tov6(laddr, (unsigned char*)&((struct sockaddr_in*)&ss)->sin_addr.s_addr);
|
|
*lport = nhgets(&((struct sockaddr_in*)&ss)->sin_port);
|
|
break;
|
|
case AF_INET6:
|
|
memcpy(laddr, &((struct sockaddr_in6*)&ss)->sin6_addr.s6_addr, sizeof(struct in6_addr));
|
|
*lport = nhgets(&((struct sockaddr_in6*)&ss)->sin6_port);
|
|
break;
|
|
default:
|
|
error("not AF_INET or AF_INET6");
|
|
}
|
|
}
|
|
|
|
void
|
|
so_listen(int fd)
|
|
{
|
|
if(listen(fd, 5) < 0)
|
|
oserror();
|
|
}
|
|
|
|
int
|
|
so_accept(int fd, unsigned char *raddr, unsigned short *rport)
|
|
{
|
|
int nfd;
|
|
int len;
|
|
struct sockaddr_storage ss;
|
|
|
|
len = sizeof(ss);
|
|
nfd = accept(fd, (struct sockaddr*)&ss, &len);
|
|
if(nfd < 0)
|
|
oserror();
|
|
|
|
switch(ss.ss_family){
|
|
case AF_INET:
|
|
v4tov6(raddr, (unsigned char*)&((struct sockaddr_in*)&ss)->sin_addr.s_addr);
|
|
*rport = nhgets(&((struct sockaddr_in*)&ss)->sin_port);
|
|
break;
|
|
case AF_INET6:
|
|
memcpy(raddr, &((struct sockaddr_in6*)&ss)->sin6_addr.s6_addr, sizeof(struct in6_addr));
|
|
*rport = nhgets(&((struct sockaddr_in6*)&ss)->sin6_port);
|
|
break;
|
|
default:
|
|
error("not AF_INET or AF_INET6");
|
|
}
|
|
return nfd;
|
|
}
|
|
|
|
void
|
|
so_bind(int fd, int su, unsigned short port, unsigned char *addr)
|
|
{
|
|
int i, one;
|
|
struct sockaddr_storage ss;
|
|
|
|
one = 1;
|
|
if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(one)) < 0){
|
|
oserrstr();
|
|
print("setsockopt: %r");
|
|
}
|
|
|
|
if(su) {
|
|
for(i = 600; i < 1024; i++) {
|
|
memset(&ss, 0, sizeof(ss));
|
|
ss.ss_family = family(addr);
|
|
|
|
switch(ss.ss_family){
|
|
case AF_INET:
|
|
((struct sockaddr_in*)&ss)->sin_port = i;
|
|
break;
|
|
case AF_INET6:
|
|
((struct sockaddr_in6*)&ss)->sin6_port = i;
|
|
break;
|
|
}
|
|
|
|
if(bind(fd, (struct sockaddr*)&ss, sizeof(ss)) >= 0)
|
|
return;
|
|
}
|
|
oserror();
|
|
}
|
|
|
|
memset(&ss, 0, sizeof(ss));
|
|
ss.ss_family = family(addr);
|
|
|
|
switch(ss.ss_family){
|
|
case AF_INET:
|
|
hnputs(&((struct sockaddr_in*)&ss)->sin_port, port);
|
|
break;
|
|
case AF_INET6:
|
|
hnputs(&((struct sockaddr_in6*)&ss)->sin6_port, port);
|
|
break;
|
|
}
|
|
|
|
if(bind(fd, (struct sockaddr*)&ss, sizeof(ss)) < 0)
|
|
oserror();
|
|
}
|
|
|
|
int
|
|
so_gethostbyname(char *host, char**hostv, int n)
|
|
{
|
|
int i;
|
|
char buf[32];
|
|
unsigned char *p;
|
|
struct hostent *hp;
|
|
|
|
hp = gethostbyname(host);
|
|
if(hp == 0)
|
|
return 0;
|
|
|
|
for(i = 0; hp->h_addr_list[i] && i < n; i++) {
|
|
p = (unsigned char*)hp->h_addr_list[i];
|
|
sprint(buf, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
|
|
hostv[i] = strdup(buf);
|
|
if(hostv[i] == 0)
|
|
break;
|
|
}
|
|
return i;
|
|
}
|
|
|
|
char*
|
|
hostlookup(char *host)
|
|
{
|
|
char buf[100];
|
|
uchar *p;
|
|
struct hostent *he;
|
|
|
|
he = gethostbyname(host);
|
|
if(he != 0 && he->h_addr_list[0]) {
|
|
p = (uchar*)he->h_addr_list[0];
|
|
sprint(buf, "%ud.%ud.%ud.%ud", p[0], p[1], p[2], p[3]);
|
|
} else
|
|
strcpy(buf, host);
|
|
|
|
return strdup(buf);
|
|
}
|
|
|
|
int
|
|
so_getservbyname(char *service, char *net, char *port)
|
|
{
|
|
struct servent *s;
|
|
|
|
s = getservbyname(service, net);
|
|
if(s == 0)
|
|
return -1;
|
|
|
|
sprint(port, "%d", nhgets(&s->s_port));
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
so_send(int fd, void *d, int n, int f)
|
|
{
|
|
return send(fd, d, n, f);
|
|
}
|
|
|
|
int
|
|
so_recv(int fd, void *d, int n, int f)
|
|
{
|
|
return recv(fd, d, n, f);
|
|
}
|