<commit_before>#include <v8.h>
#include <node.h>
#include <node_events.h>
#include <zmq.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

using namespace v8;
using namespace node;

namespace zmq {

static Persistent<Integer> p2p_symbol;

class Context : public EventEmitter {
public:
    static void
    Initialize (v8::Handle<v8::Object> target) {
        HandleScope scope;

        Local<FunctionTemplate> t = FunctionTemplate::New(New);

        t->Inherit(EventEmitter::constructor_template);
        t->InstanceTemplate()->SetInternalFieldCount(1);

        NODE_SET_PROTOTYPE_METHOD(t, "close", Close);

        target->Set(String::NewSymbol("Context"), t->GetFunction());
    }

    void * getCContext() {
        return context_;
    }

    void Close(Local<Value> exception = Local<Value>()) {
        zmq_term(context_);
        context_ = NULL;
        Unref();
    }

protected:
    static Handle<Value>
    New (const Arguments& args) {
        HandleScope scope;

        Context *context = new Context();
        context->Wrap(args.This());

        return args.This();
    }

    static Handle<Value>
    Close (const Arguments& args) {
        zmq::Context *context = ObjectWrap::Unwrap<Context>(args.This());
        HandleScope scope;
        context->Close();
        return Undefined();
    }

    Context () : EventEmitter () {
        context_ = zmq_init(1, 1, ZMQ_POLL);
    }

    ~Context () {
        assert(context_ == NULL);
    }

private:
    void * context_;
};

class Socket : public EventEmitter {
public:
    static void
    Initialize (v8::Handle<v8::Object> target) {
        HandleScope scope;

        Local<FunctionTemplate> t = FunctionTemplate::New(New);

        t->Inherit(EventEmitter::constructor_template);
        t->InstanceTemplate()->SetInternalFieldCount(1);

        NODE_DEFINE_CONSTANT(t, ZMQ_P2P);
        NODE_DEFINE_CONSTANT(t, ZMQ_PUB);
        NODE_DEFINE_CONSTANT(t, ZMQ_SUB);
        NODE_DEFINE_CONSTANT(t, ZMQ_REQ);
        NODE_DEFINE_CONSTANT(t, ZMQ_REP);
        NODE_DEFINE_CONSTANT(t, ZMQ_UPSTREAM);
        NODE_DEFINE_CONSTANT(t, ZMQ_DOWNSTREAM);

        NODE_SET_PROTOTYPE_METHOD(t, "bind", Bind);
        NODE_SET_PROTOTYPE_METHOD(t, "connect", Connect);
        NODE_SET_PROTOTYPE_METHOD(t, "close", Close);

        target->Set(String::NewSymbol("Socket"), t->GetFunction());
    }

    bool Bind(const char *address) {
        return zmq_bind(socket_, address) == 0;
    }

    bool Connect(const char *address) {
        return zmq_connect(socket_, address) == 0;
    }

    void Close(Local<Value> exception = Local<Value>()) {
        zmq_close(socket_);
        socket_ = NULL;
        Unref();
    }

    char * ErrorMessage() {
        return strerror(errno);
    }

protected:
    static Handle<Value>
    New (const Arguments &args) {
        HandleScope scope;
        if (args.Length() != 2) {
            return ThrowException(Exception::Error(
                String::New("Must pass a context and a type to constructor")));
        }
        Context *context = ObjectWrap::Unwrap<Context>(args[0]->ToObject());
        if (!args[1]->IsNumber()) {
            return ThrowException(Exception::TypeError(
                String::New("Type must be an integer")));
        }
        int type = (int) args[1]->ToInteger()->Value();

        Socket *socket = new Socket(context, type);
        socket->Wrap(args.This());

        return args.This();
    }

    static Handle<Value>
    Connect (const Arguments &args) {
        Socket *socket = getSocket(args);
        HandleScope scope;
        if (!args[0]->IsString()) {
            return ThrowException(Exception::TypeError(
                String::New("Address must be a string!")));
        }

        String::Utf8Value address(args[0]->ToString());
        if (!socket->Connect(*address)) {
            return ThrowException(Exception::Error(
                String::New(socket->ErrorMessage())));
        }
        return Undefined();
    }

    static Handle<Value>
    Bind (const Arguments &args) {
        Socket *socket = getSocket(args);
        HandleScope scope;
        if (!args[0]->IsString()) {
            return ThrowException(Exception::TypeError(
                String::New("Address must be a string!")));
        }

        String::Utf8Value address(args[0]->ToString());
        if (!socket->Bind(*address)) {
            return ThrowException(Exception::Error(
                String::New(socket->ErrorMessage())));
        }
        return Undefined();
    }

    static Handle<Value>
    Close (const Arguments &args) {
        Socket *socket = getSocket(args);
        HandleScope scope;
        socket->Close();
        return Undefined();
    }

    Socket (Context *context, int type) : EventEmitter () {
        context_ = context;
        socket_ = zmq_socket(context->getCContext(), type);
    }

    ~Socket () {
        assert(socket_ == NULL);
    }

private:
    static Socket * getSocket(const Arguments &args) {
        return ObjectWrap::Unwrap<Socket>(args.This());
    }
    void *socket_;
    void *context_;
};

}

extern "C" void
init (Handle<Object> target) {
    HandleScope scope;
    zmq::Context::Initialize(target);
    zmq::Socket::Initialize(target);
}
<commit_msg>realize we don't actually need to keep the context object around for a socket<commit_after>#include <v8.h>
#include <node.h>
#include <node_events.h>
#include <zmq.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

using namespace v8;
using namespace node;

namespace zmq {

static Persistent<Integer> p2p_symbol;

class Context : public EventEmitter {
public:
    static void
    Initialize (v8::Handle<v8::Object> target) {
        HandleScope scope;

        Local<FunctionTemplate> t = FunctionTemplate::New(New);

        t->Inherit(EventEmitter::constructor_template);
        t->InstanceTemplate()->SetInternalFieldCount(1);

        NODE_SET_PROTOTYPE_METHOD(t, "close", Close);

        target->Set(String::NewSymbol("Context"), t->GetFunction());
    }

    void * getCContext() {
        return context_;
    }

    void Close(Local<Value> exception = Local<Value>()) {
        zmq_term(context_);
        context_ = NULL;
        Unref();
    }

protected:
    static Handle<Value>
    New (const Arguments& args) {
        HandleScope scope;

        Context *context = new Context();
        context->Wrap(args.This());

        return args.This();
    }

    static Handle<Value>
    Close (const Arguments& args) {
        zmq::Context *context = ObjectWrap::Unwrap<Context>(args.This());
        HandleScope scope;
        context->Close();
        return Undefined();
    }

    Context () : EventEmitter () {
        context_ = zmq_init(1, 1, ZMQ_POLL);
    }

    ~Context () {
        assert(context_ == NULL);
    }

private:
    void * context_;
};

class Socket : public EventEmitter {
public:
    static void
    Initialize (v8::Handle<v8::Object> target) {
        HandleScope scope;

        Local<FunctionTemplate> t = FunctionTemplate::New(New);

        t->Inherit(EventEmitter::constructor_template);
        t->InstanceTemplate()->SetInternalFieldCount(1);

        NODE_DEFINE_CONSTANT(t, ZMQ_P2P);
        NODE_DEFINE_CONSTANT(t, ZMQ_PUB);
        NODE_DEFINE_CONSTANT(t, ZMQ_SUB);
        NODE_DEFINE_CONSTANT(t, ZMQ_REQ);
        NODE_DEFINE_CONSTANT(t, ZMQ_REP);
        NODE_DEFINE_CONSTANT(t, ZMQ_UPSTREAM);
        NODE_DEFINE_CONSTANT(t, ZMQ_DOWNSTREAM);

        NODE_SET_PROTOTYPE_METHOD(t, "bind", Bind);
        NODE_SET_PROTOTYPE_METHOD(t, "connect", Connect);
        NODE_SET_PROTOTYPE_METHOD(t, "close", Close);

        target->Set(String::NewSymbol("Socket"), t->GetFunction());
    }

    bool Bind(const char *address) {
        return zmq_bind(socket_, address) == 0;
    }

    bool Connect(const char *address) {
        return zmq_connect(socket_, address) == 0;
    }

    void Close(Local<Value> exception = Local<Value>()) {
        zmq_close(socket_);
        socket_ = NULL;
        Unref();
    }

    char * ErrorMessage() {
        return strerror(errno);
    }

protected:
    static Handle<Value>
    New (const Arguments &args) {
        HandleScope scope;
        if (args.Length() != 2) {
            return ThrowException(Exception::Error(
                String::New("Must pass a context and a type to constructor")));
        }
        Context *context = ObjectWrap::Unwrap<Context>(args[0]->ToObject());
        if (!args[1]->IsNumber()) {
            return ThrowException(Exception::TypeError(
                String::New("Type must be an integer")));
        }
        int type = (int) args[1]->ToInteger()->Value();

        Socket *socket = new Socket(context, type);
        socket->Wrap(args.This());

        return args.This();
    }

    static Handle<Value>
    Connect (const Arguments &args) {
        Socket *socket = getSocket(args);
        HandleScope scope;
        if (!args[0]->IsString()) {
            return ThrowException(Exception::TypeError(
                String::New("Address must be a string!")));
        }

        String::Utf8Value address(args[0]->ToString());
        if (!socket->Connect(*address)) {
            return ThrowException(Exception::Error(
                String::New(socket->ErrorMessage())));
        }
        return Undefined();
    }

    static Handle<Value>
    Bind (const Arguments &args) {
        Socket *socket = getSocket(args);
        HandleScope scope;
        if (!args[0]->IsString()) {
            return ThrowException(Exception::TypeError(
                String::New("Address must be a string!")));
        }

        String::Utf8Value address(args[0]->ToString());
        if (!socket->Bind(*address)) {
            return ThrowException(Exception::Error(
                String::New(socket->ErrorMessage())));
        }
        return Undefined();
    }

    static Handle<Value>
    Close (const Arguments &args) {
        Socket *socket = getSocket(args);
        HandleScope scope;
        socket->Close();
        return Undefined();
    }

    Socket (Context *context, int type) : EventEmitter () {
        socket_ = zmq_socket(context->getCContext(), type);
    }

    ~Socket () {
        assert(socket_ == NULL);
    }

private:
    static Socket * getSocket(const Arguments &args) {
        return ObjectWrap::Unwrap<Socket>(args.This());
    }
    void *socket_;
};

}

extern "C" void
init (Handle<Object> target) {
    HandleScope scope;
    zmq::Context::Initialize(target);
    zmq::Socket::Initialize(target);
}
<|endoftext|>


<commit_before>#include <Arduino.h>
#include "Lights.h"
#include "Adafruit_NeoPixel.h"

typedef uint32_t color;
Adafruit_NeoPixel *stripA;
Adafruit_NeoPixel *stripB;

#define MAD_LIGHTS_LOGGING 1

