Tuesday, May 16, 2017

It's a notes about Erlang. It's a generator that uses a lazy calculating.

Hello my young Erlang programmers!























































It's a result (I apologize for the strange syntax highlighting):

bodro@vbodrov-pc:~/workspace/develop/test/test58$ erl
Erlang/OTP 18 [erts-7.3] [source] [64-bit] [smp:8:8] [async-threads:10] [kernel-poll:false]

Eshell V7.3  (abort with ^G)
1> c(test).
{ok,test}
2> test:test_all().
TEST #1
0:10   -> [0,1,2,3,4,5,6,7,8,9]
1000:5 -> [1000,1001,1002,1003,1004]
1:2    -> [1,2]
1:1    -> [1]
1:0    -> []
TEST #2
0:10   -> [0,1,2,3,4,5,6,7,8,9]
1000:5 -> [1000,1001,1002,1003,1004]
1:2    -> [1,2]
1:1    -> [1]
1:0    -> []
TEST #3
0:10   -> [0,1,2,3,4,5,6,7,8,9]
1000:5 -> [1000,1001,1002,1003,1004]
1:2    -> [1,2]
1:1    -> [1]
1:0    -> []
TEST #4
0:10   -> true
1000:5 -> true
1:2    -> true
1:1    -> true
1:0    -> true
TEST #5
0:10   -> true
1000:5 -> true
1:2    -> true
1:1    -> true
1:0    -> true
TEST #6
0:10   -> true
1000:5 -> true
1:2    -> true
1:1    -> true
1:0    -> true
TEST #7
0:10   -> true
1000:5 -> true
1:2    -> true
1:1    -> true
1:0    -> true
ok
3> q().
ok
4> bodro@vbodrov-pc:~/workspace/develop/test/test58$

Best regards,
Vasiliy V. Bodrov aka Bodro,
May 16, 2017.

GNU Compiler Collection: extensions, nested functions, object-oriented programming, functional paradigm etc. It's the C language only!

Hello my dear frineds!

I want to tell you about possibilities of the C language. I will do it with the example of a linear list.

You can see the links:
All GCC Extensions
Nested Functions

So. It's a structure of the linked list:
    struct storage_data_s {
        value_t                value;
        char*                  name;
        char*                  comment;
        struct storage_data_s* next;
    }* data;

It's a structure of the storage with the linked list:
/* It's a storage */
typedef struct storage_s {
    struct storage_data_s {
        value_t                value;
        char*                  name;
        char*                  comment;
        struct storage_data_s* next;
    }* data;

    void (*init)(struct storage_s* _this);
    
    void (*add)(struct storage_s* _this,
                value_t _value,
                char* _name,
                char* _comment);
    
    void (*for_each)(struct storage_s const* _this,
                     output_f output);
    
    void (*clear)(struct storage_s* _this);
    
    void (*deinit)(struct storage_s* _this);
}      storage_t,
      *storage_p,
     **storage_pp,
*const storage_cp;

typedef storage_t const* storage_pc;
typedef storage_t const* const storage_cpc;

The first argument of all functions is a pointer to "this" (self, this etc).

This is the complete text of the code (I apologize for the strange syntax highlighting):

storage.h:
/* ****************************************************************************
 * Programmer: Vasiliy V. Bodrov aka Bodro
 * May 15, 2016.
 * ****************************************************************************
 * The MIT License (MIT)
 *
 * Copyright (c) 2016 Vasiliy V. Bodrov aka Bodro
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * 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.
 **************************************************************************** */

#pragma once

#include <stdbool.h>

/* It's a type of value */
typedef void* value_t;
typedef void** value_p;
typedef void const* value_tc;

/* The user must to determine these functions */
#ifndef __STORAGE_C_FILE__
typedef struct __value_user_helpers_handlers_s {
    value_t (*new)(user_value_t _uv);
    user_value_t (*get)(value_tc _v);
    user_value_t (*get2)(value_tc _v, user_value_t _container);
}  __value_user_helpers_handlers_t,
  *__value_user_helpers_handlers_p;
#else /* __STORAGE_C_FILE__ */
typedef void*  __value_user_helpers_handlers_p;
#endif /* __STORAGE_C_FILE__ */

typedef struct value_handlers_s {
    void (*delete)(value_p _v);
    value_t (*copy)(value_tc _v);
    value_t (*move)(value_p _v);
    bool (*p_move)(void); /* predicate */
    
    __value_user_helpers_handlers_p x;
} value_handlers_t;

#ifdef __STORAGE_C_FILE__
value_handlers_t __value_helpers_handlers;
#else /* __STORAGE_C_FILE__ */
extern value_handlers_t __value_helpers_handlers;
#endif /* __STORAGE_C_FILE__ */

/* This type is pointer to output function */
typedef void (*output_f)(value_t _value,
                         char const* _name,
                         char const* _comment);

/* It's a storage */
typedef struct storage_s {
    struct storage_data_s {
        value_t                value;
        char*                  name;
        char*                  comment;
        struct storage_data_s* next;
    }* data;

    void (*init)(struct storage_s* _this);
    
    void (*add)(struct storage_s* _this,
                value_t _value,
                char* _name,
                char* _comment);
    
    void (*for_each)(struct storage_s const* _this,
                     output_f output);
    
    void (*clear)(struct storage_s* _this);
    
    void (*deinit)(struct storage_s* _this);
}      storage_t,
      *storage_p,
     **storage_pp,
*const storage_cp;

typedef storage_t const* storage_pc;
typedef storage_t const* const storage_cpc;

/* These are creator and remover */
storage_p storage_creator(void);
void storage_remover(storage_pp);

/* ****************************************************************************
 * End of file
 **************************************************************************** */



storage.c:
/* ****************************************************************************
 * Programmer: Vasiliy V. Bodrov aka Bodro
 * May 15, 2016.
 * ****************************************************************************
 * The MIT License (MIT)
 *
 * Copyright (c) 2016 Vasiliy V. Bodrov aka Bodro
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * 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.
 **************************************************************************** */

#define __STORAGE_C_FILE__

#include "storage.h"

#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdbool.h>

static void handler_init(struct storage_s*);
static void handler_add(struct storage_s*, value_t, char*, char*);
static void handler_for_each(struct storage_s const*, output_f);
static void handler_clear(struct storage_s*);
static void handler_deinit(struct storage_s*);

/* 
 * These are exported functions
 */
storage_p storage_creator(void) {
    storage_p _storage = NULL;
    
    _storage = (storage_p) calloc(1, sizeof(storage_t));
    assert(_storage);

    if(_storage) {
        _storage->init     = handler_init;
        _storage->add      = handler_add;
        _storage->for_each = handler_for_each;
        _storage->clear    = handler_clear;
        _storage->deinit   = handler_deinit;

        _storage->init(_storage);
    }
            
    return _storage;
}

void storage_remover(storage_pp _storage) {
    assert(*_storage);

    if(*_storage) {
        if((*_storage)->deinit) {
            (*_storage)->deinit(*_storage);
        }

        free(*_storage);
        
        *_storage = NULL;
    }
}

/* 
 * These are static (internal) functions
 */

void handler_init(struct storage_s* _this) {
    assert(_this);
    
    _this->clear(_this);
    _this->data = NULL;
}

void handler_add(struct storage_s* _this,
                 value_t _value, char* _name, char* _comment) {
    assert(_this);

    auto struct storage_data_s* _search_end(struct storage_data_s*);
    auto struct storage_data_s* _allocator(struct storage_data_s*);
    auto void _add(struct storage_data_s*);
    auto value_t _copy(value_p _value);

    _add(_allocator(_search_end(_this->data)));

    struct storage_data_s* _search_end(struct storage_data_s* _) {
        if(!_ || !_->next) return _;
        return _search_end(_->next);
    }

    struct storage_data_s* _allocator(struct storage_data_s* _) {
        struct storage_data_s* _new =
            (struct storage_data_s*) calloc(1, sizeof(struct storage_data_s));
        assert(_new);

        if(_) _->next = _new;
        else _this->data = _new;

        return _new;
    }

    void _add(struct storage_data_s* _) {
        assert(_);
        
        _->value   = _copy(&_value);
        _->name    = (_name) ? strdup(_name) : NULL;
        _->comment = (_comment) ? strdup(_comment) : NULL;
        _->next    = NULL;
    }
    
    value_t _copy(value_p _value) {
        return (__value_helpers_handlers.p_move()) ?
            __value_helpers_handlers.move(_value) :
            __value_helpers_handlers.copy(*_value);
    }
}

