axeld + bonefish:
* Added syscall restart support for connect(), accept(), send(), recv(), which are implemented via ioctl()s. The actual restart support is done in the net stack driver's ioctl() hook. Lower layers need to correctly deal with socket timeouts, though, for which the stack module provides support functions. * TCPEndpoint::_WaitForEstablished() does abort now when an error occurred earlier, so that trying to connect to an unused port fails immediately, as it should. * Fixed and refactored TCP connection reset handling. The new TCPEndpoint::_HandleReset() does the job. Got rid of TCPEndpoint::fError. * Fixed sequence numbers for SYNC/FINI packets. * The former two fix the problem that connections wouldn't be closed correctly and could even be reused when trying to connect again (as was reproducible with svnserve + svn). * Some style cleanup in CPEndpoint.h. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23984 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -348,6 +348,11 @@ DECL_DATAGRAM_SOCKET(inline bigtime_t)::_SocketTimeout(uint32 flags) const
|
|||||||
else if (timeout != 0 && timeout != B_INFINITE_TIMEOUT)
|
else if (timeout != 0 && timeout != B_INFINITE_TIMEOUT)
|
||||||
timeout += system_time();
|
timeout += system_time();
|
||||||
|
|
||||||
|
if (ModuleBundle::Stack()->is_restarted_syscall())
|
||||||
|
timeout = ModuleBundle::Stack()->restore_syscall_restart_timeout();
|
||||||
|
else
|
||||||
|
ModuleBundle::Stack()->store_syscall_restart_timeout(timeout);
|
||||||
|
|
||||||
return timeout;
|
return 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.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
#ifndef NET_STACK_H
|
#ifndef NET_STACK_H
|
||||||
@@ -44,8 +44,9 @@ struct net_timer {
|
|||||||
bigtime_t due;
|
bigtime_t due;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef int32 (*net_deframe_func)(struct net_device *device, struct net_buffer *buffer);
|
typedef int32 (*net_deframe_func)(struct net_device *device,
|
||||||
typedef status_t (*net_receive_func)(void *cookie, struct net_device *,
|
struct net_buffer *buffer);
|
||||||
|
typedef status_t (*net_receive_func)(void *cookie, struct net_device *device,
|
||||||
struct net_buffer *buffer);
|
struct net_buffer *buffer);
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@@ -132,6 +133,11 @@ struct net_stack_module_info {
|
|||||||
void (*set_timer)(struct net_timer *timer, bigtime_t delay);
|
void (*set_timer)(struct net_timer *timer, bigtime_t delay);
|
||||||
bool (*cancel_timer)(struct net_timer *timer);
|
bool (*cancel_timer)(struct net_timer *timer);
|
||||||
bool (*is_timer_active)(struct net_timer *timer);
|
bool (*is_timer_active)(struct net_timer *timer);
|
||||||
|
|
||||||
|
// syscall restart
|
||||||
|
bool (*is_restarted_syscall)(void);
|
||||||
|
void (*store_syscall_restart_timeout)(bigtime_t timeout);
|
||||||
|
bigtime_t (*restore_syscall_restart_timeout)(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // NET_STACK_H
|
#endif // NET_STACK_H
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2007, Haiku, Inc. All Rights Reserved.
|
* Copyright 2002-2008, Haiku, Inc. All Rights Reserved.
|
||||||
* This file may be used under the terms of the MIT License.
|
* This file may be used under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -10,16 +10,17 @@
|
|||||||
|
|
||||||
#include <net_stack_driver.h>
|
#include <net_stack_driver.h>
|
||||||
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
|
#include <driver_settings.h>
|
||||||
#include <Drivers.h>
|
#include <Drivers.h>
|
||||||
#include <KernelExport.h>
|
#include <KernelExport.h>
|
||||||
#include <driver_settings.h>
|
|
||||||
|
|
||||||
#include <kernel.h> // IS_KERNEL_ADDRESS
|
#include <fs/fd.h>
|
||||||
#include <fs/fd.h> // user_fd_kernel_ioctl
|
#include <kernel.h>
|
||||||
|
#include <syscall_restart.h>
|
||||||
|
|
||||||
#include <net_socket.h>
|
#include <net_socket.h>
|
||||||
|
|
||||||
@@ -96,8 +97,9 @@ check_args_and_address(ArgType &args, sockaddr_storage &address, void *data, siz
|
|||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
check_message_args(message_args &args, msghdr &header, sockaddr_storage &address,
|
check_message_args(message_args &args, msghdr &header,
|
||||||
void *data, size_t length, sockaddr **originalAddress)
|
sockaddr_storage &address, void *data, size_t length,
|
||||||
|
sockaddr **originalAddress)
|
||||||
{
|
{
|
||||||
if (length < sizeof(message_args))
|
if (length < sizeof(message_args))
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
@@ -133,6 +135,7 @@ check_message_args(message_args &args, msghdr &header, sockaddr_storage &address
|
|||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename ArgType> status_t
|
template<typename ArgType> status_t
|
||||||
check_args(ArgType &args, void *data, size_t length)
|
check_args(ArgType &args, void *data, size_t length)
|
||||||
{
|
{
|
||||||
@@ -205,9 +208,9 @@ resolve_cookie(int kernel, int socket, net_stack_cookie **cookie)
|
|||||||
{
|
{
|
||||||
if (kernel)
|
if (kernel)
|
||||||
return ioctl(socket, NET_STACK_GET_COOKIE, cookie, sizeof(*cookie));
|
return ioctl(socket, NET_STACK_GET_COOKIE, cookie, sizeof(*cookie));
|
||||||
else
|
|
||||||
return user_fd_kernel_ioctl(socket, NET_STACK_GET_COOKIE, cookie,
|
return user_fd_kernel_ioctl(socket, NET_STACK_GET_COOKIE, cookie,
|
||||||
sizeof(*cookie));
|
sizeof(*cookie));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -251,7 +254,8 @@ net_stack_open(const char *name, uint32 flags, void **_cookie)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
net_stack_cookie *cookie = (net_stack_cookie *)malloc(sizeof(net_stack_cookie));
|
net_stack_cookie *cookie = (net_stack_cookie *)malloc(
|
||||||
|
sizeof(net_stack_cookie));
|
||||||
if (cookie == NULL)
|
if (cookie == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
@@ -363,7 +367,10 @@ net_stack_control(void *_cookie, uint32 op, void *data, size_t length)
|
|||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
return sSocket->connect(cookie->socket, args.address, args.address_length);
|
status = sSocket->connect(cookie->socket, args.address,
|
||||||
|
args.address_length);
|
||||||
|
|
||||||
|
return syscall_restart_ioctl_handle_post(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
case NET_STACK_BIND:
|
case NET_STACK_BIND:
|
||||||
@@ -387,7 +394,8 @@ net_stack_control(void *_cookie, uint32 op, void *data, size_t length)
|
|||||||
sockaddr_storage address;
|
sockaddr_storage address;
|
||||||
accept_args args;
|
accept_args args;
|
||||||
|
|
||||||
status = check_args_and_address(args, address, data, length, false);
|
status = check_args_and_address(args, address, data, length,
|
||||||
|
false);
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
@@ -399,8 +407,9 @@ net_stack_control(void *_cookie, uint32 op, void *data, size_t length)
|
|||||||
|
|
||||||
status = sSocket->accept(cookie->socket, args.address,
|
status = sSocket->accept(cookie->socket, args.address,
|
||||||
&args.address_length, &acceptCookie->socket);
|
&args.address_length, &acceptCookie->socket);
|
||||||
|
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
return status;
|
return syscall_restart_ioctl_handle_post(status);
|
||||||
|
|
||||||
return return_address(args, data);
|
return return_address(args, data);
|
||||||
}
|
}
|
||||||
@@ -415,13 +424,15 @@ net_stack_control(void *_cookie, uint32 op, void *data, size_t length)
|
|||||||
msghdr header;
|
msghdr header;
|
||||||
|
|
||||||
status = check_message_args(args, header, address, data,
|
status = check_message_args(args, header, address, data,
|
||||||
length, NULL);
|
length, NULL);
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
return sSocket->send(cookie->socket,
|
ssize_t bytesSent = sSocket->send(cookie->socket,
|
||||||
args.header ? &header : NULL,
|
args.header ? &header : NULL,
|
||||||
args.data, args.length, args.flags);
|
args.data, args.length, args.flags);
|
||||||
|
|
||||||
|
return syscall_restart_ioctl_handle_post(bytesSent);
|
||||||
}
|
}
|
||||||
|
|
||||||
case NET_STACK_RECEIVE:
|
case NET_STACK_RECEIVE:
|
||||||
@@ -432,25 +443,25 @@ net_stack_control(void *_cookie, uint32 op, void *data, size_t length)
|
|||||||
msghdr header;
|
msghdr header;
|
||||||
|
|
||||||
status = check_message_args(args, header, address, data,
|
status = check_message_args(args, header, address, data,
|
||||||
length, &originalAddress);
|
length, &originalAddress);
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
ssize_t bytesRead = sSocket->receive(cookie->socket,
|
ssize_t bytesRead = sSocket->receive(cookie->socket,
|
||||||
args.header ? &header : NULL, args.data,
|
args.header ? &header : NULL, args.data,
|
||||||
args.length, args.flags);
|
args.length, args.flags);
|
||||||
if (bytesRead < B_OK)
|
if (bytesRead < B_OK)
|
||||||
return bytesRead;
|
return syscall_restart_ioctl_handle_post(bytesRead);
|
||||||
|
|
||||||
if (args.header != NULL) {
|
if (args.header != NULL) {
|
||||||
if (header.msg_name != NULL) {
|
if (header.msg_name != NULL) {
|
||||||
if (user_memcpy(originalAddress, header.msg_name,
|
if (user_memcpy(originalAddress, header.msg_name,
|
||||||
header.msg_namelen) < B_OK)
|
header.msg_namelen) < B_OK)
|
||||||
return B_BAD_ADDRESS;
|
return B_BAD_ADDRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user_memcpy(&args.header->msg_flags, &header.msg_flags,
|
if (user_memcpy(&args.header->msg_flags, &header.msg_flags,
|
||||||
sizeof(int)) < B_OK)
|
sizeof(int)) < B_OK)
|
||||||
return B_BAD_ADDRESS;
|
return B_BAD_ADDRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -468,13 +479,14 @@ net_stack_control(void *_cookie, uint32 op, void *data, size_t length)
|
|||||||
if (args.length > (int)sizeof(valueBuffer))
|
if (args.length > (int)sizeof(valueBuffer))
|
||||||
return ENOBUFS;
|
return ENOBUFS;
|
||||||
|
|
||||||
status = sSocket->getsockopt(cookie->socket, args.level, args.option,
|
status = sSocket->getsockopt(cookie->socket, args.level,
|
||||||
valueBuffer, &args.length);
|
args.option, valueBuffer, &args.length);
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
if (user_memcpy(args.value, valueBuffer, args.length) < B_OK
|
if (user_memcpy(args.value, valueBuffer, args.length) < B_OK
|
||||||
|| user_memcpy(&((sockopt_args *)data)->length, &args.length, sizeof(int)) < B_OK)
|
|| user_memcpy(&((sockopt_args *)data)->length,
|
||||||
|
&args.length, sizeof(int)) < B_OK)
|
||||||
return B_BAD_ADDRESS;
|
return B_BAD_ADDRESS;
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -493,15 +505,16 @@ net_stack_control(void *_cookie, uint32 op, void *data, size_t length)
|
|||||||
if (user_memcpy(valueBuffer, args.value, args.length) < B_OK)
|
if (user_memcpy(valueBuffer, args.value, args.length) < B_OK)
|
||||||
return B_BAD_ADDRESS;
|
return B_BAD_ADDRESS;
|
||||||
|
|
||||||
return sSocket->setsockopt(cookie->socket, args.level, args.option,
|
return sSocket->setsockopt(cookie->socket, args.level,
|
||||||
valueBuffer, args.length);
|
args.option, valueBuffer, args.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
case NET_STACK_GETSOCKNAME:
|
case NET_STACK_GETSOCKNAME:
|
||||||
{
|
{
|
||||||
sockaddr_storage address;
|
sockaddr_storage address;
|
||||||
sockaddr_args args;
|
sockaddr_args args;
|
||||||
status = check_args_and_address(args, address, data, length, false);
|
status = check_args_and_address(args, address, data, length,
|
||||||
|
false);
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
@@ -517,7 +530,8 @@ net_stack_control(void *_cookie, uint32 op, void *data, size_t length)
|
|||||||
{
|
{
|
||||||
sockaddr_storage address;
|
sockaddr_storage address;
|
||||||
sockaddr_args args;
|
sockaddr_args args;
|
||||||
status = check_args_and_address(args, address, data, length, false);
|
status = check_args_and_address(args, address, data, length,
|
||||||
|
false);
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
@@ -532,16 +546,16 @@ net_stack_control(void *_cookie, uint32 op, void *data, size_t length)
|
|||||||
case FIONBIO:
|
case FIONBIO:
|
||||||
{
|
{
|
||||||
int value = (int)data;
|
int value = (int)data;
|
||||||
return sSocket->setsockopt(cookie->socket, SOL_SOCKET, SO_NONBLOCK,
|
return sSocket->setsockopt(cookie->socket, SOL_SOCKET,
|
||||||
&value, sizeof(int));
|
SO_NONBLOCK, &value, sizeof(int));
|
||||||
}
|
}
|
||||||
|
|
||||||
case B_SET_BLOCKING_IO:
|
case B_SET_BLOCKING_IO:
|
||||||
case B_SET_NONBLOCKING_IO:
|
case B_SET_NONBLOCKING_IO:
|
||||||
{
|
{
|
||||||
int value = op == B_SET_NONBLOCKING_IO;
|
int value = op == B_SET_NONBLOCKING_IO;
|
||||||
return sSocket->setsockopt(cookie->socket, SOL_SOCKET, SO_NONBLOCK,
|
return sSocket->setsockopt(cookie->socket, SOL_SOCKET,
|
||||||
&value, sizeof(int));
|
SO_NONBLOCK, &value, sizeof(int));
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -405,6 +405,9 @@ EndpointManager::ReplyWithReset(tcp_segment_header &segment,
|
|||||||
if ((segment.flags & TCP_FLAG_ACKNOWLEDGE) == 0) {
|
if ((segment.flags & TCP_FLAG_ACKNOWLEDGE) == 0) {
|
||||||
outSegment.flags |= TCP_FLAG_ACKNOWLEDGE;
|
outSegment.flags |= TCP_FLAG_ACKNOWLEDGE;
|
||||||
outSegment.acknowledge = segment.sequence + buffer->size;
|
outSegment.acknowledge = segment.sequence + buffer->size;
|
||||||
|
// TODO: Confirm:
|
||||||
|
if ((segment.flags & (TCP_FLAG_SYNCHRONIZE | TCP_FLAG_FINISH)) != 0)
|
||||||
|
outSegment.acknowledge++;
|
||||||
} else
|
} else
|
||||||
outSegment.sequence = segment.acknowledge;
|
outSegment.sequence = segment.acknowledge;
|
||||||
|
|
||||||
|
|||||||
@@ -170,6 +170,9 @@ state_needs_finish(int32 state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
WaitList::WaitList(const char *name)
|
WaitList::WaitList(const char *name)
|
||||||
{
|
{
|
||||||
fCondition = 0;
|
fCondition = 0;
|
||||||
@@ -224,6 +227,9 @@ WaitList::Signal()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
TCPEndpoint::TCPEndpoint(net_socket *socket)
|
TCPEndpoint::TCPEndpoint(net_socket *socket)
|
||||||
:
|
:
|
||||||
ProtocolSocket(socket),
|
ProtocolSocket(socket),
|
||||||
@@ -255,8 +261,7 @@ TCPEndpoint::TCPEndpoint(net_socket *socket)
|
|||||||
fCongestionWindow(0),
|
fCongestionWindow(0),
|
||||||
fSlowStartThreshold(0),
|
fSlowStartThreshold(0),
|
||||||
fState(CLOSED),
|
fState(CLOSED),
|
||||||
fFlags(FLAG_OPTION_WINDOW_SCALE | FLAG_OPTION_TIMESTAMP),
|
fFlags(FLAG_OPTION_WINDOW_SCALE | FLAG_OPTION_TIMESTAMP)
|
||||||
fError(B_OK)
|
|
||||||
{
|
{
|
||||||
//gStackModule->init_timer(&fTimer, _TimeWait, this);
|
//gStackModule->init_timer(&fTimer, _TimeWait, this);
|
||||||
|
|
||||||
@@ -394,13 +399,23 @@ TCPEndpoint::Connect(const sockaddr *address)
|
|||||||
|
|
||||||
MutexLocker locker(fLock);
|
MutexLocker locker(fLock);
|
||||||
|
|
||||||
|
if (gStackModule->is_restarted_syscall()) {
|
||||||
|
bigtime_t timeout = gStackModule->restore_syscall_restart_timeout();
|
||||||
|
status_t status = _WaitForEstablished(locker, timeout);
|
||||||
|
TRACE(" Connect(): Connection complete: %s (timeout was %llu)",
|
||||||
|
strerror(status), timeout);
|
||||||
|
return posix_error(status);
|
||||||
|
}
|
||||||
|
|
||||||
// Can only call connect() from CLOSED or LISTEN states
|
// Can only call connect() from CLOSED or LISTEN states
|
||||||
// otherwise endpoint is considered already connected
|
// otherwise endpoint is considered already connected
|
||||||
if (fState == LISTEN) {
|
if (fState == LISTEN) {
|
||||||
// this socket is about to connect; remove pending connections in the backlog
|
// this socket is about to connect; remove pending connections in the backlog
|
||||||
gSocketModule->set_max_backlog(socket, 0);
|
gSocketModule->set_max_backlog(socket, 0);
|
||||||
} else if (fState != CLOSED)
|
} else if (fState == ESTABLISHED) {
|
||||||
return EISCONN;
|
return EISCONN;
|
||||||
|
} else if (fState != CLOSED)
|
||||||
|
return EINPROGRESS;
|
||||||
|
|
||||||
status_t status = _PrepareSendPath(address);
|
status_t status = _PrepareSendPath(address);
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
@@ -432,7 +447,10 @@ TCPEndpoint::Connect(const sockaddr *address)
|
|||||||
return EINPROGRESS;
|
return EINPROGRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = _WaitForEstablished(locker, absolute_timeout(timeout));
|
bigtime_t absoluteTimeout = absolute_timeout(timeout);
|
||||||
|
gStackModule->store_syscall_restart_timeout(absoluteTimeout);
|
||||||
|
|
||||||
|
status = _WaitForEstablished(locker, absoluteTimeout);
|
||||||
TRACE(" Connect(): Connection complete: %s (timeout was %llu)",
|
TRACE(" Connect(): Connection complete: %s (timeout was %llu)",
|
||||||
strerror(status), timeout);
|
strerror(status), timeout);
|
||||||
return posix_error(status);
|
return posix_error(status);
|
||||||
@@ -448,6 +466,10 @@ TCPEndpoint::Accept(struct net_socket **_acceptedSocket)
|
|||||||
|
|
||||||
status_t status;
|
status_t status;
|
||||||
bigtime_t timeout = absolute_timeout(socket->receive.timeout);
|
bigtime_t timeout = absolute_timeout(socket->receive.timeout);
|
||||||
|
if (gStackModule->is_restarted_syscall())
|
||||||
|
timeout = gStackModule->restore_syscall_restart_timeout();
|
||||||
|
else
|
||||||
|
gStackModule->store_syscall_restart_timeout(timeout);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
locker.Unlock();
|
locker.Unlock();
|
||||||
@@ -567,6 +589,10 @@ TCPEndpoint::SendData(net_buffer *buffer)
|
|||||||
return ENOBUFS;
|
return ENOBUFS;
|
||||||
|
|
||||||
bigtime_t timeout = absolute_timeout(socket->send.timeout);
|
bigtime_t timeout = absolute_timeout(socket->send.timeout);
|
||||||
|
if (gStackModule->is_restarted_syscall())
|
||||||
|
timeout = gStackModule->restore_syscall_restart_timeout();
|
||||||
|
else
|
||||||
|
gStackModule->store_syscall_restart_timeout(timeout);
|
||||||
|
|
||||||
while (fSendQueue.Free() < buffer->size) {
|
while (fSendQueue.Free() < buffer->size) {
|
||||||
status_t status = fSendList.Wait(lock, timeout);
|
status_t status = fSendList.Wait(lock, timeout);
|
||||||
@@ -632,6 +658,10 @@ TCPEndpoint::ReadData(size_t numBytes, uint32 flags, net_buffer** _buffer)
|
|||||||
return ENOTCONN;
|
return ENOTCONN;
|
||||||
|
|
||||||
bigtime_t timeout = absolute_timeout(socket->receive.timeout);
|
bigtime_t timeout = absolute_timeout(socket->receive.timeout);
|
||||||
|
if (gStackModule->is_restarted_syscall())
|
||||||
|
timeout = gStackModule->restore_syscall_restart_timeout();
|
||||||
|
else
|
||||||
|
gStackModule->store_syscall_restart_timeout(timeout);
|
||||||
|
|
||||||
if (fState == SYNCHRONIZE_SENT || fState == SYNCHRONIZE_RECEIVED) {
|
if (fState == SYNCHRONIZE_SENT || fState == SYNCHRONIZE_RECEIVED) {
|
||||||
if (flags & MSG_DONTWAIT)
|
if (flags & MSG_DONTWAIT)
|
||||||
@@ -913,11 +943,27 @@ TCPEndpoint::DumpInternalState() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TCPEndpoint::_HandleReset(status_t error)
|
||||||
|
{
|
||||||
|
gStackModule->cancel_timer(&fRetransmitTimer);
|
||||||
|
|
||||||
|
socket->error = error;
|
||||||
|
fState = CLOSED;
|
||||||
|
|
||||||
|
fSendList.Signal();
|
||||||
|
_NotifyReader();
|
||||||
|
|
||||||
|
gSocketModule->notify(socket, B_SELECT_WRITE, error);
|
||||||
|
gSocketModule->notify(socket, B_SELECT_ERROR, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int32
|
int32
|
||||||
TCPEndpoint::_SynchronizeSentReceive(tcp_segment_header &segment,
|
TCPEndpoint::_SynchronizeSentReceive(tcp_segment_header &segment,
|
||||||
net_buffer *buffer)
|
net_buffer *buffer)
|
||||||
{
|
{
|
||||||
TRACE("SynchronizeSentReceive()");
|
TRACE("_SynchronizeSentReceive()");
|
||||||
|
|
||||||
if ((segment.flags & TCP_FLAG_ACKNOWLEDGE) != 0
|
if ((segment.flags & TCP_FLAG_ACKNOWLEDGE) != 0
|
||||||
&& (fInitialSendSequence >= segment.acknowledge
|
&& (fInitialSendSequence >= segment.acknowledge
|
||||||
@@ -925,8 +971,7 @@ TCPEndpoint::_SynchronizeSentReceive(tcp_segment_header &segment,
|
|||||||
return DROP | RESET;
|
return DROP | RESET;
|
||||||
|
|
||||||
if (segment.flags & TCP_FLAG_RESET) {
|
if (segment.flags & TCP_FLAG_RESET) {
|
||||||
fError = ECONNREFUSED;
|
_HandleReset(ECONNREFUSED);
|
||||||
fState = CLOSED;
|
|
||||||
return DROP;
|
return DROP;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1040,8 +1085,10 @@ TCPEndpoint::_SegmentReceived(tcp_segment_header &segment, net_buffer *buffer)
|
|||||||
fReceiveWindow)) {
|
fReceiveWindow)) {
|
||||||
TRACE(" Receive(): segment out of window, next: %lu wnd: %lu",
|
TRACE(" Receive(): segment out of window, next: %lu wnd: %lu",
|
||||||
(uint32)fReceiveNext, fReceiveWindow);
|
(uint32)fReceiveNext, fReceiveWindow);
|
||||||
if (segment.flags & TCP_FLAG_RESET)
|
if (segment.flags & TCP_FLAG_RESET) {
|
||||||
|
// TODO: this doesn't look right - review!
|
||||||
return DROP;
|
return DROP;
|
||||||
|
}
|
||||||
return DROP | IMMEDIATE_ACKNOWLEDGE;
|
return DROP | IMMEDIATE_ACKNOWLEDGE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1079,7 +1126,7 @@ TCPEndpoint::_CurrentFlags()
|
|||||||
return TCP_FLAG_ACKNOWLEDGE;
|
return TCP_FLAG_ACKNOWLEDGE;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return B_ERROR;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1400,16 +1447,16 @@ TCPEndpoint::_Receive(tcp_segment_header &segment, net_buffer *buffer)
|
|||||||
if (fLastAcknowledgeSent <= segment.sequence
|
if (fLastAcknowledgeSent <= segment.sequence
|
||||||
&& tcp_sequence(segment.sequence) < (fLastAcknowledgeSent
|
&& tcp_sequence(segment.sequence) < (fLastAcknowledgeSent
|
||||||
+ fReceiveWindow)) {
|
+ fReceiveWindow)) {
|
||||||
|
status_t error;
|
||||||
if (fState == SYNCHRONIZE_RECEIVED)
|
if (fState == SYNCHRONIZE_RECEIVED)
|
||||||
fError = ECONNREFUSED;
|
error = ECONNREFUSED;
|
||||||
else if (fState == CLOSING || fState == TIME_WAIT
|
else if (fState == CLOSING || fState == TIME_WAIT
|
||||||
|| fState == WAIT_FOR_FINISH_ACKNOWLEDGE)
|
|| fState == WAIT_FOR_FINISH_ACKNOWLEDGE)
|
||||||
fError = ENOTCONN;
|
error = ENOTCONN;
|
||||||
else
|
else
|
||||||
fError = ECONNRESET;
|
error = ECONNRESET;
|
||||||
|
|
||||||
_NotifyReader();
|
_HandleReset(error);
|
||||||
fState = CLOSED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return DROP;
|
return DROP;
|
||||||
@@ -1635,6 +1682,9 @@ status_t
|
|||||||
TCPEndpoint::_WaitForEstablished(MutexLocker &locker, bigtime_t timeout)
|
TCPEndpoint::_WaitForEstablished(MutexLocker &locker, bigtime_t timeout)
|
||||||
{
|
{
|
||||||
while (fState != ESTABLISHED) {
|
while (fState != ESTABLISHED) {
|
||||||
|
if (socket->error != B_OK)
|
||||||
|
return socket->error;
|
||||||
|
|
||||||
status_t status = fSendList.Wait(locker, timeout);
|
status_t status = fSendList.Wait(locker, timeout);
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
return status;
|
return status;
|
||||||
@@ -1752,7 +1802,7 @@ TCPEndpoint::_Acknowledged(tcp_segment_header &segment)
|
|||||||
if (segment.options & TCP_HAS_TIMESTAMPS)
|
if (segment.options & TCP_HAS_TIMESTAMPS)
|
||||||
_UpdateSRTT(tcp_diff_timestamp(segment.timestamp_reply));
|
_UpdateSRTT(tcp_diff_timestamp(segment.timestamp_reply));
|
||||||
else {
|
else {
|
||||||
// TODO Fallback to RFC 793 type estimation
|
// TODO: Fallback to RFC 793 type estimation
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_writable(fState)) {
|
if (is_writable(fState)) {
|
||||||
|
|||||||
@@ -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.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
@@ -42,141 +42,141 @@ private:
|
|||||||
|
|
||||||
|
|
||||||
class TCPEndpoint : public net_protocol, public ProtocolSocket {
|
class TCPEndpoint : public net_protocol, public ProtocolSocket {
|
||||||
public:
|
public:
|
||||||
TCPEndpoint(net_socket *socket);
|
TCPEndpoint(net_socket *socket);
|
||||||
~TCPEndpoint();
|
~TCPEndpoint();
|
||||||
|
|
||||||
status_t InitCheck() const;
|
status_t InitCheck() const;
|
||||||
|
|
||||||
status_t Open();
|
status_t Open();
|
||||||
status_t Close();
|
status_t Close();
|
||||||
status_t Free();
|
status_t Free();
|
||||||
status_t Connect(const struct sockaddr *address);
|
status_t Connect(const struct sockaddr *address);
|
||||||
status_t Accept(struct net_socket **_acceptedSocket);
|
status_t Accept(struct net_socket **_acceptedSocket);
|
||||||
status_t Bind(const sockaddr *address);
|
status_t Bind(const sockaddr *address);
|
||||||
status_t Unbind(struct sockaddr *address);
|
status_t Unbind(struct sockaddr *address);
|
||||||
status_t Listen(int count);
|
status_t Listen(int count);
|
||||||
status_t Shutdown(int direction);
|
status_t Shutdown(int direction);
|
||||||
status_t SendData(net_buffer *buffer);
|
status_t SendData(net_buffer *buffer);
|
||||||
ssize_t SendAvailable();
|
ssize_t SendAvailable();
|
||||||
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 FillStat(struct net_stat *stat);
|
status_t FillStat(struct net_stat *stat);
|
||||||
|
|
||||||
status_t SetSendBufferSize(size_t length);
|
status_t SetSendBufferSize(size_t length);
|
||||||
status_t SetReceiveBufferSize(size_t length);
|
status_t SetReceiveBufferSize(size_t length);
|
||||||
|
|
||||||
status_t SetOption(int option, const void *value, int length);
|
status_t SetOption(int option, const void *value, int length);
|
||||||
|
|
||||||
tcp_state State() const { return fState; }
|
tcp_state State() const { return fState; }
|
||||||
bool IsBound() const;
|
bool IsBound() const;
|
||||||
|
|
||||||
status_t DelayedAcknowledge();
|
status_t DelayedAcknowledge();
|
||||||
status_t SendAcknowledge(bool force);
|
status_t SendAcknowledge(bool force);
|
||||||
status_t UpdateTimeWait();
|
status_t UpdateTimeWait();
|
||||||
|
|
||||||
int32 SegmentReceived(tcp_segment_header& segment, net_buffer *buffer);
|
int32 SegmentReceived(tcp_segment_header& segment, net_buffer *buffer);
|
||||||
int32 Spawn(TCPEndpoint *parent, tcp_segment_header& segment,
|
int32 Spawn(TCPEndpoint *parent, tcp_segment_header& segment,
|
||||||
net_buffer *buffer);
|
net_buffer *buffer);
|
||||||
|
|
||||||
void DumpInternalState() const;
|
void DumpInternalState() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class EndpointManager;
|
friend class EndpointManager;
|
||||||
|
|
||||||
void _StartPersistTimer();
|
void _StartPersistTimer();
|
||||||
void _EnterTimeWait();
|
void _EnterTimeWait();
|
||||||
uint8 _CurrentFlags();
|
uint8 _CurrentFlags();
|
||||||
bool _ShouldSendSegment(tcp_segment_header &segment, uint32 length,
|
bool _ShouldSendSegment(tcp_segment_header &segment, uint32 length,
|
||||||
uint32 segmentMaxSize, uint32 flightSize);
|
uint32 segmentMaxSize, uint32 flightSize);
|
||||||
status_t _SendQueued(bool force = false);
|
status_t _SendQueued(bool force = false);
|
||||||
status_t _SendQueued(bool force, uint32 sendWindow);
|
status_t _SendQueued(bool force, uint32 sendWindow);
|
||||||
int _MaxSegmentSize(const struct sockaddr *) const;
|
int _MaxSegmentSize(const struct sockaddr *) const;
|
||||||
status_t _ShutdownEgress(bool closing);
|
status_t _ShutdownEgress(bool closing);
|
||||||
ssize_t _AvailableData() const;
|
ssize_t _AvailableData() const;
|
||||||
void _NotifyReader();
|
void _NotifyReader();
|
||||||
bool _ShouldReceive() const;
|
bool _ShouldReceive() const;
|
||||||
int32 _ListenReceive(tcp_segment_header& segment, net_buffer *buffer);
|
void _HandleReset(status_t error);
|
||||||
int32 _SynchronizeSentReceive(tcp_segment_header& segment,
|
int32 _ListenReceive(tcp_segment_header& segment, net_buffer *buffer);
|
||||||
net_buffer *buffer);
|
int32 _SynchronizeSentReceive(tcp_segment_header& segment,
|
||||||
int32 _SegmentReceived(tcp_segment_header& segment, net_buffer *buffer);
|
net_buffer *buffer);
|
||||||
int32 _Receive(tcp_segment_header& segment, net_buffer *buffer);
|
int32 _SegmentReceived(tcp_segment_header& segment, net_buffer *buffer);
|
||||||
void _UpdateTimestamps(tcp_segment_header& segment,
|
int32 _Receive(tcp_segment_header& segment, net_buffer *buffer);
|
||||||
size_t segmentLength);
|
void _UpdateTimestamps(tcp_segment_header& segment,
|
||||||
void _MarkEstablished();
|
size_t segmentLength);
|
||||||
status_t _WaitForEstablished(MutexLocker &lock, bigtime_t timeout);
|
void _MarkEstablished();
|
||||||
bool _AddData(tcp_segment_header &segment, net_buffer *buffer);
|
status_t _WaitForEstablished(MutexLocker &lock, bigtime_t timeout);
|
||||||
void _PrepareReceivePath(tcp_segment_header &segment);
|
bool _AddData(tcp_segment_header &segment, net_buffer *buffer);
|
||||||
status_t _PrepareSendPath(const sockaddr *peer);
|
void _PrepareReceivePath(tcp_segment_header &segment);
|
||||||
void _Acknowledged(tcp_segment_header &segment);
|
status_t _PrepareSendPath(const sockaddr *peer);
|
||||||
void _Retransmit();
|
void _Acknowledged(tcp_segment_header &segment);
|
||||||
void _UpdateSRTT(int32 roundTripTime);
|
void _Retransmit();
|
||||||
void _ResetSlowStart();
|
void _UpdateSRTT(int32 roundTripTime);
|
||||||
void _DuplicateAcknowledge(tcp_segment_header &segment);
|
void _ResetSlowStart();
|
||||||
|
void _DuplicateAcknowledge(tcp_segment_header &segment);
|
||||||
|
|
||||||
static void _TimeWaitTimer(net_timer *timer, void *data);
|
static void _TimeWaitTimer(net_timer *timer, void *data);
|
||||||
static void _RetransmitTimer(net_timer *timer, void *data);
|
static void _RetransmitTimer(net_timer *timer, void *data);
|
||||||
static void _PersistTimer(net_timer *timer, void *data);
|
static void _PersistTimer(net_timer *timer, void *data);
|
||||||
static void _DelayedAcknowledgeTimer(net_timer *timer, void *data);
|
static void _DelayedAcknowledgeTimer(net_timer *timer, void *data);
|
||||||
|
|
||||||
EndpointManager *fManager;
|
EndpointManager *fManager;
|
||||||
|
|
||||||
HashTableLink<TCPEndpoint> fConnectionHashLink;
|
HashTableLink<TCPEndpoint> fConnectionHashLink;
|
||||||
HashTableLink<TCPEndpoint> fEndpointHashLink;
|
HashTableLink<TCPEndpoint> fEndpointHashLink;
|
||||||
|
|
||||||
friend class ConnectionHashDefinition;
|
friend class ConnectionHashDefinition;
|
||||||
friend class EndpointHashDefinition;
|
friend class EndpointHashDefinition;
|
||||||
|
|
||||||
mutex fLock;
|
mutex fLock;
|
||||||
WaitList fReceiveList;
|
WaitList fReceiveList;
|
||||||
WaitList fSendList;
|
WaitList fSendList;
|
||||||
sem_id fAcceptSemaphore;
|
sem_id fAcceptSemaphore;
|
||||||
uint8 fOptions;
|
uint8 fOptions;
|
||||||
|
|
||||||
uint8 fSendWindowShift;
|
uint8 fSendWindowShift;
|
||||||
uint8 fReceiveWindowShift;
|
uint8 fReceiveWindowShift;
|
||||||
|
|
||||||
tcp_sequence fSendUnacknowledged;
|
tcp_sequence fSendUnacknowledged;
|
||||||
tcp_sequence fSendNext;
|
tcp_sequence fSendNext;
|
||||||
tcp_sequence fSendMax;
|
tcp_sequence fSendMax;
|
||||||
uint32 fSendWindow;
|
uint32 fSendWindow;
|
||||||
uint32 fSendMaxWindow;
|
uint32 fSendMaxWindow;
|
||||||
uint32 fSendMaxSegmentSize;
|
uint32 fSendMaxSegmentSize;
|
||||||
BufferQueue fSendQueue;
|
BufferQueue fSendQueue;
|
||||||
tcp_sequence fLastAcknowledgeSent;
|
tcp_sequence fLastAcknowledgeSent;
|
||||||
tcp_sequence fInitialSendSequence;
|
tcp_sequence fInitialSendSequence;
|
||||||
uint32 fDuplicateAcknowledgeCount;
|
uint32 fDuplicateAcknowledgeCount;
|
||||||
|
|
||||||
net_route *fRoute;
|
net_route *fRoute;
|
||||||
// TODO: don't use a net_route, but a net_route_info!!!
|
// TODO: don't use a net_route, but a net_route_info!!!
|
||||||
|
|
||||||
tcp_sequence fReceiveNext;
|
tcp_sequence fReceiveNext;
|
||||||
tcp_sequence fReceiveMaxAdvertised;
|
tcp_sequence fReceiveMaxAdvertised;
|
||||||
uint32 fReceiveWindow;
|
uint32 fReceiveWindow;
|
||||||
uint32 fReceiveMaxSegmentSize;
|
uint32 fReceiveMaxSegmentSize;
|
||||||
BufferQueue fReceiveQueue;
|
BufferQueue fReceiveQueue;
|
||||||
tcp_sequence fInitialReceiveSequence;
|
tcp_sequence fInitialReceiveSequence;
|
||||||
|
|
||||||
// round trip time and retransmit timeout computation
|
// round trip time and retransmit timeout computation
|
||||||
int32 fRoundTripTime;
|
int32 fRoundTripTime;
|
||||||
int32 fRoundTripDeviation;
|
int32 fRoundTripDeviation;
|
||||||
bigtime_t fRetransmitTimeout;
|
bigtime_t fRetransmitTimeout;
|
||||||
|
|
||||||
uint32 fReceivedTimestamp;
|
uint32 fReceivedTimestamp;
|
||||||
|
|
||||||
uint32 fCongestionWindow;
|
uint32 fCongestionWindow;
|
||||||
uint32 fSlowStartThreshold;
|
uint32 fSlowStartThreshold;
|
||||||
|
|
||||||
tcp_state fState;
|
tcp_state fState;
|
||||||
uint32 fFlags;
|
uint32 fFlags;
|
||||||
status_t fError;
|
|
||||||
|
|
||||||
// timer
|
// timer
|
||||||
net_timer fRetransmitTimer;
|
net_timer fRetransmitTimer;
|
||||||
net_timer fPersistTimer;
|
net_timer fPersistTimer;
|
||||||
net_timer fDelayedAcknowledgeTimer;
|
net_timer fDelayedAcknowledgeTimer;
|
||||||
net_timer fTimeWaitTimer;
|
net_timer fTimeWaitTimer;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // TCP_ENDPOINT_H
|
#endif // TCP_ENDPOINT_H
|
||||||
|
|||||||
@@ -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.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
@@ -932,6 +932,10 @@ net_stack_module_info gNetStackModule = {
|
|||||||
set_timer,
|
set_timer,
|
||||||
cancel_timer,
|
cancel_timer,
|
||||||
is_timer_active,
|
is_timer_active,
|
||||||
|
|
||||||
|
is_restarted_syscall,
|
||||||
|
store_syscall_restart_timeout,
|
||||||
|
restore_syscall_restart_timeout,
|
||||||
};
|
};
|
||||||
|
|
||||||
static module_info sNetStarterModule = {
|
static module_info sNetStarterModule = {
|
||||||
|
|||||||
@@ -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.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "utility.h"
|
#include "utility.h"
|
||||||
|
|
||||||
#include <net_buffer.h>
|
#include <net_buffer.h>
|
||||||
|
#include <syscall_restart.h>
|
||||||
#include <util/AutoLock.h>
|
#include <util/AutoLock.h>
|
||||||
|
|
||||||
#include <ByteOrder.h>
|
#include <ByteOrder.h>
|
||||||
@@ -570,3 +571,30 @@ uninit_timers(void)
|
|||||||
wait_for_thread(sTimerThread, &status);
|
wait_for_thread(sTimerThread, &status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - Syscall restart
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
is_restarted_syscall(void)
|
||||||
|
{
|
||||||
|
return syscall_restart_ioctl_is_restarted();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
store_syscall_restart_timeout(bigtime_t timeout)
|
||||||
|
{
|
||||||
|
struct thread* thread = thread_get_current_thread();
|
||||||
|
if ((thread->flags & THREAD_FLAGS_IOCTL_SYSCALL) != 0)
|
||||||
|
*(bigtime_t*)thread->syscall_restart.parameters = timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bigtime_t
|
||||||
|
restore_syscall_restart_timeout(void)
|
||||||
|
{
|
||||||
|
struct thread* thread = thread_get_current_thread();
|
||||||
|
return *(bigtime_t*)thread->syscall_restart.parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
@@ -101,4 +101,9 @@ bool is_timer_active(net_timer *timer);
|
|||||||
status_t init_timers(void);
|
status_t init_timers(void);
|
||||||
void uninit_timers(void);
|
void uninit_timers(void);
|
||||||
|
|
||||||
|
// syscall restart
|
||||||
|
bool is_restarted_syscall(void);
|
||||||
|
void store_syscall_restart_timeout(bigtime_t timeout);
|
||||||
|
bigtime_t restore_syscall_restart_timeout(void);
|
||||||
|
|
||||||
#endif // NET_UTILITY_H
|
#endif // NET_UTILITY_H
|
||||||
|
|||||||
Reference in New Issue
Block a user