Lights::Lights( int pA, int pB, int countLights )
{
  // initialize variables
  pinA = pA;
  pinB = pB;
  numLights_total = countLights * 2;
  numLights_perStrip = countLights;

  stripA = new Adafruit_NeoPixel(numLights_perStrip, pinA, NEO_GRB + NEO_KHZ800);
//  stripB = new Adafruit_NeoPixel(numLights_perStrip, pinB, NEO_GRB + NEO_KHZ800);

  stripA->begin();
  //stripB->begin();

  isOn = 0;

  // run = 0;
  // last_changed = millis();

  // // initialize physical objects
  // pinMode( pin, OUTPUT );

  // // don't forget that we don't know the state of the pin
  // // so give it one
  // digitalWrite( pin, Lights_OFF );
}

void Lights::loop() {
}

void Lights::setPixelColor(uint16_t n, uint32_t c) {
  if ( n >= numLights_perStrip ) {
    stripB->setPixelColor( n - numLights_perStrip, c);
  } else {
    stripA->setPixelColor( n, c);
  }
}

void Lights::show() {
  if ( isOn ) {
    stripA->show();
    stripB->show();
  }
}

void Lights::test() {
}

void Lights::on() {
  isOn = 1;
}

void Lights::off()
{
  for ( int i = 0; i < numLights_total; i++ ) {
    color c = stripA->Color(0,0,0);
    setPixelColor(i, c);
  }
  isOn = 0;
  stripA->show();
  stripB->show();
}

void Lights::shoot( int direction ) {
}

<commit_msg>breaking change to lights for bill to see.<commit_after>#include <Arduino.h>
#include "Lights.h"
#include "Adafruit_NeoPixel.h"

typedef uint32_t color;
Adafruit_NeoPixel *stripA;
Adafruit_NeoPixel *stripB;

#define MAD_LIGHTS_LOGGING 1

Lights::Lights( int pA, int pB, int countLights )
{
  // initialize variables
  pinA = pA;
  pinB = pB;
  numLights_total = countLights * 2;
  numLights_perStrip = countLights;

  stripA = new Adafruit_NeoPixel(numLights_perStrip, pinA, NEO_GRB + NEO_KHZ800);
//  stripB = new Adafruit_NeoPixel(numLights_perStrip, pinB, NEO_GRB + NEO_KHZ800);

  stripA->begin();
  //stripB->begin();

  isOn = 0;

  // run = 0;
  // last_changed = millis();

  // // initialize physical objects
  // pinMode( pin, OUTPUT );

  // // don't forget that we don't know the state of the pin
  // // so give it one
  // digitalWrite( pin, Lights_OFF );
}

void Lights::loop() {

  return;

  static int looper = 0;
  static int r = 40;
  static int b = 0;
  static boolean flop = false;

  unsigned long sss = millis();

  for ( int i = 0; i < numLights_perStrip; i++ ) {

    looper++;
    if ( i == looper ) {
        color c = stripA->Color(0,0,40);
        stripA->setPixelColor(i, c);
    } else {
        color c = stripA->Color(40,0,0);
        stripA->setPixelColor(i, c);
    }
 }
  stripA->show();

  unsigned long eee = millis() - sss;
  if ( eee > 10 ) {
    Serial.print("Lights took "); Serial.println(eee);
  }
}

void Lights::setPixelColor(uint16_t n, uint32_t c) {
  if ( n >= numLights_perStrip ) {
    stripB->setPixelColor( n - numLights_perStrip, c);
  } else {
    stripA->setPixelColor( n, c);
  }
}

void Lights::show() {
  if ( isOn ) {
    stripA->show();
    stripB->show();
  }
}

void Lights::test() {
}

void Lights::on() {
  isOn = 1;
}

void Lights::off()
{
  for ( int i = 0; i < numLights_total; i++ ) {
    color c = stripA->Color(0,0,0);
    setPixelColor(i, c);
  }
  isOn = 0;
  stripA->show();
  stripB->show();
}

void Lights::shoot( int direction ) {
}

<|endoftext|>


<commit_before>#ifndef MS_RTC_RTP_PACKET_HPP
#define MS_RTC_RTP_PACKET_HPP

#include "common.hpp"
#include "Utils.hpp"
#include "RTC/RtpDictionaries.hpp"
#include <map>

namespace RTC
{
	// Max MTU size.
	constexpr size_t MtuSize{ 1500 };

	class RtpPacket
	{
	public:
		/* Struct for RTP header. */
		struct Header
		{
#if defined(MS_LITTLE_ENDIAN)
			uint8_t csrcCount : 4;
			uint8_t extension : 1;
			uint8_t padding : 1;
			uint8_t version : 2;
			uint8_t payloadType : 7;
			uint8_t marker : 1;
#elif defined(MS_BIG_ENDIAN)
			uint8_t version : 2;
			uint8_t padding : 1;
			uint8_t extension : 1;
			uint8_t csrcCount : 4;
			uint8_t marker : 1;
			uint8_t payloadType : 7;
#endif
			uint16_t sequenceNumber;
			uint32_t timestamp;
			uint32_t ssrc;
		};

	private:
		/* Struct for RTP extension header. */
		struct ExtensionHeader
		{
			uint16_t id;
			uint16_t length; // Size of value in multiples of 4 bytes.
			uint8_t value[1];
		};

	private:
		/* Struct for One-Byte extension. */
		struct OneByteExtension
		{
#if defined(MS_LITTLE_ENDIAN)
			uint8_t len : 4;
			uint8_t id : 4;
#elif defined(MS_BIG_ENDIAN)
			uint8_t id : 4;
			uint8_t len : 4;
#endif
			uint8_t value[1];
		};

	private:
		/* Struct for Two-Bytes extension. */
		struct TwoBytesExtension
		{
#if defined(MS_LITTLE_ENDIAN)
			uint8_t len : 8;
			uint8_t id : 8;
#elif defined(MS_BIG_ENDIAN)
			uint8_t id : 8;
			uint8_t len : 8;
#endif
			uint8_t value[1];
		};

	public:
		static bool IsRtp(const uint8_t* data, size_t len);
		static RtpPacket* Parse(const uint8_t* data, size_t len);

	public:
		RtpPacket(
		    Header* header,
		    ExtensionHeader* extensionHeader,
		    const uint8_t* payload,
		    size_t payloadLength,
		    uint8_t payloadPadding,
		    size_t size);
		~RtpPacket();

		void Dump() const;
		const uint8_t* GetData() const;
		size_t GetSize() const;
		uint8_t GetPayloadType() const;
		void SetPayloadType(uint8_t payloadType);
		bool HasMarker() const;
		void SetMarker(bool marker);
		uint16_t GetSequenceNumber() const;
		void SetSequenceNumber(uint16_t seq);
		uint32_t GetExtendedSequenceNumber() const;
		void SetExtendedSequenceNumber(uint32_t seq32);
		uint32_t GetTimestamp() const;
		void SetTimestamp(uint32_t timestamp);
		uint32_t GetSsrc() const;
		void SetSsrc(uint32_t ssrc);
		bool HasExtensionHeader() const;
		uint16_t GetExtensionHeaderId() const;
		size_t GetExtensionHeaderLength() const;
		uint8_t* GetExtensionHeaderValue() const;
		bool HasOneByteExtensions() const;
		bool HasTwoBytesExtensions() const;
		void AddExtensionMapping(RtpHeaderExtensionUri::Type uri, uint8_t id);
		uint8_t* GetExtension(RtpHeaderExtensionUri::Type uri, uint8_t* len) const;
		bool ReadAudioLevel(uint8_t* volume, bool* voice) const;
		bool ReadAbsSendTime(uint32_t* time) const;
		uint8_t* GetPayload() const;
		size_t GetPayloadLength() const;
		void Serialize(uint8_t* buffer);
		RtpPacket* Clone(uint8_t* buffer) const;
		void RtxEncode(uint8_t payloadType, uint32_t ssrc, uint16_t seq);
		bool RtxDecode(uint8_t payloadType, uint32_t ssrc);

	private:
		void ParseExtensions();

	private:
		// Passed by argument.
		Header* header{ nullptr };
		uint8_t* csrcList{ nullptr };
		ExtensionHeader* extensionHeader{ nullptr };
		std::map<uint8_t, OneByteExtension*> oneByteExtensions;
		std::map<uint8_t, TwoBytesExtension*> twoBytesExtensions;
		std::map<RtpHeaderExtensionUri::Type, uint8_t> extensionMap;
		uint8_t* payload{ nullptr };
		size_t payloadLength{ 0 };
		uint8_t payloadPadding{ 0 };
		size_t size{ 0 };    // Full size of the packet in bytes.
		uint32_t seq32{ 0 }; // Extended seq number.
	};

	/* Inline static methods. */

	inline bool RtpPacket::IsRtp(const uint8_t* data, size_t len)
	{
		// NOTE: RtcpPacket::IsRtcp() must always be called before this method.

		auto header = const_cast<Header*>(reinterpret_cast<const Header*>(data));

		return (
		    (len >= sizeof(Header)) &&
		    // DOC: https://tools.ietf.org/html/draft-ietf-avtcore-rfc5764-mux-fixes
		    (data[0] > 127 && data[0] < 192) &&
		    // RTP Version must be 2.
		    (header->version == 2));
	}

	/* Inline instance methods. */

	inline const uint8_t* RtpPacket::GetData() const
	{
		return (const uint8_t*)this->header;
	}

	inline size_t RtpPacket::GetSize() const
	{
		return this->size;
	}

	inline uint8_t RtpPacket::GetPayloadType() const
	{
		return this->header->payloadType;
	}

	inline void RtpPacket::SetPayloadType(uint8_t payloadType)
	{
		this->header->payloadType = payloadType;
	}

	inline bool RtpPacket::HasMarker() const
	{
		return this->header->marker;
	}

	inline void RtpPacket::SetMarker(bool marker)
	{
		this->header->marker = marker;
	}

	inline uint16_t RtpPacket::GetSequenceNumber() const
	{
		return uint16_t{ ntohs(this->header->sequenceNumber) };
	}

	inline void RtpPacket::SetSequenceNumber(uint16_t seq)
	{
		this->header->sequenceNumber = uint16_t{ htons(seq) };
	}

	inline uint32_t RtpPacket::GetExtendedSequenceNumber() const
	{
		return this->seq32;
	}

	inline void RtpPacket::SetExtendedSequenceNumber(uint32_t seq32)
	{
		this->seq32 = seq32;
	}

	inline uint32_t RtpPacket::GetTimestamp() const
	{
		return uint32_t{ ntohl(this->header->timestamp) };
	}

	inline void RtpPacket::SetTimestamp(uint32_t timestamp)
	{
		this->header->timestamp = uint32_t{ htonl(timestamp) };
	}

	inline uint32_t RtpPacket::GetSsrc() const
	{
		return uint32_t{ ntohl(this->header->ssrc) };
	}

