mirror of
https://gitlab.com/sortix/sortix.git
synced 2023-02-13 20:55:38 -05:00
Implement SO_RCVBUF and SO_SNDBUF for filesystem sockets.
This commit is contained in:
parent
feea0786fc
commit
2ff72426ec
5 changed files with 305 additions and 7 deletions
|
@ -129,6 +129,7 @@ resource.o \
|
|||
scheduler.o \
|
||||
segment.o \
|
||||
signal.o \
|
||||
sockopt.o \
|
||||
string.o \
|
||||
symbol.o \
|
||||
syscall.o \
|
||||
|
|
42
kernel/include/sortix/kernel/sockopt.h
Normal file
42
kernel/include/sortix/kernel/sockopt.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
Sortix is free software: you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation, either version 3 of the License, or (at your option) any later
|
||||
version.
|
||||
|
||||
Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
sortix/kernel/sockopt.h
|
||||
getsockopt() and setsockopt() utility functions.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef INCLUDE_SORTIX_KERNEL_SOCKOPT_H
|
||||
#define INCLUDE_SORTIX_KERNEL_SOCKOPT_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <sortix/kernel/ioctx.h>
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
bool sockopt_fetch_uintmax(uintmax_t* optval_ptr, ioctx_t* ctx,
|
||||
const void* option_value, size_t option_size);
|
||||
bool sockopt_return_uintmax(uintmax_t optval, ioctx_t* ctx,
|
||||
void* option_value, size_t* option_size_ptr);
|
||||
|
||||
} // namespace Sortix
|
||||
|
||||
#endif
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2013.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2013, 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
|||
|
||||
// TODO: Should this be moved into user-space?
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
@ -47,15 +48,10 @@
|
|||
#include <sortix/kernel/poll.h>
|
||||
#include <sortix/kernel/process.h>
|
||||
#include <sortix/kernel/refcount.h>
|
||||
#include <sortix/kernel/sockopt.h>
|
||||
|
||||
#include "fs.h"
|
||||
|
||||
// TODO: This is declared in the <sys/socket.h> header that isn't ready for
|
||||
// kernel usage, so we declare it here for now.
|
||||
#ifndef AF_UNIX
|
||||
#define AF_UNIX 3
|
||||
#endif
|
||||
|
||||
namespace Sortix {
|
||||
namespace NetFS {
|
||||
|
||||
|
@ -104,6 +100,10 @@ public:
|
|||
virtual ssize_t read(ioctx_t* ctx, uint8_t* buf, size_t count);
|
||||
virtual ssize_t write(ioctx_t* ctx, const uint8_t* buf, size_t count);
|
||||
virtual int poll(ioctx_t* ctx, PollNode* node);
|
||||
virtual int getsockopt(ioctx_t* ctx, int level, int option_name,
|
||||
void* option_value, size_t* option_size_ptr);
|
||||
virtual int setsockopt(ioctx_t* ctx, int level, int option_name,
|
||||
const void* option_value, size_t option_size);
|
||||
|
||||
private:
|
||||
int do_bind(ioctx_t* ctx, const uint8_t* addr, size_t addrsize);
|
||||
|
@ -302,6 +302,57 @@ int StreamSocket::poll(ioctx_t* ctx, PollNode* node)
|
|||
return errno = ENOTCONN, -1;
|
||||
}
|
||||
|
||||
int StreamSocket::getsockopt(ioctx_t* ctx, int level, int option_name,
|
||||
void* option_value, size_t* option_size_ptr)
|
||||
{
|
||||
if ( level != SOL_SOCKET )
|
||||
return errno = EINVAL, -1;
|
||||
|
||||
uintmax_t result = 0;
|
||||
switch ( option_name )
|
||||
{
|
||||
case SO_RCVBUF: result = incoming.Size(); break;
|
||||
case SO_SNDBUF: result = outgoing.Size(); break;
|
||||
default: return errno = ENOPROTOOPT, -1; break;
|
||||
}
|
||||
|
||||
if ( !sockopt_return_uintmax(result, ctx, option_value, option_size_ptr) )
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int StreamSocket::setsockopt(ioctx_t* ctx, int level, int option_name,
|
||||
const void* option_value, size_t option_size)
|
||||
{
|
||||
if ( level != SOL_SOCKET )
|
||||
return errno = EINVAL, -1;
|
||||
|
||||
uintmax_t value;
|
||||
if ( !sockopt_fetch_uintmax(&value, ctx, option_value, option_size) )
|
||||
return -1;
|
||||
|
||||
switch ( option_name )
|
||||
{
|
||||
case SO_RCVBUF:
|
||||
if ( SIZE_MAX < value )
|
||||
return errno = EINVAL, -1;
|
||||
if ( !incoming.Resize((size_t) value) )
|
||||
return -1;
|
||||
break;
|
||||
case SO_SNDBUF:
|
||||
if ( SIZE_MAX < value )
|
||||
return errno = EINVAL, -1;
|
||||
if ( !outgoing.Resize((size_t) value) )
|
||||
return -1;
|
||||
break;
|
||||
default:
|
||||
return errno = ENOPROTOOPT, -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Manager::Manager(uid_t owner, gid_t group, mode_t mode)
|
||||
{
|
||||
inode_type = INODE_TYPE_UNKNOWN;
|
||||
|
|
|
@ -62,6 +62,10 @@ public:
|
|||
void PerhapsShutdown();
|
||||
bool GetSIGPIPEDelivery();
|
||||
void SetSIGPIPEDelivery(bool deliver_sigpipe);
|
||||
size_t ReadSize();
|
||||
size_t WriteSize();
|
||||
bool ReadResize(size_t new_size);
|
||||
bool WriteResize(size_t new_size);
|
||||
ssize_t read(ioctx_t* ctx, uint8_t* buf, size_t count);
|
||||
ssize_t write(ioctx_t* ctx, const uint8_t* buf, size_t count);
|
||||
int read_poll(ioctx_t* ctx, PollNode* node);
|
||||
|
@ -81,6 +85,7 @@ private:
|
|||
size_t bufferoffset;
|
||||
size_t bufferused;
|
||||
size_t buffersize;
|
||||
size_t pretended_read_buffer_size;
|
||||
bool anyreading;
|
||||
bool anywriting;
|
||||
bool is_sigpipe_enabled;
|
||||
|
@ -244,6 +249,56 @@ void PipeChannel::SetSIGPIPEDelivery(bool deliver_sigpipe)
|
|||
is_sigpipe_enabled = deliver_sigpipe;
|
||||
}
|
||||
|
||||
size_t PipeChannel::ReadSize()
|
||||
{
|
||||
ScopedLockSignal lock(&pipelock);
|
||||
return pretended_read_buffer_size;
|
||||
}
|
||||
|
||||
size_t PipeChannel::WriteSize()
|
||||
{
|
||||
ScopedLockSignal lock(&pipelock);
|
||||
return buffersize;
|
||||
}
|
||||
|
||||
bool PipeChannel::ReadResize(size_t new_size)
|
||||
{
|
||||
ScopedLockSignal lock(&pipelock);
|
||||
if ( !new_size )
|
||||
return errno = EINVAL, false;
|
||||
// The read and write end share the same buffer, so let the write end decide
|
||||
// how big a buffer it wants and pretend the read end can decide too.
|
||||
pretended_read_buffer_size = new_size;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PipeChannel::WriteResize(size_t new_size)
|
||||
{
|
||||
ScopedLockSignal lock(&pipelock);
|
||||
if ( !new_size )
|
||||
return errno = EINVAL, false;
|
||||
|
||||
size_t MAX_PIPE_SIZE = 2 * 1024 * 1024;
|
||||
if ( MAX_PIPE_SIZE < new_size )
|
||||
new_size = MAX_PIPE_SIZE;
|
||||
|
||||
// Refuse to lose data if the the new size would cause truncation.
|
||||
if ( new_size < bufferused )
|
||||
new_size = bufferused;
|
||||
|
||||
uint8_t* new_buffer = new uint8_t[new_size];
|
||||
if ( !new_buffer )
|
||||
return false;
|
||||
|
||||
for ( size_t i = 0; i < bufferused; i++ )
|
||||
new_buffer[i] = buffer[(bufferoffset + i) % buffersize];
|
||||
delete[] buffer;
|
||||
buffer = new_buffer;
|
||||
buffersize = new_size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
PipeEndpoint::PipeEndpoint()
|
||||
{
|
||||
channel = NULL;
|
||||
|
@ -316,6 +371,18 @@ bool PipeEndpoint::SetSIGPIPEDelivery(bool deliver_sigpipe)
|
|||
return true;
|
||||
}
|
||||
|
||||
size_t PipeEndpoint::Size()
|
||||
{
|
||||
return reading ? channel->ReadSize()
|
||||
: channel->WriteSize();
|
||||
}
|
||||
|
||||
bool PipeEndpoint::Resize(size_t new_size)
|
||||
{
|
||||
return reading ? channel->ReadResize(new_size)
|
||||
: channel->WriteResize(new_size);
|
||||
}
|
||||
|
||||
class PipeNode : public AbstractInode
|
||||
{
|
||||
public:
|
||||
|
|
137
kernel/sockopt.cpp
Normal file
137
kernel/sockopt.cpp
Normal file
|
@ -0,0 +1,137 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
Sortix is free software: you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation, either version 3 of the License, or (at your option) any later
|
||||
version.
|
||||
|
||||
Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
sockopt.cpp
|
||||
getsockopt() and setsockopt() utility functions.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <sortix/kernel/ioctx.h>
|
||||
#include <sortix/kernel/sockopt.h>
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
bool sockopt_fetch_uintmax(uintmax_t* optval_ptr, ioctx_t* ctx,
|
||||
const void* option_value, size_t option_size)
|
||||
{
|
||||
uintmax_t optval;
|
||||
|
||||
if ( option_size == 0 )
|
||||
{
|
||||
optval = 0;
|
||||
}
|
||||
else if ( option_size == 1 )
|
||||
{
|
||||
uint8_t truncated;
|
||||
if ( !ctx->copy_from_src(&truncated, option_value, sizeof(truncated)) )
|
||||
return false;
|
||||
optval = truncated;
|
||||
}
|
||||
else if ( option_size == 2 )
|
||||
{
|
||||
uint16_t truncated;
|
||||
if ( !ctx->copy_from_src(&truncated, option_value, sizeof(truncated)) )
|
||||
return false;
|
||||
optval = truncated;
|
||||
}
|
||||
else if ( option_size == 4 )
|
||||
{
|
||||
uint32_t truncated;
|
||||
if ( !ctx->copy_from_src(&truncated, option_value, sizeof(truncated)) )
|
||||
return false;
|
||||
optval = truncated;
|
||||
}
|
||||
else if ( option_size == 8 )
|
||||
{
|
||||
uint64_t truncated;
|
||||
if ( !ctx->copy_from_src(&truncated, option_value, sizeof(truncated)) )
|
||||
return false;
|
||||
optval = truncated;
|
||||
}
|
||||
#if UINT64_MAX < UINTMAX_MAX
|
||||
#error "Add support for your large uintmax_t"
|
||||
#endif
|
||||
else
|
||||
{
|
||||
return errno = EINVAL, false;
|
||||
}
|
||||
|
||||
return *optval_ptr = optval, true;
|
||||
}
|
||||
|
||||
bool sockopt_return_uintmax(uintmax_t optval, ioctx_t* ctx,
|
||||
void* option_value, size_t* option_size_ptr)
|
||||
{
|
||||
size_t option_size;
|
||||
if ( !ctx->copy_from_src(&option_size, option_size_ptr, sizeof(option_size)) )
|
||||
return false;
|
||||
|
||||
if ( /*0 <= option_size &&*/ option_size < 1 )
|
||||
{
|
||||
option_size = 0;
|
||||
}
|
||||
else if ( 1 <= option_size && option_size < 2 )
|
||||
{
|
||||
if ( UINT8_MAX < optval )
|
||||
return errno = ERANGE, false;
|
||||
uint8_t value = optval;
|
||||
option_size = sizeof(value);
|
||||
if ( !ctx->copy_to_dest(option_value, &value, sizeof(value)) )
|
||||
return false;
|
||||
}
|
||||
else if ( 2 <= option_size && option_size < 4 )
|
||||
{
|
||||
if ( UINT16_MAX < optval )
|
||||
return errno = ERANGE, false;
|
||||
uint16_t value = optval;
|
||||
option_size = sizeof(value);
|
||||
if ( !ctx->copy_to_dest(option_value, &value, sizeof(value)) )
|
||||
return false;
|
||||
}
|
||||
else if ( 4 <= option_size && option_size < 8 )
|
||||
{
|
||||
if ( UINT32_MAX < optval )
|
||||
return errno = ERANGE, false;
|
||||
uint32_t value = optval;
|
||||
option_size = sizeof(value);
|
||||
if ( !ctx->copy_to_dest(option_value, &value, sizeof(value)) )
|
||||
return false;
|
||||
}
|
||||
else if ( 8 <= option_size /* && option_size < 16 */ )
|
||||
{
|
||||
#if UINT64_MAX < UINTMAX_MAX
|
||||
#error "Add support for your large uintmax_t"
|
||||
#endif
|
||||
uint64_t value = optval;
|
||||
option_size = sizeof(value);
|
||||
if ( !ctx->copy_to_dest(option_value, &value, sizeof(value)) )
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !ctx->copy_to_dest(option_size_ptr, &option_size, sizeof(option_size)) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Sortix
|
Loading…
Reference in a new issue