<commit_before>/**
 * @file Cosa/SPI.cpp
 * @version 1.0
 *
 * @section License
 * Copyright (C) 2012-2014, Mikael Patel
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * This file is part of the Arduino Che Cosa project.
 */

#include "Cosa/SPI.hh"
#include "Cosa/Power.hh"

// Configuration: Allow SPI transfer interleaving
#if !defined(BOARD_ATTINY)
#define USE_SPI_PREFETCH
#endif

SPI spi  __attribute__ ((weak));

#if defined(SPDR)

SPI::Driver::Driver(Board::DigitalPin cs, Pulse pulse,
		    Clock rate, uint8_t mode, Order order,
		    Interrupt::Handler* irq) :
  m_next(NULL),
  m_irq(irq),
  m_cs(cs, (pulse == 0)),
  m_pulse(pulse),
  // SPI Control Register for master mode
  m_spcr(_BV(SPE)
	 | ((order & 0x1) << DORD)
	 | _BV(MSTR)
	 | ((mode & 0x3) << CPHA)
	 | ((rate & 0x3) << SPR0)),
  // SPI Clock control in Status Register
  m_spsr(((rate & 0x04) != 0) << SPI2X)
{
}

SPI::SPI(uint8_t mode, Order order) :
  m_list(NULL),
  m_dev(NULL),
  m_busy(false)
{
  // Initiate the SPI port and control for slave mode
  synchronized {
    bit_set(DDRB, Board::MISO);
    bit_mask_clear(DDRB, _BV(Board::MOSI) | _BV(Board::SCK) | _BV(Board::SS));
    SPCR = (_BV(SPIE) | _BV(SPE)
	    | ((order & 0x1) << DORD)
	    | ((mode & 0x3) << CPHA));
  }
}

SPI::SPI() :
  m_list(NULL),
  m_dev(NULL),
  m_busy(false)
{
  // Initiate the SPI data direction for master mode
  // The SPI/SS pin must be an output pin in master mode
  synchronized {
    bit_mask_set(DDRB, _BV(Board::MOSI) | _BV(Board::SCK) | _BV(Board::SS));
    bit_clear(DDRB, Board::MISO);
    bit_mask_clear(PORTB, _BV(Board::SCK) | _BV(Board::MOSI));
    bit_set(PORTB, Board::MISO);
  }
  // Other the SPI setup is done by the SPI::Driver::begin()
}

void
SPI::Slave::on_interrupt(uint16_t arg)
{
  // Sanity check that a buffer is defined
  if (m_buf == NULL) return;
  // Append to buffer and push event when buffer is full
  m_buf[m_put++] = arg;
  if (m_put != m_max) return;
  // Push receive completed to event dispatch
  Event::push(Event::RECEIVE_COMPLETED_TYPE, this, m_put);
  m_put = 0;
}

// Current slave device. Should be a singleton
SPI::Slave* SPI::Slave::s_device = NULL;

ISR(SPI_STC_vect)
{
  SPI::Slave* device = SPI::Slave::s_device;
  if (device != NULL) device->on_interrupt(SPDR);
}

#elif defined(USIDR)

// Create mapping to USI data direction register and port for ATtiny variants
#if defined(BOARD_ATTINYX4) || defined(BOARD_ATTINYX61)
#define DDR DDRA
#define PORT PORTA
#elif defined(BOARD_ATTINYX5)
#define DDR DDRB
#define PORT PORTB
#endif

SPI::Driver::Driver(Board::DigitalPin cs, Pulse pulse,
		    Clock rate, uint8_t mode, Order order,
		    Interrupt::Handler* irq) :
  m_next(NULL),
  m_irq(irq),
  m_cs(cs, (pulse == 0)),
  m_pulse(pulse),
  m_cpol(mode)
{
  UNUSED(rate);
  UNUSED(order);

  // USI command for hardware supported bit banging
  m_usicr = (_BV(USIWM0) | _BV(USICS1) | _BV(USICLK) | _BV(USITC));
  if (mode == 1 || mode == 2) m_usicr |= _BV(USICS0);

  // Set ports
  synchronized {
    bit_mask_set(DDR, _BV(Board::MOSI) | _BV(Board::SCK));
    bit_clear(DDR, Board::MISO);
    bit_set(PORT, Board::MISO);
    USICR = m_usicr;
  }
}

SPI::SPI(uint8_t mode, Order order) :
  m_list(NULL),
  m_dev(NULL),
  m_busy(false)
{
  UNUSED(order);

  // Set port data direction. Note ATtiny MOSI/MISO are DI/DO.
  // Do not confuse with SPI chip programming pins
  synchronized {
    bit_mask_set(DDR, _BV(Board::MOSI) | _BV(Board::SCK));
    bit_clear(DDR, Board::MISO);
    bit_set(PORT, Board::MISO);
    USICR = (_BV(USIWM0) | _BV(USICS1) | _BV(USICLK) | _BV(USITC));
    if (mode == 1 || mode == 2) USICR |= _BV(USICS0);
  }
}

SPI::SPI() :
  m_list(NULL),
  m_dev(NULL),
  m_busy(false)
{
  // Set port data direction. Note ATtiny MOSI/MISO are DI/DO.
  // Do not confuse with SPI chip programming pins
  synchronized {
    bit_mask_set(DDR, _BV(Board::MOSI) | _BV(Board::SCK));
    bit_clear(DDR, Board::MISO);
    bit_set(PORT, Board::MISO);
  }
}
#endif

/*
 * Prefetch optimized variants of the block transfer member functions.
 * These implementation allow higher transfer speed for block by using
 * the available cycles while a byte transfer is in progress for data
 * prefetch and store. There are at least 16 instruction cycles available
 * (CLOCK_DIV_2).
 */
#if defined(USE_SPI_PREFETCH)
void
SPI::transfer(void* buf, size_t count)
{
  if (count == 0) return;
  uint8_t* dp = (uint8_t*) buf;
  uint8_t data = *dp;
  transfer_start(data);
  while (--count) {
    uint8_t* tp = dp + 1;
    data = *tp;
    *dp = transfer_next(data);
    dp = tp;
  }
  *dp = transfer_await();
}

void
SPI::transfer(void* dst, const void* src, size_t count)
{
  if (count == 0) return;
  uint8_t* dp = (uint8_t*) dst;
  const uint8_t* sp = (const uint8_t*) src;
  uint8_t data = *sp++;
  transfer_start(data);
  while (--count) {
    uint8_t* tp = dp + 1;
    data = *sp++;
    *dp = transfer_next(data);
    dp = tp;
  }
  *dp = transfer_await();
}

void
SPI::read(void* buf, size_t count)
{
  if (count == 0) return;
  uint8_t* dp = (uint8_t*) buf;
  transfer_start(0xff);
  while (--count) *dp++ = transfer_next(0xff);
  *dp = transfer_await();
}

void
SPI::write(const void* buf, size_t count)
{
  if (count == 0) return;
  const uint8_t* sp = (const uint8_t*) buf;
  uint8_t data = *sp++;
  transfer_start(data);
  while (--count) {
    data = *sp++;
    transfer_next(data);
  }
  transfer_await();
}

void
SPI::write_P(const void* buf, size_t count)
{
  if (count == 0) return;
  const uint8_t* sp = (const uint8_t*) buf;
  uint8_t data = pgm_read_byte(sp++);
  transfer_start(data);
  while (--count) {
    data = pgm_read_byte(sp++);
    transfer_next(data);
  }
  transfer_await();
}

#else

void
SPI::transfer(void* buf, size_t count)
{
  if (count == 0) return;
  uint8_t* bp = (uint8_t*) buf;
  do {
    *bp = transfer(*bp);
    bp += 1;
  } while (--count);
}

void
SPI::transfer(void* dst, const void* src, size_t count)
{
  if (count == 0) return;
  uint8_t* dp = (uint8_t*) dst;
  const uint8_t* sp = (const uint8_t*) src;
  do *dp++ = transfer(*sp++); while (--count);
}

void
SPI::read(void* buf, size_t count)
{
  if (count == 0) return;
  uint8_t* bp = (uint8_t*) buf;
  do *bp++ = transfer(0); while (--count);
}

void
SPI::write(const void* buf, size_t count)
{
  if (count == 0) return;
  const uint8_t* bp = (const uint8_t*) buf;
  do transfer(*bp++); while (--count);
}

void
SPI::write_P(const void* buf, size_t count)
{
  if (count == 0) return;
  const uint8_t* bp = (const uint8_t*) buf;
  do transfer(pgm_read_byte(bp++)); while (--count);
}

#endif

bool
SPI::attach(Driver* dev)
{
  if (dev->m_next != NULL) return (false);
  dev->m_next = m_list;
  m_list = dev;
  return (true);
}

void
SPI::acquire(Driver* dev)
{
  // Acquire the device driver. Wait is busy. Synchronized update
  uint8_t key = lock();
  while (spi.m_busy) {
    unlock(key);
    yield();
    key = lock();
  }
  // Set current device and mark as busy
  spi.m_busy = true;
  spi.m_dev = dev;
#if defined(SPDR)
  // Initiate SPI hardware with device settings
  SPCR = dev->m_spcr;
  SPSR = dev->m_spsr;
#else
  // Set clock polarity
  bit_write(dev->m_cpol & 0x02, PORT, Board::SCK);
#endif
  // Disable all interrupt sources on SPI bus
  for (SPI::Driver* dev = spi.m_list; dev != NULL; dev = dev->m_next)
    if (dev->m_irq != NULL) dev->m_irq->disable();
  unlock(key);
}

void
SPI::release()
{
  // Lock the device driver update
  uint8_t key = lock();
  // Release the device driver
  spi.m_busy = false;
  spi.m_dev = NULL;
  // Enable all interrupt sources on SPI bus
  for (SPI::Driver* dev = spi.m_list; dev != NULL; dev = dev->m_next)
    if (dev->m_irq != NULL) dev->m_irq->enable();
  unlock(key);
}

void
SPI::Driver::set_clock(Clock rate)
{
#if defined(SPDR)
  m_spcr = (m_spcr & ~(0x3 << SPR0)) | ((rate & 0x3) << SPR0);
  m_spsr = (m_spsr & ~(1 << SPI2X)) | (((rate & 0x04) != 0) << SPI2X);
#else
  UNUSED(rate);
#endif
}

<commit_msg>Cleanup SPI::begin/end; remove reference to global spi instance.<commit_after>/**
 * @file Cosa/SPI.cpp
 * @version 1.0
 *
 * @section License
 * Copyright (C) 2012-2014, Mikael Patel
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * This file is part of the Arduino Che Cosa project.
 */

#include "Cosa/SPI.hh"
#include "Cosa/Power.hh"

// Configuration: Allow SPI transfer interleaving
#if !defined(BOARD_ATTINY)
#define USE_SPI_PREFETCH
#endif

SPI spi  __attribute__ ((weak));

#if defined(SPDR)

SPI::Driver::Driver(Board::DigitalPin cs, Pulse pulse,
		    Clock rate, uint8_t mode, Order order,
		    Interrupt::Handler* irq) :
  m_next(NULL),
  m_irq(irq),
  m_cs(cs, (pulse == 0)),
  m_pulse(pulse),
  // SPI Control Register for master mode
  m_spcr(_BV(SPE)
	 | ((order & 0x1) << DORD)
	 | _BV(MSTR)
	 | ((mode & 0x3) << CPHA)
	 | ((rate & 0x3) << SPR0)),
  // SPI Clock control in Status Register
  m_spsr(((rate & 0x04) != 0) << SPI2X)
{
}

SPI::SPI(uint8_t mode, Order order) :
  m_list(NULL),
  m_dev(NULL),
  m_busy(false)
{
  // Initiate the SPI port and control for slave mode
  synchronized {
    bit_set(DDRB, Board::MISO);
    bit_mask_clear(DDRB, _BV(Board::MOSI) | _BV(Board::SCK) | _BV(Board::SS));
    SPCR = (_BV(SPIE) | _BV(SPE)
	    | ((order & 0x1) << DORD)
	    | ((mode & 0x3) << CPHA));
  }
}

SPI::SPI() :
  m_list(NULL),
  m_dev(NULL),
  m_busy(false)
{
  // Initiate the SPI data direction for master mode
  // The SPI/SS pin must be an output pin in master mode
  synchronized {
    bit_mask_set(DDRB, _BV(Board::MOSI) | _BV(Board::SCK) | _BV(Board::SS));
    bit_clear(DDRB, Board::MISO);
    bit_mask_clear(PORTB, _BV(Board::SCK) | _BV(Board::MOSI));
    bit_set(PORTB, Board::MISO);
  }
  // Other the SPI setup is done by the SPI::Driver::begin()
}

void
SPI::Slave::on_interrupt(uint16_t arg)
{
  // Sanity check that a buffer is defined
  if (m_buf == NULL) return;
  // Append to buffer and push event when buffer is full
  m_buf[m_put++] = arg;
  if (m_put != m_max) return;
  // Push receive completed to event dispatch
  Event::push(Event::RECEIVE_COMPLETED_TYPE, this, m_put);
  m_put = 0;
}