	inline void RtpPacket::SetSsrc(uint32_t ssrc)
	{
		this->header->ssrc = uint32_t{ htonl(ssrc) };
	}

	inline bool RtpPacket::HasExtensionHeader() const
	{
		return (this->extensionHeader ? true : false);
	}

	inline uint16_t RtpPacket::GetExtensionHeaderId() const
	{
		if (!this->extensionHeader)
			return 0;

		return uint16_t{ ntohs(this->extensionHeader->id) };
	}

	inline size_t RtpPacket::GetExtensionHeaderLength() const
	{
		if (!this->extensionHeader)
			return 0;

		return static_cast<size_t>(ntohs(this->extensionHeader->length) * 4);
	}

	inline uint8_t* RtpPacket::GetExtensionHeaderValue() const
	{
		if (!this->extensionHeader)
			return nullptr;

		return this->extensionHeader->value;
	}

	inline bool RtpPacket::HasOneByteExtensions() const
	{
		return GetExtensionHeaderId() == 0xBEDE;
	}

	inline bool RtpPacket::HasTwoBytesExtensions() const
	{
		return (GetExtensionHeaderId() & 0b1111111111110000) == 0b0001000000000000;
	}

	inline void RtpPacket::AddExtensionMapping(RtpHeaderExtensionUri::Type uri, uint8_t id)
	{
		this->extensionMap[uri] = id;
	}

	inline uint8_t* RtpPacket::GetExtension(RtpHeaderExtensionUri::Type uri, uint8_t* len) const
	{
		*len = 0;

		if (this->extensionMap.find(uri) == this->extensionMap.end())
			return nullptr;

		uint8_t id = this->extensionMap.at(uri);

		if (HasOneByteExtensions())
		{
			if (this->oneByteExtensions.find(id) == this->oneByteExtensions.end())
				return nullptr;

			*len = this->oneByteExtensions.at(id)->len + 1;

			return this->oneByteExtensions.at(id)->value;
		}
		else if (HasTwoBytesExtensions())
		{
			if (this->twoBytesExtensions.find(id) == this->twoBytesExtensions.end())
				return nullptr;

			*len = this->oneByteExtensions.at(id)->len;

			return this->twoBytesExtensions.at(id)->value;
		}
		else
		{
			return nullptr;
		}
	}

	inline bool RtpPacket::ReadAudioLevel(uint8_t* volume, bool* voice) const
	{
		uint8_t extenLen;
		uint8_t* extenValue;

		extenValue = GetExtension(RtpHeaderExtensionUri::Type::SSRC_AUDIO_LEVEL, &extenLen);

		if (!extenValue || extenLen != 1)
			return false;

		*volume = Utils::Byte::Get1Byte(extenValue, 0);
		*voice  = (*volume & (1 << 7)) ? true : false;
		*volume &= ~(1 << 7);

		return true;
	}

	inline bool RtpPacket::ReadAbsSendTime(uint32_t* time) const
	{
		uint8_t extenLen;
		uint8_t* extenValue;

		extenValue = GetExtension(RtpHeaderExtensionUri::Type::ABS_SEND_TIME, &extenLen);

		if (!extenValue || extenLen != 3)
			return false;

		*time = Utils::Byte::Get3Bytes(extenValue, 0);

		return true;
	}

	inline uint8_t* RtpPacket::GetPayload() const
	{
		return this->payload;
	}

	inline size_t RtpPacket::GetPayloadLength() const
	{
		return this->payloadLength;
	}
} // namespace RTC

#endif
<commit_msg>Fix bug<commit_after>#ifndef MS_RTC_RTP_PACKET_HPP
#define MS_RTC_RTP_PACKET_HPP

#include "common.hpp"
#include "Utils.hpp"
#include "RTC/RtpDictionaries.hpp"
#include <map>

namespace RTC
{
	// Max MTU size.
	constexpr size_t MtuSize{ 1500 };

	class RtpPacket
	{
	public:
		/* Struct for RTP header. */
		struct Header
		{
#if defined(MS_LITTLE_ENDIAN)
			uint8_t csrcCount : 4;
			uint8_t extension : 1;
			uint8_t padding : 1;
			uint8_t version : 2;
			uint8_t payloadType : 7;
			uint8_t marker : 1;
#elif defined(MS_BIG_ENDIAN)
			uint8_t version : 2;
			uint8_t padding : 1;
			uint8_t extension : 1;
			uint8_t csrcCount : 4;
			uint8_t marker : 1;
			uint8_t payloadType : 7;
#endif
			uint16_t sequenceNumber;
			uint32_t timestamp;
			uint32_t ssrc;
		};

	private:
		/* Struct for RTP extension header. */
		struct ExtensionHeader
		{
			uint16_t id;
			uint16_t length; // Size of value in multiples of 4 bytes.
			uint8_t value[1];
		};

	private:
		/* Struct for One-Byte extension. */
		struct OneByteExtension
		{
#if defined(MS_LITTLE_ENDIAN)
			uint8_t len : 4;
			uint8_t id : 4;
#elif defined(MS_BIG_ENDIAN)
			uint8_t id : 4;
			uint8_t len : 4;
#endif
			uint8_t value[1];
		};

	private:
		/* Struct for Two-Bytes extension. */
		struct TwoBytesExtension
		{
#if defined(MS_LITTLE_ENDIAN)
			uint8_t len : 8;
			uint8_t id : 8;
#elif defined(MS_BIG_ENDIAN)
			uint8_t id : 8;
			uint8_t len : 8;
#endif
			uint8_t value[1];
		};

	public:
		static bool IsRtp(const uint8_t* data, size_t len);
		static RtpPacket* Parse(const uint8_t* data, size_t len);

	public:
		RtpPacket(
		    Header* header,
		    ExtensionHeader* extensionHeader,
		    const uint8_t* payload,
		    size_t payloadLength,
		    uint8_t payloadPadding,
		    size_t size);
		~RtpPacket();

		void Dump() const;
		const uint8_t* GetData() const;
		size_t GetSize() const;
		uint8_t GetPayloadType() const;
		void SetPayloadType(uint8_t payloadType);
		bool HasMarker() const;
		void SetMarker(bool marker);
		uint16_t GetSequenceNumber() const;
		void SetSequenceNumber(uint16_t seq);
		uint32_t GetExtendedSequenceNumber() const;
		void SetExtendedSequenceNumber(uint32_t seq32);
		uint32_t GetTimestamp() const;
		void SetTimestamp(uint32_t timestamp);
		uint32_t GetSsrc() const;
		void SetSsrc(uint32_t ssrc);
		bool HasExtensionHeader() const;
		uint16_t GetExtensionHeaderId() const;
		size_t GetExtensionHeaderLength() const;
		uint8_t* GetExtensionHeaderValue() const;
		bool HasOneByteExtensions() const;
		bool HasTwoBytesExtensions() const;
		void AddExtensionMapping(RtpHeaderExtensionUri::Type uri, uint8_t id);
		uint8_t* GetExtension(RtpHeaderExtensionUri::Type uri, uint8_t* len) const;
		bool ReadAudioLevel(uint8_t* volume, bool* voice) const;
		bool ReadAbsSendTime(uint32_t* time) const;
		uint8_t* GetPayload() const;
		size_t GetPayloadLength() const;
		void Serialize(uint8_t* buffer);
		RtpPacket* Clone(uint8_t* buffer) const;
		void RtxEncode(uint8_t payloadType, uint32_t ssrc, uint16_t seq);
		bool RtxDecode(uint8_t payloadType, uint32_t ssrc);

	private:
		void ParseExtensions();

	private:
		// Passed by argument.
		Header* header{ nullptr };
		uint8_t* csrcList{ nullptr };
		ExtensionHeader* extensionHeader{ nullptr };
		std::map<uint8_t, OneByteExtension*> oneByteExtensions;
		std::map<uint8_t, TwoBytesExtension*> twoBytesExtensions;
		std::map<RtpHeaderExtensionUri::Type, uint8_t> extensionMap;
		uint8_t* payload{ nullptr };
		size_t payloadLength{ 0 };
		uint8_t payloadPadding{ 0 };
		size_t size{ 0 };    // Full size of the packet in bytes.
		uint32_t seq32{ 0 }; // Extended seq number.
	};

	/* Inline static methods. */

	inline bool RtpPacket::IsRtp(const uint8_t* data, size_t len)
	{
		// NOTE: RtcpPacket::IsRtcp() must always be called before this method.

		auto header = const_cast<Header*>(reinterpret_cast<const Header*>(data));

		return (
		    (len >= sizeof(Header)) &&
		    // DOC: https://tools.ietf.org/html/draft-ietf-avtcore-rfc5764-mux-fixes
		    (data[0] > 127 && data[0] < 192) &&
		    // RTP Version must be 2.
		    (header->version == 2));
	}

	/* Inline instance methods. */

	inline const uint8_t* RtpPacket::GetData() const
	{
		return (const uint8_t*)this->header;
	}

	inline size_t RtpPacket::GetSize() const
	{
		return this->size;
	}

	inline uint8_t RtpPacket::GetPayloadType() const
	{
		return this->header->payloadType;
	}

	inline void RtpPacket::SetPayloadType(uint8_t payloadType)
	{
		this->header->payloadType = payloadType;
	}

	inline bool RtpPacket::HasMarker() const
	{
		return this->header->marker;
	}

	inline void RtpPacket::SetMarker(bool marker)
	{
		this->header->marker = marker;
	}

	inline uint16_t RtpPacket::GetSequenceNumber() const
	{
		return uint16_t{ ntohs(this->header->sequenceNumber) };
	}

	inline void RtpPacket::SetSequenceNumber(uint16_t seq)
	{
		this->header->sequenceNumber = uint16_t{ htons(seq) };
	}

	inline uint32_t RtpPacket::GetExtendedSequenceNumber() const
	{
		return this->seq32;
	}

	inline void RtpPacket::SetExtendedSequenceNumber(uint32_t seq32)
	{
		this->seq32 = seq32;
	}

	inline uint32_t RtpPacket::GetTimestamp() const
	{
		return uint32_t{ ntohl(this->header->timestamp) };
	}

	inline void RtpPacket::SetTimestamp(uint32_t timestamp)
	{
		this->header->timestamp = uint32_t{ htonl(timestamp) };
	}

	inline uint32_t RtpPacket::GetSsrc() const
	{
		return uint32_t{ ntohl(this->header->ssrc) };
	}

	inline void RtpPacket::SetSsrc(uint32_t ssrc)
	{
		this->header->ssrc = uint32_t{ htonl(ssrc) };
	}

	inline bool RtpPacket::HasExtensionHeader() const
	{
		return (this->extensionHeader ? true : false);
	}

	inline uint16_t RtpPacket::GetExtensionHeaderId() const
	{
		if (!this->extensionHeader)
			return 0;

		return uint16_t{ ntohs(this->extensionHeader->id) };
	}

