URY playd
C++ minimalist audio player
Connection Class Reference

A TCP connection from a client. More...

#include <io.hpp>

+ Collaboration diagram for Connection:

Public Member Functions

 Connection (IoCore &parent, uv_tcp_t *tcp, Player &player, size_t id)
 Constructs a Connection. More...
 
 ~Connection ()
 Destructs a Connection. More...
 
 Connection (const Connection &)=delete
 Connection cannot be copied.
 
Connectionoperator= (const Connection &)=delete
 Connection cannot be copy-assigned.
 
void Respond (const Response &response)
 Emits a Response via this Connection. More...
 
void Read (ssize_t nread, const uv_buf_t *buf)
 Processes a data read on this connection. More...
 
void Shutdown ()
 Gracefully shuts this connection down. More...
 
void Depool ()
 Removes this connection from its connection pool. More...
 
std::string Name ()
 Retrieves a name for this connection. More...
 

Private Member Functions

Response RunCommand (const std::vector< std::string > &msg)
 Handles a tokenised command line. More...
 

Private Attributes

IoCoreparent
 The pool on which this connection is running.
 
uv_tcp_t * tcp
 The libuv handle for the TCP connection.
 
Tokeniser tokeniser
 The Tokeniser to which data read on this connection should be sent.
 
Playerplayer
 The Player to which finished commands should be sent.
 
size_t id
 The Connection's ID in the connection pool.
 

Detailed Description

A TCP connection from a client.

This class wraps a libuv TCP stream representing a client connection, allowing it to be sent responses (directly, or via a broadcast), removed from its IoCore, and queried for its name.

Definition at line 186 of file io.hpp.

Constructor & Destructor Documentation

§ Connection()

Connection::Connection ( IoCore parent,
uv_tcp_t *  tcp,
Player player,
size_t  id 
)

Constructs a Connection.

Parameters
parentThe connection pool to which this Connection belongs.
tcpThe underlying libuv TCP stream.
playerThe player to which read commands should be sent.
idThe ID of this Connection in the IoCore.

Definition at line 392 of file io.cpp.

References Name().

393  : parent(parent), tcp(tcp), tokeniser(), player(player), id(id)
394 {
395  Debug() << "Opening connection from" << Name() << std::endl;
396 }
Player & player
The Player to which finished commands should be sent.
Definition: io.hpp:256
IoCore & parent
The pool on which this connection is running.
Definition: io.hpp:247
size_t id
The Connection&#39;s ID in the connection pool.
Definition: io.hpp:259
std::string Name()
Retrieves a name for this connection.
Definition: io.cpp:429
Class for telling the human what playd is doing.
Definition: errors.hpp:133
uv_tcp_t * tcp
The libuv handle for the TCP connection.
Definition: io.hpp:250
Tokeniser tokeniser
The Tokeniser to which data read on this connection should be sent.
Definition: io.hpp:253

§ ~Connection()

Connection::~Connection ( )

Destructs a Connection.

This causes libuv to close and free the libuv TCP stream.

Definition at line 398 of file io.cpp.

References Name(), tcp, and UvCloseCallback().

399 {
400  Debug() << "Closing connection from" << Name() << std::endl;
401  uv_close(reinterpret_cast<uv_handle_t *>(this->tcp), UvCloseCallback);
402 }
std::string Name()
Retrieves a name for this connection.
Definition: io.cpp:429
void UvCloseCallback(uv_handle_t *handle)
The callback fired when a client connection closes.
Definition: io.cpp:58
Class for telling the human what playd is doing.
Definition: errors.hpp:133
uv_tcp_t * tcp
The libuv handle for the TCP connection.
Definition: io.hpp:250

Member Function Documentation

§ Depool()

void Connection::Depool ( )

Removes this connection from its connection pool.

Since the pool may contain a shared reference to this connection, calling this can result in the connection being destructed.

Definition at line 535 of file io.cpp.

References parent, and IoCore::Remove().

Referenced by Read().

536 {
537  this->parent.Remove(this->id);
538 }
IoCore & parent
The pool on which this connection is running.
Definition: io.hpp:247
void Remove(size_t id)
Removes a connection.
Definition: io.cpp:260

§ Name()

std::string Connection::Name ( )

Retrieves a name for this connection.

This will be of the form "HOST:PORT", unless errors occur.

Returns
The Connection's name.