void handler_for_each(struct storage_s const* _this,
                      output_f _output)
{
    assert(_this);
    assert(_output);

    auto void _f(struct storage_data_s*);

    _f(_this->data);

    void _f(struct storage_data_s* _) {
        if(!_) return;
        _output(_->value, _->name, _->comment);
        _f(_->next);
    }
}

void handler_clear(struct storage_s* _this)
{
    assert(_this);

    auto void _purge(struct storage_data_s*);

    _purge(_this->data);

    _this->data = NULL;

    void _purge(struct storage_data_s* _)
    {
        if(!_) return;

        if(_->name) {
            free(_->name);
        }

        if(_->comment) {
            free(_->comment);
        }

        __value_helpers_handlers.delete(&(_->value));
        _->value   = NULL;
        _->name    = NULL;
        _->comment = NULL;

        /* Note. It isn't a tail call! I can do the tail recursion,
         * but I don't want this. So I use direct recursion. Bodro.
         */
        _purge(_->next);

        _->next = NULL;
        free(_);
        _ = NULL;
    }
}

void handler_deinit(struct storage_s* _this)
{
    assert(_this);
    
    _this->clear(_this);
    _this->data = NULL;
}

#ifdef __STORAGE_C_FILE__
#undef __STORAGE_C_FILE__
#endif /* __STORAGE_C_FILE__ */

/* ****************************************************************************
 * End of file
 **************************************************************************** */



test.c:
/* ****************************************************************************
 * Programmer: Vasiliy V. Bodrov aka Bodro
 * May 15, 2016.
 * ****************************************************************************
 * The MIT License (MIT)
 *
 * Copyright (c) 2016 Vasiliy V. Bodrov aka Bodro
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * 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 <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>

/* BEGIN >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */
/* We prepare the user types and functions */
struct string_s;

typedef struct string_func_s {
    char* (*s_new)(struct string_s* _this, char const* _s);
    char const* (*s_get)(struct string_s* _this);
    void (*s_del)(struct string_s* _this);
} string_func_t;

typedef struct string_s {
    struct string_s* _self;     /* It's a pointer to yourself */
    char* s;                    /* It's a date (string) */
    struct string_func_s* f;    /* It's a pointer to table of functions */
} string;

typedef string user_value_t;

#include "storage.h"
/* END <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */

string new_string(string_func_t* _f);
string new_string2(string_func_t* _f, char const* _v);
void del_string(string* _s);

inline static char* handler_s_new(struct string_s*, char const*);
inline static char const* handler_s_get(struct string_s*);
inline static void handler_s_del(struct string_s*);

void user_handler_delete(value_p);
value_t user_handler_copy(value_tc);
value_t user_handler_move(value_p);
value_t user_handler_new(user_value_t);
user_value_t user_handler_get(value_tc);
user_value_t user_handler_get2(value_tc, user_value_t);

string new_string(string_func_t* _f) {
    string* _s = malloc(sizeof(string));
    
    assert(_s);

    _s->_self = _s;
    _s->s = NULL;
    _s->f = _f;

    return *_s;
}

string new_string2(string_func_t* _f, char const* _v) {
    string s = new_string(_f);
    s.f->s_new(s._self, _v);
    return s;
}

void del_string(string* _s) {
    if(_s) {
        _s->f->s_del(_s);
        _s->f = NULL;
        _s->_self = NULL;
        free(_s);
    }
}

char* handler_s_new(struct string_s* _this, char const* _s) {
    assert(_this);
    if(_this && _this->s) _this->f->s_del(_this);
    _this->s = (_s) ? strdup(_s) : NULL;
    return _this->s;
}

char const* handler_s_get(struct string_s* _this) {
    assert(_this);
    return _this->s;
}

void handler_s_del(struct string_s* _this) {
    assert(_this);
    if(_this && _this->s) {
        free(_this->s);
        _this->s = NULL;
    }
}

void user_handler_delete(value_p _v) {
    if(_v && *_v) {
        del_string((string*) *_v);
        *_v = NULL;
    }
}

value_t user_handler_copy(value_tc _v) {
    string s_old = user_handler_get(_v);
    string s_new = new_string2(s_old.f, s_old.f->s_get(s_old._self));
    return user_handler_new(s_new);
}

value_t user_handler_move(value_p _v) {
    assert(_v);
    string s_old = user_handler_get(*_v);
    string s_new = new_string2(s_old.f, s_old.f->s_get(s_old._self));
    del_string(s_old._self);
    
    return user_handler_new(s_new);
}

value_t user_handler_new(user_value_t _uv) {
    return (value_t) _uv._self;
}

user_value_t user_handler_get(value_tc _v) {
    assert(_v);
    return *((string*) _v);
}

user_value_t user_handler_get2(value_tc _v, user_value_t _container) {
    (void) _container;
    return user_handler_get(_v);
}

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

    auto bool p_true(void);
    auto bool p_false(void);
    
    string_func_t s_func;
    
    s_func.s_new = handler_s_new;
    s_func.s_get = handler_s_get;
    s_func.s_del = handler_s_del;

    __value_user_helpers_handlers_t user_helpers;

    user_helpers.new    = user_handler_new;
    user_helpers.get    = user_handler_get;
    user_helpers.get2   = user_handler_get2;
    
    __value_helpers_handlers.delete = user_handler_delete;
    __value_helpers_handlers.copy   = user_handler_copy;
    __value_helpers_handlers.move   = user_handler_move;
    __value_helpers_handlers.x      = &user_helpers;

    /* It's a work (#1) */
    do {
        storage_p storage = storage_creator();

        do {
            /* We don't use "move". We use "copy"*/
            __value_helpers_handlers.p_move = p_false;
            
            string data = new_string2(&s_func, "> ");
            storage->add(storage,
                         __value_helpers_handlers.x->new(data), NULL, NULL);
            del_string(data._self);
        } while(0);

        /* We don't use "copy". We use "move"*/
        __value_helpers_handlers.p_move = p_true;
        
        storage->add(storage,
                     __value_helpers_handlers.x->new(
                         new_string2(&s_func, "Hello")), NULL, NULL);
        storage->add(storage,
                     __value_helpers_handlers.x->new(
                         new_string2(&s_func, ",")), NULL, NULL);
        storage->add(storage,
                     __value_helpers_handlers.x->new(
                         new_string2(&s_func, " ")), NULL, NULL);
        storage->add(storage,
                     __value_helpers_handlers.x->new(
                         new_string2(&s_func, "World")), NULL, NULL);
        storage->add(storage,
                     __value_helpers_handlers.x->new(
                         new_string2(&s_func, "!")), NULL, NULL);
        
        void output1(value_t _value,
                     char const* _name,
                     char const* _comment) {
            (void) _name; (void) _comment;
            string s = __value_helpers_handlers.x->get(_value);
            (void) printf("%s", s.f->s_get(s._self));
        }

        storage->for_each(storage, output1);
        (void) puts("");
        
        storage_remover(&storage);
    } while(0);
    /* It's the end of work */

    bool p_true(void) {
        return true;
    }
    
    bool p_false(void) {
        return false;
    }
    
    return EXIT_SUCCESS;
}

/* ****************************************************************************
 * End of file
 **************************************************************************** */


build.sh:
#! /bin/bash

# To use:
# $ rm -f test; clear; ./build.sh; ./test
# $ rm -f test; clear; ./build.sh; valgrind ./test
# $ rm -f test; clear; ./build.sh; valgrind --leak-check=full ./test

gcc -std=gnu99 -Wall -Wextra storage.c test.c -lm -lc -o test
#gcc -std=gnu99 -Wall -Wextra -Wtrampolines storage.c test.c -lm -lc -o test


It's a result (without Valgrind):

bodro@vbodrov-pc:~/workspace/develop/test/test62$ rm -f test; ./build.sh; ./test
> Hello, World!
bodro@vbodrov-pc:~/workspace/develop/test/test62$

It's a result (with Valgrind):