	inline size_t RtpPacket::GetExtensionHeaderLength() const
	{
		if (!this->extensionHeader)
			return 0;

		return static_cast<size_t>(ntohs(this->extensionHeader->length) * 4);
	}

	inline uint8_t* RtpPacket::GetExtensionHeaderValue() const
	{
		if (!this->extensionHeader)
			return nullptr;

		return this->extensionHeader->value;
	}

	inline bool RtpPacket::HasOneByteExtensions() const
	{
		return GetExtensionHeaderId() == 0xBEDE;
	}

	inline bool RtpPacket::HasTwoBytesExtensions() const
	{
		return (GetExtensionHeaderId() & 0b1111111111110000) == 0b0001000000000000;
	}

	inline void RtpPacket::AddExtensionMapping(RtpHeaderExtensionUri::Type uri, uint8_t id)
	{
		this->extensionMap[uri] = id;
	}

	inline uint8_t* RtpPacket::GetExtension(RtpHeaderExtensionUri::Type uri, uint8_t* len) const
	{
		*len = 0;

		if (this->extensionMap.find(uri) == this->extensionMap.end())
			return nullptr;

		uint8_t id = this->extensionMap.at(uri);

		if (HasOneByteExtensions())
		{
			if (this->oneByteExtensions.find(id) == this->oneByteExtensions.end())
				return nullptr;

			*len = this->oneByteExtensions.at(id)->len + 1;

			return this->oneByteExtensions.at(id)->value;
		}
		else if (HasTwoBytesExtensions())
		{
			if (this->twoBytesExtensions.find(id) == this->twoBytesExtensions.end())
				return nullptr;

			*len = this->twoByteExtensions.at(id)->len;

			return this->twoBytesExtensions.at(id)->value;
		}
		else
		{
			return nullptr;
		}
	}

	inline bool RtpPacket::ReadAudioLevel(uint8_t* volume, bool* voice) const
	{
		uint8_t extenLen;
		uint8_t* extenValue;

		extenValue = GetExtension(RtpHeaderExtensionUri::Type::SSRC_AUDIO_LEVEL, &extenLen);

		if (!extenValue || extenLen != 1)
			return false;

		*volume = Utils::Byte::Get1Byte(extenValue, 0);
		*voice  = (*volume & (1 << 7)) ? true : false;
		*volume &= ~(1 << 7);

		return true;
	}

	inline bool RtpPacket::ReadAbsSendTime(uint32_t* time) const
	{
		uint8_t extenLen;
		uint8_t* extenValue;

		extenValue = GetExtension(RtpHeaderExtensionUri::Type::ABS_SEND_TIME, &extenLen);

		if (!extenValue || extenLen != 3)
			return false;

		*time = Utils::Byte::Get3Bytes(extenValue, 0);

		return true;
	}

	inline uint8_t* RtpPacket::GetPayload() const
	{
		return this->payload;
	}

	inline size_t RtpPacket::GetPayloadLength() const
	{
		return this->payloadLength;
	}
} // namespace RTC

#endif
<|endoftext|>


<commit_before>#include "ChunkPatcher.h"
#include "../stringtools.h"
#include <assert.h>

ChunkPatcher::ChunkPatcher(void)
	: cb(NULL), require_unchanged(true)
{
}

void ChunkPatcher::setCallback(IChunkPatcherCallback *pCb)
{
	cb=pCb;
}

bool ChunkPatcher::ApplyPatch(IFile *file, IFile *patch)
{
	patch->Seek(0);
	file->Seek(0);
	_i64 patchf_pos=0;

	const unsigned int buffer_size=32768;
	char buf[buffer_size];

	if(patch->Read((char*)&filesize, sizeof(_i64))!=sizeof(_i64))
	{
		return false;
	}

	filesize = little_endian(filesize);

	patchf_pos+=sizeof(_i64);

	SPatchHeader next_header;
	next_header.patch_off=-1;
	bool has_header=true;
	for(_i64 file_pos=0,size=file->Size(); (file_pos<size && file_pos<filesize) || has_header;)
	{
		if(has_header && next_header.patch_off==-1)
		{
			has_header=readNextValidPatch(patch, patchf_pos, &next_header);
		}

		unsigned int tr=buffer_size;
		if(next_header.patch_off!=-1)
		{
			_i64 hoff=next_header.patch_off-file_pos;
			if(hoff>=0 && hoff<tr)
				tr=(unsigned int)hoff;

			assert(hoff>=0);
		}

		if(file_pos>=filesize)
		{
			Server->Log("Patch corrupt file_pos>=filesize. file_pos="+nconvert(file_pos)+" next_header.patch_off="+nconvert(next_header.patch_off)+" next_header.patch_size="+nconvert(next_header.patch_size)+" tr="+nconvert(tr)+" size="+nconvert(size)+" filesize="+nconvert(filesize)+" has_header="+nconvert(has_header), LL_ERROR);
			assert(file_pos<filesize);
			return false;
		}

		if(tr==0)
		{
			assert(file_pos==next_header.patch_off);

			file_pos+=next_header.patch_size;

			while(next_header.patch_size>0)
			{
				_u32 r=patch->Read((char*)buf, (std::min)((unsigned int)buffer_size, next_header.patch_size));
				patchf_pos+=r;
				cb->next_chunk_patcher_bytes(buf, r, true);
				next_header.patch_size-=r;
			}
			if(require_unchanged)
			{
				file->Seek(file_pos);
			}
			next_header.patch_off=-1;
		}
		else if(file_pos<size && file_pos<filesize)
		{
			while(tr>0 && file_pos<size && file_pos<filesize)
			{
				if(file_pos+tr>filesize)
				{
					tr=static_cast<unsigned int>(filesize-file_pos);
				}

				if(require_unchanged)
				{
					_u32 r=file->Read((char*)buf, tr);
					file_pos+=r;
					cb->next_chunk_patcher_bytes(buf, r, false);
					tr-=r;
				}
				else
				{
					if(file_pos+tr>size)
					{
						tr=static_cast<unsigned int>(size-file_pos);
					}

					file_pos+=tr;
					cb->next_chunk_patcher_bytes(NULL, tr, false);
					tr=0;
				}
			}
		}
		else
		{
			Server->Log("Patch corrupt. file_pos="+nconvert(file_pos)+" next_header.patch_off="+nconvert(next_header.patch_off)+" next_header.patch_size="+nconvert(next_header.patch_size)+" tr="+nconvert(tr)+" size="+nconvert(size)+" filesize="+nconvert(filesize), LL_ERROR);
			assert(false);
			return false;
		}
	}
	return true;
}

bool ChunkPatcher::readNextValidPatch(IFile *patchf, _i64 &patchf_pos, SPatchHeader *patch_header)
{
	const unsigned int to_read=sizeof(_i64)+sizeof(unsigned int);
	do
	{
		_u32 r=patchf->Read((char*)&patch_header->patch_off, to_read);
		patchf_pos+=r;
		if(r!=to_read)
		{
			patch_header->patch_off=-1;
			patch_header->patch_size=0;
			return false;
		}
		else
		{
			patch_header->patch_off = little_endian(patch_header->patch_off);
			patch_header->patch_size = little_endian(patch_header->patch_size);
		}

		if(patch_header->patch_off==-1)
		{
			patchf_pos+=patch_header->patch_size;
			patchf->Seek(patchf_pos);
		}
	}
	while(patch_header->patch_off==-1);

	return true;
}

_i64 ChunkPatcher::getFilesize(void)
{
	return filesize;
}

void ChunkPatcher::setRequireUnchanged( bool b )
{
	require_unchanged=b;
}
<commit_msg>Exit if no header was found and file was patched<commit_after>#include "ChunkPatcher.h"
#include "../stringtools.h"
#include <assert.h>

ChunkPatcher::ChunkPatcher(void)
	: cb(NULL), require_unchanged(true)
{
}

void ChunkPatcher::setCallback(IChunkPatcherCallback *pCb)
{
	cb=pCb;
}

bool ChunkPatcher::ApplyPatch(IFile *file, IFile *patch)
{
	patch->Seek(0);
	file->Seek(0);
	_i64 patchf_pos=0;

	const unsigned int buffer_size=32768;
	char buf[buffer_size];

	if(patch->Read((char*)&filesize, sizeof(_i64))!=sizeof(_i64))
	{
		return false;
	}

	filesize = little_endian(filesize);

	patchf_pos+=sizeof(_i64);

	SPatchHeader next_header;
	next_header.patch_off=-1;
	bool has_header=true;
	for(_i64 file_pos=0,size=file->Size(); (file_pos<size && file_pos<filesize) || has_header;)
	{
		if(has_header && next_header.patch_off==-1)
		{
			has_header=readNextValidPatch(patch, patchf_pos, &next_header);

			if(!has_header && file_pos>=filesize)
			{
				break;
			}
		}

		unsigned int tr=buffer_size;
		if(next_header.patch_off!=-1)
		{
			_i64 hoff=next_header.patch_off-file_pos;
			if(hoff>=0 && hoff<tr)
				tr=(unsigned int)hoff;

			assert(hoff>=0);
		}

		if(file_pos>=filesize)
		{
			Server->Log("Patch corrupt file_pos>=filesize. file_pos="+nconvert(file_pos)+" next_header.patch_off="+nconvert(next_header.patch_off)+" next_header.patch_size="+nconvert(next_header.patch_size)+" tr="+nconvert(tr)+" size="+nconvert(size)+" filesize="+nconvert(filesize)+" has_header="+nconvert(has_header), LL_ERROR);
			assert(file_pos<filesize);
			return false;
		}

		if(tr==0)
		{
			assert(file_pos==next_header.patch_off);

			file_pos+=next_header.patch_size;

			while(next_header.patch_size>0)
			{
				_u32 r=patch->Read((char*)buf, (std::min)((unsigned int)buffer_size, next_header.patch_size));
				patchf_pos+=r;
				cb->next_chunk_patcher_bytes(buf, r, true);
				next_header.patch_size-=r;
			}
			if(require_unchanged)
			{
				file->Seek(file_pos);
			}
			next_header.patch_off=-1;
		}
		else if(file_pos<size && file_pos<filesize)
		{
			while(tr>0 && file_pos<size && file_pos<filesize)
			{
				if(file_pos+tr>filesize)
				{
					tr=static_cast<unsigned int>(filesize-file_pos);
				}

				if(require_unchanged)
				{
					_u32 r=file->Read((char*)buf, tr);
					file_pos+=r;
					cb->next_chunk_patcher_bytes(buf, r, false);
					tr-=r;
				}
				else
				{
					if(file_pos+tr>size)
					{
						tr=static_cast<unsigned int>(size-file_pos);
					}

					file_pos+=tr;
					cb->next_chunk_patcher_bytes(NULL, tr, false);
					tr=0;
				}
			}
		}
		else
		{
			Server->Log("Patch corrupt. file_pos="+nconvert(file_pos)+" next_header.patch_off="+nconvert(next_header.patch_off)+" next_header.patch_size="+nconvert(next_header.patch_size)+" tr="+nconvert(tr)+" size="+nconvert(size)+" filesize="+nconvert(filesize), LL_ERROR);
			assert(false);
			return false;
		}
	}
	return true;
}

