* Added flags field in net_protocol_module_info; there is currently a single
defined flag: NET_PROTOCOL_ATOMIC_MESSAGES. * socket_send() now honours NET_PROTOCOL_ATOMIC_MESSAGES and returns either EMSGSIZE if the data to be send is larger than net_socket::send::buffer_size, or divides the data in appropriately sized chunks. * This fixes sending >=64K over a TCP socket at once (TCP would just have returned an error in that case). * TCP now overrides the default send buffer size (to 32768 for now). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23915 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2006-2008, Haiku, Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef NET_PROTOCOL_H
|
||||
@@ -22,8 +22,12 @@ typedef struct net_protocol {
|
||||
net_socket *socket;
|
||||
} net_protocol;
|
||||
|
||||
// net_protocol_module_info::flags field
|
||||
#define NET_PROTOCOL_ATOMIC_MESSAGES 0x01
|
||||
|
||||
struct net_protocol_module_info {
|
||||
module_info info;
|
||||
uint32 flags;
|
||||
|
||||
net_protocol *(*init_protocol)(net_socket *socket);
|
||||
status_t (*uninit_protocol)(net_protocol *self);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2006-2007, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2006-2008, Haiku, Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
@@ -338,6 +338,8 @@ net_protocol_module_info sICMPModule = {
|
||||
0,
|
||||
icmp_std_ops
|
||||
},
|
||||
NET_PROTOCOL_ATOMIC_MESSAGES,
|
||||
|
||||
icmp_init_protocol,
|
||||
icmp_uninit_protocol,
|
||||
icmp_open,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2006-2007, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2006-2008, Haiku, Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
@@ -1698,6 +1698,8 @@ net_protocol_module_info gIPv4Module = {
|
||||
0,
|
||||
ipv4_std_ops
|
||||
},
|
||||
NET_PROTOCOL_ATOMIC_MESSAGES,
|
||||
|
||||
ipv4_init_protocol,
|
||||
ipv4_uninit_protocol,
|
||||
ipv4_open,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2006-2007, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2006-2008, Haiku, Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
@@ -564,7 +564,7 @@ TCPEndpoint::SendData(net_buffer *buffer)
|
||||
|
||||
if (buffer->size > 0) {
|
||||
if (buffer->size > fSendQueue.Size())
|
||||
return EMSGSIZE;
|
||||
return ENOBUFS;
|
||||
|
||||
bigtime_t timeout = absolute_timeout(socket->send.timeout);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2006-2007, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2006-2008, Haiku, Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
@@ -421,6 +421,9 @@ dump_endpoint(int argc, char *argv[])
|
||||
net_protocol *
|
||||
tcp_init_protocol(net_socket *socket)
|
||||
{
|
||||
socket->send.buffer_size = 32768;
|
||||
// override net_socket default
|
||||
|
||||
TCPEndpoint *protocol = new (std::nothrow) TCPEndpoint(socket);
|
||||
if (protocol == NULL)
|
||||
return NULL;
|
||||
@@ -775,6 +778,8 @@ net_protocol_module_info sTCPModule = {
|
||||
0,
|
||||
tcp_std_ops
|
||||
},
|
||||
0,
|
||||
|
||||
tcp_init_protocol,
|
||||
tcp_uninit_protocol,
|
||||
tcp_open,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2006-2007, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2006-2008, Haiku, Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
@@ -1230,6 +1230,8 @@ net_protocol_module_info sUDPModule = {
|
||||
0,
|
||||
udp_std_ops
|
||||
},
|
||||
NET_PROTOCOL_ATOMIC_MESSAGES,
|
||||
|
||||
udp_init_protocol,
|
||||
udp_uninit_protocol,
|
||||
udp_open,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2006-2007, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2006-2008, Haiku, Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
@@ -477,6 +477,8 @@ net_protocol_module_info gLinkModule = {
|
||||
0,
|
||||
link_std_ops
|
||||
},
|
||||
NET_PROTOCOL_ATOMIC_MESSAGES,
|
||||
|
||||
link_init_protocol,
|
||||
link_uninit_protocol,
|
||||
link_open,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2006-2007, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2006-2008, Haiku, Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
@@ -48,6 +48,23 @@ struct list sSocketList;
|
||||
benaphore sSocketLock;
|
||||
|
||||
|
||||
static size_t
|
||||
compute_user_iovec_length(iovec *userVec, uint32 count)
|
||||
{
|
||||
size_t length = 0;
|
||||
|
||||
for (uint32 i = 0; i < count; i++) {
|
||||
iovec vec;
|
||||
if (user_memcpy(&vec, userVec + i, sizeof(iovec)) < B_OK)
|
||||
return 0;
|
||||
|
||||
length += vec.iov_len;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
create_socket(int family, int type, int protocol, net_socket_private **_socket)
|
||||
{
|
||||
@@ -883,11 +900,15 @@ socket_receive(net_socket *socket, msghdr *header, void *data, size_t length,
|
||||
|
||||
|
||||
ssize_t
|
||||
socket_send(net_socket *socket, msghdr *header, const void *data,
|
||||
size_t length, int flags)
|
||||
socket_send(net_socket *socket, msghdr *header, const void *data, size_t length,
|
||||
int flags)
|
||||
{
|
||||
const sockaddr *address = NULL;
|
||||
socklen_t addressLength = 0;
|
||||
size_t bytesLeft = length;
|
||||
|
||||
if (length > SSIZE_MAX)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// the convention to this function is that have header been
|
||||
// present, { data, length } would have been iovec[0] and is
|
||||
@@ -899,6 +920,10 @@ socket_send(net_socket *socket, msghdr *header, const void *data,
|
||||
|
||||
if (header->msg_iovlen <= 1)
|
||||
header = NULL;
|
||||
else {
|
||||
bytesLeft += compute_user_iovec_length(header->msg_iov + 1,
|
||||
header->msg_iovlen - 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (addressLength == 0)
|
||||
@@ -920,6 +945,10 @@ socket_send(net_socket *socket, msghdr *header, const void *data,
|
||||
return EDESTADDRREQ;
|
||||
}
|
||||
|
||||
if ((socket->first_info->flags & NET_PROTOCOL_ATOMIC_MESSAGES) != 0
|
||||
&& bytesLeft > socket->send.buffer_size)
|
||||
return EMSGSIZE;
|
||||
|
||||
if (socket->address.ss_len == 0) {
|
||||
// try to bind first
|
||||
status_t status = socket_bind(socket, NULL, 0);
|
||||
@@ -927,51 +956,79 @@ socket_send(net_socket *socket, msghdr *header, const void *data,
|
||||
return status;
|
||||
}
|
||||
|
||||
// TODO: useful, maybe even computed header space!
|
||||
net_buffer *buffer = gNetBufferModule.create(256);
|
||||
if (buffer == NULL)
|
||||
return ENOBUFS;
|
||||
ssize_t bytesSent = 0;
|
||||
size_t vecOffset = 0;
|
||||
uint32 vecIndex = 0;
|
||||
|
||||
if (gNetBufferModule.append(buffer, data, length) < B_OK) {
|
||||
gNetBufferModule.free(buffer);
|
||||
return ENOBUFS;
|
||||
}
|
||||
while (bytesLeft > 0) {
|
||||
// TODO: useful, maybe even computed header space!
|
||||
net_buffer *buffer = gNetBufferModule.create(256);
|
||||
if (buffer == NULL)
|
||||
return ENOBUFS;
|
||||
|
||||
if (header) {
|
||||
// copy additional data into buffer
|
||||
for (int i = 1; i < header->msg_iovlen; i++) {
|
||||
iovec vec;
|
||||
if (user_memcpy(&vec, header->msg_iov + i, sizeof(iovec)) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
if (gNetBufferModule.append(buffer, vec.iov_base,
|
||||
vec.iov_len) < B_OK) {
|
||||
while (buffer->size < socket->send.buffer_size
|
||||
&& buffer->size < bytesLeft) {
|
||||
if (vecIndex > 0 && vecOffset == 0) {
|
||||
// retrieve next iovec buffer from header
|
||||
iovec vec;
|
||||
if (user_memcpy(&vec, header->msg_iov + vecIndex, sizeof(iovec))
|
||||
< B_OK) {
|
||||
gNetBufferModule.free(buffer);
|
||||
return B_BAD_ADDRESS;
|
||||
}
|
||||
|
||||
data = vec.iov_base;
|
||||
length = vec.iov_len;
|
||||
}
|
||||
|
||||
size_t bytes = length;
|
||||
if (buffer->size + bytes > socket->send.buffer_size)
|
||||
bytes = socket->send.buffer_size - buffer->size;
|
||||
|
||||
if (gNetBufferModule.append(buffer, data, bytes) < B_OK) {
|
||||
gNetBufferModule.free(buffer);
|
||||
return ENOBUFS;
|
||||
}
|
||||
|
||||
length += vec.iov_len;
|
||||
if (bytes != length) {
|
||||
// partial send
|
||||
vecOffset = bytes;
|
||||
length -= vecOffset;
|
||||
data = (uint8 *)data + vecOffset;
|
||||
} else if (header != NULL) {
|
||||
// proceed with next buffer, if any
|
||||
vecOffset = 0;
|
||||
vecIndex++;
|
||||
|
||||
if (vecIndex >= (uint32)header->msg_iovlen)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
size_t bufferSize = buffer->size;
|
||||
buffer->flags = flags;
|
||||
memcpy(buffer->source, &socket->address, socket->address.ss_len);
|
||||
memcpy(buffer->destination, address, addressLength);
|
||||
|
||||
status_t status = socket->first_info->send_data(socket->first_protocol,
|
||||
buffer);
|
||||
if (status < B_OK) {
|
||||
size_t sizeAfterSend = buffer->size;
|
||||
gNetBufferModule.free(buffer);
|
||||
|
||||
if (sizeAfterSend != bufferSize
|
||||
&& (status == B_INTERRUPTED || status == B_WOULD_BLOCK)) {
|
||||
// this appears to be a partial write
|
||||
return bytesSent + (bufferSize - sizeAfterSend);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
bytesLeft -= bufferSize;
|
||||
bytesSent += bufferSize;
|
||||
}
|
||||
|
||||
buffer->flags = flags;
|
||||
memcpy(buffer->source, &socket->address, socket->address.ss_len);
|
||||
memcpy(buffer->destination, address, addressLength);
|
||||
|
||||
status_t status = socket->first_info->send_data(socket->first_protocol,
|
||||
buffer);
|
||||
if (status < B_OK) {
|
||||
size_t size = buffer->size;
|
||||
gNetBufferModule.free(buffer);
|
||||
|
||||
if (size != length
|
||||
&& (status == B_INTERRUPTED || status == B_WOULD_BLOCK)) {
|
||||
// this appears to be a partial write
|
||||
return length - size;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
return length;
|
||||
return bytesSent;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user