// Current slave device. Should be a singleton
SPI::Slave* SPI::Slave::s_device = NULL;

ISR(SPI_STC_vect)
{
  SPI::Slave* device = SPI::Slave::s_device;
  if (device != NULL) device->on_interrupt(SPDR);
}

#elif defined(USIDR)

// Create mapping to USI data direction register and port for ATtiny variants
#if defined(BOARD_ATTINYX4) || defined(BOARD_ATTINYX61)
#define DDR DDRA
#define PORT PORTA
#elif defined(BOARD_ATTINYX5)
#define DDR DDRB
#define PORT PORTB
#endif

SPI::Driver::Driver(Board::DigitalPin cs, Pulse pulse,
		    Clock rate, uint8_t mode, Order order,
		    Interrupt::Handler* irq) :
  m_next(NULL),
  m_irq(irq),
  m_cs(cs, (pulse == 0)),
  m_pulse(pulse),
  m_cpol(mode)
{
  UNUSED(rate);
  UNUSED(order);

  // USI command for hardware supported bit banging
  m_usicr = (_BV(USIWM0) | _BV(USICS1) | _BV(USICLK) | _BV(USITC));
  if (mode == 1 || mode == 2) m_usicr |= _BV(USICS0);

  // Set ports
  synchronized {
    bit_mask_set(DDR, _BV(Board::MOSI) | _BV(Board::SCK));
    bit_clear(DDR, Board::MISO);
    bit_set(PORT, Board::MISO);
    USICR = m_usicr;
  }
}

SPI::SPI(uint8_t mode, Order order) :
  m_list(NULL),
  m_dev(NULL),
  m_busy(false)
{
  UNUSED(order);

  // Set port data direction. Note ATtiny MOSI/MISO are DI/DO.
  // Do not confuse with SPI chip programming pins
  synchronized {
    bit_mask_set(DDR, _BV(Board::MOSI) | _BV(Board::SCK));
    bit_clear(DDR, Board::MISO);
    bit_set(PORT, Board::MISO);
    USICR = (_BV(USIWM0) | _BV(USICS1) | _BV(USICLK) | _BV(USITC));
    if (mode == 1 || mode == 2) USICR |= _BV(USICS0);
  }
}

SPI::SPI() :
  m_list(NULL),
  m_dev(NULL),
  m_busy(false)
{
  // Set port data direction. Note ATtiny MOSI/MISO are DI/DO.
  // Do not confuse with SPI chip programming pins
  synchronized {
    bit_mask_set(DDR, _BV(Board::MOSI) | _BV(Board::SCK));
    bit_clear(DDR, Board::MISO);
    bit_set(PORT, Board::MISO);
  }
}
#endif

/*
 * Prefetch optimized variants of the block transfer member functions.
 * These implementation allow higher transfer speed for block by using
 * the available cycles while a byte transfer is in progress for data
 * prefetch and store. There are at least 16 instruction cycles available
 * (CLOCK_DIV_2).
 */
#if defined(USE_SPI_PREFETCH)
void
SPI::transfer(void* buf, size_t count)
{
  if (count == 0) return;
  uint8_t* dp = (uint8_t*) buf;
  uint8_t data = *dp;
  transfer_start(data);
  while (--count) {
    uint8_t* tp = dp + 1;
    data = *tp;
    *dp = transfer_next(data);
    dp = tp;
  }
  *dp = transfer_await();
}

void
SPI::transfer(void* dst, const void* src, size_t count)
{
  if (count == 0) return;
  uint8_t* dp = (uint8_t*) dst;
  const uint8_t* sp = (const uint8_t*) src;
  uint8_t data = *sp++;
  transfer_start(data);
  while (--count) {
    uint8_t* tp = dp + 1;
    data = *sp++;
    *dp = transfer_next(data);
    dp = tp;
  }
  *dp = transfer_await();
}

void
SPI::read(void* buf, size_t count)
{
  if (count == 0) return;
  uint8_t* dp = (uint8_t*) buf;
  transfer_start(0xff);
  while (--count) *dp++ = transfer_next(0xff);
  *dp = transfer_await();
}

void
SPI::write(const void* buf, size_t count)
{
  if (count == 0) return;
  const uint8_t* sp = (const uint8_t*) buf;
  uint8_t data = *sp++;
  transfer_start(data);
  while (--count) {
    data = *sp++;
    transfer_next(data);
  }
  transfer_await();
}

void
SPI::write_P(const void* buf, size_t count)
{
  if (count == 0) return;
  const uint8_t* sp = (const uint8_t*) buf;
  uint8_t data = pgm_read_byte(sp++);
  transfer_start(data);
  while (--count) {
    data = pgm_read_byte(sp++);
    transfer_next(data);
  }
  transfer_await();
}

#else

void
SPI::transfer(void* buf, size_t count)
{
  if (count == 0) return;
  uint8_t* bp = (uint8_t*) buf;
  do {
    *bp = transfer(*bp);
    bp += 1;
  } while (--count);
}

void
SPI::transfer(void* dst, const void* src, size_t count)
{
  if (count == 0) return;
  uint8_t* dp = (uint8_t*) dst;
  const uint8_t* sp = (const uint8_t*) src;
  do *dp++ = transfer(*sp++); while (--count);
}

void
SPI::read(void* buf, size_t count)
{
  if (count == 0) return;
  uint8_t* bp = (uint8_t*) buf;
  do *bp++ = transfer(0); while (--count);
}

void
SPI::write(const void* buf, size_t count)
{
  if (count == 0) return;
  const uint8_t* bp = (const uint8_t*) buf;
  do transfer(*bp++); while (--count);
}

void
SPI::write_P(const void* buf, size_t count)
{
  if (count == 0) return;
  const uint8_t* bp = (const uint8_t*) buf;
  do transfer(pgm_read_byte(bp++)); while (--count);
}

#endif

bool
SPI::attach(Driver* dev)
{
  if (dev->m_next != NULL) return (false);
  dev->m_next = m_list;
  m_list = dev;
  return (true);
}

void
SPI::acquire(Driver* dev)
{
  // Acquire the device driver. Wait is busy. Synchronized update
  uint8_t key = lock();
  while (m_busy) {
    unlock(key);
    yield();
    key = lock();
  }
  // Set current device and mark as busy
  m_busy = true;
  m_dev = dev;
#if defined(SPDR)
  // Initiate SPI hardware with device settings
  SPCR = dev->m_spcr;
  SPSR = dev->m_spsr;
#else
  // Set clock polarity
  bit_write(dev->m_cpol & 0x02, PORT, Board::SCK);
#endif
  // Disable all interrupt sources on SPI bus
  for (SPI::Driver* dev = m_list; dev != NULL; dev = dev->m_next)
    if (dev->m_irq != NULL) dev->m_irq->disable();
  unlock(key);
}

void
SPI::release()
{
  // Lock the device driver update
  uint8_t key = lock();
  // Release the device driver
  m_busy = false;
  m_dev = NULL;
  // Enable all interrupt sources on SPI bus
  for (SPI::Driver* dev = m_list; dev != NULL; dev = dev->m_next)
    if (dev->m_irq != NULL) dev->m_irq->enable();
  unlock(key);
}

void
SPI::Driver::set_clock(Clock rate)
{
#if defined(SPDR)
  m_spcr = (m_spcr & ~(0x3 << SPR0)) | ((rate & 0x3) << SPR0);
  m_spsr = (m_spsr & ~(1 << SPI2X)) | (((rate & 0x04) != 0) << SPI2X);
#else
  UNUSED(rate);
#endif
}

<|endoftext|>


<commit_before>#include <iostream>
#include <map>
#include <fstream>
#include <sstream>
#include <vector>
#include <cstring>
#include <cstdlib>
#include <cerrno>
#include <unistd.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#include "rlite/common.h"
#include "rlite/utils.h"
#include "rlite/appl.h"

using namespace std;

struct InetName {
    struct sockaddr_in addr;

    InetName() { memset(&addr, 0, sizeof(addr)); }
    InetName(const struct sockaddr_in& a) : addr(a) { }

    bool operator<(const InetName& other) const;
    operator std::string() const;
};

bool
InetName::operator<(const InetName& other) const
{
    if (addr.sin_addr.s_addr != other.addr.sin_addr.s_addr) {
        return addr.sin_addr.s_addr < other.addr.sin_addr.s_addr;
    }

    return addr.sin_port < other.addr.sin_port;
}

InetName::operator std::string() const
{
    char strbuf[20];
    stringstream ss;

    inet_ntop(AF_INET, &addr.sin_addr, strbuf, sizeof(strbuf));

    ss << strbuf << ":" << ntohs(addr.sin_port);

    return ss.str();
}

struct RinaName {
    string name_s;
    struct rina_name name_r;
    string dif_name_s;
    struct rina_name dif_name_r;

    RinaName();
    RinaName(const string& n, const string& d);
    RinaName(const RinaName& other);
    RinaName& operator=(const RinaName& other);
    ~RinaName();

    bool operator<(const RinaName& other) const {
        return name_s < other.name_s;
    }

    operator std::string() const { return dif_name_s + ":" + name_s; }
};

RinaName::RinaName()
{
    memset(&name_r, 0, sizeof(name_r));
    memset(&dif_name_r, 0, sizeof(dif_name_r));
}

RinaName::~RinaName()
{
    rina_name_free(&name_r);
    rina_name_free(&dif_name_r);
}

RinaName::RinaName(const string& n, const string& d) : name_s(n), dif_name_s(d)
{
    memset(&name_r, 0, sizeof(name_r));
    memset(&dif_name_r, 0, sizeof(dif_name_r));

    if (rina_name_from_string(n.c_str(), &name_r)) {
        throw std::bad_alloc();
    }

    if (rina_name_from_string(d.c_str(), &dif_name_r)) {
        throw std::bad_alloc();
    }
}

RinaName::RinaName(const RinaName& other)
{
    memset(&name_r, 0, sizeof(name_r));

    name_s = other.name_s;
    dif_name_s = other.dif_name_s;
    if (rina_name_copy(&name_r, &other.name_r)) {
        throw std::bad_alloc();
    }
    if (rina_name_copy(&dif_name_r, &other.dif_name_r)) {
        throw std::bad_alloc();
    }
}

RinaName&
RinaName::operator=(const RinaName& other)
{
    if (this == &other) {
        return *this;
    }

    name_s = other.name_s;
    dif_name_s = other.dif_name_s;
    if (rina_name_copy(&name_r, &other.name_r)) {
        throw std::bad_alloc();
    }
    if (rina_name_copy(&dif_name_r, &other.dif_name_r)) {
        throw std::bad_alloc();
    }

    return *this;
}

struct Gateway {
    struct rlite_appl appl;
    struct rina_name appl_name;

    /* Used to map IP:PORT --> RINA_NAME, when
     * receiving TCP connection requests from the INET world
     * towards the RINA world. */
    map<InetName, RinaName> srv_map;
    map<int, RinaName> srv_fd_map;

    /* Used to map RINA_NAME --> IP:PORT, when
     * receiving flow allocation requests from the RINA world
     * towards the INET world. */
    map<RinaName, InetName> dst_map;

    /* Pending flow allocation requests issued by accept_inet_conn().
     * fa_req_event_id --> tcp_client_fd */
    map<unsigned int, int> pending_fa_reqs;

    Gateway();
    ~Gateway();
};

Gateway::Gateway()
{
    rina_name_fill(&appl_name, "rina-gw", "1", NULL, NULL);

    if (rlite_appl_init(&appl)) {
        throw std::exception();
    }

    rlite_ipcps_fetch(&appl.loop);
}

Gateway::~Gateway()
{
    for (map<int, RinaName>::iterator mit = srv_fd_map.begin();
                                    mit != srv_fd_map.end(); mit++) {
        close(mit->first);
    }

    rlite_appl_fini(&appl);
}

Gateway gw;

static int
parse_conf(const char *confname)
{
    ifstream fin(confname);

    if (fin.fail()) {
        PE("Failed to open configuration file '%s'\n", confname);
        return -1;
    }

    for (unsigned int lines_cnt = 1; !fin.eof(); lines_cnt++) {
        vector<string> tokens;
        string token;
        string line;
        int ret;

        getline(fin, line);

        {
            istringstream iss(line);
            struct sockaddr_in inet_addr;

            while (iss >> token) {
                tokens.push_back(token);
            }

            if (tokens.size() < 5) {
                if (tokens.size()) {
                    PI("Invalid configuration entry at line %d\n", lines_cnt);
                }
                continue;
            }

            try {
                memset(&inet_addr, 0, sizeof(inet_addr));
                inet_addr.sin_family = AF_INET;
                inet_addr.sin_port = atoi(tokens[4].c_str());
                if (inet_addr.sin_port >= 65536) {
                    PI("Invalid configuration entry at line %d: "
                       "invalid port number '%s'\n", lines_cnt,
                       tokens[4].c_str());
                }
                ret = inet_pton(AF_INET, tokens[3].c_str(),
                                &inet_addr.sin_addr);
                if (ret != 1) {
                    PI("Invalid configuration entry at line %d: "
                       "invalid IP address '%s'\n", lines_cnt,
                       tokens[3].c_str());
                    continue;
                }

                InetName inet_name(inet_addr);
                RinaName rina_name(tokens[2], tokens[1]);

                if (tokens[0] == "SRV") {
                    gw.srv_map.insert(make_pair(inet_name, rina_name));

                } else if (tokens[0] == "DST") {
                    gw.dst_map.insert(make_pair(rina_name, inet_name));

                } else {
                    PI("Invalid configuration entry at line %d: %s is "
                       "unknown\n", lines_cnt, tokens[0].c_str());
                    continue;
                }
            } catch (std::bad_alloc) {
                PE("Out of memory while processing configuration file\n");
            }
        }
    }

    return 0;
}