bool ChunkPatcher::readNextValidPatch(IFile *patchf, _i64 &patchf_pos, SPatchHeader *patch_header)
{
	const unsigned int to_read=sizeof(_i64)+sizeof(unsigned int);
	do
	{
		_u32 r=patchf->Read((char*)&patch_header->patch_off, to_read);
		patchf_pos+=r;
		if(r!=to_read)
		{
			patch_header->patch_off=-1;
			patch_header->patch_size=0;
			return false;
		}
		else
		{
			patch_header->patch_off = little_endian(patch_header->patch_off);
			patch_header->patch_size = little_endian(patch_header->patch_size);
		}

		if(patch_header->patch_off==-1)
		{
			patchf_pos+=patch_header->patch_size;
			patchf->Seek(patchf_pos);
		}
	}
	while(patch_header->patch_off==-1);

	return true;
}

_i64 ChunkPatcher::getFilesize(void)
{
	return filesize;
}

void ChunkPatcher::setRequireUnchanged( bool b )
{
	require_unchanged=b;
}
<|endoftext|>


<commit_before>#define __STDC_FORMAT_MACROS

#include <stdio.h>
#include <iostream>
#include <signal.h>
#include <time.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <algorithm>
#include <unistd.h>
#include <getopt.h>

extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#include "lpeg.h"
}

#include <sinsp.h>
#include <config_digwatch.h>
#include "rules.h"
#include "formats.h"
#include "fields.h"
#include "syslog.h"
#include "utils.h"

static bool g_terminate = false;

static void signal_callback(int signal)
{
	g_terminate = true;
}

std::vector<string> valid_output_names {"stdout", "syslog"};

//
// Program help
//
static void usage()
{
    printf(
	   "Usage: digwatch [options] rules_filename\n\n"
	   "Options:\n"
	   " -h, --help         Print this page\n"
	   " -o                 Output type (options are 'stdout', 'syslog', default is 'stdout')\n"
	   "\n"
    );
}

string lua_on_event = "on_event";

//
// Event processing loop
//
void do_inspect(sinsp* inspector,
		digwatch_rules* rules,
		string output_name,
		lua_State* ls)
{
	int32_t res;
	sinsp_evt* ev;
	string line;

	//
	// Loop through the events
	//
	while(1)
	{

		if(g_terminate)
		{
			break;
		}

		res = inspector->next(&ev);

		if(res == SCAP_TIMEOUT)
		{
			continue;
		}
		else if(res == SCAP_EOF)
		{
			break;
		}
		else if(res != SCAP_SUCCESS)
		{
			//
			// Event read error.
			// Notify the chisels that we're exiting, and then die with an error.
			//
			cerr << "res = " << res << endl;
			throw sinsp_exception(inspector->getlasterr().c_str());
		}

		if(!inspector->is_debug_enabled() &&
			ev->get_category() & EC_INTERNAL)
		{
			continue;
		}

		lua_getglobal(ls, lua_on_event.c_str());

		if(lua_isfunction(ls, -1))
		{
			lua_pushlightuserdata(ls, ev);
			lua_pushnumber(ls, ev->get_check_id());
			lua_pushstring(ls, output_name.c_str());

			if(lua_pcall(ls, 3, 0, 0) != 0)
			{
				const char* lerr = lua_tostring(ls, -1);
				string err = "Error invoking function output: " + string(lerr);
				throw sinsp_exception(err);
			}
		}
		else
		{
			throw sinsp_exception("No function " + lua_on_event + " found in lua compiler module");
		}
	}
}

void add_lua_path(lua_State *ls, string path)
{
	string cpath = string(path);
	path += "?.lua";
	cpath += "?.so";

	lua_getglobal(ls, "package");

	lua_getfield(ls, -1, "path");
	string cur_path = lua_tostring(ls, -1 );
	cur_path += ';';
	lua_pop(ls, 1);

	cur_path.append(path.c_str());

	lua_pushstring(ls, cur_path.c_str());
	lua_setfield(ls, -2, "path");

	lua_getfield(ls, -1, "cpath");
	string cur_cpath = lua_tostring(ls, -1 );
	cur_cpath += ';';
	lua_pop(ls, 1);

	cur_cpath.append(cpath.c_str());

	lua_pushstring(ls, cur_cpath.c_str());
	lua_setfield(ls, -2, "cpath");

	lua_pop(ls, 1);
}

//
// ARGUMENT PARSING AND PROGRAM SETUP
//
int digwatch_init(int argc, char **argv)
{
	int result = EXIT_SUCCESS;
	sinsp* inspector = NULL;
	digwatch_rules* rules = NULL;
	int op;
	sinsp_evt::param_fmt event_buffer_format = sinsp_evt::PF_NORMAL;
	int long_index = 0;
	string lua_main_filename;
	string output_name = "stdout";
	string lua_dir = DIGWATCH_LUA_DIR;
	lua_State* ls = NULL;

	static struct option long_options[] =
	{
		{"help", no_argument, 0, 'h' },
		{"main-lua", required_argument, 0, 'u' },
		{0, 0, 0, 0}
	};

	try
	{
		inspector = new sinsp();
		bool valid;

		//
		// Parse the args
		//
		while((op = getopt_long(argc, argv,
                                        "ho:",
                                        long_options, &long_index)) != -1)
		{
			switch(op)
			{
			case 'h':
				usage();
				goto exit;
			case 'o':
				valid = std::find(valid_output_names.begin(), valid_output_names.end(), optarg) != valid_output_names.end();
				if (!valid)
				{
					throw sinsp_exception(string("Invalid output name ") + optarg);
				}
				output_name = optarg;
				break;
			case '?':
				result = EXIT_FAILURE;
				goto exit;
			default:
				break;
			}

		}

		inspector->set_buffer_format(event_buffer_format);

		string rules_file;

		if(optind < argc)
		{
#ifdef HAS_FILTERING
			for(int32_t j = optind ; j < argc; j++)
			{
				rules_file += argv[j];
				if(j < argc - 1)
				{
					rules_file += " ";
				}
			}

#else
			fprintf(stderr, "filtering not compiled.\n");
			result = EXIT_FAILURE;
			goto exit;
#endif
		}

		if(rules_file.size() == 0) {
			usage();
			result = EXIT_FAILURE;
			goto exit;

		}

		if(signal(SIGINT, signal_callback) == SIG_ERR)
		{
			fprintf(stderr, "An error occurred while setting SIGINT signal handler.\n");
			result = EXIT_FAILURE;
			goto exit;
		}

		if(signal(SIGTERM, signal_callback) == SIG_ERR)
		{
			fprintf(stderr, "An error occurred while setting SIGTERM signal handler.\n");
			result = EXIT_FAILURE;
			goto exit;
		}

		lua_main_filename = lua_dir + DIGWATCH_LUA_MAIN;
		if (!std::ifstream(lua_main_filename))
		{
			lua_dir = DIGWATCH_SOURCE_LUA_DIR;
			lua_main_filename = lua_dir + DIGWATCH_LUA_MAIN;
			if (!std::ifstream(lua_main_filename))
			{
				fprintf(stderr, "Could not find Digwatch Lua libraries (tried %s, %s). \n",
					DIGWATCH_LUA_DIR DIGWATCH_LUA_MAIN,
					lua_main_filename.c_str());
				result = EXIT_FAILURE;
				goto exit;
			}
		}

		// Initialize Lua interpreter
		ls = lua_open();
		luaL_openlibs(ls);
		luaopen_lpeg(ls);
		add_lua_path(ls, lua_dir);

		rules = new digwatch_rules(inspector, ls, lua_main_filename);

		digwatch_formats::init(inspector, ls);
		digwatch_fields::init(inspector, ls);

		digwatch_syslog::init(ls);

		rules->load_rules(rules_file);
		inspector->set_filter(rules->get_filter());

		inspector->set_hostname_and_port_resolution_mode(false);

		try
		{
			inspector->open("");
		}
		catch(sinsp_exception e)
		{
			if(system("modprobe " PROBE_NAME " > /dev/null 2> /dev/null"))
			{
				fprintf(stderr, "Unable to load the driver\n");
			}
			inspector->open("");
		}

		do_inspect(inspector,
			   rules,
			   output_name,
			   ls);

		inspector->close();
	}
	catch(sinsp_exception& e)
	{
		cerr << e.what() << endl;
		result = EXIT_FAILURE;
	}
	catch(...)
	{
		printf("Exception\n");
		result = EXIT_FAILURE;
	}

exit:

	if(inspector)
	{
		delete inspector;
	}

	if(ls)
	{
		lua_close(ls);
	}
	return result;
}

//
// MAIN
//
int main(int argc, char **argv)
{
	return digwatch_init(argc, argv);
}
<commit_msg>Add support for reading .scap files<commit_after>#define __STDC_FORMAT_MACROS

#include <stdio.h>
#include <iostream>
#include <signal.h>
#include <time.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <algorithm>
#include <unistd.h>
#include <getopt.h>

extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#include "lpeg.h"
}

#include <sinsp.h>
#include <config_digwatch.h>
#include "rules.h"
#include "formats.h"
#include "fields.h"
#include "syslog.h"
#include "utils.h"

static bool g_terminate = false;

static void signal_callback(int signal)
{
	g_terminate = true;
}

std::vector<string> valid_output_names {"stdout", "syslog"};

//
// Program help
//
static void usage()
{
    printf(
	   "Usage: digwatch [options] rules_filename\n\n"
	   "Options:\n"
	   " -h, --help         Print this page\n"
	   " -o                 Output type (options are 'stdout', 'syslog', default is 'stdout')\n"
           " -r <readfile>, --read=<readfile>\n"
           "                    Read the events from <readfile>.\n"
	   "\n"
    );
}

string lua_on_event = "on_event";

//
// Event processing loop
//
void do_inspect(sinsp* inspector,
		digwatch_rules* rules,
		string output_name,
		lua_State* ls)
{
	int32_t res;
	sinsp_evt* ev;
	string line;

	//
	// Loop through the events
	//
	while(1)
	{

		if(g_terminate)
		{
			break;
		}

		res = inspector->next(&ev);

		if(res == SCAP_TIMEOUT)
		{
			continue;
		}
		else if(res == SCAP_EOF)
		{
			break;
		}
		else if(res != SCAP_SUCCESS)
		{
			//
			// Event read error.
			// Notify the chisels that we're exiting, and then die with an error.
			//
			cerr << "res = " << res << endl;
			throw sinsp_exception(inspector->getlasterr().c_str());
		}

		if(!inspector->is_debug_enabled() &&
			ev->get_category() & EC_INTERNAL)
		{
			continue;
		}

		lua_getglobal(ls, lua_on_event.c_str());

		if(lua_isfunction(ls, -1))
		{
			lua_pushlightuserdata(ls, ev);
			lua_pushnumber(ls, ev->get_check_id());
			lua_pushstring(ls, output_name.c_str());

			if(lua_pcall(ls, 3, 0, 0) != 0)
			{
				const char* lerr = lua_tostring(ls, -1);
				string err = "Error invoking function output: " + string(lerr);
				throw sinsp_exception(err);
			}
		}
		else
		{
			throw sinsp_exception("No function " + lua_on_event + " found in lua compiler module");
		}
	}
}

