Sponge
CS144's user-space TCP library
file_descriptor.cc
Go to the documentation of this file.
1 #include "file_descriptor.hh"
2 
3 #include "util.hh"
4 
5 #include <algorithm>
6 #include <fcntl.h>
7 #include <iostream>
8 #include <stdexcept>
9 #include <sys/uio.h>
10 #include <unistd.h>
11 
12 using namespace std;
13 
15 FileDescriptor::FDWrapper::FDWrapper(const int fd) : _fd(fd) {
16  if (fd < 0) {
17  throw runtime_error("invalid fd number:" + to_string(fd));
18  }
19 }
20 
22  SystemCall("close", ::close(_fd));
23  _eof = _closed = true;
24 }
25 
27  try {
28  if (_closed) {
29  return;
30  }
31  close();
32  } catch (const exception &e) {
33  // don't throw an exception from the destructor
34  std::cerr << "Exception destructing FDWrapper: " << e.what() << std::endl;
35  }
36 }
37 
40 
42 FileDescriptor::FileDescriptor(shared_ptr<FDWrapper> other_shared_ptr) : _internal_fd(move(other_shared_ptr)) {}
43 
46 
49 void FileDescriptor::read(std::string &str, const size_t limit) {
50  constexpr size_t BUFFER_SIZE = 1024 * 1024; // maximum size of a read
51  const size_t size_to_read = min(BUFFER_SIZE, limit);
52  str.resize(size_to_read);
53 
54  ssize_t bytes_read = SystemCall("read", ::read(fd_num(), str.data(), size_to_read));
55  if (limit > 0 && bytes_read == 0) {
56  _internal_fd->_eof = true;
57  }
58  if (bytes_read > static_cast<ssize_t>(size_to_read)) {
59  throw runtime_error("read() read more than requested");
60  }
61  str.resize(bytes_read);
62 
63  register_read();
64 }
65 
68 string FileDescriptor::read(const size_t limit) {
69  string ret;
70 
71  read(ret, limit);
72 
73  return ret;
74 }
75 
76 size_t FileDescriptor::write(BufferViewList buffer, const bool write_all) {
77  size_t total_bytes_written = 0;
78 
79  do {
80  auto iovecs = buffer.as_iovecs();
81 
82  const ssize_t bytes_written = SystemCall("writev", ::writev(fd_num(), iovecs.data(), iovecs.size()));
83  if (bytes_written == 0 and buffer.size() != 0) {
84  throw runtime_error("write returned 0 given non-empty input buffer");
85  }
86 
87  if (bytes_written > ssize_t(buffer.size())) {
88  throw runtime_error("write wrote more than length of input buffer");
89  }
90 
91  register_write();
92 
93  buffer.remove_prefix(bytes_written);
94 
95  total_bytes_written += bytes_written;
96  } while (write_all and buffer.size());
97 
98  return total_bytes_written;
99 }
100 
101 void FileDescriptor::set_blocking(const bool blocking_state) {
102  int flags = SystemCall("fcntl", fcntl(fd_num(), F_GETFL));
103  if (blocking_state) {
104  flags ^= (flags & O_NONBLOCK);
105  } else {
106  flags |= O_NONBLOCK;
107  }
108 
109  SystemCall("fcntl", fcntl(fd_num(), F_SETFL, flags));
110 }
std::string::resize
T resize(T... args)
util.hh
std::string
std::shared_ptr
std::exception
FileDescriptor::write
size_t write(const char *str, const bool write_all=true)
Write a string, possibly blocking until all is written.
Definition: file_descriptor.hh:65
std::move
T move(T... args)
file_descriptor.hh
FileDescriptor::FDWrapper::close
void close()
Calls close(2) on FDWrapper::_fd.
Definition: file_descriptor.cc:21
SystemCall
SystemCall("socketpair", ::socketpair(AF_UNIX, SOCK_STREAM, 0, fds.data()))
std::make_shared
T make_shared(T... args)
std::string::size
T size(T... args)
FileDescriptor::FDWrapper::FDWrapper
FDWrapper(const int fd)
Construct from a file descriptor number returned by the kernel.
Definition: file_descriptor.cc:15
FileDescriptor::close
void close()
Close the underlying file descriptor.
Definition: file_descriptor.hh:74
FileDescriptor::fd_num
int fd_num() const
underlying descriptor number
Definition: file_descriptor.hh:86
BufferViewList
A non-owning temporary view (similar to std::string_view) of a discontiguous string.
Definition: buffer.hh:97
FileDescriptor
A reference-counted handle to a file descriptor.
Definition: file_descriptor.hh:12
FileDescriptor::read
std::string read(const size_t limit=std::numeric_limits< size_t >::max())
Read up to limit bytes.
buffer
std::string buffer
Definition: parser_example.cc:7
std::cerr
std::to_string
T to_string(T... args)
FileDescriptor::set_blocking
void set_blocking(const bool blocking_state)
Set blocking(true) or non-blocking(false)
Definition: file_descriptor.cc:101
std::runtime_error
FileDescriptor::FDWrapper
A handle on a kernel file descriptor.
Definition: file_descriptor.hh:15
std::min
T min(T... args)
std::endl
T endl(T... args)
FileDescriptor::FileDescriptor
FileDescriptor(std::shared_ptr< FDWrapper > other_shared_ptr)
Private constructor used by duplicate()
Definition: file_descriptor.cc:42
FileDescriptor::FDWrapper::~FDWrapper
~FDWrapper()
Closes the file descriptor upon destruction.
Definition: file_descriptor.cc:26
std
FileDescriptor::_internal_fd
std::shared_ptr< FDWrapper > _internal_fd
A reference-counted handle to a shared FDWrapper.
Definition: file_descriptor.hh:42
std::string::data
T data(T... args)
FileDescriptor::duplicate
FileDescriptor duplicate() const
Copy a FileDescriptor explicitly, increasing the FDWrapper refcount.
Definition: file_descriptor.cc:45
std::exception::what
T what(T... args)