Definition at line 429 of file io.cpp.

References tcp.

Referenced by Connection(), Read(), and ~Connection().

430 {
431  // Warning: fairly low-level Berkeley sockets code ahead!
432  // (Thankfully, libuv makes sure the appropriate headers are included.)
433 
434  // Using this instead of struct sockaddr is advised by the libuv docs,
435  // for IPv6 compatibility.
436  struct sockaddr_storage s;
437  auto sp = (struct sockaddr *)&s;
438 
439  // Turns out if you don't do this, Windows (and only Windows?) is upset.
440  socklen_t namelen = sizeof(s);
441 
442  int pe = uv_tcp_getpeername(this->tcp, sp, (int *)&namelen);
443  // These std::string()s are needed as, otherwise, the compiler would
444  // think we're trying to add const char*s together. We need AT LEAST
445  // ONE of the sides of the first + to be a std::string.
446  if (pe) return "<error@peer: " + std::string(uv_strerror(pe)) + ">";
447 
448  // Now, split the sockaddr into host and service.
449  char host[NI_MAXHOST];
450  char serv[NI_MAXSERV];
451 
452  // We use NI_NUMERICSERV to ensure a port number comes out.
453  // Otherwise, we could get a (likely erroneous) string description of
454  // what the network stack *thinks* the port is used for.
455  int ne = getnameinfo(sp, namelen, host, sizeof(host), serv,
456  sizeof(serv), NI_NUMERICSERV);
457  // See comment for above error.
458  if (ne) return "<error@name: " + std::string(gai_strerror(ne)) + ">";
459 
460  auto id = std::to_string(this->id);
461  return id + std::string("!") + host + std::string(":") + serv;
462 }
uv_tcp_t * tcp
The libuv handle for the TCP connection.
Definition: io.hpp:250

§ Read()

void Connection::Read ( ssize_t  nread,
const uv_buf_t *  buf 
)

Processes a data read on this connection.

Parameters
nreadThe number of bytes read.
bufThe buffer containing the read data.

Definition at line 464 of file io.cpp.

References Depool(), Tokeniser::Feed(), Name(), Respond(), RunCommand(), and tokeniser.

465 {
466  assert(buf != nullptr);
467 
468  // Did the connection hang up? If so, de-pool it.
469  // De-pooling the connection will usually lead to the connection being
470  // destroyed.
471  if (nread == UV_EOF) {
472  this->Depool();
473  return;
474  }
475 
476  // Did we hit any other read errors? Also de-pool, but log the error.
477  if (nread < 0) {
478  Debug() << "Error on" << Name() << "-" << uv_err_name(nread)
479  << std::endl;
480  this->Depool();
481  return;
482  }
483 
484  // Make sure we actually have some data to read!
485  if (buf->base == nullptr) return;
486 
487  // Everything looks okay for reading.
488  auto cmds = this->tokeniser.Feed(std::string(buf->base, nread));
489  for (auto cmd : cmds) {
490  if (cmd.empty()) continue;
491 
492  Response res = RunCommand(cmd);
493  this->Respond(res);
494  }
495 
496  delete[] buf->base;
497 }
A response.
Definition: response.hpp:23
std::string Name()
Retrieves a name for this connection.
Definition: io.cpp:429
void Depool()
Removes this connection from its connection pool.
Definition: io.cpp:535
std::vector< std::vector< std::string > > Feed(const std::string &raw)
Feeds a string into a Tokeniser.
Definition: tokeniser.cpp:24
Response RunCommand(const std::vector< std::string > &msg)
Handles a tokenised command line.
Definition: io.cpp:499
Class for telling the human what playd is doing.
Definition: errors.hpp:133
Tokeniser tokeniser
The Tokeniser to which data read on this connection should be sent.
Definition: io.hpp:253
void Respond(const Response &response)
Emits a Response via this Connection.
Definition: io.cpp:404

§ Respond()

void Connection::Respond ( const Response response)

Emits a Response via this Connection.

Parameters
responseThe response to send.

Definition at line 404 of file io.cpp.

References Response::Pack(), tcp, and UvWriteCallback().

Referenced by Read().