static int
gw_fa_req_arrived(struct rlite_evloop *loop,
                  const struct rina_msg_base_resp *b_resp,
                  const struct rina_msg_base *b_req)
{
    return 0;
}

static int
gw_fa_resp_arrived(struct rlite_evloop *loop,
                   const struct rina_msg_base_resp *b_resp,
                   const struct rina_msg_base *b_req)
{
    return 0;
}

static void
accept_inet_conn(struct rlite_evloop *loop, int lfd)
{
    struct rlite_appl *appl = container_of(loop, struct rlite_appl, loop);
    Gateway * gw = container_of(appl, struct Gateway, appl);
    struct sockaddr_in remote_addr;
    socklen_t addrlen = sizeof(remote_addr);
    map<int, RinaName>::iterator mit;
    struct rina_flow_spec flowspec;
    unsigned int event_id;
    unsigned int unused;
    int cfd;
    int ret;

    /* First of all let's call accept, so that we consume the event
     * on lfd, independently of what happen next. */
    cfd = accept(lfd, (struct sockaddr *)&remote_addr, &addrlen);
    if (cfd < 0) {
        PE("accept() failed\n");
        return;
    }

    mit = gw->srv_fd_map.find(lfd);
    if (mit == gw->srv_fd_map.end()) {
        PE("Internal error: Failed to lookup lfd %d into srv_fd_map\n", lfd);
        return;
    }

    strcpy(flowspec.cubename, "rel");
    event_id = rlite_evloop_get_id(loop);

    /* Issue a non-blocking flow allocation request. */
    ret = rlite_flow_allocate(appl, event_id, &mit->second.dif_name_r, NULL,
                              &gw->appl_name, &mit->second.name_r, &flowspec,
                              &unused, 0, 0);
    if (ret) {
        PE("Flow allocation failed");
        return;
    }

    gw->pending_fa_reqs[event_id] = cfd;

    PD("Flow allocation request issued, event id %d\n", event_id);
}

static int
inet_server_socket(const InetName& inet_name)
{
    int enable = 1;
    int fd;

    fd = socket(PF_INET, SOCK_STREAM, 0);

    if (fd < 0) {
        PE("socket() failed [%d]\n", errno);
        return -1;
    }

    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable,
                   sizeof(enable))) {
        PE("setsockopt(SO_REUSEADDR) failed [%d]\n", errno);
        close(fd);
        return -1;
    }

    if (bind(fd, (struct sockaddr *)&inet_name.addr, sizeof(inet_name.addr))) {
        PE("bind() failed [%d]\n", errno);
        close(fd);
        return -1;
    }

    if (listen(fd, 10)) {
        PE("listen() failed [%d]\n", errno);
        close(fd);
        return -1;
    }

    if (rlite_evloop_fdcb_add(&gw.appl.loop, fd, accept_inet_conn)) {
        PE("rlite_evloop_fcdb_add() failed [%d]\n", errno);
        close(fd);
        return -1;
    }

    return 0;
}

static int
setup()
{
    int ret;

    /* Register the handler for incoming flow allocation requests and
     * response, since we'll not be using rlite/appl.h functionalities for
     * that. */
    ret = rlite_evloop_set_handler(&gw.appl.loop, RINA_KERN_FA_REQ_ARRIVED,
                                   gw_fa_req_arrived);
    ret |= rlite_evloop_set_handler(&gw.appl.loop, RINA_KERN_FA_RESP_ARRIVED,
                                    gw_fa_resp_arrived);
    if (ret) {
        return -1;
    }

    for (map<InetName, RinaName>::iterator mit = gw.srv_map.begin();
                                    mit != gw.srv_map.end(); mit++) {
        int fd = inet_server_socket(mit->first);

        if (fd < 0) {
            PE("Failed to open listening socket for '%s'\n",
               static_cast<string>(mit->first).c_str());
        } else {
            gw.srv_fd_map[fd] = mit->second;
        }
    }

    for (map<RinaName, InetName>::iterator mit = gw.dst_map.begin();
                                    mit != gw.dst_map.end(); mit++) {
        rlite_appl_register_wait(&gw.appl, 1, &mit->first.dif_name_r, NULL,
                                 &mit->first.name_r, 3000);
        if (ret) {
            PE("Registration of application '%s'\n",
               static_cast<string>(mit->first).c_str());
        }
    }

    return 0;
}

static void
print_conf()
{
    for (map<InetName, RinaName>::iterator mit = gw.srv_map.begin();
                                    mit != gw.srv_map.end(); mit++) {
        cout << "SRV: " << static_cast<string>(mit->first) << " --> "
                << static_cast<string>(mit->second) << endl;
    }

    for (map<RinaName, InetName>::iterator mit = gw.dst_map.begin();
                                    mit != gw.dst_map.end(); mit++) {
        cout << "DST: " << static_cast<string>(mit->first) << " --> "
                << static_cast<string>(mit->second) << endl;
    }
}

int main()
{
    const char *confname = "rina-gw.conf";
    int ret;

    ret = parse_conf(confname);
    if (ret) {
        return ret;
    }

    print_conf();
    setup();

    return 0;
}
<commit_msg>gateway: gw_fa_resp_arrived() sketched<commit_after>#include <iostream>
#include <map>
#include <fstream>
#include <sstream>
#include <vector>
#include <cstring>
#include <cstdlib>
#include <cerrno>
#include <unistd.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#include "rlite/common.h"
#include "rlite/utils.h"
#include "rlite/appl.h"

using namespace std;

struct InetName {
    struct sockaddr_in addr;

    InetName() { memset(&addr, 0, sizeof(addr)); }
    InetName(const struct sockaddr_in& a) : addr(a) { }

    bool operator<(const InetName& other) const;
    operator std::string() const;
};

bool
InetName::operator<(const InetName& other) const
{
    if (addr.sin_addr.s_addr != other.addr.sin_addr.s_addr) {
        return addr.sin_addr.s_addr < other.addr.sin_addr.s_addr;
    }

    return addr.sin_port < other.addr.sin_port;
}

InetName::operator std::string() const
{
    char strbuf[20];
    stringstream ss;

    inet_ntop(AF_INET, &addr.sin_addr, strbuf, sizeof(strbuf));

    ss << strbuf << ":" << ntohs(addr.sin_port);

    return ss.str();
}

struct RinaName {
    string name_s;
    struct rina_name name_r;
    string dif_name_s;
    struct rina_name dif_name_r;

    RinaName();
    RinaName(const string& n, const string& d);
    RinaName(const RinaName& other);
    RinaName& operator=(const RinaName& other);
    ~RinaName();

    bool operator<(const RinaName& other) const {
        return name_s < other.name_s;
    }

    operator std::string() const { return dif_name_s + ":" + name_s; }
};

RinaName::RinaName()
{
    memset(&name_r, 0, sizeof(name_r));
    memset(&dif_name_r, 0, sizeof(dif_name_r));
}

RinaName::~RinaName()
{
    rina_name_free(&name_r);
    rina_name_free(&dif_name_r);
}

RinaName::RinaName(const string& n, const string& d) : name_s(n), dif_name_s(d)
{
    memset(&name_r, 0, sizeof(name_r));
    memset(&dif_name_r, 0, sizeof(dif_name_r));

    if (rina_name_from_string(n.c_str(), &name_r)) {
        throw std::bad_alloc();
    }

    if (rina_name_from_string(d.c_str(), &dif_name_r)) {
        throw std::bad_alloc();
    }
}

RinaName::RinaName(const RinaName& other)
{
    memset(&name_r, 0, sizeof(name_r));

    name_s = other.name_s;
    dif_name_s = other.dif_name_s;
    if (rina_name_copy(&name_r, &other.name_r)) {
        throw std::bad_alloc();
    }
    if (rina_name_copy(&dif_name_r, &other.dif_name_r)) {
        throw std::bad_alloc();
    }
}

RinaName&
RinaName::operator=(const RinaName& other)
{
    if (this == &other) {
        return *this;
    }

    name_s = other.name_s;
    dif_name_s = other.dif_name_s;
    if (rina_name_copy(&name_r, &other.name_r)) {
        throw std::bad_alloc();
    }
    if (rina_name_copy(&dif_name_r, &other.dif_name_r)) {
        throw std::bad_alloc();
    }

    return *this;
}

struct Gateway {
    struct rlite_appl appl;
    struct rina_name appl_name;

    /* Used to map IP:PORT --> RINA_NAME, when
     * receiving TCP connection requests from the INET world
     * towards the RINA world. */
    map<InetName, RinaName> srv_map;
    map<int, RinaName> srv_fd_map;

    /* Used to map RINA_NAME --> IP:PORT, when
     * receiving flow allocation requests from the RINA world
     * towards the INET world. */
    map<RinaName, InetName> dst_map;

    /* Pending flow allocation requests issued by accept_inet_conn().
     * fa_req_event_id --> tcp_client_fd */
    map<unsigned int, int> pending_fa_reqs;

    map<int, int> active_mappings;

    Gateway();
    ~Gateway();
};

Gateway::Gateway()
{
    rina_name_fill(&appl_name, "rina-gw", "1", NULL, NULL);

    if (rlite_appl_init(&appl)) {
        throw std::exception();
    }

    rlite_ipcps_fetch(&appl.loop);
}

Gateway::~Gateway()
{
    for (map<int, RinaName>::iterator mit = srv_fd_map.begin();
                                    mit != srv_fd_map.end(); mit++) {
        close(mit->first);
    }

    rlite_appl_fini(&appl);
}

Gateway gw;

static int
parse_conf(const char *confname)
{
    ifstream fin(confname);

    if (fin.fail()) {
        PE("Failed to open configuration file '%s'\n", confname);
        return -1;
    }

    for (unsigned int lines_cnt = 1; !fin.eof(); lines_cnt++) {
        vector<string> tokens;
        string token;
        string line;
        int ret;

        getline(fin, line);

        {
            istringstream iss(line);
            struct sockaddr_in inet_addr;

            while (iss >> token) {
                tokens.push_back(token);
            }

            if (tokens.size() < 5) {
                if (tokens.size()) {
                    PI("Invalid configuration entry at line %d\n", lines_cnt);
                }
                continue;
            }

            try {
                memset(&inet_addr, 0, sizeof(inet_addr));
                inet_addr.sin_family = AF_INET;
                inet_addr.sin_port = atoi(tokens[4].c_str());
                if (inet_addr.sin_port >= 65536) {
                    PI("Invalid configuration entry at line %d: "
                       "invalid port number '%s'\n", lines_cnt,
                       tokens[4].c_str());
                }
                ret = inet_pton(AF_INET, tokens[3].c_str(),
                                &inet_addr.sin_addr);
                if (ret != 1) {
                    PI("Invalid configuration entry at line %d: "
                       "invalid IP address '%s'\n", lines_cnt,
                       tokens[3].c_str());
                    continue;
                }

                InetName inet_name(inet_addr);
                RinaName rina_name(tokens[2], tokens[1]);

                if (tokens[0] == "SRV") {
                    gw.srv_map.insert(make_pair(inet_name, rina_name));

                } else if (tokens[0] == "DST") {
                    gw.dst_map.insert(make_pair(rina_name, inet_name));

                } else {
                    PI("Invalid configuration entry at line %d: %s is "
                       "unknown\n", lines_cnt, tokens[0].c_str());
                    continue;
                }
            } catch (std::bad_alloc) {
                PE("Out of memory while processing configuration file\n");
            }
        }
    }

    return 0;
}

static int
gw_fa_req_arrived(struct rlite_evloop *loop,
                  const struct rina_msg_base_resp *b_resp,
                  const struct rina_msg_base *b_req)
{
    return 0;
}

static int
gw_fa_resp_arrived(struct rlite_evloop *loop,
                   const struct rina_msg_base_resp *b_resp,
                   const struct rina_msg_base *b_req)
{
    struct rlite_appl *appl = container_of(loop, struct rlite_appl, loop);
    Gateway * gw = container_of(appl, struct Gateway, appl);
    struct rina_kmsg_fa_resp_arrived *resp =
            (struct rina_kmsg_fa_resp_arrived *)b_resp;
    map<unsigned int, int>::iterator mit;
    int cfd;
    int rfd;

    mit = gw->pending_fa_reqs.find(b_req->event_id);
    if (mit == gw->pending_fa_reqs.end()) {
        PE("Spurious flow allocation response [id=%u]\n", b_req->event_id);
        return 0;
    }

    cfd = mit->second;
    gw->pending_fa_reqs.erase(mit);

    rfd = rlite_open_appl_port(resp->port_id);
    if (rfd < 0) {
        PE("Failed to open application port\n");
        close(cfd);
        return 0;
    }

    gw->active_mappings[cfd] = rfd;
    gw->active_mappings[rfd] = cfd;

    PI("New mapping created %d <--> %d\n", cfd, rfd);

    return 0;
}