bodro@vbodrov-pc:~/workspace/develop/test/test62$ rm -f test; ./build.sh; valgrind --leak-check=full ./test
==23326== Memcheck, a memory error detector
==23326== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==23326== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==23326== Command: ./test
==23326== 
> Hello, World!
==23326== 
==23326== HEAP SUMMARY:
==23326==     in use at exit: 0 bytes in 0 blocks
==23326==   total heap usage: 32 allocs, 32 frees, 1,594 bytes allocated
==23326== 
==23326== All heap blocks were freed -- no leaks are possible
==23326== 
==23326== For counts of detected and suppressed errors, rerun with: -v
==23326== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
bodro@vbodrov-pc:~/workspace/develop/test/test62$

Best regards,
Vasiliy V. Bodrov aka Bodro,
May 15-16, 2017.

How do you swap two variable?

Hi!

How do you swap two variable?

Look at this! It's a C++ code.
#include <iostream>

using namespace std;

inline void swap_var(int& _x, int& _y) {
    int _ = _x; _x = _y; _y = _;
}

inline void swap_xor(int& _x, int& _y) {
    _x ^= _y; _y ^= _x; _x ^= _y;
}

inline void swap_math(int& _x, int& _y) {
    _x += _y; _y = _x - _y; _x -= _y;
}

int main(void) {
    int a = 5;
    int b = 77201;

    cout << a << ":" << b << endl;
    swap_var(a, b);
    cout << a << ":" << b << endl;
    swap_xor(a, b);
    cout << a << ":" << b << endl;
    swap_math(a, b);
    cout << a << ":" << b << endl;
}


It's the result:
$ rm -f t; g++ -Wall -Wextra -Werror -O2 t.cpp -o t; ./t;
5:77201
77201:5
5:77201
77201:5
$


This is a C code.
#include <stdlib.h>
#include <stdio.h>

void swap_var(int* _x, int* _y) {
    int _ = *_x; *_x = *_y; *_y = _;
}

void swap_xor(int* _x, int* _y) {
    *_x ^= *_y; *_y ^= *_x; *_x ^= *_y;
}

void swap_math(int* _x, int* _y) {
    *_x += *_y; *_y = *_x - *_y; *_x -= *_y;
}

int main(void) {
    int a = 5;
    int b = 77201;

    (void) printf("%d:%d\n", a, b);
    swap_var(&a, &b);
    (void) printf("%d:%d\n", a, b);
    swap_xor(&a, &b);
    (void) printf("%d:%d\n", a, b);
    swap_math(&a, &b);
    (void) printf("%d:%d\n", a, b);

    return EXIT_SUCCESS;
}


It's the result:
$ rm -f t; gcc -Wall -Wextra -Werror -O2 t.c -o t; ./t
5:77201
77201:5
5:77201
77201:5
$

And finally, Erlang :)
-module(t).
-export([t/0]).

swap({X, Y}) ->
    {Y, X}.

t() ->
    A = {1, 2},
    swap(A).

It's the result:
$ erl
Erlang/OTP 18 [erts-7.3] [source] [64-bit] [smp:8:8] [async-threads:10] [kernel-poll:false]

Eshell V7.3  (abort with ^G)
1> c(t).
{ok,t}
2> t:t().
{2,1}
3> q().
ok
4> $

Best regards,
Vasiliy V. Bodrov aka Bodro,
May 16, 2017.

Friday, May 12, 2017

It's a notes about Erlang. It's a work with "crypto" (DES CBC).

Hi, my readers!

I continue the experiments with Erlang. Today I want to introduce a code that works with library "crypto".
I'm trying to encrypt any strings. I'm using DES CBC algorithm.

Look at this!

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Module: des.erl
% Description: it's a program for a work with crypto module (tests)
% Author: Vasiliy V. Bodrov aka Bodro (bodrov@qtech.ru)
% Date: it's the 19-th of April, 2017 year
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% The MIT License (MIT)
%
% Copyright (c) 2017 Vasiliy V. Bodrov aka Bodro
%
% Permission is hereby granted, free of charge, to any person obtaining a
% copy of this software and associated documentation files (the "Software"),
% 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.
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% See: http://directory.fsf.org/wiki/License:Expat
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

-module(des).
-export([test/0, license/0]).
-vsn(1.0).

-define(BLOCK_SIZE, 8).
-define(INPUT_PROMPT, "    Input data: ").

test() ->
    io:format("*****************************************************~n", []),
    io:format("TEST #1:~n~n", []),
    test_impl(),
    io:format("*****************************************************~n", []).

test_impl() ->
    Key = <<16#01,16#23,16#45,16#67,16#89,16#ab,16#cd,16#ef>>,
    IVec = <<16#12,16#34,16#56,16#78,16#90,16#ab,16#cd,16#ef>>,
    Str = io:get_line(?INPUT_PROMPT),
    P = normalize_str(Str),
    C = crypto:block_encrypt(des_cbc, Key, IVec, P),
    R = crypto:block_decrypt(des_cbc, Key, IVec, C),
    print({P, C, R}).

print({P, C, R}) ->
    io:format("    --------------------------------------------~n", []),
    io:format("    Source: ~p~n", [P]),
    io:format("    --------------------------------------------~n", []),
    io:format("    Source as string: ~p~n", [denormalize_str(P)]),
    io:format("    --------------------------------------------~n", []),
    io:format("    Encrypted: ~p~n", [C]),
    io:format("    --------------------------------------------~n", []),
    io:format("    Decrypted: ~p~n", [R]),
    io:format("    --------------------------------------------~n", []),
    io:format("    Decrypted as string: ~p~n", [denormalize_str(erlang:binary_to_list(R))]).

list_size(L) when is_list(L) ->
    list_size_impl(L, 0).

list_size_impl([], S) ->
    S;
list_size_impl([_|T], S) ->
    list_size_impl(T, S + 1).

normalize_str([]) ->
    [];
normalize_str(L) when is_list(L)->
    C = list_size(L) rem ?BLOCK_SIZE,
    normalizator(L, ?BLOCK_SIZE - C).
    
normalizator(L, 0) ->
    L;
normalizator(L, N) ->
    normalizator(L ++ [0], N - 1).

denormalize_str([]) ->
    [];
denormalize_str(L) when is_list(L) ->
    denormalizator(L, []).

denormalizator([], X) ->
    X;
denormalizator([0|_], X) ->
    X;
denormalizator([10|_], X) ->
    X;
denormalizator([H|T], X) ->
    denormalizator(T, X ++ [H]).

license() ->
    io:format(" The MIT License (MIT)~n"),
    io:format("~n"),
    io:format(" Copyright (c) 2017 Vasiliy V. Bodrov aka Bodro~n"),
    io:format("~n"),
    io:format(" Permission is hereby granted, free of charge, to any person obtaining a~n"),
    io:format(" copy of this software and associated documentation files (the \"Software\"),~n"),
    io:format(" Software is furnished to do so, subject to the following conditions:~n"),
    io:format("~n"),
    io:format(" The above copyright notice and this permission notice shall be included~n"),
    io:format(" in all copies or substantial portions of the Software.~n"),
    io:format("~n"),
    io:format(" THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS~n"),
    io:format(" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF~n"),
    io:format(" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.~n"),
    io:format(" IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY~n"),
    io:format(" CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT~n"),
    io:format(" OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR~n"),
    io:format(" THE USE OR OTHER DEALINGS IN THE SOFTWARE.").
    
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% End of file
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%



It's a result:
bodro@vbodrov-pc:~/workspace/develop/test/test56$ erl
Erlang/OTP 18 [erts-7.3] [source] [64-bit] [smp:8:8] [async-threads:10] [kernel-poll:false]

Eshell V7.3  (abort with ^G)
1> des:license().
 The MIT License (MIT)

 Copyright (c) 2017 Vasiliy V. Bodrov aka Bodro

 Permission is hereby granted, free of charge, to any person obtaining a
 copy of this software and associated documentation files (the "Software"),
 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.ok
2> des:test().
*****************************************************
TEST #1:

    Input data: Hello, world!
    --------------------------------------------
    Source: [72,101,108,108,111,44,32,119,111,114,108,100,33,10,0,0]
    --------------------------------------------
    Source as string: "Hello, world!"
    --------------------------------------------
    Encrypted: <<202,49,22,168,11,91,77,221,161,37,37,51,151,179,205,184>>
    --------------------------------------------
    Decrypted: <<72,101,108,108,111,44,32,119,111,114,108,100,33,10,0,0>>
    --------------------------------------------
    Decrypted as string: "Hello, world!"
*****************************************************
ok
3> q().
ok
4> bodro@vbodrov-pc:~/workspace/develop/test/test56$

See you later! Bye! :)

Best regards,
Vasiliy V. Bodrov aka Bodro,
May 12, 2017.

Thursday, May 11, 2017

I want to tell you a little about myself

Hello dear friends!

My name is Vasiliy. My last name is Bodrov. I was born in the USSR (Russia) in 1984 year. I am a programmer, blogger and motorist. I have got accounts in many social networks.

Blogger (this blog) (English):
http://bodro-ipbsoftware.blogspot.com

LinkedIn (Russian, English):

Facebook (Russian, English):

Twitter (Russian, English):

Instagram (Russian, English):

Github (Russian, English):
https://github.com/vasiliybodrov

VKontakte (Russian):

Odnoklassniki (Russian):

LiveJournal (Russian):

I like to play guitar. Also I like to repair and tune cars. I really love cats and all animals in general. But the most of all I love cats. I have got several cats. I don't like a war. And I'm kind of cosmopolite.

In Myers–Briggs type indicator I'm an Intuitive Logical Extrovert (ENTP). I'm proud of it. ENTP is a fairly rare type in MBTI.

I'm a professional programmer. I like different programming languages, computer technology and I like to study a foundations of programming languages. I know quite a few programming languages, e.g.: C, C++, Linux shell (bash, sh, dash, ash, sed, awk etc), Erlang, Java, LISP (Common LISP, Scheme), JavaScript, Pascal, PHP, Assembler (x86), MS-DOS shell, Could Fusion, HTML, XHTML, HTML5, XUL, XSLT, CSS, ADA, BASIC, PL/1, Prolog, SQL, several DSL, VBA, .NET/C#, Python, Perl, Lua, Haskell, Brainfuck, Brainloller etc. But, having written the word "I know", I exaggerated a little. :) I just used these languages. However many of them I know quite well. I enjoy when I make code on C++ and Erlang! I love this languages! I just love them! And I very love GNU/Linux. Also I used many library in my work and hobby, e.g.: STL, Boost, Qt4, OpenGL, OpenCL, OpenMP, ExtJS, ExtGWT, GWT, Swing, AWT, Spring, VCL, Qt5, MFC, LibVLC, GTK, Android SDK, Nexgen TCP/IP stack, QDBus, libdbus, libxml2, Erlang/OTP, ZeroC ICE, PGQ, libcurl, Broadcom SDK, Zend Framework etc. But this doesn't mean that I know them all perfectly. I just use them at my work, hobby and for training. However many of them I know quite well. E.g. STL, Boost, Qt4 etc. I very like a functional paradigm and object-oriented programming. I enjoy programming!

I think that I told quite a lot about myself. See you later! Bye!




Best regards,
Vasiliy V. Bodrov aka Bodro,
the 11-th of May, 2017 year.

How to create a final class in C ++? Do you know?

Hi, my dear hackers!

We continue to talk about C++.
I assume you know the Java programming language. And also I assume you know keyword final. But do you think we can use it in C++? I mean the standard of the 98-th year (ISO/IEC 14882:1998). It turns out you can!

Look at this!


I'm trying to compile and run this code. I use GNU compiler and GNU/Linux as the operation system. I know and like them!

$ g++ -Wall -Wextra -Werror -o final final.cpp
$ ./final 
cons Lock
cons A
$ g++ -Wall -Wextra -Werror -o final final.cpp -DI_WANT_ERROR
final.cpp: In constructor 'B::B()':
final.cpp:13:2: error: 'Lock::Lock()' is private
  Lock() { cout << "cons Lock" << endl; }
  ^
final.cpp:26:6: error: within this context
  B() { cout << "cons B" << endl; }
      ^
$

You can see that we have an error when we use macro I_WANT_ERROR. Why?

The constructor of the class Lock cant't be called by the child classes. However class A is a friend of class Lock. So we can create an instance of class A because the constructor of class A can call the constructor of class Lock. Do you agree with me? I continue. But if we don't use a virtual inheritance we can create an instance of class B, because the constructor of class B can call the constructor of class A and the constructor of class A can call the constructor of class Lock. It's confusing and difficult, isn't it? But if you understand everything is simple.

Look at this: B -> A -> Lock.
It's OK? Do you understand me?

But if we use the virtual inheritance the constructor of class B must call the constructor of class Lock directly! But it can't do it because it doesn't have access to it (I mean the constructor of class Lock) because the constructor of class Lock is private and class B isn't a friend of class Lock. It's a very simple, my dear friend! And it's great!

This reaction as the final keywords applied to the class, isn't it? Do you agree with me? :)


Best regards,
Vasiliy V. Bodrov aka Bodro,
the 10-11-th of May, 2017 year.

Wednesday, May 10, 2017

It's my Python experience. IGMP generator. Version 0.11 (MIT License).

Hi, my dear friends!

This is a code of the next version of the program with name "IGMP generator". Do you remember my first experience with Python? It's my second Python experience.
I wrote this code after the 12-th of June 2015 year, when I created my first Python program (IGMP generator version 0.1).

I apologize for the strange syntax highlighting and ugly formatting.

#! /usr/bin/env python

# ******************************************************************************
# Program name: igmp_generator
# Description: IGMP packet generator for IPv4
# Version: 0.11 (Hydrocyclone-2)
# Author: Vasiliy V. Bodrov aka Bodro (mailto:mobile.ipbsoftware@gmail.com)
# Date: 12.06.2015
# Programming language: Python
# Commenting language: English
# ******************************************************************************
# The MIT License (MIT)
#
# Copyright (c) 2015 IPB Software (Vasiliy V. Bodrov aka Bodro)
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# 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.
# ******************************************************************************

# ******************************************************************************
# Import
# ******************************************************************************

import getopt, sys
from struct import *
from socket import socket, inet_aton, htons, AF_PACKET, SOCK_RAW

# ******************************************************************************
# Global variable
# ******************************************************************************

# Self variable
version_num_str = '0.11'
version_name = 'Hydrocyclone-2'

# Common variable
common_interface = "eth0"

# Layer 2
l2_header = 0x00;

l2_src_addr1 = 0x02 
l2_src_addr2 = 0x01
l2_src_addr3 = 0x02
l2_src_addr4 = 0x03
l2_src_addr5 = 0x04
l2_src_addr6 = 0x05

l2_dst_addr1 = 0x01
l2_dst_addr2 = 0x02
l2_dst_addr3 = 0x03
l2_dst_addr4 = 0x04
l2_dst_addr5 = 0x05
l2_dst_addr6 = 0x06

l2_ether_type = 0x0800

# Layer 3 (IP)
l3_ip_v4_header = 0x00

l3_ip_v4_source = '192.168.0.1'
l3_ip_v4_dest = '224.0.0.22'

l3_ip_v4_ihl = 5
l3_ip_v4_ver = 4
l3_ip_v4_tos = 0
l3_ip_v4_tot_len = 0
l3_ip_v4_id = 54321
l3_ip_v4_frag_off = 0
l3_ip_v4_ttl = 1
l3_ip_v4_proto = 2
l3_ip_v4_check = 0

l3_ip_v4_saddr = 0x00
l3_ip_v4_daddr = 0x00
l3_ip_v4_ihl_ver = 0x00

# Layer 3 (IGMP)
l3_igmp_data = 0x00

l3_igmp_v3_t22 = 0x00

l3_igmp_v3_t22_prefix = 0x00

l3_igmp_v3_t22_group_record1 = 0x00

l3_igmp_v3_t22_group_record1_src_addr1 = 0x00000000
l3_igmp_v3_t22_group_record1_src_addr2 = 0x00000000
l3_igmp_v3_t22_group_record1_src_addr3 = 0x00000000
l3_igmp_v3_t22_group_record1_src_addr4 = 0x00000000
l3_igmp_v3_t22_group_record1_src_addr5 = 0x00000000

l3_igmp_v3_t22_type = 0x22
l3_igmp_v3_t22_reserved = 0x00
l3_igmp_v3_t22_check = 0x0000
l3_igmp_v3_t22_reserved = 0x0000
l3_igmp_v3_t22_num_of_grp_rec = 0x0001;