405 {
406  // Pack provides us the response's wire format, except the newline.
407  // We can provide that here.
408  auto string = response.Pack();
409  string.push_back('\n');
410 
411  unsigned int l = string.length();
412 
413  // Make a libuv buffer and pour the request into it.
414  // The onus is on UvRespondCallback to free buf.base.
415  auto buf = uv_buf_init(new char[l], l);
416  assert(buf.base != nullptr);
417  string.copy(buf.base, l);
418 
419  // Make a write request.
420  // Since the callback must free the buffer, pass it through as data.
421  // The callback will also free req.
422  auto req = new uv_write_t;
423  req->data = static_cast<void *>(buf.base);
424 
425  uv_write((uv_write_t *)req, (uv_stream_t *)this->tcp, &buf, 1,
427 }
void UvWriteCallback(uv_write_t *req, int status)
The callback fired when a response has been sent to a client.
Definition: io.cpp:92
std::string Pack() const
Packs the Response, converting it to a BAPS3 protocol message.
Definition: response.cpp:44
uv_tcp_t * tcp
The libuv handle for the TCP connection.
Definition: io.hpp:250

§ RunCommand()

Response Connection::RunCommand ( const std::vector< std::string > &  msg)
private

Handles a tokenised command line.

Parameters
msgA vector of command words representing a command line.
Returns
A final response returning whether the command succeeded.

Definition at line 499 of file io.cpp.

References Player::Dump(), Player::Eject(), Player::End(), Response::Invalid(), Player::Load(), MSG_CMD_INVALID, MSG_CMD_SHORT, player, Player::Pos(), and Player::SetPlaying().

Referenced by Read().

500 {
501  // First of all, figure out what the tag of this command is.
502  // The first word is always the tag.
503  auto tag = cmd[0];
504  if (cmd.size() <= 1) return Response::Invalid(tag, MSG_CMD_SHORT);
505 
506  // The next words are the actual command, and any other arguments.
507  auto word = cmd[1];
508  auto nargs = cmd.size() - 2;
509 
510  if (nargs == 0) {
511  if ("play" == word) return this->player.SetPlaying(tag, true);
512  if ("stop" == word) return this->player.SetPlaying(tag, false);
513  if ("end" == word) return this->player.End(tag);
514  if ("eject" == word) return this->player.Eject(tag);
515  if ("dump" == word) return this->player.Dump(id, tag);
516  } else if (nargs == 1) {
517  if ("fload" == word) return this->player.Load(tag, cmd[2]);
518  if ("pos" == word) return this->player.Pos(tag, cmd[2]);
519  }
520 
521  return Response::Invalid(tag, MSG_CMD_INVALID);
522 }
const std::string MSG_CMD_SHORT
Message shown when the CommandHandler receives an under-length command.
Definition: messages.h:32
Player & player
The Player to which finished commands should be sent.
Definition: io.hpp:256
Response Load(const std::string &tag, const std::string &path)
Loads a file.
Definition: player.cpp:122
Response Eject(const std::string &tag)
Ejects the current loaded song, if any.
Definition: player.cpp:85
const std::string MSG_CMD_INVALID
Message shown when the CommandHandler receives an invalid command.
Definition: messages.h:36
Response Pos(const std::string &tag, const std::string &pos_str)
Seeks to a given position in the current file.
Definition: player.cpp:155
Response Dump(size_t id, const std::string &tag) const
Dumps the current player state to the given ID.
Definition: player.cpp:65
Response SetPlaying(const std::string &tag, bool playing)
Tells the audio file to start or stop playing.
Definition: player.cpp:188
Response End(const std::string &tag)
Ends a file, stopping and rewinding.
Definition: player.cpp:104
static Response Invalid(const std::string &tag, const std::string &msg)
Shortcut for constructing a final response to a invalid request.
Definition: response.cpp:56

§ Shutdown()

void Connection::Shutdown ( )

Gracefully shuts this connection down.

This is similar to (and implemented in terms of) Depool, but waits for all writes to finish first.

Definition at line 524 of file io.cpp.

References tcp, and UvShutdownCallback().

525 {
526  auto req = new uv_shutdown_t;
527  assert(req != nullptr);
528 
529  req->data = this;
530 
531  uv_shutdown(req, reinterpret_cast<uv_stream_t *>(this->tcp),
533 }
void UvShutdownCallback(uv_shutdown_t *handle, int status)
The callback fired when a client is shut down.
Definition: io.cpp:146
uv_tcp_t * tcp
The libuv handle for the TCP connection.
Definition: io.hpp:250

The documentation for this class was generated from the following files: