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 \
|
scheduler.o \
|
||||||
segment.o \
|
segment.o \
|
||||||
signal.o \
|
signal.o \
|
||||||
|
sockopt.o \
|
||||||
string.o \
|
string.o \
|
||||||
symbol.o \
|
symbol.o \
|
||||||
syscall.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.
|
This file is part of Sortix.
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
// TODO: Should this be moved into user-space?
|
// TODO: Should this be moved into user-space?
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
@ -47,15 +48,10 @@
|
||||||
#include <sortix/kernel/poll.h>
|
#include <sortix/kernel/poll.h>
|
||||||
#include <sortix/kernel/process.h>
|
#include <sortix/kernel/process.h>
|
||||||
#include <sortix/kernel/refcount.h>
|
#include <sortix/kernel/refcount.h>
|
||||||
|
#include <sortix/kernel/sockopt.h>
|
||||||
|
|
||||||
#include "fs.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 Sortix {
|
||||||
namespace NetFS {
|
namespace NetFS {
|
||||||
|
|
||||||
|
@ -104,6 +100,10 @@ public:
|
||||||
virtual ssize_t read(ioctx_t* ctx, uint8_t* buf, size_t count);
|
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 ssize_t write(ioctx_t* ctx, const uint8_t* buf, size_t count);
|
||||||
virtual int poll(ioctx_t* ctx, PollNode* node);
|
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:
|
private:
|
||||||
int do_bind(ioctx_t* ctx, const uint8_t* addr, size_t addrsize);
|
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;
|
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)
|
Manager::Manager(uid_t owner, gid_t group, mode_t mode)
|
||||||
{
|
{
|
||||||
inode_type = INODE_TYPE_UNKNOWN;
|
inode_type = INODE_TYPE_UNKNOWN;
|
||||||
|
|
|
@ -62,6 +62,10 @@ public:
|
||||||
void PerhapsShutdown();
|
void PerhapsShutdown();
|
||||||
bool GetSIGPIPEDelivery();
|
bool GetSIGPIPEDelivery();
|
||||||
void SetSIGPIPEDelivery(bool deliver_sigpipe);
|
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 read(ioctx_t* ctx, uint8_t* buf, size_t count);
|
||||||
ssize_t write(ioctx_t* ctx, const 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);
|
int read_poll(ioctx_t* ctx, PollNode* node);
|
||||||
|
@ -81,6 +85,7 @@ private:
|
||||||
size_t bufferoffset;
|
size_t bufferoffset;
|
||||||
size_t bufferused;
|
size_t bufferused;
|
||||||
size_t buffersize;
|
size_t buffersize;
|
||||||
|
size_t pretended_read_buffer_size;
|
||||||
bool anyreading;
|
bool anyreading;
|
||||||
bool anywriting;
|
bool anywriting;
|
||||||
bool is_sigpipe_enabled;
|
bool is_sigpipe_enabled;
|
||||||
|
@ -244,6 +249,56 @@ void PipeChannel::SetSIGPIPEDelivery(bool deliver_sigpipe)
|
||||||
is_sigpipe_enabled = 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()
|
PipeEndpoint::PipeEndpoint()
|
||||||
{
|
{
|
||||||
channel = NULL;
|
channel = NULL;
|
||||||
|
@ -316,6 +371,18 @@ bool PipeEndpoint::SetSIGPIPEDelivery(bool deliver_sigpipe)
|
||||||
return true;
|
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
|
class PipeNode : public AbstractInode
|
||||||
{
|
{
|
||||||
public:
|
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