l3_igmp_v3_t22_group_record1_rec_type = 0x00
l3_igmp_v3_t22_group_record1_aux_data_len = 0x00
l3_igmp_v3_t22_group_record1_num_of_src = 0x0001
l3_igmp_v3_t22_group_record1_milticast_addr1 = 0xE0
l3_igmp_v3_t22_group_record1_milticast_addr2 = 0x01
l3_igmp_v3_t22_group_record1_milticast_addr3 = 0x01
l3_igmp_v3_t22_group_record1_milticast_addr4 = 0x01
l3_igmp_v3_t22_group_record1_aux_data = 0x00

l3_igmp_v3_t22_group_record1_src_addr1_1 = 0xC0
l3_igmp_v3_t22_group_record1_src_addr1_2 = 0xA8
l3_igmp_v3_t22_group_record1_src_addr1_3 = 0x01
l3_igmp_v3_t22_group_record1_src_addr1_4 = 0x01

l3_igmp_v3_t22_group_record1_src_addr2_1 = 0xC0
l3_igmp_v3_t22_group_record1_src_addr2_2 = 0xA8
l3_igmp_v3_t22_group_record1_src_addr2_3 = 0x01
l3_igmp_v3_t22_group_record1_src_addr2_4 = 0x02

l3_igmp_v3_t22_group_record1_src_addr3_1 = 0xC0
l3_igmp_v3_t22_group_record1_src_addr3_2 = 0xA8
l3_igmp_v3_t22_group_record1_src_addr3_3 = 0x01
l3_igmp_v3_t22_group_record1_src_addr3_4 = 0x03

l3_igmp_v3_t22_group_record1_src_addr4_1 = 0xC0
l3_igmp_v3_t22_group_record1_src_addr4_2 = 0xA8
l3_igmp_v3_t22_group_record1_src_addr4_3 = 0x01
l3_igmp_v3_t22_group_record1_src_addr4_4 = 0x04

l3_igmp_v3_t22_group_record1_src_addr5_1 = 0xC0
l3_igmp_v3_t22_group_record1_src_addr5_2 = 0xA8
l3_igmp_v3_t22_group_record1_src_addr5_3 = 0x01
l3_igmp_v3_t22_group_record1_src_addr5_4 = 0x05

# ******************************************************************************
# Code
# ******************************************************************************

# ------------------------------------------------------------------------------
# Function: version
# Description: show version info
# ------------------------------------------------------------------------------
def version():
    print("Program: " + sys.argv[0])
    print("version " + version_num_str + ' (' + version_name + ')')
    print("IGMP packet generator for IPv4")
    print("Note: This version support only IGMPv3 (over IPv4) and packet type 0x22 (Membership Report Message)")
    print("Limits: Max group: 1. Max source in group: 5.");

# ------------------------------------------------------------------------------
# Function: authors
# Description: show authors
# ------------------------------------------------------------------------------
def authors():
    version()
    print("Author: Vasiliy V. Bodrov aka Bodro (mailto:mobile.ipbsoftware@gmail.com)");
    
# ------------------------------------------------------------------------------
# Function: license
# Description: show license
# ------------------------------------------------------------------------------
def license():
    version()
    print("")
    print("The MIT License (MIT)")
    print("")
    print("Copyright (c) 2015 IPB Software (Vasiliy V. Bodrov aka Bodro)")
    print("")
    print("Permission is hereby granted, free of charge, to any person obtaining a")
    print("copy of this software and associated documentation files (the \"Software\"),")
    print("Software is furnished to do so, subject to the following conditions:")
    print("")
    print("The above copyright notice and this permission notice shall be included")
    print("in all copies or substantial portions of the Software.")
    print("")
    print("THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS")
    print("OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF")
    print("MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.")
    print("IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY")
    print("CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT")
    print("OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR")
    print("THE USE OR OTHER DEALINGS IN THE SOFTWARE.")

# ------------------------------------------------------------------------------
# Function: usage
# Description:
# ------------------------------------------------------------------------------
def usage():
    print("Use --help or -h for help")
    print("Example: " + sys.argv[0] + " --help")

# ------------------------------------------------------------------------------
# Function: help
# Description:
# ------------------------------------------------------------------------------
def help():
    version();
    print("");
    print(sys.argv[0] + " [OPTIONS]");
    print("");
    print("-h,\t--help\t\t\t\t- show this help and exit");
    print("-v,\t--version\t\t\t- show version and exit");
    print("-a,\t--authors\t\t\t- show authors and exit");
    print("-l,\t--license\t\t\t- show license and exit");
    print("-i,\t--interface=INTERFACE\t\t- network interface (default: " + common_interface + ")");
    print("\t--ip-src=IP\t\t\t- source IP-address (default: " + l3_ip_v4_source + ")");
    print("\t--ip-dst=IP\t\t\t- destination IP-address (default: " + l3_ip_v4_dest + ")");
    print("\t--mac-src=MAC\t\t\t- source MAC-address (default: " + format(l2_src_addr1, '02x') + ":" + format(l2_src_addr2, '02x') + ":" + format(l2_src_addr3, '02x') + ":" + format(l2_src_addr4, '02x') + ":" + format(l2_src_addr5, '02x') + ":" + format(l2_src_addr6, '02x') + ")");
    print("\t--mac-dst=MAC\t\t\t- destination MAC-address (default: " + format(l2_dst_addr1, '02x') + ":" + format(l2_dst_addr2, '02x') + ":" + format(l2_dst_addr3, '02x') + ":" + format(l2_dst_addr4, '02x') + ":" + format(l2_dst_addr5, '02x') + ":" + format(l2_dst_addr6, '02x') + ")");
    print("\t--ttl=NUM\t\t\t- time to live (default: " + format(l3_ip_v4_ttl, 'd') + ")");
    print("\t--gr1-rec-type=NUM\t\t- record type (group record 1) (default: " + format(l3_igmp_v3_t22_group_record1_rec_type, 'd') + ")");
    print("\t--gr1-mult-addr=IP\t\t- multicast (group) address (group record 1) (default: " + format(l3_igmp_v3_t22_group_record1_milticast_addr1, 'd') + "." + format(l3_igmp_v3_t22_group_record1_milticast_addr2, 'd') + "." + format(l3_igmp_v3_t22_group_record1_milticast_addr3, 'd') + "." + format(l3_igmp_v3_t22_group_record1_milticast_addr4, 'd') + ")");
    print("\t--gr1-num-of-src=NUM\t\t- number of sources (group record 1) (default: " + format(l3_igmp_v3_t22_group_record1_num_of_src, 'd') + ")");
    print("\t--gr1-src-addr1=IP\t\t- source address 1 (group record 1) (default: " + format(l3_igmp_v3_t22_group_record1_src_addr1_1, 'd') + "." + format(l3_igmp_v3_t22_group_record1_src_addr1_2, 'd') + "." + format(l3_igmp_v3_t22_group_record1_src_addr1_3, 'd') + "." + format(l3_igmp_v3_t22_group_record1_src_addr1_4, 'd')  + ")");
    print("\t--gr1-src-addr2=IP\t\t- source address 2 (group record 1) (default: " + format(l3_igmp_v3_t22_group_record1_src_addr2_1, 'd') + "." + format(l3_igmp_v3_t22_group_record1_src_addr2_2, 'd') + "." + format(l3_igmp_v3_t22_group_record1_src_addr2_3, 'd') + "." + format(l3_igmp_v3_t22_group_record1_src_addr2_4, 'd') + ")");
    print("\t--gr1-src-addr3=IP\t\t- source address 3 (group record 1) (default: " + format(l3_igmp_v3_t22_group_record1_src_addr3_1, 'd') + "." + format(l3_igmp_v3_t22_group_record1_src_addr3_2, 'd') + "." + format(l3_igmp_v3_t22_group_record1_src_addr3_3, 'd') + "." + format(l3_igmp_v3_t22_group_record1_src_addr3_4, 'd') + ")");
    print("\t--gr1-src-addr4=IP\t\t- source address 4 (group record 1) (default: " + format(l3_igmp_v3_t22_group_record1_src_addr4_1, 'd') + "." + format(l3_igmp_v3_t22_group_record1_src_addr4_2, 'd') + "." + format(l3_igmp_v3_t22_group_record1_src_addr4_3, 'd') + "." + format(l3_igmp_v3_t22_group_record1_src_addr4_4, 'd') + ")");
    print("\t--gr1-src-addr5=IP\t\t- source address 5 (group record 1) (default: " + format(l3_igmp_v3_t22_group_record1_src_addr5_1, 'd') + "." + format(l3_igmp_v3_t22_group_record1_src_addr5_2, 'd') + "." + format(l3_igmp_v3_t22_group_record1_src_addr5_3, 'd') + "." + format(l3_igmp_v3_t22_group_record1_src_addr5_4, 'd') + ")");
    print("");
    print("Record type:");
    print("");
    print("0 - Unknown (0x00)");
    print("1 - Mode Is Include (0x01)");
    print("2 - Mode Is Exclude (0x02)");
    print("3 - Change To Include Mode (0x03)");
    print("4 - Change To Exclude Mode (0x04)");
    print("5 - Allow New Sources (0x05)");
    print("6 - Block Old Sources (0x06)");
    print("");
    print("Example: " + "\n\t# " + sys.argv[0] + " \\\n\t\t\
--interface=eth0 \\\n\t\t\
--ip-src=\"200.100.1.1\" \\\n\t\t\
--ip-dst=\"224.0.0.22\" \\\n\t\t\
--mac-src=\"23:A1:01:02:02:05\" \\\n\t\t\
--mac-dst=\"F0:FA:00:05:07:FF\" \\\n\t\t\
--gr1-rec-type=\"2\" \\\n\t\t\
--gr1-mult-addr=\"225.1.2.3\" \\\n\t\t\
--gr1-num-of-src=5 \\\n\t\t\
--gr1-src-addr1=\"127.0.0.1\" \\\n\t\t\
--gr1-src-addr2=\"127.0.0.2\" \\\n\t\t\
--gr1-src-addr3=\"127.0.0.3\" \\\n\t\t\
--gr1-src-addr4=\"127.0.0.4\" \\\n\t\t\
--gr1-src-addr5=\"127.0.0.5\" \\\n\t\t\
--ttl=1")