void add_lua_path(lua_State *ls, string path)
{
	string cpath = string(path);
	path += "?.lua";
	cpath += "?.so";

	lua_getglobal(ls, "package");

	lua_getfield(ls, -1, "path");
	string cur_path = lua_tostring(ls, -1 );
	cur_path += ';';
	lua_pop(ls, 1);

	cur_path.append(path.c_str());

	lua_pushstring(ls, cur_path.c_str());
	lua_setfield(ls, -2, "path");

	lua_getfield(ls, -1, "cpath");
	string cur_cpath = lua_tostring(ls, -1 );
	cur_cpath += ';';
	lua_pop(ls, 1);

	cur_cpath.append(cpath.c_str());

	lua_pushstring(ls, cur_cpath.c_str());
	lua_setfield(ls, -2, "cpath");

	lua_pop(ls, 1);
}

//
// ARGUMENT PARSING AND PROGRAM SETUP
//
int digwatch_init(int argc, char **argv)
{
	int result = EXIT_SUCCESS;
	sinsp* inspector = NULL;
	digwatch_rules* rules = NULL;
	int op;
	sinsp_evt::param_fmt event_buffer_format = sinsp_evt::PF_NORMAL;
	int long_index = 0;
	string lua_main_filename;
	string output_name = "stdout";
	string infile;
	string lua_dir = DIGWATCH_LUA_DIR;
	lua_State* ls = NULL;

	static struct option long_options[] =
	{
		{"help", no_argument, 0, 'h' },
		{"readfile", required_argument, 0, 'r' },
		{0, 0, 0, 0}
	};

	try
	{
		inspector = new sinsp();
		bool valid;

		//
		// Parse the args
		//
		while((op = getopt_long(argc, argv,
                                        "ho:r:",
                                        long_options, &long_index)) != -1)
		{
			switch(op)
			{
			case 'h':
				usage();
				goto exit;
			case 'o':
				valid = std::find(valid_output_names.begin(), valid_output_names.end(), optarg) != valid_output_names.end();
				if (!valid)
				{
					throw sinsp_exception(string("Invalid output name ") + optarg);
				}
				output_name = optarg;
				break;
			case 'r':
				infile = optarg;
				break;
			case '?':
				result = EXIT_FAILURE;
				goto exit;
			default:
				break;
			}

		}

		inspector->set_buffer_format(event_buffer_format);

		string rules_file;

		if(optind < argc)
		{
#ifdef HAS_FILTERING
			for(int32_t j = optind ; j < argc; j++)
			{
				rules_file += argv[j];
				if(j < argc - 1)
				{
					rules_file += " ";
				}
			}

#else
			fprintf(stderr, "filtering not compiled.\n");
			result = EXIT_FAILURE;
			goto exit;
#endif
		}

		if(rules_file.size() == 0) {
			usage();
			result = EXIT_FAILURE;
			goto exit;

		}

		if(signal(SIGINT, signal_callback) == SIG_ERR)
		{
			fprintf(stderr, "An error occurred while setting SIGINT signal handler.\n");
			result = EXIT_FAILURE;
			goto exit;
		}

		if(signal(SIGTERM, signal_callback) == SIG_ERR)
		{
			fprintf(stderr, "An error occurred while setting SIGTERM signal handler.\n");
			result = EXIT_FAILURE;
			goto exit;
		}

		lua_main_filename = lua_dir + DIGWATCH_LUA_MAIN;
		if (!std::ifstream(lua_main_filename))
		{
			lua_dir = DIGWATCH_SOURCE_LUA_DIR;
			lua_main_filename = lua_dir + DIGWATCH_LUA_MAIN;
			if (!std::ifstream(lua_main_filename))
			{
				fprintf(stderr, "Could not find Digwatch Lua libraries (tried %s, %s). \n",
					DIGWATCH_LUA_DIR DIGWATCH_LUA_MAIN,
					lua_main_filename.c_str());
				result = EXIT_FAILURE;
				goto exit;
			}
		}

		// Initialize Lua interpreter
		ls = lua_open();
		luaL_openlibs(ls);
		luaopen_lpeg(ls);
		add_lua_path(ls, lua_dir);

		rules = new digwatch_rules(inspector, ls, lua_main_filename);

		digwatch_formats::init(inspector, ls);
		digwatch_fields::init(inspector, ls);

		digwatch_syslog::init(ls);

		rules->load_rules(rules_file);
		inspector->set_filter(rules->get_filter());

		inspector->set_hostname_and_port_resolution_mode(false);

		if (infile.size())
		{
			inspector->open(infile);
		}
		else
		{
			try
			{
				inspector->open();
			}
			catch(sinsp_exception e)
			{
				if(system("modprobe " PROBE_NAME " > /dev/null 2> /dev/null"))
				{
					fprintf(stderr, "Unable to load the driver\n");
				}
				inspector->open();
			}
		}
		do_inspect(inspector,
			   rules,
			   output_name,
			   ls);

		inspector->close();
	}
	catch(sinsp_exception& e)
	{
		cerr << e.what() << endl;
		result = EXIT_FAILURE;
	}
	catch(...)
	{
		printf("Exception\n");
		result = EXIT_FAILURE;
	}

exit:

	if(inspector)
	{
		delete inspector;
	}

	if(ls)
	{
		lua_close(ls);
	}
	return result;
}

//
// MAIN
//
int main(int argc, char **argv)
{
	return digwatch_init(argc, argv);
}
<|endoftext|>


<commit_before>// Copyright 2004-present Facebook. All Rights Reserved.

#include <string>
#include <fstream>
#include <streambuf>
#include <sstream>
#include <map>

#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <proc/readproc.h>

#include <boost/lexical_cast.hpp>

#include "osquery/core.h"
#include "osquery/database.h"
#include "osquery/filesystem.h"

namespace osquery {
namespace tables {

#ifdef PROC_EDITCMDLCVT
/// EDITCMDLCVT is available in libprocps3-dev
#define PROC_SELECTS                                                 \
  PROC_FILLCOM | PROC_EDITCMDLCVT | PROC_FILLMEM | PROC_FILLSTATUS | \
      PROC_FILLSTAT
#else
#define PROC_SELECTS \
  PROC_FILLCOM | PROC_FILLMEM | PROC_FILLSTATUS | PROC_FILLSTAT
#endif

std::string proc_name(const proc_t* proc_info) {
  char cmd[17]; // cmd is a 16 char buffer

  memset(cmd, 0, 17);
  memcpy(cmd, proc_info->cmd, 16);
  return std::string(cmd);
}

std::string proc_attr(const std::string& attr, const proc_t* proc_info) {
  std::stringstream filename;

  filename << "/proc/" << proc_info->tid << "/" << attr;
  return filename.str();
}

std::string proc_cmdline(const proc_t* proc_info) {
  std::string attr;
  std::string result;

  attr = proc_attr("cmdline", proc_info);
  std::ifstream fd(attr, std::ios::in | std::ios::binary);
  if (fd) {
    result = std::string(std::istreambuf_iterator<char>(fd),
                         std::istreambuf_iterator<char>());
  }

  return result;
}

std::string proc_link(const proc_t* proc_info) {
  std::string attr;
  std::string result;
  char* link_path;
  long path_max;
  int bytes;

  // The exe is a symlink to the binary on-disk.
  attr = proc_attr("exe", proc_info);
  path_max = pathconf(attr.c_str(), _PC_PATH_MAX);
  link_path = (char*)malloc(path_max);

  memset(link_path, 0, path_max);
  bytes = readlink(attr.c_str(), link_path, path_max);
  if (bytes >= 0) {
    result = std::string(link_path);
  }

  free(link_path);
  return result;
}

std::map<std::string, std::string> proc_env(const proc_t* proc_info) {
  std::map<std::string, std::string> env;
  std::string attr = osquery::tables::proc_attr("environ", proc_info);
  std::string buf;

  uid_t euid = geteuid();
  struct stat info;
  if (stat(filename, &info) == -1) {
    return env;
  }

  if (euid != 0 && info.st_uid != euid) {
    return env;
  }

  std::ifstream fd(attr, std::ios::in | std::ios::binary);

  while (!fd.eof()) {
    std::getline(fd, buf, '\0');
    size_t idx = buf.find_first_of("=");

    std::string key = buf.substr(0, idx);
    std::string value = buf.substr(idx + 1);

    env[key] = value;
  }
  return env;
}

/**
 * @brief deallocate the space allocated by readproc if the passed rbuf was NULL
 *
 * @param p The rbuf to free
 */
void standard_freeproc(proc_t* p) {
  if (!p) { // in case p is NULL
    return;
  }
  // ptrs are after strings to avoid copying memory when building them.
  // so free is called on the address of the address of strvec[0].
  if (p->cmdline) {
    free((void*)*p->cmdline);
  }
  if (p->environ) {
    free((void*)*p->environ);
  }
  free(p);
}

QueryData genProcesses() {
  QueryData results;

  proc_t* proc_info;
  PROCTAB* proc = openproc(PROC_SELECTS);

  // Populate proc struc for each process.
  while ((proc_info = readproc(proc, NULL))) {
    Row r;

    r["pid"] = boost::lexical_cast<std::string>(proc_info->tid);
    r["name"] = proc_name(proc_info);
    r["cmdline"] = proc_cmdline(proc_info);
    r["path"] = proc_link(proc_info);
    r["on_disk"] = osquery::pathExists(r["path"]).toString();

    r["resident_size"] = boost::lexical_cast<std::string>(proc_info->vm_rss);
    r["phys_footprint"] = boost::lexical_cast<std::string>(proc_info->vm_size);
    r["user_time"] = boost::lexical_cast<std::string>(proc_info->utime);
    r["system_time"] = boost::lexical_cast<std::string>(proc_info->stime);
    r["start_time"] = boost::lexical_cast<std::string>(proc_info->start_time);
    r["parent"] = boost::lexical_cast<std::string>(proc_info->ppid);

    results.push_back(r);
    standard_freeproc(proc_info);
  }

  closeproc(proc);

  return results;
}

QueryData genProcessEnvs() {
  QueryData results;

  proc_t* proc_info;
  PROCTAB* proc = openproc(PROC_SELECTS);

  // Populate proc struc for each process.

  while ((proc_info = readproc(proc, NULL))) {
    auto env = proc_env(proc_info);
    for (auto itr = env.begin(); itr != env.end(); ++itr) {
      Row r;
      r["pid"] = boost::lexical_cast<std::string>(proc_info->tid);
      r["name"] = proc_name(proc_info);
      r["path"] = proc_link(proc_info);
      r["key"] = itr->first;
      r["value"] = itr->second;
      results.push_back(r);
    }

    standard_freeproc(proc_info);
  }

  closeproc(proc);

  return results;
}

QueryData genProcessOpenFiles() {
  QueryData results;
  return results;
}
}
}
<commit_msg>Add note about blocking process_env as non-su<commit_after>// Copyright 2004-present Facebook. All Rights Reserved.

