/*
Copyright (C) 2009 Red Hat, Inc.
This program 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 2 of
the License, or (at your option) any later version.
This program 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 this program. If not, see .
*/
#include
#include
#include
#include
#include "named_pipe.h"
#include "utils.h"
#include "debug.h"
Session::Session(int fd, EventsLoop& events_loop)
: _fd_client(fd)
, _events_loop(events_loop)
{
}
void Session::on_event()
{
_conn_interface->on_data();
}
void Session::bind(NamedPipe::ConnectionInterface* conn_interface)
{
_conn_interface = conn_interface;
_events_loop.add_socket(*this);
}
Session::~Session()
{
_events_loop.remove_socket(*this);
close(_fd_client);
}
int32_t Session::write(const uint8_t *buf, int32_t size)
{
const uint8_t *pos = buf;
while (size) {
int now;
if ((now = send(_fd_client, (char *)pos, size, 0)) == -1) {
if (errno == EAGAIN) {
break;
}
if (errno == EINTR) {
continue;
}
DBG(0, "send error errno=%d, %s", errno, strerror(errno));
return -1;
}
size -= now;
pos += now;
}
return (pos - buf);
}
int32_t Session::read(uint8_t *buf, int32_t size)
{
uint8_t *pos = buf;
while (size) {
int now;
if ((now = recv(_fd_client, (char *)pos, size, 0)) <= 0) {
if (now == 0) {
DBG(0, "read error, connetion shutdown");
return -1;
}
if (errno == EAGAIN) {
break;
}
if (errno == EINTR) {
continue;
}
DBG(0, "read error errno=%d, %s", errno, strerror(errno));
return -1;
}
size -= now;
pos += now;
}
return (pos - buf);
}
int LinuxListener::create_socket(const char *socket_name)
{
int listen_socket;
struct sockaddr_un local;
if ((listen_socket = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
DBG(0, "create socket error, errno=%d, %s", errno, strerror(errno));
return -1;
}
_name = socket_name;
local.sun_family = AF_UNIX;
strcpy(local.sun_path, socket_name);
unlink(local.sun_path);
if (bind(listen_socket, (struct sockaddr *)&local,
strlen(local.sun_path) + sizeof(local.sun_family)) == -1) {
DBG(0, "bind error, errno=%d, %s", errno, strerror(errno));
return -1;
}
if (listen(listen_socket, 10) == -1) {
DBG(0, "listen error, errno=%d, %s", errno, strerror(errno));
return -1;
}
return listen_socket;
}
LinuxListener::LinuxListener(const char *name, NamedPipe::ListenerInterface &listener_interface,
EventsLoop &events_loop)
: _listener_interface (listener_interface)
, _events_loop (events_loop)
{
_listen_socket = create_socket(name);
if (_listen_socket <= 0) {
THROW("Listener creation failed %d", _listen_socket);
}
_events_loop.add_socket(*this);
DBG(0, "listening socket - %s, added to events_loop", name);
}
LinuxListener::~LinuxListener()
{
_events_loop.remove_socket(*this);
close(_listen_socket);
unlink(_name.c_str());
}
void LinuxListener::on_event()
{
for (;;) {
int fd_client;
Session *conn;
struct sockaddr_un remote;
socklen_t len = sizeof(remote);
if ((fd_client = accept(_listen_socket, (struct sockaddr *)&remote, &len)) == -1) {
if (errno == EAGAIN) {
break;
}
if (errno == EINTR) {
continue;
}
THROW("errno=%d, %s", errno, strerror(errno));
}
conn = new Session(fd_client, _events_loop);
DBG(0, "New connection created, fd: %d", fd_client);
NamedPipe::ConnectionInterface &conn_interface = _listener_interface.create();
conn->bind(&conn_interface);
conn_interface.bind((NamedPipe::ConnectionRef)conn);
}
}