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

View File

@ -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);

View File

@ -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

View File

@ -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,

View File

@ -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},
{}
};

View File

@ -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

View File

@ -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;

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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