#include <string>
#include <fstream>
#include <streambuf>
#include <sstream>
#include <map>

#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <proc/readproc.h>

#include <boost/lexical_cast.hpp>

#include "osquery/core.h"
#include "osquery/database.h"
#include "osquery/filesystem.h"

namespace osquery {
namespace tables {

#ifdef PROC_EDITCMDLCVT
/// EDITCMDLCVT is available in libprocps3-dev
#define PROC_SELECTS                                                 \
  PROC_FILLCOM | PROC_EDITCMDLCVT | PROC_FILLMEM | PROC_FILLSTATUS | \
      PROC_FILLSTAT
#else
#define PROC_SELECTS \
  PROC_FILLCOM | PROC_FILLMEM | PROC_FILLSTATUS | PROC_FILLSTAT
#endif

std::string proc_name(const proc_t* proc_info) {
  char cmd[17]; // cmd is a 16 char buffer

  memset(cmd, 0, 17);
  memcpy(cmd, proc_info->cmd, 16);
  return std::string(cmd);
}

std::string proc_attr(const std::string& attr, const proc_t* proc_info) {
  std::stringstream filename;

  filename << "/proc/" << proc_info->tid << "/" << attr;
  return filename.str();
}

std::string proc_cmdline(const proc_t* proc_info) {
  std::string attr;
  std::string result;

  attr = proc_attr("cmdline", proc_info);
  std::ifstream fd(attr, std::ios::in | std::ios::binary);
  if (fd) {
    result = std::string(std::istreambuf_iterator<char>(fd),
                         std::istreambuf_iterator<char>());
  }

  return result;
}

std::string proc_link(const proc_t* proc_info) {
  std::string attr;
  std::string result;
  char* link_path;
  long path_max;
  int bytes;

  // The exe is a symlink to the binary on-disk.
  attr = proc_attr("exe", proc_info);
  path_max = pathconf(attr.c_str(), _PC_PATH_MAX);
  link_path = (char*)malloc(path_max);

  memset(link_path, 0, path_max);
  bytes = readlink(attr.c_str(), link_path, path_max);
  if (bytes >= 0) {
    result = std::string(link_path);
  }

  free(link_path);
  return result;
}

std::map<std::string, std::string> proc_env(const proc_t* proc_info) {
  std::map<std::string, std::string> env;
  std::string attr = osquery::tables::proc_attr("environ", proc_info);
  std::string buf;

  uid_t euid = geteuid();
  struct stat info;
  if (stat(filename, &info) == -1) {
    return env;
  }

  // Avoid a non-su block: https://github.com/facebook/osquery/issues/323
  if (euid != 0 && info.st_uid != euid) {
    return env;
  }

  std::ifstream fd(attr, std::ios::in | std::ios::binary);

  while (!fd.eof()) {
    std::getline(fd, buf, '\0');
    size_t idx = buf.find_first_of("=");

    std::string key = buf.substr(0, idx);
    std::string value = buf.substr(idx + 1);

    env[key] = value;
  }
  return env;
}

/**
 * @brief deallocate the space allocated by readproc if the passed rbuf was NULL
 *
 * @param p The rbuf to free
 */
void standard_freeproc(proc_t* p) {
  if (!p) { // in case p is NULL
    return;
  }
  // ptrs are after strings to avoid copying memory when building them.
  // so free is called on the address of the address of strvec[0].
  if (p->cmdline) {
    free((void*)*p->cmdline);
  }
  if (p->environ) {
    free((void*)*p->environ);
  }
  free(p);
}

QueryData genProcesses() {
  QueryData results;

  proc_t* proc_info;
  PROCTAB* proc = openproc(PROC_SELECTS);

  // Populate proc struc for each process.
  while ((proc_info = readproc(proc, NULL))) {
    Row r;

    r["pid"] = boost::lexical_cast<std::string>(proc_info->tid);
    r["name"] = proc_name(proc_info);
    r["cmdline"] = proc_cmdline(proc_info);
    r["path"] = proc_link(proc_info);
    r["on_disk"] = osquery::pathExists(r["path"]).toString();

    r["resident_size"] = boost::lexical_cast<std::string>(proc_info->vm_rss);
    r["phys_footprint"] = boost::lexical_cast<std::string>(proc_info->vm_size);
    r["user_time"] = boost::lexical_cast<std::string>(proc_info->utime);
    r["system_time"] = boost::lexical_cast<std::string>(proc_info->stime);
    r["start_time"] = boost::lexical_cast<std::string>(proc_info->start_time);
    r["parent"] = boost::lexical_cast<std::string>(proc_info->ppid);

    results.push_back(r);
    standard_freeproc(proc_info);
  }

  closeproc(proc);

  return results;
}

QueryData genProcessEnvs() {
  QueryData results;

  proc_t* proc_info;
  PROCTAB* proc = openproc(PROC_SELECTS);

  // Populate proc struc for each process.

  while ((proc_info = readproc(proc, NULL))) {
    auto env = proc_env(proc_info);
    for (auto itr = env.begin(); itr != env.end(); ++itr) {
      Row r;
      r["pid"] = boost::lexical_cast<std::string>(proc_info->tid);
      r["name"] = proc_name(proc_info);
      r["path"] = proc_link(proc_info);
      r["key"] = itr->first;
      r["value"] = itr->second;
      results.push_back(r);
    }

    standard_freeproc(proc_info);
  }

  closeproc(proc);

  return results;
}

QueryData genProcessOpenFiles() {
  QueryData results;
  return results;
}
}
}
<|endoftext|>


<commit_before>#ifndef TIME_UTILS_HPP_INCLUDED
#define TIME_UTILS_HPP_INCLUDED

