Skip to content
connection.hxx 5.06 KiB
Newer Older
/*
  This file is part of SLL.
  Copyright (C) 2008 Sebastien LUTTRINGER <contact@seblu.net>

  SLL 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; version 2 of the License.

  SLL 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 SLLo; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

# include "error.hh"

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>

/*******************************************************************************
 ** Public method
 ******************************************************************************/

/**
 * Return the connection sate
 * Cannot be const, du to mutex locking
 *
 * @return see description
 */
bool Connection::connected() {
  // get connection mutex

  pthread_mutex_lock(&c_mutex_);

  bool ret = (socket_fd_ >= 0);

  pthread_mutex_unlock(&c_mutex_);

  return ret;
}

/**
 * Send @param data on socket
 */
void Connection::send(const string &data) {
  send(data.c_str(), data.length());
}

/**
 * Send @param data followed by '\n' on socket
 */
void Connection::sendln(const string &data) {
  string tosend = data + "\n";
  send(tosend.c_str(), tosend.length());
}

/*******************************************************************************
 ** Protected method
 ******************************************************************************/

/**
 * Free a socket
 * No mutex used !
 */
void Connection::disconnect_() {
Seblu's avatar
Seblu committed
  if (socket_fd_ < 0)
    return;

  close(socket_fd_);
  socket_fd_ = -1;
Seblu's avatar
Seblu committed
  rbuf_.clear();
  wbuf_.clear();
}

/**
 * Reserve a socket
 * No mutex used !
 */
void Connection::socket_() {
  assert(socket_fd_ == -1);
  int yes = 1;

  if ((socket_fd_ = ::socket(AF_INET, SOCK_STREAM, 0)) == -1)
    throw Error(ERR_NET, (string) "Unable to open socket: " + strerror(errno));

  if (::setsockopt(socket_fd_, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
    throw Error(ERR_NET, (string) "Unable to set socket options: " + strerror(errno));
}

Seblu's avatar
Seblu committed
/**
 * Send @param size byte of @param buf into socket @param socket
 * No mutex used!
 */
void Connection::send_(int socket_fd, const void *buf, size_t size) {
  if (::send(socket_fd, buf, size, MSG_NOSIGNAL)) {
    if (errno == ECONNRESET || errno == EPIPE)
      throw Error(ERR_NET, "Connection reset by peer");
    else
      throw Error(ERR_NET, "send: " + (string) strerror(errno));
  }
}

/**
 * Send @param size byte of @param buf into socket @param socket
 * No mutex used!
 */
int Connection::recv_(int socket_fd, void *buf, size_t size) {
  int ret = ::recv(socket_fd, buf, size, 0);
  if (ret == 0)
    throw Error(ERR_NET, "Connection reset by peer");
  else if (ret == -1)
    throw Error(ERR_NET, (string) "recvln: " + strerror(errno));
  return ret;
}

/**
 * Set local ip
 * No mutex used !
 */
void Connection::setlocalip_() {
  struct sockaddr_in addr;
  socklen_t len = sizeof addr;

  if (::getsockname(socket_fd_, (struct sockaddr*) &addr, &len) != 0)
    throw Error(ERR_NET, (string) "Unable to get local ip: " + strerror(errno));
  local_ip_ = inet_ntoa(addr.sin_addr);
}

/**
 * Set local port
 * No mutex used !
 */
void Connection::setlocalport_() {
  struct sockaddr_in addr;
  socklen_t len = sizeof addr;

  if (::getsockname(socket_fd_, (struct sockaddr*) &addr, &len) != 0)
    throw Error(ERR_NET, (string) "Unable to get local port: " + strerror(errno));
  local_port_ = ntohs(addr.sin_port);
}

/**
 * Set remote ip
 * No mutex used !
 */
void Connection::setremoteip_() {
  struct sockaddr_in addr;
  socklen_t len = sizeof addr;

  // get socket
  if (::getpeername(socket_fd_, (struct sockaddr*) &addr, &len) != 0)
    throw Error(ERR_NET, (string) "Unable to get remote ip: " + strerror(errno));
  remote_ip_ = inet_ntoa(addr.sin_addr);
}

/**
 * Set remote hostname
 * No mutex used !
 */
void Connection::setremotehostname_() {
  struct sockaddr_in addr;
  socklen_t len = sizeof addr;

  // get sockaddr_in
  if (::getpeername(socket_fd_, (struct sockaddr*) &addr, &len) != 0)
    throw Error(ERR_NET, (string) "Unable to get remote ip: " + strerror(errno));
  if (remote_ip_.empty())
    remote_ip_ = inet_ntoa(addr.sin_addr);

  // get hostname
  struct hostent *h;
  if ((h = ::gethostbyaddr(&addr.sin_addr, sizeof addr.sin_addr, AF_INET)) == 0)
    throw Error(ERR_NET, (string) "Unable to get remote hostname: " + hstrerror(h_errno));
  remote_hostname_ = h->h_name;
}

/**
 * Set remote port
 * No mutex used !
 */
void Connection::setremoteport_() {
  struct sockaddr_in addr;
  socklen_t len = sizeof addr;

  if (::getpeername(socket_fd_, (struct sockaddr*) &addr, &len) != 0)
    throw Error(ERR_NET, (string) "Unable to get remote port: " + strerror(errno));
  remote_port_ = ntohs(addr.sin_port);
}