static void
accept_inet_conn(struct rlite_evloop *loop, int lfd)
{
    struct rlite_appl *appl = container_of(loop, struct rlite_appl, loop);
    Gateway * gw = container_of(appl, struct Gateway, appl);
    struct sockaddr_in remote_addr;
    socklen_t addrlen = sizeof(remote_addr);
    map<int, RinaName>::iterator mit;
    struct rina_flow_spec flowspec;
    unsigned int event_id;
    unsigned int unused;
    int cfd;
    int ret;

    /* First of all let's call accept, so that we consume the event
     * on lfd, independently of what happen next. */
    cfd = accept(lfd, (struct sockaddr *)&remote_addr, &addrlen);
    if (cfd < 0) {
        PE("accept() failed\n");
        return;
    }

    mit = gw->srv_fd_map.find(lfd);
    if (mit == gw->srv_fd_map.end()) {
        PE("Internal error: Failed to lookup lfd %d into srv_fd_map\n", lfd);
        return;
    }

    strcpy(flowspec.cubename, "rel");
    event_id = rlite_evloop_get_id(loop);

    /* Issue a non-blocking flow allocation request. */
    ret = rlite_flow_allocate(appl, event_id, &mit->second.dif_name_r, NULL,
                              &gw->appl_name, &mit->second.name_r, &flowspec,
                              &unused, 0, 0);
    if (ret) {
        PE("Flow allocation failed");
        return;
    }

    gw->pending_fa_reqs[event_id] = cfd;

    PD("Flow allocation request issued, event id %d\n", event_id);
}

static int
inet_server_socket(const InetName& inet_name)
{
    int enable = 1;
    int fd;

    fd = socket(PF_INET, SOCK_STREAM, 0);

    if (fd < 0) {
        PE("socket() failed [%d]\n", errno);
        return -1;
    }

    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable,
                   sizeof(enable))) {
        PE("setsockopt(SO_REUSEADDR) failed [%d]\n", errno);
        close(fd);
        return -1;
    }

    if (bind(fd, (struct sockaddr *)&inet_name.addr, sizeof(inet_name.addr))) {
        PE("bind() failed [%d]\n", errno);
        close(fd);
        return -1;
    }

    if (listen(fd, 10)) {
        PE("listen() failed [%d]\n", errno);
        close(fd);
        return -1;
    }

    if (rlite_evloop_fdcb_add(&gw.appl.loop, fd, accept_inet_conn)) {
        PE("rlite_evloop_fcdb_add() failed [%d]\n", errno);
        close(fd);
        return -1;
    }

    return 0;
}

static int
setup()
{
    int ret;

    /* Register the handler for incoming flow allocation requests and
     * response, since we'll not be using rlite/appl.h functionalities for
     * that. */
    ret = rlite_evloop_set_handler(&gw.appl.loop, RINA_KERN_FA_REQ_ARRIVED,
                                   gw_fa_req_arrived);
    ret |= rlite_evloop_set_handler(&gw.appl.loop, RINA_KERN_FA_RESP_ARRIVED,
                                    gw_fa_resp_arrived);
    if (ret) {
        return -1;
    }

    for (map<InetName, RinaName>::iterator mit = gw.srv_map.begin();
                                    mit != gw.srv_map.end(); mit++) {
        int fd = inet_server_socket(mit->first);

        if (fd < 0) {
            PE("Failed to open listening socket for '%s'\n",
               static_cast<string>(mit->first).c_str());
        } else {
            gw.srv_fd_map[fd] = mit->second;
        }
    }

    for (map<RinaName, InetName>::iterator mit = gw.dst_map.begin();
                                    mit != gw.dst_map.end(); mit++) {
        rlite_appl_register_wait(&gw.appl, 1, &mit->first.dif_name_r, NULL,
                                 &mit->first.name_r, 3000);
        if (ret) {
            PE("Registration of application '%s'\n",
               static_cast<string>(mit->first).c_str());
        }
    }

    return 0;
}

static void
print_conf()
{
    for (map<InetName, RinaName>::iterator mit = gw.srv_map.begin();
                                    mit != gw.srv_map.end(); mit++) {
        cout << "SRV: " << static_cast<string>(mit->first) << " --> "
                << static_cast<string>(mit->second) << endl;
    }

    for (map<RinaName, InetName>::iterator mit = gw.dst_map.begin();
                                    mit != gw.dst_map.end(); mit++) {
        cout << "DST: " << static_cast<string>(mit->first) << " --> "
                << static_cast<string>(mit->second) << endl;
    }
}

int main()
{
    const char *confname = "rina-gw.conf";
    int ret;

    ret = parse_conf(confname);
    if (ret) {
        return ret;
    }

    print_conf();
    setup();

    return 0;
}
<|endoftext|>


<commit_before>/*
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following
 * conditions are met:
 *
 * 1. Redistributions of source code must retain the above
 *    copyright notice, this list of conditions and the
 *    following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above
 *    copyright notice, this list of conditions and the following
 *    disclaimer in the documentation and/or other materials
 *    provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
 * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
#include "ipc.h"
#include "fiber.h"
#include <stdlib.h>
#include "salad/rlist.h"

struct ipc_channel {
	struct rlist readers, writers;
	struct fiber *bcast;		/* broadcast waiter */
	struct fiber *close;		/* close waiter */
	bool closed;			/* channel is closed */
	unsigned size;
	unsigned beg;
	unsigned count;
	void *bcast_msg;
	void *item[0];
};

static void
ipc_channel_create(struct ipc_channel *ch);

static void
ipc_channel_destroy(struct ipc_channel *ch);

bool
ipc_channel_is_empty(struct ipc_channel *ch)
{
	return ch->count == 0;
}

bool
ipc_channel_is_full(struct ipc_channel *ch)
{
	return ch->count >= ch->size;
}

struct ipc_channel *
ipc_channel_new(unsigned size)
{
	if (!size)
		size = 1;
	struct ipc_channel *res = (struct ipc_channel *)
		malloc(sizeof(struct ipc_channel) + sizeof(void *) * size);
	if (res == NULL)
		return NULL;
	res->size = size;
	ipc_channel_create(res);
	return res;
}

void
ipc_channel_delete(struct ipc_channel *ch)
{
	ipc_channel_destroy(ch);
	free(ch);
}

static void
ipc_channel_create(struct ipc_channel *ch)
{
	ch->beg = ch->count = 0;
	ch->closed = false;
	ch->close = NULL;
	ch->bcast = NULL;
	rlist_create(&ch->readers);
	rlist_create(&ch->writers);
}

static void
ipc_channel_destroy(struct ipc_channel *ch)
{
	while (!rlist_empty(&ch->writers)) {
		struct fiber *f =
			rlist_first_entry(&ch->writers, struct fiber, state);
		rlist_del_entry(f, state);
	}
	while (!rlist_empty(&ch->readers)) {
		struct fiber *f =
			rlist_first_entry(&ch->readers, struct fiber, state);
		rlist_del_entry(f, state);
	}
}

void *
ipc_channel_get_timeout(struct ipc_channel *ch, ev_tstamp timeout)
{
	if (ch->closed)
		return NULL;

	struct fiber *f;
	bool first_try = true;
	ev_tstamp started = ev_now(loop());
	void *res;
	/* channel is empty */
	while (ch->count == 0) {
		/* try to be in FIFO order */
		if (first_try) {
			rlist_add_tail_entry(&ch->readers, fiber(), state);
			first_try = false;
		} else {
			rlist_add_entry(&ch->readers, fiber(), state);
		}
		bool cancellable = fiber_setcancellable(true);
		fiber_yield_timeout(timeout);
		rlist_del_entry(fiber(), state);

		/* broadcast messsage wakes us up */
		if (ch->bcast) {
			fiber_wakeup(ch->bcast);
			fiber_testcancel();
			fiber_setcancellable(cancellable);
			res = ch->bcast_msg;
			goto exit;
		}

		fiber_testcancel();
		fiber_setcancellable(cancellable);

		timeout -= ev_now(loop()) - started;
		if (timeout <= 0) {
			res = NULL;
			goto exit;
		}

		if (ch->closed) {
			res = NULL;
			goto exit;
		}
	}

	res = ch->item[ch->beg];
	if (++ch->beg >= ch->size)
		ch->beg -= ch->size;
	ch->count--;

	if (!rlist_empty(&ch->writers)) {
		f = rlist_first_entry(&ch->writers, struct fiber, state);
		rlist_del_entry(f, state);
		fiber_wakeup(f);
	}

exit:
	if (ch->closed && ch->close) {
		fiber_wakeup(ch->close);
		ch->close = NULL;
	}

	return res;
}

void *
ipc_channel_get(struct ipc_channel *ch)
{
	return ipc_channel_get_timeout(ch, TIMEOUT_INFINITY);
}

static void
ipc_channel_close_waiter(struct ipc_channel *ch, struct fiber *f)
{
	ch->close = fiber();

	while (ch->close) {
		bool cancellable = fiber_setcancellable(true);
		fiber_wakeup(f);
		fiber_yield();
		ch->close = NULL;
		rlist_del_entry(fiber(), state);
		fiber_testcancel();
		fiber_setcancellable(cancellable);
	}
}

void
ipc_channel_close(struct ipc_channel *ch)
{
	if (ch->closed)
		return;
	ch->closed = true;

	struct fiber *f;
	while(!rlist_empty(&ch->readers)) {
		f = rlist_first_entry(&ch->readers, struct fiber, state);
		ipc_channel_close_waiter(ch, f);
	}
	while(!rlist_empty(&ch->writers)) {
		f = rlist_first_entry(&ch->writers, struct fiber, state);
		ipc_channel_close_waiter(ch, f);
	}
	if (ch->bcast)
		fiber_wakeup(ch->bcast);
}

bool
ipc_channel_is_closed(struct ipc_channel *ch)
{
	return ch->closed;
}

int
ipc_channel_put_timeout(struct ipc_channel *ch, void *data,
			ev_tstamp timeout)
{
	if (ch->closed) {
		errno = EBADF;
		return -1;
	}

	bool first_try = true;
	int res;
	unsigned i;
	ev_tstamp started = ev_now(loop());
	/* channel is full */
	while (ch->count >= ch->size) {

		/* try to be in FIFO order */
		if (first_try) {
			rlist_add_tail_entry(&ch->writers, fiber(), state);
			first_try = false;
		} else {
			rlist_add_entry(&ch->writers, fiber(), state);
		}

		bool cancellable = fiber_setcancellable(true);
		fiber_yield_timeout(timeout);
		rlist_del_entry(fiber(), state);

		fiber_testcancel();
		fiber_setcancellable(cancellable);

		timeout -= ev_now(loop()) - started;
		if (timeout <= 0) {
			errno = ETIMEDOUT;
			res = -1;
			goto exit;
		}

		if (ch->closed) {
			errno = EBADF;
			res = -1;
			goto exit;
		}
	}

	i = ch->beg;
	i += ch->count;
	ch->count++;
	if (i >= ch->size)
		i -= ch->size;

	ch->item[i] = data;
	if (!rlist_empty(&ch->readers)) {
		struct fiber *f;
		f = rlist_first_entry(&ch->readers, struct fiber, state);
		rlist_del_entry(f, state);
		fiber_wakeup(f);
	}
	res = 0;
exit:
	if (ch->closed && ch->close) {
		int save_errno = errno;
		fiber_wakeup(ch->close);
		ch->close = NULL;
		errno = save_errno;
	}
	return res;
}

void
ipc_channel_put(struct ipc_channel *ch, void *data)
{
	ipc_channel_put_timeout(ch, data, TIMEOUT_INFINITY);
}

bool
ipc_channel_has_readers(struct ipc_channel *ch)
{
	return !rlist_empty(&ch->readers);
}

bool
ipc_channel_has_writers(struct ipc_channel *ch)
{
	return !rlist_empty(&ch->writers);
}