/**
 @file time_utils.hpp
 @author François Becker

MIT License

Copyright (c) 2015-2017 François Becker

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

#include <cassert>
#include <ctime>

namespace tu
{
    inline std::time_t timeFromYMDString(const char* pString)
    {
        // Time from YYYY-MM-DD
        int lYear, lMonth, lDay;
        sscanf(pString, "%d-%d-%d", &lYear, &lMonth, &lDay);
        struct tm t = {0};
        t.tm_year = lYear - 1900;
        t.tm_mon = lMonth - 1;
        t.tm_mday = lDay;
        t.tm_isdst = -1;
        return mktime(&t);
    }

    inline std::time_t timeFromYMDHMSString(const char* pString)
    {
        // Time from YYYY-mm-DD HH:MM:SS
        int lYear, lMonth, lDay, lHour, lMinute, lSecond;
        sscanf(pString, "%d-%d-%d %d:%d:%d", &lYear, &lMonth, &lDay, &lHour, &lMinute, &lSecond);
        struct tm t = {0};
        t.tm_year = lYear - 1900;
        t.tm_mon = lMonth - 1;
        t.tm_mday = lDay;
        t.tm_hour = lHour;
        t.tm_min = lMinute;
        t.tm_sec = lSecond;
        t.tm_isdst = -1;
        return mktime(&t);
    }

    inline std::time_t timeFromStringDate(const char *time)
    {
        char s_month[5];
        int month, day, year;
        struct tm t = {0};
        static const char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";

        sscanf(time, "%s %d %d", s_month, &day, &year);

        month = (int)(strstr(month_names, s_month)-month_names)/3;

        t.tm_mon = month;
        t.tm_mday = day;
        t.tm_year = year - 1900;
        t.tm_isdst = -1;

        return mktime(&t);
    }
}

#endif
<commit_msg>time_utils.hpp: fixed missing includes<commit_after>#ifndef TIME_UTILS_HPP_INCLUDED
#define TIME_UTILS_HPP_INCLUDED

/**
 @file time_utils.hpp
 @author François Becker

MIT License

Copyright (c) 2015-2017 François Becker

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

#include <ctime>
#include <cstdio>
#include <cstring>
#include <cassert>

namespace tu
{
    inline std::time_t timeFromYMDString(const char* pString)
    {
        // Time from YYYY-MM-DD
        int lYear, lMonth, lDay;
        sscanf(pString, "%d-%d-%d", &lYear, &lMonth, &lDay);
        struct tm t = {0};
        t.tm_year = lYear - 1900;
        t.tm_mon = lMonth - 1;
        t.tm_mday = lDay;
        t.tm_isdst = -1;
        return mktime(&t);
    }

    inline std::time_t timeFromYMDHMSString(const char* pString)
    {
        // Time from YYYY-mm-DD HH:MM:SS
        int lYear, lMonth, lDay, lHour, lMinute, lSecond;
        sscanf(pString, "%d-%d-%d %d:%d:%d", &lYear, &lMonth, &lDay, &lHour, &lMinute, &lSecond);
        struct tm t = {0};
        t.tm_year = lYear - 1900;
        t.tm_mon = lMonth - 1;
        t.tm_mday = lDay;
        t.tm_hour = lHour;
        t.tm_min = lMinute;
        t.tm_sec = lSecond;
        t.tm_isdst = -1;
        return mktime(&t);
    }

    inline std::time_t timeFromStringDate(const char *time)
    {
        char s_month[5];
        int month, day, year;
        struct tm t = {0};
        static const char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";

        sscanf(time, "%s %d %d", s_month, &day, &year);

        month = (int)(strstr(month_names, s_month)-month_names)/3;

        t.tm_mon = month;
        t.tm_mday = day;
        t.tm_year = year - 1900;
        t.tm_isdst = -1;

        return mktime(&t);
    }
}

#endif
<|endoftext|>


<commit_before>// Copyright (C) 2017 Elviss Strazdins
// This file is part of the Ouzel engine.

#include <X11/cursorfont.h>
#include <X11/Xcursor/Xcursor.h>
#include "CursorResourceLinux.h"
#include "core/Engine.h"
#include "core/linux/WindowLinux.h"
#include "utils/Log.h"

namespace ouzel
{
    namespace input
    {
        CursorResourceLinux::~CursorResourceLinux()
        {
            if (sharedEngine)
            {
                WindowLinux* windowLinux = static_cast<WindowLinux*>(sharedEngine->getWindow());
                Display* display = windowLinux->getDisplay();
                if (cursor != None) XFreeCursor(display, cursor);
            }
        }

        bool CursorResourceLinux::upload()
        {
            std::lock_guard<std::mutex> lock(uploadMutex);

            if (dirty)
            {
                if (sharedEngine)
                {
                    WindowLinux* windowLinux = static_cast<WindowLinux*>(sharedEngine->getWindow());
                    Display* display = windowLinux->getDisplay();

                    if (cursor != None)
                    {
                        XFreeCursor(display, cursor);
                        cursor = None;
                    }

                    if (data.empty())
                    {
                        switch (systemCursor)
                        {
                            case SystemCursor::DEFAULT:
                                cursor = XcursorLibraryLoadCursor(display, "arrow");
                                break;
                            case SystemCursor::ARROW:
                                cursor = XcursorLibraryLoadCursor(display, "arrow");
                                break;
                            case SystemCursor::HAND:
                                cursor = XcursorLibraryLoadCursor(display, "hand1");
                                break;
                            case SystemCursor::HORIZONTAL_RESIZE:
                                cursor = XcursorLibraryLoadCursor(display, "sb_h_double_arrow");
                                break;
                            case SystemCursor::VERTICAL_RESIZE:
                                cursor = XcursorLibraryLoadCursor(display, "sb_v_double_arrow");
                                break;
                            case SystemCursor::CROSS:
                                cursor = XcursorLibraryLoadCursor(display, "crosshair");
                                break;
                            case SystemCursor::I_BEAM:
                                cursor = XcursorLibraryLoadCursor(display, "xterm");
                                break;
                        }
                    }
                    else
                    {
                        int width = static_cast<int>(size.v[0]);
                        int height = static_cast<int>(size.v[1]);

                        XcursorImage* cursorImage = XcursorImageCreate(width, height);

                        if (!cursorImage)
                        {
                            Log(Log::Level::ERR) << "Failed to create cursor image";
                            return false;
                        }

                        cursorImage->xhot = static_cast<int>(hotSpot.v[0]);
                        cursorImage->yhot = height - static_cast<int>(hotSpot.v[1]) - 1;
                        cursorImage->delay = 0;

                        for (int i = 0; i < width * height; i++)
                        {
                            cursorImage->pixels[i * 4 + 0] = data[i * 4 + 2];
                            cursorImage->pixels[i * 4 + 1] = data[i * 4 + 1];
                            cursorImage->pixels[i * 4 + 2] = data[i * 4 + 0];
                            cursorImage->pixels[i * 4 + 3] = data[i * 4 + 3];
                        }

                        cursor = X11_XcursorImageLoadCursor(display, cursorImage);

                        X11_XcursorImageDestroy(cursorImage);
                    }
                }

                dirty = false;
            }

            return true;
        }
    } // namespace input
} // namespace ouzel
<commit_msg>Fix typo<commit_after>// Copyright (C) 2017 Elviss Strazdins
// This file is part of the Ouzel engine.

#include <X11/cursorfont.h>
#include <X11/Xcursor/Xcursor.h>
#include "CursorResourceLinux.h"
#include "core/Engine.h"
#include "core/linux/WindowLinux.h"
#include "utils/Log.h"

namespace ouzel
{
    namespace input
    {
        CursorResourceLinux::~CursorResourceLinux()
        {
            if (sharedEngine)
            {
                WindowLinux* windowLinux = static_cast<WindowLinux*>(sharedEngine->getWindow());
                Display* display = windowLinux->getDisplay();
                if (cursor != None) XFreeCursor(display, cursor);
            }
        }

        bool CursorResourceLinux::upload()
        {
            std::lock_guard<std::mutex> lock(uploadMutex);

            if (dirty)
            {
                if (sharedEngine)
                {
                    WindowLinux* windowLinux = static_cast<WindowLinux*>(sharedEngine->getWindow());
                    Display* display = windowLinux->getDisplay();

                    if (cursor != None)
                    {
                        XFreeCursor(display, cursor);
                        cursor = None;
                    }

                    if (data.empty())
                    {
                        switch (systemCursor)
                        {
                            case SystemCursor::DEFAULT:
                                cursor = XcursorLibraryLoadCursor(display, "arrow");
                                break;
                            case SystemCursor::ARROW:
                                cursor = XcursorLibraryLoadCursor(display, "arrow");
                                break;
                            case SystemCursor::HAND:
                                cursor = XcursorLibraryLoadCursor(display, "hand1");
                                break;
                            case SystemCursor::HORIZONTAL_RESIZE:
                                cursor = XcursorLibraryLoadCursor(display, "sb_h_double_arrow");
                                break;
                            case SystemCursor::VERTICAL_RESIZE:
                                cursor = XcursorLibraryLoadCursor(display, "sb_v_double_arrow");
                                break;
                            case SystemCursor::CROSS:
                                cursor = XcursorLibraryLoadCursor(display, "crosshair");
                                break;
                            case SystemCursor::I_BEAM:
                                cursor = XcursorLibraryLoadCursor(display, "xterm");
                                break;
                        }
                    }
                    else
                    {
                        int width = static_cast<int>(size.v[0]);
                        int height = static_cast<int>(size.v[1]);

                        XcursorImage* cursorImage = XcursorImageCreate(width, height);

                        if (!cursorImage)
                        {
                            Log(Log::Level::ERR) << "Failed to create cursor image";
                            return false;
                        }

                        cursorImage->xhot = static_cast<int>(hotSpot.v[0]);
                        cursorImage->yhot = height - static_cast<int>(hotSpot.v[1]) - 1;
                        cursorImage->delay = 0;

                        for (int i = 0; i < width * height; i++)
                        {
                            cursorImage->pixels[i * 4 + 0] = data[i * 4 + 2];
                            cursorImage->pixels[i * 4 + 1] = data[i * 4 + 1];
                            cursorImage->pixels[i * 4 + 2] = data[i * 4 + 0];
                            cursorImage->pixels[i * 4 + 3] = data[i * 4 + 3];
                        }

                        cursor = XcursorImageLoadCursor(display, cursorImage);

                        XcursorImageDestroy(cursorImage);
                    }
                }

                dirty = false;
            }

            return true;
        }
    } // namespace input
} // namespace ouzel
<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <regex>

double interceptXAxis(double m, double c) {
  ///
  /// A function to calculate the intercept on the x-axis of a straight line
  ///
  return c/m;
}

int main(int argc, char *argv[])
{
  // string to decide what to do
  // TODO make it 'human' so that the user could type (e.g.)
  // > Please can I find out the intercept of a straight line on the x-axis
  // and the program knows what to do (by matching 'intercept' and 'x-axis')
  std::string decision;

  std::cout << "Hello World" << std::endl;

  std::cout << "Welcome to PP6Calculator (reborn). "
	    << "Please specify which function you would like to perform: "
	    << std::endl
	    << "> ";
  std::cin >> decision;
  if(std::regex_match(decision, std::regex("(^i$)|(intercept)")))
    {
     std::cout << "You have chosen the intercept function!" << std::endl;
    }
p
  std::cout << "You chose " << decision << std::endl;
  std::cout << "Sorry, I'm not yet complete enough to give you what you want."
	    << std::endl
	    << "Goodbye! I hope to see you again soon!"
	    << std::endl;

  return 0;
}
<commit_msg>Added quadratic solver function to program<commit_after>#include <iostream>
#include <string>
#include <regex>
// #include <cmath>
#include <complex>

double interceptXAxis(double m, double c) {
  ///
  /// A function to calculate the intercept on the x-axis of a straight line
  ///
  return c/m;
}

struct quadraticRoots
{
  std::complex<double> root1,root2;
};

std::ostream& operator<<(std::ostream& s, const quadraticRoots& c)
{
  ///
  /// Be smart about what to print when it comes to roots of quadratic equations
  ///
  if(c.root1 == c.root2 && c.root1.imag() != 0)
    s << c.root1 << " (repeated root)";
  else if(c.root1 == c.root2 && c.root1.imag() == 0)
    s << c.root1.real() << " (repeated root)";
  else if(c.root1.imag() == 0 || c.root2.imag() == 0)
    s << c.root1.real() << " and " << c.root2.real();
  else 				// all that's left is root1, root2 are complex
    s << c.root1 << " and " << c.root2;
  return s;
}

quadraticRoots quadraticSolver(double aReal, double bReal, double cReal)
{
  quadraticRoots roots = quadraticRoots();
  roots.root1 = std::complex<double>(0,0);
  roots.root2 = std::complex<double>(0,0);

  std::complex<double> a = aReal;
  std::complex<double> b = bReal;
  std::complex<double> c = cReal;

  if((b*b - 4.0*a*c) == std::complex<double>(0,0))
    {
      roots.root1 = (-b)/(2.0*a);
      roots.root2 = roots.root1;
    }
  else
    {
      roots.root1 = (-b+sqrt(b*b-4.0*a*c))/(2.0*a);
      roots.root2 = (-b-sqrt(b*b-4.0*a*c))/(2.0*a);
    }
    return roots;
}

void coutChosen(std::string x)
{
  ///
  /// Function to cout "You have chosen the [x] function"
  ///
  std::cout << "You have chosen the " << x << " function!" << std::endl;
}

int main(int argc, char *argv[])
{
  // string to decide what to do
  // TODO make it 'human' so that the user could type (e.g.)
  // > Please can I find out the intercept of a straight line on the x-axis
  // and the program knows what to do (by matching 'intercept' and 'x-axis')
  std::string decision;

  std::cout << "Hello World" << std::endl;

  std::cout << "Welcome to PP6Calculator (reborn). "
	    << "Please specify which function you would like to perform: "
	    << std::endl
	    << "> ";

  std::getline(std::cin,decision);

  if(std::regex_match(decision, std::regex("(^i$)|(.*intercept.*)")))
    {
      // initialise variables for y=mx+c
      double m,c;

      coutChosen("intercept");
      std::cout << "Please specify a gradient (m): ";
      std::cin >> m;
      std::cout << "Please specify an intercept (c): " << std::endl;
      std::cin >> c;
      std::cout << "The x intercept for the line y = " << m << "x + " << c
		<< " is " << interceptXAxis(m,c) << "." << std::endl;
    }
  else if(std::regex_match(decision, std::regex("(^q$)|(.*quadratic.*)")))
    {
      // Initialise variables for (-b±√(b^2 - 4ac))/(2a)
      double a, b, c;

      coutChosen("quadratic solver");
      std::cout << "Choose the x^2 term (a): " << std::endl << "> ";
      std::cin >> a;
      std::cout << "Choose the x term (b): " << std::endl << "> ";
      std::cin >> b;
      std::cout << "Choose the constant term (c): " << std::endl << "> ";
      std::cin >> c;

      std::cout << "The roots for your chosen quadratic are  "
		<< quadraticSolver(a,b,c) << std::endl;
    }
  else
    {
      std::cout << "You chose " << decision << std::endl;
      std::cout << "Sorry, I'm not yet complete enough to give you what you want."
		<< std::endl;
    }
  return 0;
}
<|endoftext|>