# ------------------------------------------------------------------------------
# Function: checksum
# Description: calculate checksum
# ------------------------------------------------------------------------------
def checksum(msg):
    s = 0x0000
     
    for i in range(0, len(msg), 2):
        w = ord(msg[i]) + (ord(msg[i + 1]) << 8)
        s = s + w
     
    s = (s >> 16) + (s & 0xFFFF);
    s = s + (s >> 16);
     
    s = ~s & 0xFFFF
     
    return s
    
# ------------------------------------------------------------------------------
# Function: data_send
# Description:
# ------------------------------------------------------------------------------
def data_send():
    global version_num_str
    global version_name

    global common_interface

    global l2_header

    global l2_src_addr1
    global l2_src_addr2
    global l2_src_addr3
    global l2_src_addr4
    global l2_src_addr5
    global l2_src_addr6

    global l2_dst_addr1
    global l2_dst_addr2
    global l2_dst_addr3
    global l2_dst_addr4
    global l2_dst_addr5
    global l2_dst_addr6

    global l2_ether_type

    global l3_ip_v4_header

    global l3_ip_v4_source
    global l3_ip_v4_dest

    global l3_ip_v4_ihl
    global l3_ip_v4_ver
    global l3_ip_v4_tos
    global l3_ip_v4_tot_len
    global l3_ip_v4_id
    global l3_ip_v4_frag_off
    global l3_ip_v4_ttl
    global l3_ip_v4_proto
    global l3_ip_v4_check

    global l3_ip_v4_saddr
    global l3_ip_v4_daddr
    global l3_ip_v4_ihl_ver

    global l3_igmp_data

    global l3_igmp_v3_t22

    global l3_igmp_v3_t22_prefix

    global l3_igmp_v3_t22_group_record1

    global l3_igmp_v3_t22_group_record1_src_addr1
    global l3_igmp_v3_t22_group_record1_src_addr2
    global l3_igmp_v3_t22_group_record1_src_addr3
    global l3_igmp_v3_t22_group_record1_src_addr4
    global l3_igmp_v3_t22_group_record1_src_addr5

    global l3_igmp_v3_t22_type
    global l3_igmp_v3_t22_reserved
    global l3_igmp_v3_t22_check
    global l3_igmp_v3_t22_reserved
    global l3_igmp_v3_t22_num_of_grp_rec

    global l3_igmp_v3_t22_group_record1_rec_type
    global l3_igmp_v3_t22_group_record1_aux_data_len
    global l3_igmp_v3_t22_group_record1_num_of_src
    global l3_igmp_v3_t22_group_record1_milticast_addr1
    global l3_igmp_v3_t22_group_record1_milticast_addr2
    global l3_igmp_v3_t22_group_record1_milticast_addr3
    global l3_igmp_v3_t22_group_record1_milticast_addr4
    global l3_igmp_v3_t22_group_record1_aux_data

    global l3_igmp_v3_t22_group_record1_src_addr1_1
    global l3_igmp_v3_t22_group_record1_src_addr1_2
    global l3_igmp_v3_t22_group_record1_src_addr1_3
    global l3_igmp_v3_t22_group_record1_src_addr1_4

    global l3_igmp_v3_t22_group_record1_src_addr2_1
    global l3_igmp_v3_t22_group_record1_src_addr2_2
    global l3_igmp_v3_t22_group_record1_src_addr2_3
    global l3_igmp_v3_t22_group_record1_src_addr2_4

    global l3_igmp_v3_t22_group_record1_src_addr3_1
    global l3_igmp_v3_t22_group_record1_src_addr3_2
    global l3_igmp_v3_t22_group_record1_src_addr3_3
    global l3_igmp_v3_t22_group_record1_src_addr3_4

    global l3_igmp_v3_t22_group_record1_src_addr4_1
    global l3_igmp_v3_t22_group_record1_src_addr4_2
    global l3_igmp_v3_t22_group_record1_src_addr4_3
    global l3_igmp_v3_t22_group_record1_src_addr4_4

    global l3_igmp_v3_t22_group_record1_src_addr5_1
    global l3_igmp_v3_t22_group_record1_src_addr5_2
    global l3_igmp_v3_t22_group_record1_src_addr5_3
    global l3_igmp_v3_t22_group_record1_src_addr5_4

    l3_ip_v4_saddr = inet_aton(l3_ip_v4_source)
    l3_ip_v4_daddr = inet_aton(l3_ip_v4_dest)
    l3_ip_v4_ihl_ver = (l3_ip_v4_ver << 4) + l3_ip_v4_ihl

    l2_header = pack('!BBBBBBBBBBBBH',\
                 l2_dst_addr1,\
                 l2_dst_addr2,\
                 l2_dst_addr3,\
                 l2_dst_addr4,
                 l2_dst_addr5,
                 l2_dst_addr6,
                 l2_src_addr1,
                 l2_src_addr2,
                 l2_src_addr3,
                 l2_src_addr4,
                 l2_src_addr5,
                 l2_src_addr6,
                 l2_ether_type)

    l3_ip_v4_header = pack('!BBHHHBBH4s4s',\
                 l3_ip_v4_ihl_ver,\
                 l3_ip_v4_tos,\
                 l3_ip_v4_tot_len,\
                 l3_ip_v4_id,\
                 l3_ip_v4_frag_off,\
                 l3_ip_v4_ttl,\
                 l3_ip_v4_proto,\
                 l3_ip_v4_check,\
                 l3_ip_v4_saddr,\
                 l3_ip_v4_daddr)

    l3_igmp_v3_t22_prefix = pack('!BBHHH',\
                 l3_igmp_v3_t22_type,\
                 l3_igmp_v3_t22_reserved,\
                 l3_igmp_v3_t22_check,\
                 l3_igmp_v3_t22_reserved,\
                 l3_igmp_v3_t22_num_of_grp_rec)

    l3_igmp_v3_t22_group_record1_src_addr1 = pack('!BBBB',\
                l3_igmp_v3_t22_group_record1_src_addr1_1,\
                l3_igmp_v3_t22_group_record1_src_addr1_2,\
                l3_igmp_v3_t22_group_record1_src_addr1_3,\
                l3_igmp_v3_t22_group_record1_src_addr1_4)

    l3_igmp_v3_t22_group_record1_src_addr2 = pack('!BBBB',\
                l3_igmp_v3_t22_group_record1_src_addr2_1,\
                l3_igmp_v3_t22_group_record1_src_addr2_2,\
                l3_igmp_v3_t22_group_record1_src_addr2_3,\
                l3_igmp_v3_t22_group_record1_src_addr2_4)

    l3_igmp_v3_t22_group_record1_src_addr3 = pack('!BBBB',\
                l3_igmp_v3_t22_group_record1_src_addr3_1,\
                l3_igmp_v3_t22_group_record1_src_addr3_2,\
                l3_igmp_v3_t22_group_record1_src_addr3_3,\
                l3_igmp_v3_t22_group_record1_src_addr3_4)

    l3_igmp_v3_t22_group_record1_src_addr4 = pack('!BBBB',\
                l3_igmp_v3_t22_group_record1_src_addr4_1,\
                l3_igmp_v3_t22_group_record1_src_addr4_2,\
                l3_igmp_v3_t22_group_record1_src_addr4_3,\
                l3_igmp_v3_t22_group_record1_src_addr4_4)

    l3_igmp_v3_t22_group_record1_src_addr5 = pack('!BBBB',\
                l3_igmp_v3_t22_group_record1_src_addr5_1,\
                l3_igmp_v3_t22_group_record1_src_addr5_2,\
                l3_igmp_v3_t22_group_record1_src_addr5_3,\
                l3_igmp_v3_t22_group_record1_src_addr5_4)

    l3_igmp_v3_t22_group_record1 = pack('!BBHBBBB',\
                l3_igmp_v3_t22_group_record1_rec_type,\
                l3_igmp_v3_t22_group_record1_aux_data_len,\
                l3_igmp_v3_t22_group_record1_num_of_src,\
                l3_igmp_v3_t22_group_record1_milticast_addr1,\
                l3_igmp_v3_t22_group_record1_milticast_addr2,\
                l3_igmp_v3_t22_group_record1_milticast_addr3,\
                l3_igmp_v3_t22_group_record1_milticast_addr4)

    if(l3_igmp_v3_t22_group_record1_num_of_src >= 1):
        l3_igmp_v3_t22_group_record1 = l3_igmp_v3_t22_group_record1 + l3_igmp_v3_t22_group_record1_src_addr1

    if(l3_igmp_v3_t22_group_record1_num_of_src >= 2):
        l3_igmp_v3_t22_group_record1 = l3_igmp_v3_t22_group_record1 + l3_igmp_v3_t22_group_record1_src_addr2

    if(l3_igmp_v3_t22_group_record1_num_of_src >= 3):
        l3_igmp_v3_t22_group_record1 = l3_igmp_v3_t22_group_record1 + l3_igmp_v3_t22_group_record1_src_addr3

    if(l3_igmp_v3_t22_group_record1_num_of_src >= 4):
        l3_igmp_v3_t22_group_record1 = l3_igmp_v3_t22_group_record1 + l3_igmp_v3_t22_group_record1_src_addr4

    if(l3_igmp_v3_t22_group_record1_num_of_src >= 5):
        l3_igmp_v3_t22_group_record1 = l3_igmp_v3_t22_group_record1 + l3_igmp_v3_t22_group_record1_src_addr5

    if(l3_igmp_v3_t22_group_record1_num_of_src >= 6):
        print("Support only 5 source addresses")

    l3_igmp_v3_t22 = l3_igmp_v3_t22_prefix + l3_igmp_v3_t22_group_record1

    l3_igmp_data = l3_igmp_v3_t22

    # IGMP checksum calculate
    
    l3_igmp_v3_t22_check = htons(checksum(l3_igmp_v3_t22))
    
    l3_igmp_v3_t22_prefix = pack('!BBHHH',\
                 l3_igmp_v3_t22_type,\
                 l3_igmp_v3_t22_reserved,\
                 l3_igmp_v3_t22_check,\
                 l3_igmp_v3_t22_reserved,\
                 l3_igmp_v3_t22_num_of_grp_rec)
                 
    l3_igmp_v3_t22 = l3_igmp_v3_t22_prefix + l3_igmp_v3_t22_group_record1

    l3_igmp_data = l3_igmp_v3_t22
    
    s = socket(AF_PACKET, SOCK_RAW)

    s.bind((common_interface, 0))

    s.send(l2_header + l3_ip_v4_header + l3_igmp_data)