int
ipc_channel_broadcast(struct ipc_channel *ch, void *data)
{
	/* do nothing at closed channel */
	if (ch->closed)
		return 0;

	/* broadcast in broadcast: marasmus */
	if (ch->bcast)
		return 0;

	/* there is no reader on channel */
	if (rlist_empty(&ch->readers)) {
		ipc_channel_put(ch, data);
		return 1;
	}

	unsigned readers = 0;
	struct fiber *f;
	rlist_foreach_entry(f, &ch->readers, state) {
		readers++;
	}

	unsigned cnt = 0;
	while (!rlist_empty(&ch->readers)) {
		if (ch->closed)
			break;
		f = rlist_first_entry(&ch->readers, struct fiber, state);

		ch->bcast_msg = data;
		ch->bcast = fiber();
		fiber_wakeup(f);
		bool cancellable = fiber_setcancellable(true);
		fiber_yield();
		ch->bcast = NULL;
		rlist_del_entry(fiber(), state);
		fiber_testcancel();
		fiber_setcancellable(cancellable);
		/* if any other reader was added don't wake it up */
		if (++cnt >= readers)
			break;
	}

	if (ch->closed && ch->close) {
		fiber_wakeup(ch->close);
		ch->close = NULL;
	}

	return cnt;
}
<commit_msg>Fix a spelling error.<commit_after>/*
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following
 * conditions are met:
 *
 * 1. Redistributions of source code must retain the above
 *    copyright notice, this list of conditions and the
 *    following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above
 *    copyright notice, this list of conditions and the following
 *    disclaimer in the documentation and/or other materials
 *    provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
 * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
#include "ipc.h"
#include "fiber.h"
#include <stdlib.h>
#include "salad/rlist.h"

struct ipc_channel {
	struct rlist readers, writers;
	struct fiber *bcast;		/* broadcast waiter */
	struct fiber *close;		/* close waiter */
	bool closed;			/* channel is closed */
	unsigned size;
	unsigned beg;
	unsigned count;
	void *bcast_msg;
	void *item[0];
};

static void
ipc_channel_create(struct ipc_channel *ch);

static void
ipc_channel_destroy(struct ipc_channel *ch);

bool
ipc_channel_is_empty(struct ipc_channel *ch)
{
	return ch->count == 0;
}

bool
ipc_channel_is_full(struct ipc_channel *ch)
{
	return ch->count >= ch->size;
}

struct ipc_channel *
ipc_channel_new(unsigned size)
{
	if (!size)
		size = 1;
	struct ipc_channel *res = (struct ipc_channel *)
		malloc(sizeof(struct ipc_channel) + sizeof(void *) * size);
	if (res == NULL)
		return NULL;
	res->size = size;
	ipc_channel_create(res);
	return res;
}

void
ipc_channel_delete(struct ipc_channel *ch)
{
	ipc_channel_destroy(ch);
	free(ch);
}

static void
ipc_channel_create(struct ipc_channel *ch)
{
	ch->beg = ch->count = 0;
	ch->closed = false;
	ch->close = NULL;
	ch->bcast = NULL;
	rlist_create(&ch->readers);
	rlist_create(&ch->writers);
}

static void
ipc_channel_destroy(struct ipc_channel *ch)
{
	while (!rlist_empty(&ch->writers)) {
		struct fiber *f =
			rlist_first_entry(&ch->writers, struct fiber, state);
		rlist_del_entry(f, state);
	}
	while (!rlist_empty(&ch->readers)) {
		struct fiber *f =
			rlist_first_entry(&ch->readers, struct fiber, state);
		rlist_del_entry(f, state);
	}
}

void *
ipc_channel_get_timeout(struct ipc_channel *ch, ev_tstamp timeout)
{
	if (ch->closed)
		return NULL;

	struct fiber *f;
	bool first_try = true;
	ev_tstamp started = ev_now(loop());
	void *res;
	/* channel is empty */
	while (ch->count == 0) {
		/* try to be in FIFO order */
		if (first_try) {
			rlist_add_tail_entry(&ch->readers, fiber(), state);
			first_try = false;
		} else {
			rlist_add_entry(&ch->readers, fiber(), state);
		}
		bool cancellable = fiber_setcancellable(true);
		fiber_yield_timeout(timeout);
		rlist_del_entry(fiber(), state);

		/* broadcast message wakes us up */
		if (ch->bcast) {
			fiber_wakeup(ch->bcast);
			fiber_testcancel();
			fiber_setcancellable(cancellable);
			res = ch->bcast_msg;
			goto exit;
		}

		fiber_testcancel();
		fiber_setcancellable(cancellable);

		timeout -= ev_now(loop()) - started;
		if (timeout <= 0) {
			res = NULL;
			goto exit;
		}

		if (ch->closed) {
			res = NULL;
			goto exit;
		}
	}

	res = ch->item[ch->beg];
	if (++ch->beg >= ch->size)
		ch->beg -= ch->size;
	ch->count--;

	if (!rlist_empty(&ch->writers)) {
		f = rlist_first_entry(&ch->writers, struct fiber, state);
		rlist_del_entry(f, state);
		fiber_wakeup(f);
	}

exit:
	if (ch->closed && ch->close) {
		fiber_wakeup(ch->close);
		ch->close = NULL;
	}

	return res;
}

void *
ipc_channel_get(struct ipc_channel *ch)
{
	return ipc_channel_get_timeout(ch, TIMEOUT_INFINITY);
}

static void
ipc_channel_close_waiter(struct ipc_channel *ch, struct fiber *f)
{
	ch->close = fiber();

	while (ch->close) {
		bool cancellable = fiber_setcancellable(true);
		fiber_wakeup(f);
		fiber_yield();
		ch->close = NULL;
		rlist_del_entry(fiber(), state);
		fiber_testcancel();
		fiber_setcancellable(cancellable);
	}
}

void
ipc_channel_close(struct ipc_channel *ch)
{
	if (ch->closed)
		return;
	ch->closed = true;

	struct fiber *f;
	while(!rlist_empty(&ch->readers)) {
		f = rlist_first_entry(&ch->readers, struct fiber, state);
		ipc_channel_close_waiter(ch, f);
	}
	while(!rlist_empty(&ch->writers)) {
		f = rlist_first_entry(&ch->writers, struct fiber, state);
		ipc_channel_close_waiter(ch, f);
	}
	if (ch->bcast)
		fiber_wakeup(ch->bcast);
}

bool
ipc_channel_is_closed(struct ipc_channel *ch)
{
	return ch->closed;
}

int
ipc_channel_put_timeout(struct ipc_channel *ch, void *data,
			ev_tstamp timeout)
{
	if (ch->closed) {
		errno = EBADF;
		return -1;
	}

	bool first_try = true;
	int res;
	unsigned i;
	ev_tstamp started = ev_now(loop());
	/* channel is full */
	while (ch->count >= ch->size) {

		/* try to be in FIFO order */
		if (first_try) {
			rlist_add_tail_entry(&ch->writers, fiber(), state);
			first_try = false;
		} else {
			rlist_add_entry(&ch->writers, fiber(), state);
		}

		bool cancellable = fiber_setcancellable(true);
		fiber_yield_timeout(timeout);
		rlist_del_entry(fiber(), state);

		fiber_testcancel();
		fiber_setcancellable(cancellable);

		timeout -= ev_now(loop()) - started;
		if (timeout <= 0) {
			errno = ETIMEDOUT;
			res = -1;
			goto exit;
		}

		if (ch->closed) {
			errno = EBADF;
			res = -1;
			goto exit;
		}
	}

	i = ch->beg;
	i += ch->count;
	ch->count++;
	if (i >= ch->size)
		i -= ch->size;

	ch->item[i] = data;
	if (!rlist_empty(&ch->readers)) {
		struct fiber *f;
		f = rlist_first_entry(&ch->readers, struct fiber, state);
		rlist_del_entry(f, state);
		fiber_wakeup(f);
	}
	res = 0;
exit:
	if (ch->closed && ch->close) {
		int save_errno = errno;
		fiber_wakeup(ch->close);
		ch->close = NULL;
		errno = save_errno;
	}
	return res;
}

void
ipc_channel_put(struct ipc_channel *ch, void *data)
{
	ipc_channel_put_timeout(ch, data, TIMEOUT_INFINITY);
}

bool
ipc_channel_has_readers(struct ipc_channel *ch)
{
	return !rlist_empty(&ch->readers);
}

bool
ipc_channel_has_writers(struct ipc_channel *ch)
{
	return !rlist_empty(&ch->writers);
}

int
ipc_channel_broadcast(struct ipc_channel *ch, void *data)
{
	/* do nothing at closed channel */
	if (ch->closed)
		return 0;

	/* broadcast in broadcast: marasmus */
	if (ch->bcast)
		return 0;

	/* there is no reader on channel */
	if (rlist_empty(&ch->readers)) {
		ipc_channel_put(ch, data);
		return 1;
	}

	unsigned readers = 0;
	struct fiber *f;
	rlist_foreach_entry(f, &ch->readers, state) {
		readers++;
	}

	unsigned cnt = 0;
	while (!rlist_empty(&ch->readers)) {
		if (ch->closed)
			break;
		f = rlist_first_entry(&ch->readers, struct fiber, state);

		ch->bcast_msg = data;
		ch->bcast = fiber();
		fiber_wakeup(f);
		bool cancellable = fiber_setcancellable(true);
		fiber_yield();
		ch->bcast = NULL;
		rlist_del_entry(fiber(), state);
		fiber_testcancel();
		fiber_setcancellable(cancellable);
		/* if any other reader was added don't wake it up */
		if (++cnt >= readers)
			break;
	}

	if (ch->closed && ch->close) {
		fiber_wakeup(ch->close);
		ch->close = NULL;
	}

	return cnt;
}
<|endoftext|>


<commit_before>#include <stdlib.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <cstring>
#include <stdio.h>
#include <string>
#include <iostream>
#include <list>
#include <map>

#include "server.h"
#include "duckchat.h"

// TODO Server can accept connections.
// TODO Server handles Login and Logout from users, and keeps records of which users are logged in.
// TODO Server handles Join and Leave from users, keeps records of which channels a user belongs to,
// and keeps records of which users are in a channel.
// TODO Server handles the Say message.
// TODO Server correctly handles List and Who.
// TODO Create copies of your client and server source. Modify them to send invalid packets to your good client
// and server, to see if you can make your client or server crash. Fix any bugs you find.

//std::string user;

class Channel {
public:
  std::string name;
  std::list<User *> users;

  Channel(std::string name): name(name) {};
};

class User {
public:
  std::string name;
  struct sockaddr_in *address;
  std::list<Channel *> channels;

  User(std::string name, struct sockaddr_in *address): name(name), address(address) {};
};

std::map<std::string, User *> users;
std::map<std::string, Channel *> channels;

void Error(const char *msg) {
  perror(msg);
  exit(1);
}

void ProcessRequest(void *buffer, struct sockaddr_in *address) {
  struct request current_request;
  memcpy(&current_request, buffer, sizeof(struct request));
  std::cout << "request type: " << current_request.req_type << std::endl;
  request_t request_type = current_request.req_type;

  switch(request_type){
    case REQ_LOGIN:
      struct request_login login_request;
      memcpy(&login_request, buffer, sizeof(struct request_login));

      User new_user = User(login_request.req_username, address);
      users.insert({std::string(login_request.req_username), &new_user});

      for (auto user : users) {
        std::cout << user.first << " " << user.second->name << std::endl;
      }

      std::cout << "server: " << login_request.req_username << " logs in" << std::endl;
      break;
    case REQ_LOGOUT:
      struct request_logout logout_request;
      memcpy(&logout_request, buffer, sizeof(struct request_logout));
//      std::cout << "server: " << username << " logs out" << std::endl;
      break;
    case REQ_JOIN:
      struct request_join join_request;
      memcpy(&join_request, buffer, sizeof(struct request_join));
//      std::cout << "server: " << username << " joins channel " << join_request.req_channel << std::endl;
      break;
    default:
      break;
  }

}

