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:
Hugo Santos
2007-04-20 01:58:14 +00:00
parent 618aaaed08
commit 2445c00e64
10 changed files with 189 additions and 86 deletions
+4
View File
@@ -36,6 +36,10 @@ struct net_protocol_module_info {
status_t (*accept)(net_protocol *self, struct net_socket **_acceptedSocket); status_t (*accept)(net_protocol *self, struct net_socket **_acceptedSocket);
status_t (*control)(net_protocol *self, int level, int option, void *value, status_t (*control)(net_protocol *self, int level, int option, void *value,
size_t *_length); 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 (*bind)(net_protocol *self, struct sockaddr *address);
status_t (*unbind)(net_protocol *self, struct sockaddr *address); status_t (*unbind)(net_protocol *self, struct sockaddr *address);
+5
View File
@@ -59,6 +59,11 @@ struct net_socket_module_info {
status_t (*receive_data)(net_socket *socket, size_t length, uint32 flags, status_t (*receive_data)(net_socket *socket, size_t length, uint32 flags,
net_buffer **_buffer); 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); status_t (*get_next_stat)(uint32 *cookie, int family, struct net_stat *stat);
// connections // connections
@@ -330,6 +330,8 @@ net_protocol_module_info sICMPModule = {
icmp_connect, icmp_connect,
icmp_accept, icmp_accept,
icmp_control, icmp_control,
NULL, // getsockopt
NULL, // setsockopt
icmp_bind, icmp_bind,
icmp_unbind, icmp_unbind,
icmp_listen, icmp_listen,
@@ -181,6 +181,7 @@ net_buffer_module_info *gBufferModule;
static struct net_domain *sDomain; static struct net_domain *sDomain;
static net_datalink_module_info *sDatalinkModule; static net_datalink_module_info *sDatalinkModule;
static net_socket_module_info *sSocketModule;
static int32 sPacketID; static int32 sPacketID;
static RawSocketList sRawSockets; static RawSocketList sRawSockets;
static benaphore sRawSocketsLock; static benaphore sRawSocketsLock;
@@ -1049,7 +1050,7 @@ get_int_option(void *target, size_t length, int value)
template<typename Type> static status_t 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; int value;
@@ -1071,56 +1072,80 @@ ipv4_control(net_protocol *_protocol, int level, int option, void *value,
if ((level & LEVEL_MASK) != IPPROTO_IP) if ((level & LEVEL_MASK) != IPPROTO_IP)
return sDatalinkModule->control(sDomain, option, value, _length); 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; ipv4_protocol *protocol = (ipv4_protocol *)_protocol;
if (level & LEVEL_GET_OPTION) { // as we are the last protocol in the chain (i.e. no socket protocol
// get options // 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) { switch (option) {
case IP_HDRINCL: case IP_HDRINCL:
return get_int_option(value, *_length, return get_int_option(value, *_length,
(protocol->flags & IP_FLAG_HEADER_INCLUDED) != 0); (protocol->flags & IP_FLAG_HEADER_INCLUDED) != 0);
case IP_TTL: case IP_TTL:
return get_int_option(value, *_length, protocol->time_to_live); return get_int_option(value, *_length, protocol->time_to_live);
case IP_TOS: case IP_TOS:
return get_int_option(value, *_length, protocol->service_type); return get_int_option(value, *_length, protocol->service_type);
case IP_MULTICAST_TTL: case IP_MULTICAST_TTL:
return get_int_option(value, *_length, return get_int_option(value, *_length,
protocol->multicast_time_to_live); protocol->multicast_time_to_live);
case IP_ADD_MEMBERSHIP: case IP_ADD_MEMBERSHIP:
case IP_DROP_MEMBERSHIP: case IP_DROP_MEMBERSHIP:
case IP_BLOCK_SOURCE: case IP_BLOCK_SOURCE:
case IP_UNBLOCK_SOURCE: case IP_UNBLOCK_SOURCE:
case IP_ADD_SOURCE_MEMBERSHIP: case IP_ADD_SOURCE_MEMBERSHIP:
case IP_DROP_SOURCE_MEMBERSHIP: case IP_DROP_SOURCE_MEMBERSHIP:
case MCAST_JOIN_GROUP: case MCAST_JOIN_GROUP:
case MCAST_LEAVE_GROUP: case MCAST_LEAVE_GROUP:
case MCAST_BLOCK_SOURCE: case MCAST_BLOCK_SOURCE:
case MCAST_UNBLOCK_SOURCE: case MCAST_UNBLOCK_SOURCE:
case MCAST_JOIN_SOURCE_GROUP: case MCAST_JOIN_SOURCE_GROUP:
case MCAST_LEAVE_SOURCE_GROUP: case MCAST_LEAVE_SOURCE_GROUP:
// RFC 3678, Section 4.1: // RFC 3678, Section 4.1:
// ``An error of EOPNOTSUPP is returned if these options are // ``An error of EOPNOTSUPP is returned if these options are
// used with getsockopt().'' // used with getsockopt().''
return EOPNOTSUPP; return EOPNOTSUPP;
default: default:
dprintf("IPv4::control(): get unknown option: %d\n", option); dprintf("IPv4::getsockopt(): get unknown option: %d\n", option);
return ENOPROTOOPT; 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) { switch (option) {
case IP_HDRINCL: case IP_HDRINCL:
{ {
int headerIncluded; int headerIncluded;
if (*_length != sizeof(int)) if (length != sizeof(int))
return B_BAD_VALUE; return B_BAD_VALUE;
if (user_memcpy(&headerIncluded, value, sizeof(headerIncluded)) < B_OK) if (user_memcpy(&headerIncluded, value, sizeof(headerIncluded)) < B_OK)
return B_BAD_ADDRESS; return B_BAD_ADDRESS;
@@ -1133,20 +1158,20 @@ ipv4_control(net_protocol *_protocol, int level, int option, void *value,
} }
case IP_TTL: 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: 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: case IP_MULTICAST_TTL:
return set_int_option(protocol->multicast_time_to_live, value, return set_int_option(protocol->multicast_time_to_live, value,
*_length); length);
case IP_ADD_MEMBERSHIP: case IP_ADD_MEMBERSHIP:
case IP_DROP_MEMBERSHIP: case IP_DROP_MEMBERSHIP:
{ {
ip_mreq mreq; ip_mreq mreq;
if (*_length != sizeof(ip_mreq)) if (length != sizeof(ip_mreq))
return B_BAD_VALUE; return B_BAD_VALUE;
if (user_memcpy(&mreq, value, sizeof(ip_mreq)) < B_OK) if (user_memcpy(&mreq, value, sizeof(ip_mreq)) < B_OK)
return B_BAD_ADDRESS; return B_BAD_ADDRESS;
@@ -1161,7 +1186,7 @@ ipv4_control(net_protocol *_protocol, int level, int option, void *value,
case IP_DROP_SOURCE_MEMBERSHIP: case IP_DROP_SOURCE_MEMBERSHIP:
{ {
ip_mreq_source mreq; ip_mreq_source mreq;
if (*_length != sizeof(ip_mreq_source)) if (length != sizeof(ip_mreq_source))
return B_BAD_VALUE; return B_BAD_VALUE;
if (user_memcpy(&mreq, value, sizeof(ip_mreq_source)) < B_OK) if (user_memcpy(&mreq, value, sizeof(ip_mreq_source)) < B_OK)
return B_BAD_ADDRESS; return B_BAD_ADDRESS;
@@ -1174,7 +1199,7 @@ ipv4_control(net_protocol *_protocol, int level, int option, void *value,
case MCAST_LEAVE_GROUP: case MCAST_LEAVE_GROUP:
{ {
group_req greq; group_req greq;
if (*_length != sizeof(group_req)) if (length != sizeof(group_req))
return B_BAD_VALUE; return B_BAD_VALUE;
if (user_memcpy(&greq, value, sizeof(group_req)) < B_OK) if (user_memcpy(&greq, value, sizeof(group_req)) < B_OK)
return B_BAD_ADDRESS; return B_BAD_ADDRESS;
@@ -1189,7 +1214,7 @@ ipv4_control(net_protocol *_protocol, int level, int option, void *value,
case MCAST_LEAVE_SOURCE_GROUP: case MCAST_LEAVE_SOURCE_GROUP:
{ {
group_source_req greq; group_source_req greq;
if (*_length != sizeof(group_source_req)) if (length != sizeof(group_source_req))
return B_BAD_VALUE; return B_BAD_VALUE;
if (user_memcpy(&greq, value, sizeof(group_source_req)) < B_OK) if (user_memcpy(&greq, value, sizeof(group_source_req)) < B_OK)
return B_BAD_ADDRESS; return B_BAD_ADDRESS;
@@ -1199,12 +1224,9 @@ ipv4_control(net_protocol *_protocol, int level, int option, void *value,
} }
default: default:
dprintf("IPv4::control(): set unknown option: %d\n", option); dprintf("IPv4::setsockopt(): set unknown option: %d\n", option);
return ENOPROTOOPT; return ENOPROTOOPT;
} }
// never gets here
return B_BAD_VALUE;
} }
@@ -1689,6 +1711,8 @@ net_protocol_module_info gIPv4Module = {
ipv4_connect, ipv4_connect,
ipv4_accept, ipv4_accept,
ipv4_control, ipv4_control,
ipv4_getsockopt,
ipv4_setsockopt,
ipv4_bind, ipv4_bind,
ipv4_unbind, ipv4_unbind,
ipv4_listen, ipv4_listen,
@@ -1710,6 +1734,7 @@ module_dependency module_dependencies[] = {
{NET_STACK_MODULE_NAME, (module_info **)&gStackModule}, {NET_STACK_MODULE_NAME, (module_info **)&gStackModule},
{NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule}, {NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule},
{NET_DATALINK_MODULE_NAME, (module_info **)&sDatalinkModule}, {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) } else if (fState != CLOSED)
return EISCONN; return EISCONN;
fSendQueue.SetMaxBytes(socket->send.buffer_size);
fReceiveQueue.SetMaxBytes(socket->receive.buffer_size);
status_t status = _PrepareSendPath(address); status_t status = _PrepareSendPath(address);
if (status < B_OK) if (status < B_OK)
return status; 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 // #pragma mark - misc
@@ -59,6 +59,9 @@ class TCPEndpoint : public net_protocol {
status_t ReadData(size_t numBytes, uint32 flags, net_buffer **_buffer); status_t ReadData(size_t numBytes, uint32 flags, net_buffer **_buffer);
ssize_t ReadAvailable(); ssize_t ReadAvailable();
status_t SetSendBufferSize(size_t length);
status_t SetReceiveBufferSize(size_t length);
tcp_state State() const { return fState; } tcp_state State() const { return fState; }
bool IsBound() const; bool IsBound() const;
@@ -410,24 +410,46 @@ tcp_control(net_protocol *_protocol, int level, int option, void *value,
{ {
TCPEndpoint *protocol = (TCPEndpoint *)_protocol; TCPEndpoint *protocol = (TCPEndpoint *)_protocol;
switch (level & LEVEL_MASK) { if ((level & LEVEL_MASK) == IPPROTO_TCP) {
case IPPROTO_TCP: if (option == NET_STAT_SOCKET) {
if (option == NET_STAT_SOCKET) { net_stat *stat = (net_stat *)value;
net_stat *stat = (net_stat *)value; strlcpy(stat->state, name_for_state(protocol->State()),
strlcpy(stat->state, name_for_state(protocol->State()), sizeof(stat->state));
sizeof(stat->state)); return B_OK;
return B_OK; }
}
break;
case SOL_SOCKET:
break;
default:
return protocol->next->module->control(protocol->next, level, option,
value, _length);
} }
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_connect,
tcp_accept, tcp_accept,
tcp_control, tcp_control,
NULL, // getsockopt
tcp_setsockopt,
tcp_bind, tcp_bind,
tcp_unbind, tcp_unbind,
tcp_listen, tcp_listen,
@@ -1212,6 +1212,8 @@ net_protocol_module_info sUDPModule = {
udp_connect, udp_connect,
udp_accept, udp_accept,
udp_control, udp_control,
NULL, // getsockopt
NULL, // setsockopt
udp_bind, udp_bind,
udp_unbind, udp_unbind,
udp_listen, udp_listen,
@@ -498,6 +498,8 @@ net_protocol_module_info gLinkModule = {
link_connect, link_connect,
link_accept, link_accept,
link_control, link_control,
NULL, // getsockopt
NULL, // setsockopt
link_bind, link_bind,
link_unbind, link_unbind,
link_listen, link_listen,
+41 -20
View File
@@ -639,15 +639,9 @@ socket_getsockname(net_socket *socket, struct sockaddr *address, socklen_t *_add
} }
int status_t
socket_getsockopt(net_socket *socket, int level, int option, void *value, socket_get_option(net_socket *socket, int option, void *value, int *_length)
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) { switch (option) {
case SO_SNDBUF: 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 int
socket_listen(net_socket *socket, int backlog) socket_listen(net_socket *socket, int backlog)
{ {
@@ -940,15 +951,10 @@ socket_send(net_socket *socket, msghdr *header, const void *data,
} }
int status_t
socket_setsockopt(net_socket *socket, int level, int option, const void *value, socket_set_option(net_socket *socket, int option, const void *value,
int length) 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) { switch (option) {
// TODO: implement other options! // TODO: implement other options!
case SO_LINGER: case SO_LINGER:
@@ -968,8 +974,6 @@ socket_setsockopt(net_socket *socket, int level, int option, const void *value,
} }
case SO_SNDBUF: 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)) if (length != sizeof(uint32))
return B_BAD_VALUE; return B_BAD_VALUE;
@@ -977,7 +981,6 @@ socket_setsockopt(net_socket *socket, int level, int option, const void *value,
return B_OK; return B_OK;
case SO_RCVBUF: case SO_RCVBUF:
// TODO: see above (SO_SNDBUF)
if (length != sizeof(uint32)) if (length != sizeof(uint32))
return B_BAD_VALUE; return B_BAD_VALUE;
@@ -985,7 +988,6 @@ socket_setsockopt(net_socket *socket, int level, int option, const void *value,
return B_OK; return B_OK;
case SO_SNDLOWAT: case SO_SNDLOWAT:
// TODO: see above (SO_SNDBUF)
if (length != sizeof(uint32)) if (length != sizeof(uint32))
return B_BAD_VALUE; return B_BAD_VALUE;
@@ -993,7 +995,6 @@ socket_setsockopt(net_socket *socket, int level, int option, const void *value,
return B_OK; return B_OK;
case SO_RCVLOWAT: case SO_RCVLOWAT:
// TODO: see above (SO_SNDBUF)
if (length != sizeof(uint32)) if (length != sizeof(uint32))
return B_BAD_VALUE; 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 int
socket_shutdown(net_socket *socket, int direction) socket_shutdown(net_socket *socket, int direction)
{ {
@@ -1111,6 +1129,9 @@ net_socket_module_info gNetSocketModule = {
socket_send_data, socket_send_data,
socket_receive_data, socket_receive_data,
socket_get_option,
socket_set_option,
socket_get_next_stat, socket_get_next_stat,
// connections // connections