# ------------------------------------------------------------------------------
# Function: main
# Description:
# ------------------------------------------------------------------------------
def main():
    global common_interface

    global l3_ip_v4_source
    global l3_ip_v4_dest

    global l3_ip_v4_ttl

    global l2_src_addr1 
    global l2_src_addr2
    global l2_src_addr3
    global l2_src_addr4
    global l2_src_addr5
    global l2_src_addr6

    global l2_dst_addr1
    global l2_dst_addr2
    global l2_dst_addr3
    global l2_dst_addr4
    global l2_dst_addr5
    global l2_dst_addr6

    global l3_igmp_v3_t22_group_record1_rec_type

    global l3_igmp_v3_t22_group_record1_milticast_addr1
    global l3_igmp_v3_t22_group_record1_milticast_addr2
    global l3_igmp_v3_t22_group_record1_milticast_addr3
    global l3_igmp_v3_t22_group_record1_milticast_addr4

    global l3_igmp_v3_t22_group_record1_num_of_src

    global l3_igmp_v3_t22_group_record1_src_addr1_1
    global l3_igmp_v3_t22_group_record1_src_addr1_2
    global l3_igmp_v3_t22_group_record1_src_addr1_3
    global l3_igmp_v3_t22_group_record1_src_addr1_4

    global l3_igmp_v3_t22_group_record1_src_addr2_1
    global l3_igmp_v3_t22_group_record1_src_addr2_2
    global l3_igmp_v3_t22_group_record1_src_addr2_3
    global l3_igmp_v3_t22_group_record1_src_addr2_4

    global l3_igmp_v3_t22_group_record1_src_addr3_1
    global l3_igmp_v3_t22_group_record1_src_addr3_2
    global l3_igmp_v3_t22_group_record1_src_addr3_3
    global l3_igmp_v3_t22_group_record1_src_addr3_4

    global l3_igmp_v3_t22_group_record1_src_addr4_1
    global l3_igmp_v3_t22_group_record1_src_addr4_2
    global l3_igmp_v3_t22_group_record1_src_addr4_3
    global l3_igmp_v3_t22_group_record1_src_addr4_4

    global l3_igmp_v3_t22_group_record1_src_addr5_1
    global l3_igmp_v3_t22_group_record1_src_addr5_2
    global l3_igmp_v3_t22_group_record1_src_addr5_3
    global l3_igmp_v3_t22_group_record1_src_addr5_4

    try:
        opts, args = getopt.getopt(sys.argv[1:], "hvali:",\
              ["help",\
              "version",\
              "authors",\
              "license",\
              "interface=",\
              "ip-src=",\
              "ip-dst=",\
              "mac-src=",\
              "mac-dst=",\
              "ttl=",\
              "gr1-rec-type=",\
              "gr1-mult-addr=",\
              "gr1-num-of-src=",\
              "gr1-src-addr1=",\
              "gr1-src-addr2=",\
              "gr1-src-addr3=",\
              "gr1-src-addr4=",\
              "gr1-src-addr5="] )
    except getopt.GetoptError as err:
        print(err) # will print something like "option -a not recognized"
        usage()
        sys.exit(2)

    for o, a in opts:
        if o == "-v":
            version()
            sys.exit()
        elif o in ("-a", "--authors"):
            authors()
            sys.exit()
        elif o in ("-h", "--help"):
            help()
            sys.exit()
        elif o in ("-v", "--version"):
            version()
            sys.exit()
        elif o in ("-l", "--license"):
            license()
            sys.exit()
        elif o in ("-i", "--interface"):
            common_interface = a
        elif o in ("--ip-src"):
            l3_ip_v4_source = a
        elif o in ("--ip-dst"):
            l3_ip_v4_dest = a
        elif o in ("--mac-src"):
            mac_src = a.split(':')

            l2_src_addr1 = int(mac_src[0], 16)
            l2_src_addr2 = int(mac_src[1], 16)
            l2_src_addr3 = int(mac_src[2], 16)
            l2_src_addr4 = int(mac_src[3], 16)
            l2_src_addr5 = int(mac_src[4], 16)
            l2_src_addr6 = int(mac_src[5], 16)
        elif o in ("--mac-dst"):
            mac_dst = a.split(":")

            l2_dst_addr1 = int(mac_dst[0], 16)
            l2_dst_addr2 = int(mac_dst[1], 16)
            l2_dst_addr3 = int(mac_dst[2], 16)
            l2_dst_addr4 = int(mac_dst[3], 16)
            l2_dst_addr5 = int(mac_dst[4], 16)
            l2_dst_addr6 = int(mac_dst[5], 16)
        elif o in ("--ttl"):
            l3_ip_v4_ttl = int(a, 10)
        elif o in ("--gr1-rec-type"):
            l3_igmp_v3_t22_group_record1_rec_type = int(a, 16)
        elif o in ("--gr1-mult-addr"):
            gr1_milticast_address = a.split(".")

            l3_igmp_v3_t22_group_record1_milticast_addr1 = int(gr1_milticast_address[0], 10)
            l3_igmp_v3_t22_group_record1_milticast_addr2 = int(gr1_milticast_address[1], 10)
            l3_igmp_v3_t22_group_record1_milticast_addr3 = int(gr1_milticast_address[2], 10)
            l3_igmp_v3_t22_group_record1_milticast_addr4 = int(gr1_milticast_address[3], 10)
        elif o in ("--gr1-num-of-src"):
            if(int(a, 10) > 5):
                print("Support only 5 source addresses")
                sys.exit()

            l3_igmp_v3_t22_group_record1_num_of_src = int(a, 10)
        elif o in ("--gr1-src-addr1"):
            gr1_source_address1 = a.split(".")

            l3_igmp_v3_t22_group_record1_src_addr1_1 = int(gr1_source_address1[0], 10)
            l3_igmp_v3_t22_group_record1_src_addr1_2 = int(gr1_source_address1[1], 10)
            l3_igmp_v3_t22_group_record1_src_addr1_3 = int(gr1_source_address1[2], 10)
            l3_igmp_v3_t22_group_record1_src_addr1_4 = int(gr1_source_address1[3], 10)
        elif o in ("--gr1-src-addr2"):
            gr1_source_address2 = a.split(".")

            l3_igmp_v3_t22_group_record1_src_addr2_1 = int(gr1_source_address2[0], 10)
            l3_igmp_v3_t22_group_record1_src_addr2_2 = int(gr1_source_address2[1], 10)
            l3_igmp_v3_t22_group_record1_src_addr2_3 = int(gr1_source_address2[2], 10)
            l3_igmp_v3_t22_group_record1_src_addr2_4 = int(gr1_source_address2[3], 10)
        elif o in ("--gr1-src-addr3"):
            gr1_source_address3 = a.split(".")

            l3_igmp_v3_t22_group_record1_src_addr3_1 = int(gr1_source_address3[0], 10)
            l3_igmp_v3_t22_group_record1_src_addr3_2 = int(gr1_source_address3[1], 10)
            l3_igmp_v3_t22_group_record1_src_addr3_3 = int(gr1_source_address3[2], 10)
            l3_igmp_v3_t22_group_record1_src_addr3_4 = int(gr1_source_address3[3], 10)
        elif o in ("--gr1-src-addr4"):
            gr1_source_address4 = a.split(".")

            l3_igmp_v3_t22_group_record1_src_addr4_1 = int(gr1_source_address4[0], 10)
            l3_igmp_v3_t22_group_record1_src_addr4_2 = int(gr1_source_address4[1], 10)
            l3_igmp_v3_t22_group_record1_src_addr4_3 = int(gr1_source_address4[2], 10)
            l3_igmp_v3_t22_group_record1_src_addr4_4 = int(gr1_source_address4[3], 10)
        elif o in ("--gr1-src-addr5"):
            gr1_source_address5 = a.split(".")

            l3_igmp_v3_t22_group_record1_src_addr5_1 = int(gr1_source_address5[0], 10)
            l3_igmp_v3_t22_group_record1_src_addr5_2 = int(gr1_source_address5[1], 10)
            l3_igmp_v3_t22_group_record1_src_addr5_3 = int(gr1_source_address5[2], 10)
            l3_igmp_v3_t22_group_record1_src_addr5_4 = int(gr1_source_address5[3], 10)

        else:
            assert False, "unhandled option"

    data_send()    
    