int main(int argc, char *argv[]) {
  struct sockaddr_in server_addr;

  int server_socket;
  int receive_len;
  void* buffer[kBufferSize];
  int port;

//  user = "";

  if (argc < 2) {
    std::cerr << "server: no port provided" << std::endl;
    exit(1);
  }

  port = atoi(argv[1]);

  memset((char *) &server_addr, 0, sizeof(server_addr));
  server_addr.sin_family = AF_INET;
  server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  server_addr.sin_port = htons(port);

  if ((server_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
    Error("server: can't open socket\n");
  }

  if (bind(server_socket, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) {
    Error("server: bind failed\n");
  }

  printf("server: waiting on port %d\n", port);
  while (1) {
    struct sockaddr_in client_addr;
    socklen_t client_addr_len = sizeof(client_addr);
//    std::cout << "before recvfrom" << std::endl;
    receive_len = recvfrom(server_socket, buffer, kBufferSize, 0, (struct sockaddr *) &client_addr, &client_addr_len);
    if (receive_len > 0) {
      buffer[receive_len] = 0;
      ProcessRequest(buffer, &client_addr);
    }
  }
}
<commit_msg>comment out cased, user to pointer again<commit_after>#include <stdlib.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <cstring>
#include <stdio.h>
#include <string>
#include <iostream>
#include <list>
#include <map>

#include "server.h"
#include "duckchat.h"

// TODO Server can accept connections.
// TODO Server handles Login and Logout from users, and keeps records of which users are logged in.
// TODO Server handles Join and Leave from users, keeps records of which channels a user belongs to,
// and keeps records of which users are in a channel.
// TODO Server handles the Say message.
// TODO Server correctly handles List and Who.
// TODO Create copies of your client and server source. Modify them to send invalid packets to your good client
// and server, to see if you can make your client or server crash. Fix any bugs you find.

//std::string user;

class Channel {
public:
  std::string name;
  std::list<User *> users;

  Channel(std::string name): name(name) {};
};

class User {
public:
  std::string name;
  struct sockaddr_in *address;
  std::list<Channel *> channels;

  User(std::string name, struct sockaddr_in *address): name(name), address(address) {};
};

std::map<std::string, User *> users;
std::map<std::string, Channel *> channels;

void Error(const char *msg) {
  perror(msg);
  exit(1);
}

void ProcessRequest(void *buffer, struct sockaddr_in *address) {
  struct request current_request;
  memcpy(&current_request, buffer, sizeof(struct request));
  std::cout << "request type: " << current_request.req_type << std::endl;
  request_t request_type = current_request.req_type;

  switch(request_type){
    case REQ_LOGIN:
      struct request_login login_request;
      memcpy(&login_request, buffer, sizeof(struct request_login));

      User *new_user = new User(login_request.req_username, address);
      users.insert({std::string(login_request.req_username), &new_user});

      for (auto user : users) {
        std::cout << user.first << " " << user.second->name << std::endl;
      }

      std::cout << "server: " << login_request.req_username << " logs in" << std::endl;
      break;
//    case REQ_LOGOUT:
//      struct request_logout logout_request;
//      memcpy(&logout_request, buffer, sizeof(struct request_logout));
////      std::cout << "server: " << username << " logs out" << std::endl;
//      break;
//    case REQ_JOIN:
//      struct request_join join_request;
//      memcpy(&join_request, buffer, sizeof(struct request_join));
////      std::cout << "server: " << username << " joins channel " << join_request.req_channel << std::endl;
//      break;
    default:
      break;
  }

}

int main(int argc, char *argv[]) {
  struct sockaddr_in server_addr;

  int server_socket;
  int receive_len;
  void* buffer[kBufferSize];
  int port;

//  user = "";

  if (argc < 2) {
    std::cerr << "server: no port provided" << std::endl;
    exit(1);
  }

  port = atoi(argv[1]);

  memset((char *) &server_addr, 0, sizeof(server_addr));
  server_addr.sin_family = AF_INET;
  server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  server_addr.sin_port = htons(port);

  if ((server_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
    Error("server: can't open socket\n");
  }

  if (bind(server_socket, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) {
    Error("server: bind failed\n");
  }

  printf("server: waiting on port %d\n", port);
  while (1) {
    struct sockaddr_in client_addr;
    socklen_t client_addr_len = sizeof(client_addr);
//    std::cout << "before recvfrom" << std::endl;
    receive_len = recvfrom(server_socket, buffer, kBufferSize, 0, (struct sockaddr *) &client_addr, &client_addr_len);
    if (receive_len > 0) {
      buffer[receive_len] = 0;
      ProcessRequest(buffer, &client_addr);
    }
  }
}
<|endoftext|>


<commit_before>#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/time.h>
#include <string.h>
#include <iostream>
#include <fstream>
#include <boost/lexical_cast.hpp>
#include "packet.h"

#define USAGE "Usage:\r\nc \r\n[tux machine number] \r\n[probability of packet corruption in int form] \r\n[probability of packet loss in int form] \r\n[probability of packet delay] \r\n[length of delay in ms] \r\n"
#define PORT 10038
#define PAKSIZE 129
#define ACK 0
#define NAK 1
#define BUFSIZE 122
#define FILENAME "Testfile"
#define TIMEOUT 100 //in ms
#define WIN_SIZE 16

using namespace std;

bool isvpack(unsigned char * p);
bool init(int argc, char** argv);
bool loadFile();
bool getFile();
bool sendFile();
bool isAck();
void handleAck();
void handleNak(int& x);
bool* gremlin(Packet * pack, int corruptProb, int lossProb, int delayProb);
Packet createPacket(int index);
void loadWindow();
bool sendPacket();
bool getGet();

struct sockaddr_in a;
struct sockaddr_in ca;
socklen_t calen;
int rlen;
int s;
bool ack;
string fstr;
char * file;
int probCorrupt;
int probLoss;
int probDelay;
int delayT;
Packet p;
Packet window[16];
int length;
bool dropPck;
bool delayPck;
int toms;
unsigned char b[BUFSIZE];
int base;

int main(int argc, char** argv) {

  if(!init(argc, argv)) return -1;

  sendFile();

  return 0;
}

bool init(int argc, char** argv){

  if(argc != 6) {
    cout << USAGE << endl;
    return false;
  }

  char * probCorruptStr = argv[2];
  probCorrupt = boost::lexical_cast<int>(probCorruptStr);
  char * probLossStr = argv[3];
  probLoss = boost::lexical_cast<int>(probLossStr);
  char * probDelayStr = argv[4];
  probDelay = boost::lexical_cast<int>(probDelayStr);
  char* delayTStr = argv[5];
  delayT = boost::lexical_cast<int>(delayTStr);

  struct timeval timeout;
  timeout.tv_usec = TIMEOUT * 1000;
  toms = TIMEOUT;

  /* Create our socket. */
  if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
    cout << "Socket creation failed. (socket s)" << endl;
    return 0;
  }

  setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));

  /*
   * Bind our socket to an IP (whatever the computer decides)
   * and a specified port.
   *
   */

  if (!loadFile()) {
    cout << "Loading file failed. (filename FILENAME)" << endl;
    return false;
  }

  memset((char *)&a, 0, sizeof(a));
  a.sin_family = AF_INET;
  a.sin_addr.s_addr = htonl(INADDR_ANY);
  a.sin_port = htons(PORT);

  if (bind(s, (struct sockaddr *)&a, sizeof(a)) < 0) {
    cout << "Socket binding failed. (socket s, address a)" << endl;
    return 0;
  }

  fstr = string(file);
  cout << "File: " << endl << fstr << endl;

  base = 0;
  dropPck = false;
  calen = sizeof(ca);

  getGet();

  return true;
}

bool getGet(){
	unsigned char packet[PAKSIZE + 1];
	rlen = recvfrom(s, packet, PAKSIZE, 0, (struct sockaddr *)&ca, &calen);
	return (rlen > 0) ? true : false;
}

bool isvpack(unsigned char * p) {
  cout << endl << "=== IS VALID PACKET TESTING" << endl;

  char * sns = new char[2];
  memcpy(sns, &p[0], 1);
  sns[1] = '\0';

  char * css = new char[7];
  memcpy(css, &p[1], 6);
  css[6] = '\0';

  char * db = new char[121 + 1];
  memcpy(db, &p[2], 121);
  db[121] = '\0';

  cout << "Seq. num: " << sns << endl;
  cout << "Checksum: " << css << endl;
  cout << "Message: " << db << endl;

  int sn = boost::lexical_cast<int>(sns);
  int cs = boost::lexical_cast<int>(css);

  Packet pk (0, db);
  pk.setSequenceNum(sn);

  // change to validate based on checksum and sequence number

  if(sn == 0) return false; //doesn't matter, only for the old version (netwark)
  if(cs != pk.generateCheckSum()) return false;
  return true;
}

bool getFile(){

  /* Loop forever, waiting for messages from a client. */
  cout << "Waiting on port " << PORT << "..." << endl;

  ofstream file("Dumpfile");

  for (;;) {
    unsigned char packet[PAKSIZE + 1];
    unsigned char dataPull[PAKSIZE - 7 + 1];
    rlen = recvfrom(s, packet, PAKSIZE, 0, (struct sockaddr *)&ca, &calen);

    for(int x = 0; x < PAKSIZE - 7; x++) {
      dataPull[x] = packet[x + 7];
    }
    dataPull[PAKSIZE - 7] = '\0';
    packet[PAKSIZE] = '\0';
    if (rlen > 0) {
      char * css = new char[6];
      memcpy(css, &packet[1], 5);
      css[5] = '\0';
      cout << endl << endl << "=== RECEIPT" << endl;
      cout << "Seq. num: " << packet[0] << endl;
      cout << "Checksum: " << css << endl;
      cout << "Received message: " << dataPull << endl;
      cout << "Sent response: ";
      if(isvpack(packet)) {
        ack = ACK;
        //seqNum = (seqNum) ? false : true;
        file << dataPull;
      } else {
        ack = NAK;
      }
      cout << ((ack == ACK) ? "ACK" : "NAK") << endl;
      Packet p (false, reinterpret_cast<const char *>(dataPull));
      p.setCheckSum(boost::lexical_cast<int>(css));
      p.setAckNack(ack);

      if(sendto(s, p.str(), PAKSIZE, 0, (struct sockaddr *)&ca, calen) < 0) {
        cout << "Acknowledgement failed. (socket s, acknowledgement message ack, client address ca, client address length calen)" << endl;
        return 0;
      }
      delete css;
    }
  }
  file.close();
  return true;
}

bool loadFile() {

  ifstream is (FILENAME, ifstream::binary);

  if(is) {
    is.seekg(0, is.end);
    length = is.tellg();
    is.seekg(0, is.beg);

    file = new char[length];

    cout << "Reading " << length << " characters..." << endl;
    is.read(file, length);

    if(!is) { cout << "File reading failed. (filename " << FILENAME << "). Only " << is.gcount() << " could be read."; return false; }
    is.close();
  }
  return true;
}

void loadWindow(){
	for(int i = base; i < base + WIN_SIZE; i++) {
		window[i-base] = createPacket(i);
		if(strlen(window[i-base].getDataBuffer()) < BUFSIZE) {
			break;
		}
	}
}

bool sendFile() {
	/*Currently causes the program to only send the first 16 packets of file out
		requires additional code later to sendFile again with updated window*/
	base = 0;
	while(base * BUFSIZE < length) {
		loadWindow();

		for(int x = 0; x < WIN_SIZE; x++) {
			p = window[x];
			if(!sendPacket()) continue;
		}
		for(int x = 0; x < WIN_SIZE; x++) {
			if(recvfrom(s, b, BUFSIZE + 7, 0, (struct sockaddr *)&ca, &calen) < 0) {
				cout << "=== ACK TIMEOUT" << endl;
				x--;
				continue;
			}

			if(isAck()) {
				handleAck();
			} else {
				handleAck();
				//handleNak(x);
			}

			memset(b, 0, BUFSIZE);
		}
	}
	return true;
}

Packet createPacket(int index){
    cout << endl;
	cout << "=== PACKET CREATION TESTING" << endl;
	cout << "index: " << index << endl;
	cout << "BUFSIZE: " << BUFSIZE << endl;
	cout << "file index (index * BUFSIZE): " << index * BUFSIZE << endl;
	cout << "file length: " << length << endl;

    string mstr = fstr.substr(index * BUFSIZE, BUFSIZE);
	if(mstr.length() < BUFSIZE) {
      mstr[length - (index * BUFSIZE)] = '\0';
    }
    return Packet (index, mstr.c_str());
}

bool sendPacket(){
	cout << endl;
    cout << "=== TRANSMISSION START" << endl;
    int pc = probCorrupt; int pl = probLoss; int pd = probDelay;
	bool* pckStatus = gremlin(&p, pc, pl, pd);

	dropPck = pckStatus[0];
	delayPck = pckStatus[1];

	if (dropPck == true) return false;
	if (delayPck == true) p.setAckNack(1);

    if(sendto(s, p.str(), BUFSIZE + 7, 0, (struct sockaddr *)&ca, sizeof(ca)) < 0) {
		cout << "Package sending failed. (socket s, server address sa, message m)" << endl;
		return false;
    }
    return true;
}
bool isAck() {
    cout << endl << "=== SERVER RESPONSE TEST" << endl;
    cout << "Data: " << b << endl;
    if(b[6] == '0') return true;
    else return false;
}
void handleAck() {
	int ack = boost::lexical_cast<int>(b);
	if(base < ack) base = ack;
	cout << "Window base: " << base << endl;
}
void handleNak(int& x) {

      char * sns = new char[2];
      memcpy(sns, &b[0], 1);
      sns[1] = '\0';

      char * css = new char[5];
      memcpy(css, &b[1], 5);

      char * db = new char[BUFSIZE + 1];
      memcpy(db, &b[2], BUFSIZE);
      db[BUFSIZE] = '\0';

      cout << "Sequence number: " << sns << endl;
      cout << "Checksum: " << css << endl;

      Packet pk (0, db);
      pk.setSequenceNum(boost::lexical_cast<int>(sns));
      pk.setCheckSum(boost::lexical_cast<int>(css));

      if(!pk.chksm()) x--;
      else x = (x - 2 > 0) ? x - 2 : 0;
}
bool* gremlin(Packet * pack, int corruptProb, int lossProb, int delayProb){

  bool* packStatus = new bool[2];
  int r = rand() % 100;

  cout << "Corruption probability: " << corruptProb << endl;
  cout << "Random number: " << r << endl;

  packStatus[0] = false;
  packStatus[1] = false;

  if(r <= (lossProb)){
	packStatus[0] = true;
    cout << "Dropped!" << endl;
  }
  else if(r <= (delayProb)){
	  packStatus[1] = true;
	  cout << "Delayed!" << endl;
  }
  else if(r <= (corruptProb)){
    cout << "Corrupted!" << endl;
    pack->loadDataBuffer((char*)"GREMLIN LOL");
  }
  cout << "Seq. num: " << pack->getSequenceNum() << endl;
  cout << "Checksum: " << pack->getCheckSum() << endl;
  cout << "Message: "  << pack->getDataBuffer() << endl;

  return packStatus;
}<commit_msg>Test packet creation aversion<commit_after>#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/time.h>
#include <string.h>
#include <iostream>
#include <fstream>
#include <boost/lexical_cast.hpp>
#include "packet.h"

#define USAGE "Usage:\r\nc \r\n[tux machine number] \r\n[probability of packet corruption in int form] \r\n[probability of packet loss in int form] \r\n[probability of packet delay] \r\n[length of delay in ms] \r\n"
#define PORT 10038
#define PAKSIZE 129
#define ACK 0
#define NAK 1
#define BUFSIZE 122
#define FILENAME "Testfile"
#define TIMEOUT 100 //in ms
#define WIN_SIZE 16

using namespace std;

bool isvpack(unsigned char * p);
bool init(int argc, char** argv);
bool loadFile();
bool getFile();
bool sendFile();
bool isAck();
void handleAck();
void handleNak(int& x);
bool* gremlin(Packet * pack, int corruptProb, int lossProb, int delayProb);
Packet createPacket(int index);
void loadWindow();
bool sendPacket();
bool getGet();

struct sockaddr_in a;
struct sockaddr_in ca;
socklen_t calen;
int rlen;
int s;
bool ack;
string fstr;
char * file;
int probCorrupt;
int probLoss;
int probDelay;
int delayT;
Packet p;
Packet window[16];
int length;
bool dropPck;
bool delayPck;
int toms;
unsigned char b[BUFSIZE];
int base;

int main(int argc, char** argv) {

  if(!init(argc, argv)) return -1;

  sendFile();

  return 0;
}

bool init(int argc, char** argv){

  if(argc != 6) {
    cout << USAGE << endl;
    return false;
  }

  char * probCorruptStr = argv[2];
  probCorrupt = boost::lexical_cast<int>(probCorruptStr);
  char * probLossStr = argv[3];
  probLoss = boost::lexical_cast<int>(probLossStr);
  char * probDelayStr = argv[4];
  probDelay = boost::lexical_cast<int>(probDelayStr);
  char* delayTStr = argv[5];
  delayT = boost::lexical_cast<int>(delayTStr);

  struct timeval timeout;
  timeout.tv_usec = TIMEOUT * 1000;
  toms = TIMEOUT;

  /* Create our socket. */
  if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
    cout << "Socket creation failed. (socket s)" << endl;
    return 0;
  }

  setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));

  /*
   * Bind our socket to an IP (whatever the computer decides)
   * and a specified port.
   *
   */

  if (!loadFile()) {
    cout << "Loading file failed. (filename FILENAME)" << endl;
    return false;
  }

  memset((char *)&a, 0, sizeof(a));
  a.sin_family = AF_INET;
  a.sin_addr.s_addr = htonl(INADDR_ANY);
  a.sin_port = htons(PORT);

  if (bind(s, (struct sockaddr *)&a, sizeof(a)) < 0) {
    cout << "Socket binding failed. (socket s, address a)" << endl;
    return 0;
  }

  fstr = string(file);
  cout << "File: " << endl << fstr << endl;

  base = 0;
  dropPck = false;
  calen = sizeof(ca);

  getGet();

  return true;
}

