// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*-
// Copyright (c) 2001-2007 International Computer Science Institute
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software")
// to deal in the Software without restriction, subject to the conditions
// listed in the XORP LICENSE file. These conditions include: you must
// preserve this copyright notice, and you cannot mention the copyright
// holders in advertising related to the Software without their permission.
// The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
// notice is a summary of the XORP LICENSE file; the license in that file is
// legally binding.
#ident "$XORP: xorp/fea/rawsock4.cc,v 1.18 2007/02/16 22:45:49 pavlin Exp $"
#include "fea_module.h"
#include "libxorp/xorp.h"
#include "libxorp/xlog.h"
#include "libxorp/debug.h"
#include "libxorp/ipvx.hh"
#include "rawsock4.hh"
/* ------------------------------------------------------------------------- */
/* RawSocket4 methods */
RawSocket4::RawSocket4(EventLoop& eventloop, uint32_t ip_protocol,
const IfTree& iftree)
: RawSocket(eventloop, IPv4::af(), ip_protocol, iftree)
{
}
RawSocket4::~RawSocket4()
{
string error_msg;
RawSocket::stop(error_msg);
}
/* ------------------------------------------------------------------------- */
/* FilterRawSocket4 methods */
FilterRawSocket4::FilterRawSocket4(EventLoop& eventloop, uint32_t protocol,
const IfTree& iftree)
: RawSocket4(eventloop, protocol, iftree)
{
}
FilterRawSocket4::~FilterRawSocket4()
{
if (_filters.empty() == false) {
string dummy_error_msg;
RawSocket::stop(dummy_error_msg);
do {
InputFilter* i = _filters.front();
_filters.erase(_filters.begin());
i->bye();
} while (_filters.empty() == false);
}
}
bool
FilterRawSocket4::add_filter(InputFilter* filter)
{
if (filter == 0) {
XLOG_FATAL("Adding a null filter");
return false;
}
if (find(_filters.begin(), _filters.end(), filter) != _filters.end()) {
debug_msg("filter already exists\n");
return false;
}
_filters.push_back(filter);
if (_filters.front() == filter) {
string error_msg;
if (RawSocket4::start(error_msg) != XORP_OK) {
XLOG_ERROR("%s", error_msg.c_str());
return false;
}
}
return true;
}
bool
FilterRawSocket4::remove_filter(InputFilter* filter)
{
list<InputFilter*>::iterator i;
i = find(_filters.begin(), _filters.end(), filter);
if (i == _filters.end()) {
debug_msg("filter does not exist\n");
return false;
}
_filters.erase(i);
if (_filters.empty()) {
string error_msg;
if (RawSocket4::stop(error_msg) != XORP_OK) {
XLOG_ERROR("%s", error_msg.c_str());
return false;
}
}
return true;
}
int
FilterRawSocket4::proto_socket_write(const string& if_name,
const string& vif_name,
const IPv4& src_address,
const IPv4& dst_address,
int32_t ip_ttl,
int32_t ip_tos,
bool ip_router_alert,
const vector<uint8_t>& payload,
string& error_msg)
{
// XXX: The extention headers are not used in IPv4
vector<uint8_t> ext_headers_type;
vector<vector<uint8_t> > ext_headers_payload;
return (RawSocket4::proto_socket_write(if_name,
vif_name,
IPvX(src_address),
IPvX(dst_address),
ip_ttl,
ip_tos,
ip_router_alert,
ext_headers_type,
ext_headers_payload,
payload,
error_msg));
}
void
FilterRawSocket4::process_recv_data(const string& if_name,
const string& vif_name,
const IPvX& src_address,
const IPvX& dst_address,
int32_t ip_ttl,
int32_t ip_tos,
bool ip_router_alert,
const vector<uint8_t>& ext_headers_type,
const vector<vector<uint8_t> >& ext_headers_payload,
const vector<uint8_t>& payload)
{
struct IPv4HeaderInfo header;
// XXX: The extention headers are not used in IPv4
UNUSED(ext_headers_type);
UNUSED(ext_headers_payload);
XLOG_ASSERT(src_address.is_ipv4());
XLOG_ASSERT(dst_address.is_ipv4());
header.if_name = if_name;
header.vif_name = vif_name;
header.src_address = src_address.get_ipv4();
header.dst_address = dst_address.get_ipv4();
header.ip_protocol = RawSocket4::ip_protocol();
header.ip_ttl = ip_ttl;
header.ip_tos = ip_tos;
header.ip_router_alert = ip_router_alert;
for (list<InputFilter*>::iterator i = _filters.begin();
i != _filters.end(); ++i) {
(*i)->recv(header, payload);
}
}
int
FilterRawSocket4::join_multicast_group(const string& if_name,
const string& vif_name,
const IPv4& group_address,
const string& receiver_name,
string& error_msg)
{
JoinedGroupsTable::iterator iter;
//
// Check the arguments
//
if (! group_address.is_multicast()) {
error_msg = c_format("Cannot join group %s: not a multicast address",
group_address.str().c_str());
return (XORP_ERROR);
}
if (if_name.empty()) {
error_msg = c_format("Cannot join group %s: empty interface name",
group_address.str().c_str());
return (XORP_ERROR);
}
if (vif_name.empty()) {
error_msg = c_format("Cannot join group %s on interface %s: "
"empty vif name",
group_address.str().c_str(),
if_name.c_str());
return (XORP_ERROR);
}
if (receiver_name.empty()) {
error_msg = c_format("Cannot join group %s on interface %s vif %s: "
"empty receiver name",
group_address.str().c_str(),
if_name.c_str(),
vif_name.c_str());
return (XORP_ERROR);
}
JoinedMulticastGroup init_jmg(if_name, vif_name, group_address);
iter = _joined_groups_table.find(init_jmg);
if (iter == _joined_groups_table.end()) {
//
// First receiver, hence join the multicast group first to check
// for errors.
//
if (RawSocket::join_multicast_group(if_name,
vif_name,
IPvX(group_address),
error_msg)
!= XORP_OK) {
return (XORP_ERROR);
}
_joined_groups_table.insert(make_pair(init_jmg, init_jmg));
iter = _joined_groups_table.find(init_jmg);
}
XLOG_ASSERT(iter != _joined_groups_table.end());
JoinedMulticastGroup& jmg = iter->second;
jmg.add_receiver(receiver_name);
return (XORP_OK);
}
int
FilterRawSocket4::leave_multicast_group(const string& if_name,
const string& vif_name,
const IPv4& group_address,
const string& receiver_name,
string& error_msg)
{
JoinedGroupsTable::iterator iter;
JoinedMulticastGroup init_jmg(if_name, vif_name, group_address);
iter = _joined_groups_table.find(init_jmg);
if (iter == _joined_groups_table.end()) {
error_msg = c_format("Cannot leave group %s on interface %s vif %s: "
"the group was not joined",
group_address.str().c_str(),
if_name.c_str(),
vif_name.c_str());
return (XORP_ERROR);
}
JoinedMulticastGroup& jmg = iter->second;
jmg.delete_receiver(receiver_name);
if (jmg.empty()) {
//
// The last receiver, hence leave the group
//
_joined_groups_table.erase(iter);
if (RawSocket::leave_multicast_group(if_name,
vif_name,
IPvX(group_address),
error_msg)
!= XORP_OK) {
return (XORP_ERROR);
}
}
return (XORP_OK);
}
syntax highlighted by Code2HTML, v. 0.9.1