diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage index 50ee7b100b..6269649995 100644 --- a/build/jam/HaikuImage +++ b/build/jam/HaikuImage @@ -136,6 +136,7 @@ AddFilesToHaikuImage beos system : kernel_$(TARGET_ARCH) ; AddFilesToHaikuImage beos system lib : $(BEOS_SYSTEM_LIB) ; AddSymlinkToHaikuImage beos system lib : libnetwork.so : libsocket.so ; AddSymlinkToHaikuImage beos system lib : libnetwork.so : libbind.so ; +AddSymlinkToHaikuImage beos system lib : libnetwork.so : libnet.so ; # servers AddFilesToHaikuImage beos system servers : $(BEOS_SYSTEM_SERVERS) ; diff --git a/headers/private/net/r5_compatibility.h b/headers/private/net/r5_compatibility.h index c005ddf194..2be5708207 100644 --- a/headers/private/net/r5_compatibility.h +++ b/headers/private/net/r5_compatibility.h @@ -5,11 +5,39 @@ #ifndef NET_R5_COMPATIBILITY_H #define NET_R5_COMPATIBILITY_H -// TODO: judging from R5 headers, this is all wrong, though (this has been taken from -// our old socket header) - we'll need to test this later on! -// Also, more problematic is that IPPROTO_* constants also don't seem to be compatible, too -#define R5_SOCK_DGRAM 10 -#define R5_SOCK_STREAM 11 -#define R5_SOCK_RAW 12 + +#include + + +#define R5_SOCK_DGRAM 1 +#define R5_SOCK_STREAM 2 + +#define R5_AF_INET 1 + +#define R5_IPPROTO_UDP 1 +#define R5_IPPROTO_TCP 2 +#define R5_IPPROTO_ICMP 3 + +// setsockopt() defines + +#define R5_SOL_SOCKET 1 + +#define R5_SO_DEBUG 1 +#define R5_SO_REUSEADDR 2 +#define R5_SO_NONBLOCK 3 +#define R5_SO_REUSEPORT 4 +#define R5_SO_FIONREAD 5 + +#define R5_MSG_OOB 0x01 + + +struct r5_sockaddr_in { + uint16 sin_family; + uint16 sin_port; + uint32 sin_addr; + char sin_zero[4]; +}; + +extern bool __gR5Compatibility; #endif // NET_R5_COMPATIBILITY_H diff --git a/src/kits/network/Jamfile b/src/kits/network/Jamfile index 96bd3bcc5e..e954403cdf 100644 --- a/src/kits/network/Jamfile +++ b/src/kits/network/Jamfile @@ -1,8 +1,9 @@ SubDir HAIKU_TOP src kits network ; -UsePrivateHeaders net ; +UsePrivateHeaders libroot net ; SharedLibrary libnetwork.so : + init.cpp interfaces.cpp socket.cpp : diff --git a/src/kits/network/init.cpp b/src/kits/network/init.cpp new file mode 100644 index 0000000000..70a74a528c --- /dev/null +++ b/src/kits/network/init.cpp @@ -0,0 +1,56 @@ +/* + * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ + + +#include + +#include +#include + + +bool __gR5Compatibility = false; + + +extern "C" void +initialize_before() +{ + // determine if we have to run in R5 compatibility mode + + // get image of executable + image_info info; + uint32 cookie = 0; + if (get_next_image_info(B_CURRENT_TEAM, (int32 *)&cookie, &info) != B_OK) + return; + + if (get_image_symbol(info.id, "__gHaikuStartupCode", B_SYMBOL_TYPE_DATA, + NULL) == B_OK) { + // we were linked on/for Haiku + return; + } + + // We're using the BeOS startup code, check if BONE libraries are in + // use, and if not, enable the R5 compatibility layer. + + const char *name; + cookie = 0; + int enable = 0; + + while (__get_next_image_dependency(info.id, &cookie, &name) == B_OK) { + if (!strcmp(name, "libbind.so") + || !strcmp(name, "libsocket.so") + || !strcmp(name, "libnetwork.so") + enable -= 2; + else if (!strcmp(name, "libnet.so")) + enable++; + } + + if (enable > 0) { + __gR5Compatibility = true; + debug_printf("libnetwork.so running in R5 compatibility mode.\n"); + } +} diff --git a/src/kits/network/socket.cpp b/src/kits/network/socket.cpp index 0d393fdb19..2d377dbe79 100644 --- a/src/kits/network/socket.cpp +++ b/src/kits/network/socket.cpp @@ -9,10 +9,14 @@ */ #include +#include #include -#include +#include #include +#include +#include +#include // TODO: this is meant for debugging purposes only, and should be disabled later @@ -29,6 +33,106 @@ stack_driver_path(void) } +static void +convert_from_r5_sockaddr(struct sockaddr *_to, const struct sockaddr *_from) +{ + const r5_sockaddr_in *from = (r5_sockaddr_in *)_from; + sockaddr_in *to = (sockaddr_in *)_to; + + memset(to, 0, sizeof(*to)); + to->sin_len = sizeof(*to); + + if (from->sin_family == R5_AF_INET) + to->sin_family = AF_INET; + else + to->sin_family = from->sin_family; + + to->sin_port = from->sin_port; + to->sin_addr.s_addr = from->sin_addr; +} + + +static void +convert_to_r5_sockaddr(struct sockaddr *_to, const struct sockaddr *_from) +{ + const sockaddr_in *from = (sockaddr_in *)_from; + r5_sockaddr_in *to = (r5_sockaddr_in *)_to; + + memset(to, 0, sizeof(*to)); + if (from->sin_family == AF_INET) + to->sin_family = R5_AF_INET; + else + to->sin_family = from->sin_family; + + to->sin_port = from->sin_port; + to->sin_addr = from->sin_addr.s_addr; +} + + +static void +convert_from_r5_socket(int& family, int& type, int& protocol) +{ + switch (family) { + case R5_AF_INET: + family = AF_INET; + break; + } + + switch (type) { + case R5_SOCK_DGRAM: + type = SOCK_DGRAM; + break; + case R5_SOCK_STREAM: + type = SOCK_STREAM; + break; +#if 0 + case R5_SOCK_RAW: + type = SOCK_RAW; + break; +#endif + } + + switch (protocol) { + case R5_IPPROTO_UDP: + protocol = IPPROTO_UDP; + break; + case R5_IPPROTO_TCP: + protocol = R5_IPPROTO_TCP; + break; + case R5_IPPROTO_ICMP: + protocol = R5_IPPROTO_ICMP; + break; + } +} + + +static void +convert_from_r5_sockopt(int& level, int& option) +{ + if (level == R5_SOL_SOCKET) + level = SOL_SOCKET; + + switch (option) { + case R5_SO_DEBUG: + option = SO_DEBUG; + break; + case R5_SO_REUSEADDR: + option = SO_REUSEADDR; + break; + case R5_SO_NONBLOCK: + option = SO_NONBLOCK; + break; + case R5_SO_REUSEPORT: + option = SO_REUSEPORT; + break; + case R5_SO_FIONREAD: + // there is no SO_FIONREAD + option = -1; + break; + } +} + + // #pragma mark - @@ -39,6 +143,9 @@ socket(int family, int type, int protocol) if (socket < 0) return -1; + if (__gR5Compatibility) + convert_from_r5_socket(family, type, protocol); + socket_args args; args.family = family; args.type = type; @@ -56,6 +163,14 @@ socket(int family, int type, int protocol) extern "C" int bind(int socket, const struct sockaddr *address, socklen_t addressLength) { + struct sockaddr r5addr; + + if (__gR5Compatibility) { + convert_from_r5_sockaddr(&r5addr, address); + address = &r5addr; + addressLength = sizeof(struct sockaddr_in); + } + sockaddr_args args; args.address = const_cast(address); args.address_length = addressLength; @@ -74,6 +189,14 @@ shutdown(int socket, int how) extern "C" int connect(int socket, const struct sockaddr *address, socklen_t addressLength) { + struct sockaddr r5addr; + + if (__gR5Compatibility) { + convert_from_r5_sockaddr(&r5addr, address); + address = &r5addr; + addressLength = sizeof(struct sockaddr_in); + } + sockaddr_args args; args.address = const_cast(address); args.address_length = addressLength; @@ -106,17 +229,30 @@ accept(int socket, struct sockaddr *address, socklen_t *_addressLength) return -1; } + struct sockaddr r5addr; accept_args args; + args.cookie = cookie; - args.address = address; - args.address_length = _addressLength ? *_addressLength : 0; + + if (__gR5Compatibility) { + args.address = &r5addr; + args.address_length = sizeof(r5addr); + } else { + args.address = address; + args.address_length = _addressLength ? *_addressLength : 0; + } if (ioctl(socket, NET_STACK_ACCEPT, &args, sizeof(args)) < 0) { close(acceptSocket); return -1; } - *_addressLength = args.address_length; + if (__gR5Compatibility) { + convert_to_r5_sockaddr(address, &r5addr); + if (_addressLength != NULL) + *_addressLength = sizeof(struct r5_sockaddr_in); + } else if (_addressLength != NULL) + *_addressLength = args.address_length; return acceptSocket; } @@ -140,18 +276,30 @@ extern "C" ssize_t recvfrom(int socket, void *data, size_t length, int flags, struct sockaddr *address, socklen_t *_addressLength) { + struct sockaddr r5addr; + transfer_args args; args.data = data; args.data_length = length; args.flags = flags; - args.address = address; - args.address_length = _addressLength ? *_addressLength : 0; + + if (__gR5Compatibility) { + args.address = &r5addr; + args.address_length = sizeof(r5addr); + } else { + args.address = address; + args.address_length = _addressLength ? *_addressLength : 0; + } ssize_t bytesReceived = ioctl(socket, NET_STACK_RECVFROM, &args, sizeof(args)); if (bytesReceived < 0) return -1; - if (_addressLength) + if (__gR5Compatibility) { + convert_to_r5_sockaddr(address, &r5addr); + if (_addressLength != NULL) + *_addressLength = sizeof(struct r5_sockaddr_in); + } else if (_addressLength != NULL) *_addressLength = args.address_length; return bytesReceived; @@ -184,6 +332,14 @@ extern "C" ssize_t sendto(int socket, const void *data, size_t length, int flags, const struct sockaddr *address, socklen_t addressLength) { + struct sockaddr r5addr; + + if (__gR5Compatibility) { + convert_from_r5_sockaddr(&r5addr, address); + address = &r5addr; + addressLength = sizeof(struct sockaddr_in); + } + transfer_args args; args.data = const_cast(data); args.data_length = length; @@ -206,6 +362,16 @@ sendmsg(int socket, const struct msghdr *message, int flags) extern "C" int getsockopt(int socket, int level, int option, void *value, size_t *_length) { + if (__gR5Compatibility) { + if (option == R5_SO_FIONREAD) { + // there is no SO_FIONREAD in our stack; we're using FIONREAD instead + *_length = sizeof(int); + return ioctl(socket, FIONREAD, &value); + } + + convert_from_r5_sockopt(level, option); + } + sockopt_args args; args.level = level; args.option = option; @@ -225,6 +391,9 @@ getsockopt(int socket, int level, int option, void *value, size_t *_length) extern "C" int setsockopt(int socket, int level, int option, const void *value, size_t length) { + if (__gR5Compatibility) + convert_from_r5_sockopt(level, option); + sockopt_args args; args.level = level; args.option = option; @@ -238,14 +407,25 @@ setsockopt(int socket, int level, int option, const void *value, size_t length) extern "C" int getpeername(int socket, struct sockaddr *address, socklen_t *_addressLength) { + struct sockaddr r5addr; + sockaddr_args args; - args.address = address; - args.address_length = _addressLength ? *_addressLength : 0; + if (__gR5Compatibility) { + args.address = &r5addr; + args.address_length = sizeof(r5addr); + } else { + args.address = address; + args.address_length = _addressLength ? *_addressLength : 0; + } if (ioctl(socket, NET_STACK_GETPEERNAME, &args, sizeof(args)) < 0) return -1; - if (_addressLength) + if (__gR5Compatibility) { + convert_to_r5_sockaddr(address, &r5addr); + if (_addressLength != NULL) + *_addressLength = sizeof(struct r5_sockaddr_in); + } else if (_addressLength != NULL) *_addressLength = args.address_length; return 0; @@ -255,14 +435,25 @@ getpeername(int socket, struct sockaddr *address, socklen_t *_addressLength) extern "C" int getsockname(int socket, struct sockaddr *address, socklen_t *_addressLength) { + struct sockaddr r5addr; + sockaddr_args args; - args.address = address; - args.address_length = _addressLength ? *_addressLength : 0; + if (__gR5Compatibility) { + args.address = &r5addr; + args.address_length = sizeof(r5addr); + } else { + args.address = address; + args.address_length = _addressLength ? *_addressLength : 0; + } if (ioctl(socket, NET_STACK_GETSOCKNAME, &args, sizeof(args)) < 0) return -1; - if (_addressLength) + if (__gR5Compatibility) { + convert_to_r5_sockaddr(address, &r5addr); + if (_addressLength != NULL) + *_addressLength = sizeof(struct r5_sockaddr_in); + } else if (_addressLength != NULL) *_addressLength = args.address_length; return 0;