bool getGet(){
	unsigned char packet[PAKSIZE + 1];
	rlen = recvfrom(s, packet, PAKSIZE, 0, (struct sockaddr *)&ca, &calen);
	return (rlen > 0) ? true : false;
}

bool isvpack(unsigned char * p) {
  cout << endl << "=== IS VALID PACKET TESTING" << endl;

  char * sns = new char[2];
  memcpy(sns, &p[0], 1);
  sns[1] = '\0';

  char * css = new char[7];
  memcpy(css, &p[1], 6);
  css[6] = '\0';

  char * db = new char[121 + 1];
  memcpy(db, &p[2], 121);
  db[121] = '\0';

  cout << "Seq. num: " << sns << endl;
  cout << "Checksum: " << css << endl;
  cout << "Message: " << db << endl;

  int sn = boost::lexical_cast<int>(sns);
  int cs = boost::lexical_cast<int>(css);

  Packet pk (0, db);
  pk.setSequenceNum(sn);

  // change to validate based on checksum and sequence number

  if(sn == 0) return false; //doesn't matter, only for the old version (netwark)
  if(cs != pk.generateCheckSum()) return false;
  return true;
}

bool getFile(){

  /* Loop forever, waiting for messages from a client. */
  cout << "Waiting on port " << PORT << "..." << endl;

  ofstream file("Dumpfile");

  for (;;) {
    unsigned char packet[PAKSIZE + 1];
    unsigned char dataPull[PAKSIZE - 7 + 1];
    rlen = recvfrom(s, packet, PAKSIZE, 0, (struct sockaddr *)&ca, &calen);

    for(int x = 0; x < PAKSIZE - 7; x++) {
      dataPull[x] = packet[x + 7];
    }
    dataPull[PAKSIZE - 7] = '\0';
    packet[PAKSIZE] = '\0';
    if (rlen > 0) {
      char * css = new char[6];
      memcpy(css, &packet[1], 5);
      css[5] = '\0';
      cout << endl << endl << "=== RECEIPT" << endl;
      cout << "Seq. num: " << packet[0] << endl;
      cout << "Checksum: " << css << endl;
      cout << "Received message: " << dataPull << endl;
      cout << "Sent response: ";
      if(isvpack(packet)) {
        ack = ACK;
        //seqNum = (seqNum) ? false : true;
        file << dataPull;
      } else {
        ack = NAK;
      }
      cout << ((ack == ACK) ? "ACK" : "NAK") << endl;
      Packet p (false, reinterpret_cast<const char *>(dataPull));
      p.setCheckSum(boost::lexical_cast<int>(css));
      p.setAckNack(ack);

      if(sendto(s, p.str(), PAKSIZE, 0, (struct sockaddr *)&ca, calen) < 0) {
        cout << "Acknowledgement failed. (socket s, acknowledgement message ack, client address ca, client address length calen)" << endl;
        return 0;
      }
      delete css;
    }
  }
  file.close();
  return true;
}

bool loadFile() {

  ifstream is (FILENAME, ifstream::binary);

  if(is) {
    is.seekg(0, is.end);
    length = is.tellg();
    is.seekg(0, is.beg);

    file = new char[length];

    cout << "Reading " << length << " characters..." << endl;
    is.read(file, length);

    if(!is) { cout << "File reading failed. (filename " << FILENAME << "). Only " << is.gcount() << " could be read."; return false; }
    is.close();
  }
  return true;
}

void loadWindow(){
	for(int i = base; i < base + WIN_SIZE; i++) {
		window[i-base] = createPacket(i);
		if(strlen(window[i-base].getDataBuffer()) < BUFSIZE) {
			cout << "strlen: " << strlen(window[i-base].getDataBuffer()) << endl;
			cout << "BUFSIZE: " << BUFSIZE << endl;
			break;
		}
	}
}

bool sendFile() {
	/*Currently causes the program to only send the first 16 packets of file out
		requires additional code later to sendFile again with updated window*/
	base = 0;
	while(base * BUFSIZE < length) {
		loadWindow();

		for(int x = 0; x < WIN_SIZE; x++) {
			p = window[x];
			if(!sendPacket()) continue;
		}
		for(int x = 0; x < WIN_SIZE; x++) {
			if(recvfrom(s, b, BUFSIZE + 7, 0, (struct sockaddr *)&ca, &calen) < 0) {
				cout << "=== ACK TIMEOUT" << endl;
				x--;
				continue;
			}

			if(isAck()) {
				handleAck();
			} else {
				handleAck();
				//handleNak(x);
			}

			memset(b, 0, BUFSIZE);
		}
	}
	return true;
}

Packet createPacket(int index){
    cout << endl;
	cout << "=== PACKET CREATION TESTING" << endl;
	cout << "index: " << index << endl;
	cout << "BUFSIZE: " << BUFSIZE << endl;
	cout << "file index (index * BUFSIZE): " << index * BUFSIZE << endl;
	cout << "file length: " << length << endl;

    string mstr = fstr.substr(index * BUFSIZE, BUFSIZE);
	if(mstr.length() < BUFSIZE) {
      mstr[length - (index * BUFSIZE)] = '\0';
    }
    return Packet (index, mstr.c_str());
}

bool sendPacket(){
	cout << endl;
    cout << "=== TRANSMISSION START" << endl;
    int pc = probCorrupt; int pl = probLoss; int pd = probDelay;
	bool* pckStatus = gremlin(&p, pc, pl, pd);

	dropPck = pckStatus[0];
	delayPck = pckStatus[1];

	if (dropPck == true) return false;
	if (delayPck == true) p.setAckNack(1);

    if(sendto(s, p.str(), BUFSIZE + 7, 0, (struct sockaddr *)&ca, sizeof(ca)) < 0) {
		cout << "Package sending failed. (socket s, server address sa, message m)" << endl;
		return false;
    }
    return true;
}
bool isAck() {
    cout << endl << "=== SERVER RESPONSE TEST" << endl;
    cout << "Data: " << b << endl;
    if(b[6] == '0') return true;
    else return false;
}
void handleAck() {
	int ack = boost::lexical_cast<int>(b);
	if(base < ack) base = ack;
	cout << "Window base: " << base << endl;
}
void handleNak(int& x) {

      char * sns = new char[2];
      memcpy(sns, &b[0], 1);
      sns[1] = '\0';

      char * css = new char[5];
      memcpy(css, &b[1], 5);

      char * db = new char[BUFSIZE + 1];
      memcpy(db, &b[2], BUFSIZE);
      db[BUFSIZE] = '\0';

      cout << "Sequence number: " << sns << endl;
      cout << "Checksum: " << css << endl;

      Packet pk (0, db);
      pk.setSequenceNum(boost::lexical_cast<int>(sns));
      pk.setCheckSum(boost::lexical_cast<int>(css));

      if(!pk.chksm()) x--;
      else x = (x - 2 > 0) ? x - 2 : 0;
}
bool* gremlin(Packet * pack, int corruptProb, int lossProb, int delayProb){

  bool* packStatus = new bool[2];
  int r = rand() % 100;

  cout << "Corruption probability: " << corruptProb << endl;
  cout << "Random number: " << r << endl;

  packStatus[0] = false;
  packStatus[1] = false;

  if(r <= (lossProb)){
	packStatus[0] = true;
    cout << "Dropped!" << endl;
  }
  else if(r <= (delayProb)){
	  packStatus[1] = true;
	  cout << "Delayed!" << endl;
  }
  else if(r <= (corruptProb)){
    cout << "Corrupted!" << endl;
    pack->loadDataBuffer((char*)"GREMLIN LOL");
  }
  cout << "Seq. num: " << pack->getSequenceNum() << endl;
  cout << "Checksum: " << pack->getCheckSum() << endl;
  cout << "Message: "  << pack->getDataBuffer() << endl;

  return packStatus;
}<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

//! [0]
QByteArray encodedString = "...";
QTextCodec *codec = QTextCodec::codecForName("KOI8-R");
QString string = codec->toUnicode(encodedString);
//! [0]

//! [1]
QString string = "...";
QTextCodec *codec = QTextCodec::codecForName("KOI8-R");
QByteArray encodedString = codec->fromUnicode(string);
//! [1]

//! [2]
QTextCodec *codec = QTextCodec::codecForName("Shift-JIS");
QTextDecoder *decoder = codec->makeDecoder();

QString string;
while (new_data_available()) {
    QByteArray chunk = get_new_data();
    string += decoder->toUnicode(chunk);
}
//! [2]

//! [3]
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    QTextCodec::setCodecForTr(QTextCodec::codecForName("eucKR"));
    ...
}
//! [3]
<commit_msg>Doc: the QTextDecoder need to be destroyed, reflect that in the example<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

//! [0]
QByteArray encodedString = "...";
QTextCodec *codec = QTextCodec::codecForName("KOI8-R");
QString string = codec->toUnicode(encodedString);
//! [0]

//! [1]
QString string = "...";
QTextCodec *codec = QTextCodec::codecForName("KOI8-R");
QByteArray encodedString = codec->fromUnicode(string);
//! [1]

//! [2]
QTextCodec *codec = QTextCodec::codecForName("Shift-JIS");
QTextDecoder *decoder = codec->makeDecoder();

QString string;
while (new_data_available()) {
    QByteArray chunk = get_new_data();
    string += decoder->toUnicode(chunk);
}
delete decoder;
//! [2]

//! [3]
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    QTextCodec::setCodecForTr(QTextCodec::codecForName("eucKR"));
    ...
}
//! [3]
<|endoftext|>