# ------------------------------------------------------------------------------
# Run
# ------------------------------------------------------------------------------
main()

# ******************************************************************************
# End of file
# ******************************************************************************

I try to run program with --help option:
bodro@vbodrov-pc:~/workspace/develop/igmp_generator/igmp_generator_0.11$ ./igmp_generator.py --help
Program: ./igmp_generator.py
version 0.11 (Hydrocyclone-2)
IGMP packet generator for IPv4
Note: This version support only IGMPv3 (over IPv4) and packet type 0x22 (Membership Report Message)
Limits: Max group: 1. Max source in group: 5.

./igmp_generator.py [OPTIONS]

-h,     --help                          - show this help and exit
-v,     --version                       - show version and exit
-a,     --authors                       - show authors and exit
-l,     --license                       - show license and exit
-i,     --interface=INTERFACE           - network interface (default: eth0)
        --ip-src=IP                     - source IP-address (default: 192.168.0.1)
        --ip-dst=IP                     - destination IP-address (default: 224.0.0.22)
        --mac-src=MAC                   - source MAC-address (default: 02:01:02:03:04:05)
        --mac-dst=MAC                   - destination MAC-address (default: 01:02:03:04:05:06)
        --ttl=NUM                       - time to live (default: 1)
        --gr1-rec-type=NUM              - record type (group record 1) (default: 0)
        --gr1-mult-addr=IP              - multicast (group) address (group record 1) (default: 224.1.1.1)
        --gr1-num-of-src=NUM            - number of sources (group record 1) (default: 1)
        --gr1-src-addr1=IP              - source address 1 (group record 1) (default: 192.168.1.1)
        --gr1-src-addr2=IP              - source address 2 (group record 1) (default: 192.168.1.2)
        --gr1-src-addr3=IP              - source address 3 (group record 1) (default: 192.168.1.3)
        --gr1-src-addr4=IP              - source address 4 (group record 1) (default: 192.168.1.4)
        --gr1-src-addr5=IP              - source address 5 (group record 1) (default: 192.168.1.5)

Record type:

0 - Unknown (0x00)
1 - Mode Is Include (0x01)
2 - Mode Is Exclude (0x02)
3 - Change To Include Mode (0x03)
4 - Change To Exclude Mode (0x04)
5 - Allow New Sources (0x05)
6 - Block Old Sources (0x06)

Example: 
        # ./igmp_generator.py \
                --interface=eth0 \
                --ip-src="200.100.1.1" \
                --ip-dst="224.0.0.22" \
                --mac-src="23:A1:01:02:02:05" \
                --mac-dst="F0:FA:00:05:07:FF" \
                --gr1-rec-type="2" \
                --gr1-mult-addr="225.1.2.3" \
                --gr1-num-of-src=5 \
                --gr1-src-addr1="127.0.0.1" \
                --gr1-src-addr2="127.0.0.2" \
                --gr1-src-addr3="127.0.0.3" \
                --gr1-src-addr4="127.0.0.4" \
                --gr1-src-addr5="127.0.0.5" \
                --ttl=1
bodro@vbodrov-pc:~/workspace/develop/igmp_generator/igmp_generator_0.11$

I try to run program with --license option:
bodro@vbodrov-pc:~/workspace/develop/igmp_generator/igmp_generator_0.11$ ./igmp_generator.py --license
Program: ./igmp_generator.py
version 0.11 (Hydrocyclone-2)
IGMP packet generator for IPv4
Note: This version support only IGMPv3 (over IPv4) and packet type 0x22 (Membership Report Message)
Limits: Max group: 1. Max source in group: 5.

The MIT License (MIT)

Copyright (c) 2015 IPB Software (Vasiliy V. Bodrov aka Bodro)

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
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.
bodro@vbodrov-pc:~/workspace/develop/igmp_generator/igmp_generator_0.11$

You must know that IGMP generator both versions is my first Python programs. Be lenient :)

See ya! :)

Best regards,
Vasiliy V. Bodrov aka Bodro,
the 10-th of May, 2017 year.

How to reverse singly linked list in C (trivial way)

There is a beautiful morning. It's snowing. And I decided to write one more article. Today it will be just simple article where I would...