some internal reorganization of getsockopt()/setsockopt() handling. TCP is now able to fully use the application requested sender/receiver buffer sizes for improved performance.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20764 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
618aaaed08
commit
2445c00e64
@ -36,6 +36,10 @@ struct net_protocol_module_info {
|
||||
status_t (*accept)(net_protocol *self, struct net_socket **_acceptedSocket);
|
||||
status_t (*control)(net_protocol *self, int level, int option, void *value,
|
||||
size_t *_length);
|
||||
status_t (*getsockopt)(net_protocol *self, int level, int option,
|
||||
void *value, int *_length);
|
||||
status_t (*setsockopt)(net_protocol *self, int level, int option,
|
||||
const void *value, int length);
|
||||
|
||||
status_t (*bind)(net_protocol *self, struct sockaddr *address);
|
||||
status_t (*unbind)(net_protocol *self, struct sockaddr *address);
|
||||
|
@ -59,6 +59,11 @@ struct net_socket_module_info {
|
||||
status_t (*receive_data)(net_socket *socket, size_t length, uint32 flags,
|
||||
net_buffer **_buffer);
|
||||
|
||||
status_t (*get_option)(net_socket *socket, int option, void *value,
|
||||
int *_length);
|
||||
status_t (*set_option)(net_socket *socket, int option,
|
||||
const void *value, int length);
|
||||
|
||||
status_t (*get_next_stat)(uint32 *cookie, int family, struct net_stat *stat);
|
||||
|
||||
// connections
|
||||
|
@ -330,6 +330,8 @@ net_protocol_module_info sICMPModule = {
|
||||
icmp_connect,
|
||||
icmp_accept,
|
||||
icmp_control,
|
||||
NULL, // getsockopt
|
||||
NULL, // setsockopt
|
||||
icmp_bind,
|
||||
icmp_unbind,
|
||||
icmp_listen,
|
||||
|
@ -181,6 +181,7 @@ net_buffer_module_info *gBufferModule;
|
||||
|
||||
static struct net_domain *sDomain;
|
||||
static net_datalink_module_info *sDatalinkModule;
|
||||
static net_socket_module_info *sSocketModule;
|
||||
static int32 sPacketID;
|
||||
static RawSocketList sRawSockets;
|
||||
static benaphore sRawSocketsLock;
|
||||
@ -1049,7 +1050,7 @@ get_int_option(void *target, size_t length, int value)
|
||||
|
||||
|
||||
template<typename Type> static status_t
|
||||
set_int_option(Type &target, void *_value, size_t length)
|
||||
set_int_option(Type &target, const void *_value, size_t length)
|
||||
{
|
||||
int value;
|
||||
|
||||
@ -1071,56 +1072,80 @@ ipv4_control(net_protocol *_protocol, int level, int option, void *value,
|
||||
if ((level & LEVEL_MASK) != IPPROTO_IP)
|
||||
return sDatalinkModule->control(sDomain, option, value, _length);
|
||||
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ipv4_getsockopt(net_protocol *_protocol, int level, int option, void *value,
|
||||
int *_length)
|
||||
{
|
||||
ipv4_protocol *protocol = (ipv4_protocol *)_protocol;
|
||||
|
||||
if (level & LEVEL_GET_OPTION) {
|
||||
// get options
|
||||
// as we are the last protocol in the chain (i.e. no socket protocol
|
||||
// below) we must call into the socket module directly.
|
||||
if (level == SOL_SOCKET)
|
||||
return sSocketModule->get_option(protocol->socket, option, value,
|
||||
_length);
|
||||
else if (level != IPPROTO_IP)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
switch (option) {
|
||||
case IP_HDRINCL:
|
||||
return get_int_option(value, *_length,
|
||||
(protocol->flags & IP_FLAG_HEADER_INCLUDED) != 0);
|
||||
switch (option) {
|
||||
case IP_HDRINCL:
|
||||
return get_int_option(value, *_length,
|
||||
(protocol->flags & IP_FLAG_HEADER_INCLUDED) != 0);
|
||||
|
||||
case IP_TTL:
|
||||
return get_int_option(value, *_length, protocol->time_to_live);
|
||||
case IP_TTL:
|
||||
return get_int_option(value, *_length, protocol->time_to_live);
|
||||
|
||||
case IP_TOS:
|
||||
return get_int_option(value, *_length, protocol->service_type);
|
||||
case IP_TOS:
|
||||
return get_int_option(value, *_length, protocol->service_type);
|
||||
|
||||
case IP_MULTICAST_TTL:
|
||||
return get_int_option(value, *_length,
|
||||
protocol->multicast_time_to_live);
|
||||
case IP_MULTICAST_TTL:
|
||||
return get_int_option(value, *_length,
|
||||
protocol->multicast_time_to_live);
|
||||
|
||||
case IP_ADD_MEMBERSHIP:
|
||||
case IP_DROP_MEMBERSHIP:
|
||||
case IP_BLOCK_SOURCE:
|
||||
case IP_UNBLOCK_SOURCE:
|
||||
case IP_ADD_SOURCE_MEMBERSHIP:
|
||||
case IP_DROP_SOURCE_MEMBERSHIP:
|
||||
case MCAST_JOIN_GROUP:
|
||||
case MCAST_LEAVE_GROUP:
|
||||
case MCAST_BLOCK_SOURCE:
|
||||
case MCAST_UNBLOCK_SOURCE:
|
||||
case MCAST_JOIN_SOURCE_GROUP:
|
||||
case MCAST_LEAVE_SOURCE_GROUP:
|
||||
// RFC 3678, Section 4.1:
|
||||
// ``An error of EOPNOTSUPP is returned if these options are
|
||||
// used with getsockopt().''
|
||||
return EOPNOTSUPP;
|
||||
case IP_ADD_MEMBERSHIP:
|
||||
case IP_DROP_MEMBERSHIP:
|
||||
case IP_BLOCK_SOURCE:
|
||||
case IP_UNBLOCK_SOURCE:
|
||||
case IP_ADD_SOURCE_MEMBERSHIP:
|
||||
case IP_DROP_SOURCE_MEMBERSHIP:
|
||||
case MCAST_JOIN_GROUP:
|
||||
case MCAST_LEAVE_GROUP:
|
||||
case MCAST_BLOCK_SOURCE:
|
||||
case MCAST_UNBLOCK_SOURCE:
|
||||
case MCAST_JOIN_SOURCE_GROUP:
|
||||
case MCAST_LEAVE_SOURCE_GROUP:
|
||||
// RFC 3678, Section 4.1:
|
||||
// ``An error of EOPNOTSUPP is returned if these options are
|
||||
// used with getsockopt().''
|
||||
return EOPNOTSUPP;
|
||||
|
||||
default:
|
||||
dprintf("IPv4::control(): get unknown option: %d\n", option);
|
||||
return ENOPROTOOPT;
|
||||
}
|
||||
default:
|
||||
dprintf("IPv4::getsockopt(): get unknown option: %d\n", option);
|
||||
return ENOPROTOOPT;
|
||||
}
|
||||
}
|
||||
|
||||
// set options
|
||||
|
||||
status_t
|
||||
ipv4_setsockopt(net_protocol *_protocol, int level, int option,
|
||||
const void *value, int length)
|
||||
{
|
||||
ipv4_protocol *protocol = (ipv4_protocol *)_protocol;
|
||||
|
||||
if (level == SOL_SOCKET)
|
||||
return sSocketModule->set_option(protocol->socket, option, value,
|
||||
length);
|
||||
else if (level != IPPROTO_IP)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
switch (option) {
|
||||
case IP_HDRINCL:
|
||||
{
|
||||
int headerIncluded;
|
||||
if (*_length != sizeof(int))
|
||||
if (length != sizeof(int))
|
||||
return B_BAD_VALUE;
|
||||
if (user_memcpy(&headerIncluded, value, sizeof(headerIncluded)) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
@ -1133,20 +1158,20 @@ ipv4_control(net_protocol *_protocol, int level, int option, void *value,
|
||||
}
|
||||
|
||||
case IP_TTL:
|
||||
return set_int_option(protocol->time_to_live, value, *_length);
|
||||
return set_int_option(protocol->time_to_live, value, length);
|
||||
|
||||
case IP_TOS:
|
||||
return set_int_option(protocol->service_type, value, *_length);
|
||||
return set_int_option(protocol->service_type, value, length);
|
||||
|
||||
case IP_MULTICAST_TTL:
|
||||
return set_int_option(protocol->multicast_time_to_live, value,
|
||||
*_length);
|
||||
length);
|
||||
|
||||
case IP_ADD_MEMBERSHIP:
|
||||
case IP_DROP_MEMBERSHIP:
|
||||
{
|
||||
ip_mreq mreq;
|
||||
if (*_length != sizeof(ip_mreq))
|
||||
if (length != sizeof(ip_mreq))
|
||||
return B_BAD_VALUE;
|
||||
if (user_memcpy(&mreq, value, sizeof(ip_mreq)) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
@ -1161,7 +1186,7 @@ ipv4_control(net_protocol *_protocol, int level, int option, void *value,
|
||||
case IP_DROP_SOURCE_MEMBERSHIP:
|
||||
{
|
||||
ip_mreq_source mreq;
|
||||
if (*_length != sizeof(ip_mreq_source))
|
||||
if (length != sizeof(ip_mreq_source))
|
||||
return B_BAD_VALUE;
|
||||
if (user_memcpy(&mreq, value, sizeof(ip_mreq_source)) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
@ -1174,7 +1199,7 @@ ipv4_control(net_protocol *_protocol, int level, int option, void *value,
|
||||
case MCAST_LEAVE_GROUP:
|
||||
{
|
||||
group_req greq;
|
||||
if (*_length != sizeof(group_req))
|
||||
if (length != sizeof(group_req))
|
||||
return B_BAD_VALUE;
|
||||
if (user_memcpy(&greq, value, sizeof(group_req)) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
@ -1189,7 +1214,7 @@ ipv4_control(net_protocol *_protocol, int level, int option, void *value,
|
||||
case MCAST_LEAVE_SOURCE_GROUP:
|
||||
{
|
||||
group_source_req greq;
|
||||
if (*_length != sizeof(group_source_req))
|
||||
if (length != sizeof(group_source_req))
|
||||
return B_BAD_VALUE;
|
||||
if (user_memcpy(&greq, value, sizeof(group_source_req)) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
@ -1199,12 +1224,9 @@ ipv4_control(net_protocol *_protocol, int level, int option, void *value,
|
||||
}
|
||||
|
||||
default:
|
||||
dprintf("IPv4::control(): set unknown option: %d\n", option);
|
||||
dprintf("IPv4::setsockopt(): set unknown option: %d\n", option);
|
||||
return ENOPROTOOPT;
|
||||
}
|
||||
|
||||
// never gets here
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
|
||||
@ -1689,6 +1711,8 @@ net_protocol_module_info gIPv4Module = {
|
||||
ipv4_connect,
|
||||
ipv4_accept,
|
||||
ipv4_control,
|
||||
ipv4_getsockopt,
|
||||
ipv4_setsockopt,
|
||||
ipv4_bind,
|
||||
ipv4_unbind,
|
||||
ipv4_listen,
|
||||
@ -1710,6 +1734,7 @@ module_dependency module_dependencies[] = {
|
||||
{NET_STACK_MODULE_NAME, (module_info **)&gStackModule},
|
||||
{NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule},
|
||||
{NET_DATALINK_MODULE_NAME, (module_info **)&sDatalinkModule},
|
||||
{NET_SOCKET_MODULE_NAME, (module_info **)&sSocketModule},
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -385,9 +385,6 @@ TCPEndpoint::Connect(const sockaddr *address)
|
||||
} else if (fState != CLOSED)
|
||||
return EISCONN;
|
||||
|
||||
fSendQueue.SetMaxBytes(socket->send.buffer_size);
|
||||
fReceiveQueue.SetMaxBytes(socket->receive.buffer_size);
|
||||
|
||||
status_t status = _PrepareSendPath(address);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
@ -689,6 +686,24 @@ TCPEndpoint::ReadAvailable()
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
TCPEndpoint::SetSendBufferSize(size_t length)
|
||||
{
|
||||
RecursiveLocker _(fLock);
|
||||
fSendQueue.SetMaxBytes(length);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
TCPEndpoint::SetReceiveBufferSize(size_t length)
|
||||
{
|
||||
RecursiveLocker _(fLock);
|
||||
fReceiveQueue.SetMaxBytes(length);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - misc
|
||||
|
||||
|
||||
|
@ -59,6 +59,9 @@ class TCPEndpoint : public net_protocol {
|
||||
status_t ReadData(size_t numBytes, uint32 flags, net_buffer **_buffer);
|
||||
ssize_t ReadAvailable();
|
||||
|
||||
status_t SetSendBufferSize(size_t length);
|
||||
status_t SetReceiveBufferSize(size_t length);
|
||||
|
||||
tcp_state State() const { return fState; }
|
||||
bool IsBound() const;
|
||||
|
||||
|
@ -410,24 +410,46 @@ tcp_control(net_protocol *_protocol, int level, int option, void *value,
|
||||
{
|
||||
TCPEndpoint *protocol = (TCPEndpoint *)_protocol;
|
||||
|
||||
switch (level & LEVEL_MASK) {
|
||||
case IPPROTO_TCP:
|
||||
if (option == NET_STAT_SOCKET) {
|
||||
net_stat *stat = (net_stat *)value;
|
||||
strlcpy(stat->state, name_for_state(protocol->State()),
|
||||
sizeof(stat->state));
|
||||
return B_OK;
|
||||
}
|
||||
break;
|
||||
case SOL_SOCKET:
|
||||
break;
|
||||
|
||||
default:
|
||||
return protocol->next->module->control(protocol->next, level, option,
|
||||
value, _length);
|
||||
if ((level & LEVEL_MASK) == IPPROTO_TCP) {
|
||||
if (option == NET_STAT_SOCKET) {
|
||||
net_stat *stat = (net_stat *)value;
|
||||
strlcpy(stat->state, name_for_state(protocol->State()),
|
||||
sizeof(stat->state));
|
||||
return B_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return B_BAD_VALUE;
|
||||
return protocol->next->module->control(protocol->next, level, option,
|
||||
value, _length);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
tcp_setsockopt(net_protocol *_protocol, int level, int option,
|
||||
const void *_value, int length)
|
||||
{
|
||||
TCPEndpoint *protocol = (TCPEndpoint *)_protocol;
|
||||
|
||||
if (level == SOL_SOCKET) {
|
||||
if (option == SO_SNDBUF || option == SO_RCVBUF) {
|
||||
if (length != sizeof(int))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
status_t status;
|
||||
const int *value = (const int *)_value;
|
||||
|
||||
if (option == SO_SNDBUF)
|
||||
status = protocol->SetSendBufferSize(*value);
|
||||
else
|
||||
status = protocol->SetReceiveBufferSize(*value);
|
||||
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
return protocol->next->module->setsockopt(protocol, level, option, _value,
|
||||
length);
|
||||
}
|
||||
|
||||
|
||||
@ -671,6 +693,8 @@ net_protocol_module_info sTCPModule = {
|
||||
tcp_connect,
|
||||
tcp_accept,
|
||||
tcp_control,
|
||||
NULL, // getsockopt
|
||||
tcp_setsockopt,
|
||||
tcp_bind,
|
||||
tcp_unbind,
|
||||
tcp_listen,
|
||||
|
@ -1212,6 +1212,8 @@ net_protocol_module_info sUDPModule = {
|
||||
udp_connect,
|
||||
udp_accept,
|
||||
udp_control,
|
||||
NULL, // getsockopt
|
||||
NULL, // setsockopt
|
||||
udp_bind,
|
||||
udp_unbind,
|
||||
udp_listen,
|
||||
|
@ -498,6 +498,8 @@ net_protocol_module_info gLinkModule = {
|
||||
link_connect,
|
||||
link_accept,
|
||||
link_control,
|
||||
NULL, // getsockopt
|
||||
NULL, // setsockopt
|
||||
link_bind,
|
||||
link_unbind,
|
||||
link_listen,
|
||||
|
@ -639,15 +639,9 @@ socket_getsockname(net_socket *socket, struct sockaddr *address, socklen_t *_add
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
socket_getsockopt(net_socket *socket, int level, int option, void *value,
|
||||
int *_length)
|
||||
status_t
|
||||
socket_get_option(net_socket *socket, int option, void *value, int *_length)
|
||||
{
|
||||
if (level != SOL_SOCKET) {
|
||||
return socket->first_info->control(socket->first_protocol,
|
||||
level | LEVEL_GET_OPTION, option, value, (size_t *)_length);
|
||||
}
|
||||
|
||||
switch (option) {
|
||||
case SO_SNDBUF:
|
||||
{
|
||||
@ -747,6 +741,23 @@ socket_getsockopt(net_socket *socket, int level, int option, void *value,
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
socket_getsockopt(net_socket *socket, int level, int option, void *value,
|
||||
int *_length)
|
||||
{
|
||||
status_t status = (level == SOL_SOCKET) ? B_OK : B_BAD_VALUE;
|
||||
|
||||
if (socket->first_info->getsockopt)
|
||||
status = socket->first_info->getsockopt(socket->first_protocol, level,
|
||||
option, value, _length);
|
||||
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
return socket_get_option(socket, option, value, _length);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
socket_listen(net_socket *socket, int backlog)
|
||||
{
|
||||
@ -940,15 +951,10 @@ socket_send(net_socket *socket, msghdr *header, const void *data,
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
socket_setsockopt(net_socket *socket, int level, int option, const void *value,
|
||||
status_t
|
||||
socket_set_option(net_socket *socket, int option, const void *value,
|
||||
int length)
|
||||
{
|
||||
if (level != SOL_SOCKET) {
|
||||
return socket->first_info->control(socket->first_protocol,
|
||||
level | LEVEL_SET_OPTION, option, (void *)value, (size_t *)&length);
|
||||
}
|
||||
|
||||
switch (option) {
|
||||
// TODO: implement other options!
|
||||
case SO_LINGER:
|
||||
@ -968,8 +974,6 @@ socket_setsockopt(net_socket *socket, int level, int option, const void *value,
|
||||
}
|
||||
|
||||
case SO_SNDBUF:
|
||||
// TODO: should be handled in the protocol modules - they can actually
|
||||
// check if setting the value is allowed and within valid bounds.
|
||||
if (length != sizeof(uint32))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
@ -977,7 +981,6 @@ socket_setsockopt(net_socket *socket, int level, int option, const void *value,
|
||||
return B_OK;
|
||||
|
||||
case SO_RCVBUF:
|
||||
// TODO: see above (SO_SNDBUF)
|
||||
if (length != sizeof(uint32))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
@ -985,7 +988,6 @@ socket_setsockopt(net_socket *socket, int level, int option, const void *value,
|
||||
return B_OK;
|
||||
|
||||
case SO_SNDLOWAT:
|
||||
// TODO: see above (SO_SNDBUF)
|
||||
if (length != sizeof(uint32))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
@ -993,7 +995,6 @@ socket_setsockopt(net_socket *socket, int level, int option, const void *value,
|
||||
return B_OK;
|
||||
|
||||
case SO_RCVLOWAT:
|
||||
// TODO: see above (SO_SNDBUF)
|
||||
if (length != sizeof(uint32))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
@ -1057,6 +1058,23 @@ socket_setsockopt(net_socket *socket, int level, int option, const void *value,
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
socket_setsockopt(net_socket *socket, int level, int option, const void *value,
|
||||
int length)
|
||||
{
|
||||
status_t status = (level == SOL_SOCKET) ? B_OK : B_BAD_VALUE;
|
||||
|
||||
if (socket->first_info->setsockopt)
|
||||
status = socket->first_info->setsockopt(socket->first_protocol, level,
|
||||
option, value, length);
|
||||
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
return socket_set_option(socket, option, value, length);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
socket_shutdown(net_socket *socket, int direction)
|
||||
{
|
||||
@ -1111,6 +1129,9 @@ net_socket_module_info gNetSocketModule = {
|
||||
socket_send_data,
|
||||
socket_receive_data,
|
||||
|
||||
socket_get_option,
|
||||
socket_set_option,
|
||||
|
||||
socket_get_next_stat,
|
||||
|
||||
// connections
|
||||
|
Loading…
x
Reference in New Issue
Block a user