<commit_before>#include <IO.h>

#include <ValueType.h>
#include <UnitType.h>
#include <ScaleType.h>
#include <AttributeType.h>
#include <EventType.h>
#include <FormatID.h>
#include <MetaValueElement.h>

using std::ostream;
using std::endl;

ostream& operator<<(ostream& o, const ValueType& t) {
  return o << (t.hasUncertainty()?"uncertain ":"") << id::type::name(t.typeId()) << "[" << t.n() << "]";
}

ostream& operator<<(ostream& o, const ScaleType& t) {
  if(t.num()==1 && t.denom()==1)
    return o;
  if(t.denom()!=1)
    return o << t.num() << "/" << t.denom() << " ";
  else
    return o << t.num() << " ";
}

ostream& operator<<(ostream& o, const UnitType& t) {
  unsigned int i=0;
  for(const auto& v : t)
    switch(v){
      case(0): i++;
               continue;
      case(1): o << id::unit::shortName(i++);
               continue;
      default: o << id::unit::shortName(i++) << "^" << v;
               continue;
    }
  return o;
}

ostream& operator<<(ostream& o, const AttributeType& t) {
  return o << id::attribute::name(t.attributeId()) << ": " << t.value() << " " << t.scale() << t.unit();
}

ostream& operator<<(ostream& o, const EventType& t) {
  o << "EventType: " << endl;
  for(const auto& aT : t)
    o << "\t" << aT << endl;
  return o;
}

ostream& operator<<(ostream& o, const FormatID& id) {
  return o << id.node() << ":" << (id.direction()==FormatID::Direction::publisher?"P":"S") << id.nr();
}

ostream& operator<<(ostream& o, const MetaValueElement& mve) {
  o << "(" << id::type::name(mve.id()) << ")";
  switch(mve.id()){
    case(id::type::UInt8::value()):
    case(id::type::UInt16::value()):
    case(id::type::UInt32::value()):
    case(id::type::UInt64::value()): o << mve._uint;
                                     break;

    case(id::type::Int8::value())  :
    case(id::type::Int16::value()) :
    case(id::type::Int32::value()) :
    case(id::type::Int64::value()) : o << mve._int;
                                     break;

    case(id::type::Float::value()) : o << mve._float;
                                     break;

    case(id::type::Double::value()): o << mve._double;
                                     break;
  }
  return o;
}
<commit_msg>Changed FormatID String conversion for ROS<commit_after>#include <IO.h>

#include <ValueType.h>
#include <UnitType.h>
#include <ScaleType.h>
#include <AttributeType.h>
#include <EventType.h>
#include <FormatID.h>
#include <MetaValueElement.h>

using std::ostream;
using std::endl;

ostream& operator<<(ostream& o, const ValueType& t) {
  return o << (t.hasUncertainty()?"uncertain ":"") << id::type::name(t.typeId()) << "[" << t.n() << "]";
}

ostream& operator<<(ostream& o, const ScaleType& t) {
  if(t.num()==1 && t.denom()==1)
    return o;
  if(t.denom()!=1)
    return o << t.num() << "/" << t.denom() << " ";
  else
    return o << t.num() << " ";
}

ostream& operator<<(ostream& o, const UnitType& t) {
  unsigned int i=0;
  for(const auto& v : t)
    switch(v){
      case(0): i++;
               continue;
      case(1): o << id::unit::shortName(i++);
               continue;
      default: o << id::unit::shortName(i++) << "^" << v;
               continue;
    }
  return o;
}

ostream& operator<<(ostream& o, const AttributeType& t) {
  return o << id::attribute::name(t.attributeId()) << ": " << t.value() << " " << t.scale() << t.unit();
}

ostream& operator<<(ostream& o, const EventType& t) {
  o << "EventType: " << endl;
  for(const auto& aT : t)
    o << "\t" << aT << endl;
  return o;
}

ostream& operator<<(ostream& o, const FormatID& id) {
  return o << id.node() << (id.direction()==FormatID::Direction::publisher?"P":"S") << id.nr();
}

ostream& operator<<(ostream& o, const MetaValueElement& mve) {
  o << "(" << id::type::name(mve.id()) << ")";
  switch(mve.id()){
    case(id::type::UInt8::value()):
    case(id::type::UInt16::value()):
    case(id::type::UInt32::value()):
    case(id::type::UInt64::value()): o << mve._uint;
                                     break;

    case(id::type::Int8::value())  :
    case(id::type::Int16::value()) :
    case(id::type::Int32::value()) :
    case(id::type::Int64::value()) : o << mve._int;
                                     break;

    case(id::type::Float::value()) : o << mve._float;
                                     break;

    case(id::type::Double::value()): o << mve._double;
                                     break;
  }
  return o;
}
<|endoftext|>


<commit_before>///
/// @file  Li.cpp
/// @brief Logarithmic integral and Riemann R functions
///
/// Copyright (C) 2017 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primecount-internal.hpp>
#include <generate.hpp>
#include <int128_t.hpp>

#include <stdint.h>
#include <algorithm>
#include <cassert>
#include <cmath>
#include <limits>

using namespace std;

namespace primecount {

/// Calculate the logarithmic integral using
/// Ramanujan's formula:
/// https://en.wikipedia.org/wiki/Logarithmic_integral_function#Series_representation
///
long double li(long double x)
{
  assert(x >= 2);

  long double gamma = 0.57721566490153286061;
  long double sum = 0;
  long double inner_sum = 0;
  long double factorial = 1;
  long double p = -1;
  long double q = 0;
  long double power2 = 1;
  long double term;
  int k = 0;

  for (int n = 1; n < 200; n++)
  {
    p *= -log(x);
    factorial *= n;
    q = factorial * power2;
    power2 *= 2;
    for (; k <= (n - 1) / 2; k++)
      inner_sum += 1.0L / (2 * k + 1);
    term = (p / q) * inner_sum;
    sum += term;
    if (abs(term) < numeric_limits<double>::epsilon())
      break;
  }

  return gamma + log(log(x)) + sqrt(x) * sum;
}

/// Calculate the offset logarithmic integral which is a very
/// accurate approximation of the number of primes <= x.
/// Li(x) > pi(x) for 24 <= x <= ~ 10^316
///
long double Li(long double x)
{
  if (x < 2)
    return 0;

  long double li2 = 1.04516378011749278484;

  return li(x) - li2;
}

/// Calculate the inverse offset logarithmic integral which
/// is a very accurate approximation of the nth prime.
/// Li^-1(x) < nth_prime(x) for 7 <= x <= 10^316
///
long double Li_inverse(long double x)
{
  if (x < 2)
    return 0;

  long double t = x * log(x);
  long double old_term = numeric_limits<long double>::infinity();

  for (int i = 0; i < 100; i++)
  {
    long double term = (Li(t) - x) * log(t);
    t -= term;
    // not converging anymore
    if (abs(term) >= abs(old_term))
      break;
    old_term = term;
  }

  return t;
}

/// Calculate the Riemann R function which is a very accurate
/// approximation of the number of primes below x.
///
long double Ri(long double x)
{
  if (x < 2)
    return 0;

  int terms = 200;
  auto mu = generate_moebius(terms);
  long double sum = 0;
  long double root;
  long double term;

  for (int n = 1; n < terms; n++)
  {
    if (mu[n])
    {
      root = pow(x, 1.0L / n);
      term = (Li(root) * mu[n]) / n;
      sum += term;
      if (abs(term) < numeric_limits<double>::epsilon())
        break;
    }
  }

  return sum;
}

/// Calculate the inverse Riemann R function which is a very
/// accurate approximation of the nth prime.
///
long double Ri_inverse(long double x)
{
  if (x < 2)
    return 0;

  long double t = Li_inverse(x);
  long double old_term = numeric_limits<long double>::infinity();

  for (int i = 0; i < 100; i++)
  {
    long double term = (Ri(t) - x) * log(t);
    t -= term;
    // not converging anymore
    if (abs(term) >= abs(old_term))
      break;
    old_term = term;
  }

  return t;
}

int64_t Li(int64_t x)
{
  return (int64_t) Li((long double) x);
}

int64_t Li_inverse(int64_t x)
{
  return (int64_t) Li_inverse((long double) x);
}

#ifdef HAVE_INT128_T

int128_t Li(int128_t x)
{
  return (int128_t) Li((long double) x);
}

int128_t Li_inverse(int128_t x)
{
  return (int128_t) Li_inverse((long double) x);
}

#endif

int64_t Ri(int64_t x)
{
  return (int64_t) Ri((long double) x);
}

int64_t Ri_inverse(int64_t x)
{
  return (int64_t) Ri_inverse((long double) x);
}

#ifdef HAVE_INT128_T

int128_t Ri(int128_t x)
{
  return (int128_t) Ri((long double) x);
}

int128_t Ri_inverse(int128_t x)
{
  return (int128_t) Ri_inverse((long double) x);
}

#endif

} // namespace
<commit_msg>Remove unused header<commit_after>///
/// @file  Li.cpp
/// @brief Logarithmic integral and Riemann R functions
///
/// Copyright (C) 2018 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primecount-internal.hpp>
#include <generate.hpp>
#include <int128_t.hpp>

#include <stdint.h>
#include <cassert>
#include <cmath>
#include <limits>

using namespace std;

namespace primecount {

/// Calculate the logarithmic integral using
/// Ramanujan's formula:
/// https://en.wikipedia.org/wiki/Logarithmic_integral_function#Series_representation
///
long double li(long double x)
{
  assert(x >= 2);

  long double gamma = 0.57721566490153286061;
  long double sum = 0;
  long double inner_sum = 0;
  long double factorial = 1;
  long double p = -1;
  long double q = 0;
  long double power2 = 1;
  long double term;
  int k = 0;

  for (int n = 1; n < 200; n++)
  {
    p *= -log(x);
    factorial *= n;
    q = factorial * power2;
    power2 *= 2;
    for (; k <= (n - 1) / 2; k++)
      inner_sum += 1.0L / (2 * k + 1);
    term = (p / q) * inner_sum;
    sum += term;
    if (abs(term) < numeric_limits<double>::epsilon())
      break;
  }

  return gamma + log(log(x)) + sqrt(x) * sum;
}

/// Calculate the offset logarithmic integral which is a very
/// accurate approximation of the number of primes <= x.
/// Li(x) > pi(x) for 24 <= x <= ~ 10^316
///
long double Li(long double x)
{
  if (x < 2)
    return 0;

  long double li2 = 1.04516378011749278484;

  return li(x) - li2;
}

/// Calculate the inverse offset logarithmic integral which
/// is a very accurate approximation of the nth prime.
/// Li^-1(x) < nth_prime(x) for 7 <= x <= 10^316
///
long double Li_inverse(long double x)
{
  if (x < 2)
    return 0;

  long double t = x * log(x);
  long double old_term = numeric_limits<long double>::infinity();

  for (int i = 0; i < 100; i++)
  {
    long double term = (Li(t) - x) * log(t);
    t -= term;
    // not converging anymore
    if (abs(term) >= abs(old_term))
      break;
    old_term = term;
  }

  return t;
}

/// Calculate the Riemann R function which is a very accurate
/// approximation of the number of primes below x.
///
long double Ri(long double x)
{
  if (x < 2)
    return 0;

  int terms = 200;
  auto mu = generate_moebius(terms);
  long double sum = 0;
  long double root;
  long double term;

  for (int n = 1; n < terms; n++)
  {
    if (mu[n])
    {
      root = pow(x, 1.0L / n);
      term = (Li(root) * mu[n]) / n;
      sum += term;
      if (abs(term) < numeric_limits<double>::epsilon())
        break;
    }
  }

  return sum;
}

/// Calculate the inverse Riemann R function which is a very
/// accurate approximation of the nth prime.
///
long double Ri_inverse(long double x)
{
  if (x < 2)
    return 0;

  long double t = Li_inverse(x);
  long double old_term = numeric_limits<long double>::infinity();

  for (int i = 0; i < 100; i++)
  {
    long double term = (Ri(t) - x) * log(t);
    t -= term;
    // not converging anymore
    if (abs(term) >= abs(old_term))
      break;
    old_term = term;
  }

  return t;
}

int64_t Li(int64_t x)
{
  return (int64_t) Li((long double) x);
}

int64_t Li_inverse(int64_t x)
{
  return (int64_t) Li_inverse((long double) x);
}

#ifdef HAVE_INT128_T

int128_t Li(int128_t x)
{
  return (int128_t) Li((long double) x);
}

int128_t Li_inverse(int128_t x)
{
  return (int128_t) Li_inverse((long double) x);
}

#endif

int64_t Ri(int64_t x)
{
  return (int64_t) Ri((long double) x);
}

int64_t Ri_inverse(int64_t x)
{
  return (int64_t) Ri_inverse((long double) x);
}

#ifdef HAVE_INT128_T

int128_t Ri(int128_t x)
{
  return (int128_t) Ri((long double) x);
}

int128_t Ri_inverse(int128_t x)
{
  return (int128_t) Ri_inverse((long double) x);
}

#endif

} // namespace
<|endoftext|>