Month: December 2014

Free software licenses (Copyleft, GPL, LGPL, BSD, Apache, MIT/X11, …)

  • GPL/GPL@wiki is one of many free software licenses. It covers derivative work with a Copyleft and not end-user licensing (for now), so it doesn’t cover for example the use of GCC compiler to compile your close-source product.
    • Your product must also be GPL if change or include GPL source code (no need to ask for permissions) or if link statically (or also dynamically according to FSF interpretation).
    • GPLv2 vs GPLv3: addresses patents, license compatibility, DRM, and “Tivo-ization” hardware.
  • LGPL – Lesser GPL relaxes and allows free libraries to be used (linked statically or dinamically) and distributed with proprietary software. For example, GNU Libc used by Linux is LGPL, otherwise closed-source products couldn’t legally run under Linux.

  • AGPL – Affero General Public License is GPL plus addicional section to trigger copyleft to application service providers. It requires that the complete source code be made available to any network user of the AGPL-licensed work, typically a Web application.

  • BSD licenses are a family of permissive free software licenses, imposing minimal restrictions on the redistribution of covered software. The revised/modivied 3-clauses license allows unlimited redistribution for any purpose as long as its copyright notices and the license’s disclaimers of warranty are maintained. The license also contains a clause restricting use of the names of contributors for endorsement of a derived work without specific permission. Apache 2.0 license is better for substantial programs, since it prevents patent treachery.

  • MIT/X11 license is permissive license, very similar to 3-causes “modified” BSD license, except that the BSD license contains a notice prohibiting the use of the name of the copyright holder in promotion.

  • Apache License is permissive in that it does not require a derivative work of the software, or modifications to the original, to be distributed using the same license. It still requires application of the same license to all unmodified parts and, in every licensed file, any original copyright, patent, trademark, and attribution notices in redistributed code must be preserved (excluding notices that do not pertain to any part of the derivative works); and, in every licensed file changed, a notification must be added stating that changes have been made to that file.

  • MPL – Mozilla Public License partial copyleft, hybridization of the modified BSD license and GNU General Public License (GPL) that seeks to balance the concerns of proprietary and open source developers. The MPL allows covered source code to be mixed with other files under a different, even proprietary license.

See choosing an OSS license and comparison of free and open-source software licenses.

Advertisements

How to protect servers (ssh, apache, asterisk, …) from brute-force attacks (using fail2ban)

## install
$ sudo yum install failban (EPEL) | sudo apt-get install fail2ban

## configure fail2bain, in '/etc/fail2ban/jail.conf'
$ cat /etc/fail2ban/jail.conf
...
# 1 - generic configuration
# "bantime" is the number of seconds that a host is banned
bantime  = 600
# ip addresses that should be excluded from fail2ban rules
ignoreip = 127.0.0.1/8
# A host is banned if it has generated "maxretry" during the last "findtime" seconds.
findtime = 600
maxretry = 3
...
# 2 - define ban actions
# config file in '/etc/fail2ban/action.d' used when ban is needed; default uses iptables to ban an IP on all ports when it fails authentication
banaction = iptables-multiport
# calls banaction script; default is 'action_' which passes the name, port, protocol, and chain to the script; other values are 'action_mw' to ban and send an e-mail
action_ = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%($
action = %(action_)s

# 3 - application-specific jails
[ssh]
enabled  = true
port     = ssh
# file in '/etc/fail2ban/filter.d' telling how to parse the log file, see failregex in '/etc/fail2ban/filter.d/sshd.conf'
filter   = sshd
# what files to parse for failures
logpath  = /var/log/auth.log

## configure firewall, iptables in our case
$ cat /etc/fail2ban/action.d/iptables-multiport.conf
...
# commands executed when fail2ban starts and stop; it creates a new chain for given port (see above)
actionstart/actionstop = ...
# commands executed when banning and unbanning an ip; basically drops the packet 
actionban = iptables -I fail2ban-<name> 1 -s <ip> -j DROP
actionunban = iptables -D fail2ban-<name> -s <ip> -j <blocktype>

$ sudo service fail2ban restart
$ sudo iptables -L
Chain INPUT (policy ACCEPT)
fail2ban-ssh  tcp  --  anywhere             anywhere             multiport dports ssh
...
Chain fail2ban-ssh (1 references)
DROP       all  --  xxx-xxxxxxxx.dyn.xxxxxxxxx.net  anywhere            
RETURN     all  --  anywhere             anywhere

from How To Protect SSH with fail2ban on Debian 7

# enable predefined Apache jails, if not already enabled
$ cat /etc/fail2ban/jail.conf
# detect password authentication failures
[apache]
enabled  = true
...
[apache-multiport]
enabled = true
...
# uses default action, otherwise set
$ cat /etc/fail2ban/jail.conf
[DEFAULT]
banaction = iptables-multiport
$ sudo systemctl restart fail2ban | sudo service fail2ban restart

# check and manage Fail2ban banning status
$ sudo fail2ban-client status
# ban/unban a given IP address
$ sudo fail2ban-client set [name-of-jail] banip [ip-address]

from How to configure fail2ban to protect Apache HTTP server

Same but for asterisk both with and without Asterisk Security Framework (Asterisk 10+)

$ cat /etc/fail2ban/filter.d/asterisk.conf
[Definition]
# regex to match the password failures messages in the logfile. The host must be matched by a group named "host". 
# The tag "<HOST>" can be used for standard IP/hostname matching and is only an alias for (?:::f{4,6}:)?(?P<host>S+)
# without asterisk security framework
#failregex = SECURITY.* SecurityEvent="FailedACL".*RemoteAddress=".+?/.+?/<HOST>/.+?".*
            SECURITY.* SecurityEvent="InvalidAccountID".*RemoteAddress=".+?/.+?/<HOST>/.+?".*
            SECURITY.* SecurityEvent="ChallengeResponseFailed".*RemoteAddress=".+?/.+?/<HOST>/.+?".*
            SECURITY.* SecurityEvent="InvalidPassword".*RemoteAddress=".+?/.+?/<HOST>/.+?".*
# with asterisk security framework
failregex = SECURITY.* SecurityEvent="FailedACL".*RemoteAddress=".+?/.+?/<HOST>/.+?".*
            SECURITY.* SecurityEvent="InvalidAccountID".*RemoteAddress=".+?/.+?/<HOST>/.+?".*
            SECURITY.* SecurityEvent="ChallengeResponseFailed".*RemoteAddress=".+?/.+?/<HOST>/.+?".*
            SECURITY.* SecurityEvent="InvalidPassword".*RemoteAddress=".+?/.+?/<HOST>/.+?".*

# regex to ignore. If this regex matches, the line is ignored.
ignoreregex =

$ cat /etc/fail2ban/jail.conf
[asterisk-iptables]
enabled  = true
filter   = asterisk
action   = iptables-allports[name=ASTERISK, protocol=all]
           sendmail-whois[name=ASTERISK, dest=root, sender=fail2ban@example.org]
# without asterisk security framework
#logpath  = /var/log/asterisk/messages
# with asterisk security framework
logpath  = /var/log/asterisk/security

# cat /etc/fail2ban/jail.conf
[DEFAULT] 
ignoreip=<your_ip_address>

$ cat /etc/asterisk/logger.conf
[general]
dateformat=%F %T

$ service iptables start; service fail2ban start
$ iptables -L -v
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
2104K 414M fail2ban-ASTERISK all — any any anywhere anywhere

from Fail2Ban (with iptables) and asterisk

Using Linux syscalls (without GNU libc)

syscall@man/syscall@wiki invokes the system by id/number without any C library wrapper (e.g.: GNU libc)

/* compile: gcc -o helloworld -nostdlib helloworld.c */
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/types.h>
int main(int argc, char *argv[]) {
    /* same as write to stdout, see http://linux.die.net/man/2/write */
    syscall(SYS_write, 1, "Hello, worldn", 13);

    /* same as gettid, get thread identification */
    pid_t tid = syscall(SYS_gettid);

    /* same as tgkill, send a signal to a thread, see http://linux.die.net/man/2/tgkill */
    tid = syscall(SYS_tgkill, getpid(), tid);
}

from syscall@man
see also linux syscall table

When are logs rotated in Linux (using logrotate/analog)

  • logrotate@man is an entry in cron daily (actually on anacron), that ALLWAYS runs once a day
$ cat /etc/cron.daily/logrotate
...
/usr/sbin/logrotate /etc/logrotate.conf
...
  • anacron@man jobs dont allways run on the same hour … see RANDOM_DELAY and START_HOURS_RANGE
$ cat /etc/anacrontab
# the maximal random delay added to the base delay of the jobs
RANDOM_DELAY=45
# the jobs will be started during the following hours only
START_HOURS_RANGE=3-22
1       5       cron.daily              nice run-parts /etc/cron.daily

$ cat /var/log/cron.1 | grep "starting logrotate"
Jan  3 03:19:01 vbox5 run-parts(/etc/cron.daily)[23355]: starting logrotate
Jan  4 03:08:01 vbox5 run-parts(/etc/cron.daily)[15843]: starting logrotate
Jan  5 03:08:01 vbox5 run-parts(/etc/cron.daily)[4828]: starting logrotate
Jan  6 03:19:01 vbox5 run-parts(/etc/cron.daily)[3977]: starting logrotate

When logrotate runs (once a day), it compares its daily/weekly/monthy in logrotate.d/file with the dates on /var/lib/logrotate.status (the last rotation), to decide whether to rotate or not

How to unlock root, add admin privileges (using sudo) and reset root password in Linux

  • How to unlock root from login (and ssh)
# set a password will unlock root
$ sudo passwd

# to lock back use '-l'
$ sudo passwd -l root

# to enable/disable root ssh login
$ cat /etc/ssh/sshd_config
PermitRootLogin yes
$ service sshd restart

see passwd@man

  • How to add administrator privileges to users
# add user to sudo(rhel) or wheel(ubuntu) group
$ sudo usedmod -a -G wheel username
$ newgrp wheel

# if not defined, define a group to allow to execute any command
# note: need to be in 'sudo/whell' to edit sudoers
$ cat /etc/sudoers
%wheel ALL=(ALL) ALL
# same but without password
%wheel ALL=(ALL) NOPASSWD:ALL
# optionally set sudo session timeout (default is 15 mins, <0 never expires, 0 asks every time for password)
Defaults env_reset,timestamp_timeout=10

# if you get 'username is not in the sudoers file' then
# reboot into recovery mode (or single-user mode)
$ mount -o remount,rw /
$ usermod -a -G sudo username
$ exit

see sudoers@man

  • How to reset root password using single-user mode
# pre-GRUB2, boot into single-user mode by 'esc' or 'shift' to enter GRUB menu and append '1' (for runlevel 1)

# in GRUB2 root passwd is now required to operate in single-user mode so 
# find 'linux' line and replace 'rhgb quiet' with 'init=/bin/sh' (or 'rd.break' to drop to emergency mode)

# ctrl+x to boot
$ passwd
$ exit (or reboot) 

# if 'passwd' is read-only then
$ mount -o remount,rw /

# alternatively to single-user mode is boot into recovery (ubuntu only)

from lostpassword@ubuntu and resetpasswd@centos

Using non-blocking and asynchronous I/O (CK10 problem) in Linux and Windows (with epool, iocp, libevent/libev/libuv/boost.asio and librt/libaio)

C10k problem/C10k problem@wiki is the problem of optimizing network sockets to handle a large number of clients at the same time.

Thread per client scales only to a certain amount of clients per RAM. If you like to scale beyond that to like to minimize your state per client.

On most UNIXes, that number is around 300. On Windows, it’s around 800. I personally would only recommend it for applications that plan to handle 100 clients or fewer, or one platforms where you know the threading library works well this way.

Converting threaded programs to pure async is a disaster.For one thing, you can never, ever block under any circumstances on pain of total disaster. This means every single line of code is performance critical. For all but the most trivial applications, this alone is a deal killer.
from lkml.org

One thread per client doesn’t scale. We must serve many clients with each thread

In non-blocking IO (O_NONBLOCK) you start IO, get notified (EWOULDBLOCK) if it blocks, and readiness notify (pool, ...) to know when it's OK to start next IO. Usable in network but not disk IO.

In asynchronous/completion IO you start IO and get completion notification (signal or completion ports) to known when it finished. Works in both network and disk IO.

Edge-triggered readiness notification means you give the kernel a file descriptor, and later, when that descriptor transitions from not ready to ready, the kernel notifies you somehow. It then assumes you know the file descriptor is ready, and will not send any more readiness notifications of that type for that file descriptor until you do something that causes the file descriptor to no longer be ready (e.g. until you receive the EWOULDBLOCK error on a send, recv, or accept call, or a send or recv transfers less than the requested number of bytes).
from lkml.org

/* using edge-trigger epoll */

void setnonblocking(int fd)
    int flags = fcntl(fd, F_GETFL, 0);
    fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}

/* set up listening socket, 'listen_sock' (socket(), bind(), listen()) */
epollfd = epoll_create(10);
ev.events = EPOLLIN;
ev.data.fd = listen_sock;
epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_sock, &ev);

for (;;) {
    /* block until some events happens */
    nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
    for (n = 0; n < nfds; ++n) {
        if (events[n].data.fd == listen_sock) {
            conn_sock = accept(listen_sock, (struct sockaddr *) &local, &addrlen);
            setnonblocking(conn_sock);
            ev.events = EPOLLIN | EPOLLET;
            ev.data.fd = conn_sock;
            epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock, &ev);
        } else {
            do_use_fd(events[n].data.fd);
        }
    }
}

from epoll@man

  • Asyncronous IO port completion@wiki Windows/Solaris only. You start some operation asynchronously, and receive a notification when that operation has completed. Works in both network and disk IO.

There is a notify on ready model in Windows as well (select or WSAWaitForMultipleEvents) but it can’t scale to large numbers of sockets, so it’s not suitable for high-performance network applications.

The fundamental variation is that in a Unix you generally ask the kernel to wait for state change in a file descriptor’s readability or writablity. With overlapped I/O and IOCPs the programmers waits for asynchronous function calls to complete. For example, instead of waiting for a socket to become writable and then using send(2) on it, as you commonly would do in a Unix, with overlapped I/O you would rather WSASend() the data and then wait for it to have been sent.
from Asynchronous I/O in Windows for Unix Programmers

// TCP echo-server

DWORD WINAPI ServerWorkerThread(LPVOID CompletionPortID) {
    while(TRUE) {
        GetQueuedCompletionStatus((HANDLE)CompletionPortID, &BytesTransferred, (LPDWORD)&PerHandleData, (LPOVERLAPPED *) &PerIoData, INFINITE);
        // ...

        // continue sending until all bytes are sent
        if (PerIoData->BytesRECV > PerIoData->BytesSEND) {
            WSASend(PerHandleData->Socket, &(PerIoData->DataBuf), 1, &SendBytes, 0, &(PerIoData->Overlapped), NULL);
        } else {
            WSARecv(PerHandleData->Socket, &(PerIoData->DataBuf), 1, &RecvBytes, &Flags, &(PerIoData->Overlapped), NULL);
        }
    }
}

int main(int argc, char **argv) {
    // setup an I/O completion port
    HANDLE CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);

    // create a server worker thread and pass the completion port to the thread
    HANDLE ThreadHandle = CreateThread(NULL, 0, ServerWorkerThread, CompletionPort,  0, &ThreadID);

    // create a listening socket
    // ...

    // accept connections and assign to the completion port
    while(TRUE) {
        SOCKET Accept = WSAAccept(Listen, NULL, NULL, NULL, 0);

        // associate the accepted socket with the original completion port
        LPPER_HANDLE_DATA PerHandleData = (LPPER_HANDLE_DATA) GlobalAlloc(GPTR, sizeof(PER_HANDLE_DATA));
        PerHandleData->Socket = Accept;
        CreateIoCompletionPort((HANDLE) Accept, CompletionPort, (DWORD) PerHandleData, 0);

        // create per I/O socket information structure to associate with the WSARecv
        LPPER_IO_OPERATION_DATA PerIoData = (LPPER_IO_OPERATION_DATA) GlobalAlloc(GPTR, sizeof(PER_IO_OPERATION_DATA));
        // ...
        WSARecv(Accept, &(PerIoData->DataBuf), 1, &RecvBytes, &Flags, &(PerIoData->Overlapped), NULL);    
    }
}

from IOComplete

  • libevent/libevent@wiki replaces main event loop to support execution of callbacks when a specific event occurs on a file descriptor or after a timeout.
    Its a wrapper around epoll, kqueue and IOCP.
/* TCP echo-server */

struct client { int fd; struct bufferevent *buf_ev; };

int setnonblock(int fd) {
    int flags = fcntl(fd, F_GETFL);
    flags |= O_NONBLOCK;
    fcntl(fd, F_SETFL, flags);
}

void buf_read_callback(struct bufferevent *incoming, void *arg) {
    /* echo back */
    char *req = evbuffer_readline(incoming->input);
    evreturn = evbuffer_new();
    evbuffer_add_printf(evreturn, "You said %sn",req);
    bufferevent_write_buffer(incoming, evreturn);
    evbuffer_free(evreturn);
    free(req);
}

void buf_write_callback(struct bufferevent *bev, void *arg) {}
void buf_error_callback(struct bufferevent *bev, short what, void *arg) {...}

void accept_callback(int fd, short ev, void *arg) {
    /* accept non-blocking client socket */
    int client_fd = accept(fd, (struct sockaddr *)&client_addr, &client_len);
    setnonblock(client_fd);

    /* register callbacks */
    struct client *client = calloc(1, sizeof(*client));
    client->fd = client_fd;
    client->buf_ev = bufferevent_new(client_fd, buf_read_callback, buf_write_callback, buf_error_callback, client);

    bufferevent_enable(client->buf_ev, EV_READ);
}

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

    /* bind, listen on non-blocking  */
    bind(socketlisten, (struct sockaddr *)&addresslisten, sizeof(addresslisten));
    listen(socketlisten, 5);
    setsockopt(socketlisten, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
    setnonblock(socketlisten);

    /* register callbacks and start loop */
    event_set(&accept_event, socketlisten, EV_READ|EV_PERSIST, accept_callback, NULL);
    event_add(&accept_event, NULL);
    event_dispatch();

    close(socketlisten);
    return 0;
}

from Boost network performance with libevent and libev

  • libev re-written libevent also using epoll/kqueue but no IOCP. Focus on Unix I/O multiplexers.
    For disk IO use libeio, asynchronous read, write, open, close, stat, unlink, fdatasync, mknod, readdir etc.
/* TCP echo server */

void accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents) {
    int client_sd = accept(watcher->fd, (struct sockaddr *)&client_addr, &client_len);

    /* initialize and start watcher to read client requests */
    ev_io_init(w_client, read_cb, client_sd, EV_READ);
    ev_io_start(loop, w_client);
}

void read_cb(struct ev_loop *loop, struct ev_io *watcher, int revents) {
    /* receive message from client socket */
    read = recv(watcher->fd, buffer, BUFFER_SIZE, 0);
    if(read == 0) {
        /* stop and free watchet if client socket is closing */
        ev_io_stop(loop, watcher);
        free(watcher);
        return;
    }

    /* send message bach to the client */
    send(watcher->fd, buffer, read, 0);
    bzero(buffer, read);
}

int main() {
    struct ev_loop *loop = ev_default_loop(0);

    /* bind and listen ... */

    /* initialize and start a watcher to accepts client requests */
    ev_io_init(&w_accept, accept_cb, sd, EV_READ);
    ev_io_start(loop, &w_accept);

    while (1) ev_loop(loop, 0);

    return 0;
}

from libev tcp echo server

/* TCP echo server */

uv_loop_t *loop;

void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) {
    buf->base = (char*) malloc(suggested_size);
    buf->len = suggested_size;
}

void echo_write(uv_write_t *req, int status) { free(req); }

void echo_read(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) {
    if (nread < 0) {
        uv_close((uv_handle_t*) client, NULL);
        return;
    }

    uv_write_t *req = (uv_write_t *) malloc(sizeof(uv_write_t));
    uv_buf_t wrbuf = uv_buf_init(buf->base, nread);
    uv_write(req, client, &wrbuf, 1, echo_write);
    free(buf->base);
}

void on_new_connection(uv_stream_t *server, int status) {
    if (status == -1) return;

    uv_tcp_t *client = (uv_tcp_t*) malloc(sizeof(uv_tcp_t));
    uv_tcp_init(loop, client);
    if (uv_accept(server, (uv_stream_t*) client) == 0) {
        uv_read_start((uv_stream_t*) client, alloc_buffer, echo_read);
    }
    else {
        uv_close((uv_handle_t*) client, NULL);
    }
}

int main() {
    loop = uv_default_loop();

    uv_tcp_t server;
    uv_tcp_init(loop, &server);

    struct sockaddr_in addr;
    uv_ip4_addr("0.0.0.0", DEFAULT_PORT, &addr);

    uv_tcp_bind(&server, (const struct sockaddr*)&addr, 0);
    int r = uv_listen((uv_stream_t*) &server, DEFAULT_BACKLOG, on_new_connection);
    if (r) return 1;

    return uv_run(loop, UV_RUN_DEFAULT);
}

from uvbook

/* TCP echo server */
using boost::asio::ip::tcp;

class session : public std::enable_shared_from_this<session> {
public:
    session(tcp::socket socket) : socket_(std::move(socket)) { }
    void start() { do_read(); }
private:
    void do_read() {
        auto self(shared_from_this());
        socket_.async_read_some(boost::asio::buffer(data_, max_length), 
            [this, self](boost::system::error_code ec, std::size_t length) {
                if (!ec) { do_write(length); }
            });
    }
    void do_write(std::size_t length) {
        auto self(shared_from_this());
        boost::asio::async_write(socket_, boost::asio::buffer(data_, length),
            [this, self](boost::system::error_code ec, std::size_t /*length*/) {
                if (!ec) { do_read(); }
        });
    }
    tcp::socket socket_;
    enum { max_length = 1024 };
    char data_[max_length];
};

class server {
public:
  server(boost::asio::io_service& io_service, short port)
    : acceptor_(io_service, tcp::endpoint(tcp::v4(), port)), socket_(io_service) {
    do_accept();
  }
private:
    void do_accept() {
        acceptor_.async_accept(socket_, [this](boost::system::error_code ec) {
            if (!ec) { std::make_shared<session>(std::move(socket_))->start(); }
            do_accept();
        });
    }
    tcp::acceptor acceptor_;
    tcp::socket socket_;
};

int main(int argc, char* argv[]) {
    boost::asio::io_service io_service;
    server s(io_service, std::atoi(argv[1]));
    io_service.run();
    return 0;
}

from boost samples

  • POSIX Asynchronous I/O implemented on Linux as aio_*@man in GNU libc using pthreads, link with librt(-lrt). Works in both network and disk IO. It works on files with buffering enabled (no need for O_DIRECT), but outstanding operations queue is limited to number of threads.
#include <aio.h>
/* using signals as notification for AIO requests */
void setup_io( ... ) {
    int fd;
    struct sigaction sig_act;
    struct aiocb my_aiocb;

    /* set up the signal handler */
    sigemptyset(&sig_act.sa_mask);
    sig_act.sa_flags = SA_SIGINFO;
    sig_act.sa_sigaction = aio_completion_handler;

    /* set up the AIO request */
    bzero( (char *)&my_aiocb, sizeof(struct aiocb) );
    my_aiocb.aio_fildes = fd;
    my_aiocb.aio_buf = malloc(BUF_SIZE+1);
    my_aiocb.aio_nbytes = BUF_SIZE;
    my_aiocb.aio_offset = next_offset;

    /* link the AIO request with the signal handler */
    my_aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
    my_aiocb.aio_sigevent.sigev_signo = SIGIO;
    my_aiocb.aio_sigevent.sigev_value.sival_ptr = &my_aiocb;

    /* map the signal to the signal handler */
    ret = sigaction( SIGIO, &sig_act, NULL );

    ret = aio_read( &my_aiocb );
}

void aio_completion_handler( int signo, siginfo_t *info, void *context ) {
    struct aiocb *req;
    if (info->si_signo == SIGIO) {
        req = (struct aiocb *)info->si_value.sival_ptr;
        /* did the request complete? */
        if (aio_error( req ) == 0) {
            /* request completed successfully, get the return status */
            ret = aio_return( req );
        }
    }
    return;
}

from Using POSIX AIO API

  • Native/Kernel-Linux Asynchronous I/O implemented in libaio, link with (-laio). Works only in disk IO (and only with O_DIRECT), no network IO. Will silently fallback to syncronous if underlying IO doesn’t support it.

Enables overlap I/O operations with other processing, by providing an interface for submitting one or more I/O requests in one system call io_submit without waiting for completion, and a separate interface io_getevents to reap completed I/O operations associated with a given completion group.

/* or #include <libaio.h>
int io_setup(unsigned nr, aio_context_t *ctxp) {
    return syscall(__NR_io_setup, nr, ctxp);
}
int io_destroy(aio_context_t ctx) {
    return syscall(__NR_io_destroy, ctx);
}
int io_submit(aio_context_t ctx, long nr,  struct iocb **iocbpp) {
    return syscall(__NR_io_submit, ctx, nr, iocbpp);
}
int io_getevents(aio_context_t ctx, long min_nr, long max_nr, struct io_event *events, struct timespec *timeout) {
    return syscall(__NR_io_getevents, ctx, min_nr, max_nr, events, timeout);
}*/

int main() {
    aio_context_t ctx = 0;
    struct iocb cb;
    struct iocb *cbs[1];
    char data[4096];
    struct io_event events[1];
    int ret, fd;

    fd = open("/tmp/testfile", O_RDWR | O_CREAT);
    ret = io_setup(128, &ctx);

    /* setup I/O control block */
    memset(&cb, 0, sizeof(cb));
    cb.aio_fildes = fd;
    cb.aio_lio_opcode = IOCB_CMD_PWRITE;
    cb.aio_buf = (uint64_t)data;
    cb.aio_offset = 0;
    cb.aio_nbytes = 4096;
    cbs[0] = &cb;

    ret = io_submit(ctx, 1, cbs);

    /* get the reply */
    ret = io_getevents(ctx, 1, 1, events, NULL);
    printf("%dn", ret);

    ret = io_destroy(ctx);
    return 0;
}

from Linux Asynchronous I/O Explained and AIOUserGuide

Using SO_REUSEPORT (in Linux 3.9 and BSD) in prefork multithreaded servers

The new socket option allows multiple sockets on the same host to bind to the same port, and is intended to improve the performance of multithreaded network server applications running on top of multicore systems.

Incoming connections and datagrams are distributed to the server sockets using a hash based on the 4-tuple of the connection—that is, the peer IP address and port plus the local IP address and port.

SO_REUSEADDR socket option already allows multiple UDP sockets to be bound to, and accept datagrams on, the same UDP port. However, by contrast with SO_REUSEPORT, SO_REUSEADDR does not prevent port hijacking and does not distribute datagrams evenly across the receiving threads.
from The SO_REUSEPORT socket option, Linux 3.9 introduced new way of writing socket servers

SO_REUSEADDR enables local address reuse, SO_REUSEPORT enables duplicate address and port bindings
from getsockopt@freebsd and SO_REUSEPORT vs SO_REUSEADDR

#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include <arpa/inet.h>
#include <pthread.h>

void* do_work(void *arg)
{
    int *port = (int *) arg;

    int listen_socket = socket(AF_INET, SOCK_STREAM, 0);
    int one = 1;
    setsockopt(listen_socket, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));

    struct sockaddr_in serv_addr;
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(*port);

    int ret = bind(listen_socket, (struct sockaddr *) &serv_addr, sizeof(serv_addr)); 
    listen(listen_socket, 5);

    struct sockaddr_in cli_addr;
    memset(&cli_addr, 0, sizeof(cli_addr));
    int addr_length = sizeof(cli_addr);

    do
    {
        int cli_sock = accept(listen_socket, (struct sockaddr *) &cli_addr, (socklen_t *) &addr_length);
        close(cli_sock);
    } while (true);

    close(listen_socket);

    return 0;
}

int main(int ac, const char *av[])
{ 
    int port = atoi(av[1]);

    const int MAX_THREADS = 10;
    pthread_t tid[MAX_THREADS];
    for (int i = 0; i < MAX_THREADS; i++) {
        pthread_create(&tid[i], NULL, do_work, &port);
    }

    for (int i = 0; i < MAX_THREADS; i++) {
        pthread_join(tid[i], NULL);
    }
    return 0;
}

How to install minimal Arch Linux desktop (using i3, Mate, Openbox and LightDM)

Arch is largely based around binary packages. Packages are targeted for i686 and x86-64 microprocessors to assist performance on modern hardware. A ports/ebuild-like system is also provided for automated source compilation, known as the Arch Build System. ~600MB

# download ISO from https://archlinux.org/download/, mount and boot
$ loadkeys pt-latin1
# boot uses dhcpcd and wireed, test
$ ping -c 3 www.google.com 

# erase partition table
$ sgdisk --zap-all /dev/sda
# using cgdisk to create GPT (root, home, swap) partitions; alternative to fdisk (which creates MBR partitions)
$ cgdisk /dev/sda
   1        6.0 GiB    Linux filesystem
   2        1024MB GiB  Linux filesystem
   3        1024MB GiB  Linux filesystem
# create filesystems
$ mkfs.ext4 /dev/sda1 ; mkfs.ext4 /dev/sda2
$ mkswap /dev/sda3 ; swapon /dev/sda3
# mount the partitions
$ lsblk -f
$ mount /dev/sda1 /mnt
$ mkdir /mnt/home ; mount /dev/sda2 /mnt/home

# optionally select a mirror
$ nano /etc/pacman.d/mirrorlist
# install the base system
$ pacstrap -i /mnt base base-devel
# generate an fstab
$ genfstab -U -p /mnt >> /mnt/etc/fstab
$ nano /mnt/etc/fstab

# chroot and configure the base system
$ arch-chroot /mnt /bin/bash
# locale, uncomment 'en_US.UTF-8 UTF-8'
$ nano /etc/locale.gen
$ locale-gen
$ echo LANG=en_US.UTF-8 > /etc/locale.conf
$ export LANG=en_US.UTF-8
# console font and keymap
# nano /etc/vconsole.conf
KEYMAP=pt-latin1
FONT=lat9w-16
# time zone
$ ln -s /usr/share/zoneinfo/Europe/Lisbon /etc/localtime
# hardware clock
$ hwclock --systohc --utc
# kernel modules '/etc/modules-load.d/*.conf', no need to set since all are loaded automatically by udev
# hostname
$ echo archlinux > /etc/hostname

# configure the network; wired using dhcpd (see 'ip link')
$ systemctl enable dhcpcd@ens32.service

# generate kernel config
$ nano /etc/mkinitcpio.conf
$ mkinitcpio -p linux

# set the root password
$ passwd

# install and configure a bootloader, using grub
$ pacman -S grub
$(ether BIOS) grub-install --target=i386-pc --recheck --force /dev/sda
$(or UEFI) grub-install --target=x86_64-efi --efi-directory=$esp --bootloader-id=arch_grub --recheck
$ grub-mkconfig -o /boot/grub/grub.cfg

# add users, see https://wiki.archlinux.org/index.php/users_and_groups
$ useradd -m -G wheel -s /bin/bash 
$ passwd 
$ nano /etc/sudoers
%sudo ALL=(ALL) ALL

# add openssh, see https://wiki.archlinux.org/index.php/Secure_Shell
$ pacman -S openssh
$ systemctl start sshd.service
$ systemctl enable sshd.service

# change shell prompt, see https://wiki.archlinux.org/index.php/Color_Bash_Prompt
$ cat ~/.bashrc
PS1='\[\e[1;32m\][\u@\h \W]\$\[\e[0m\] '

# unmount the partitions and reboot
$ exit ; reboot

from arch beginners guide

  • Xorg is the public, open-source implementation of the X window system version 11.
  • LightDM is a lightweight cross-desktop display manager, replaces deprecated SLiM.
  • i3 is a dynamic tiling window manager.
  • MATE Desktop Environment is the continuation of GNOME 2.
  • openbox is a lightweight, powerful, and highly configurable stacking window manager with extensive standards support. Runs independently or within other desktops (e.g.: LXDE).
# update system
$ pacman -Syu
# removing orphaned packages
$ pacman -Rns $(pacman -Qtdq)

# install xorg and drivers
$ pacman -S xf86-video-vmware | xf86-video-intel | nvidia nvidia-utils pangox-compat | xf86-video-ati (see https://wiki.archlinux.org/index.php/xorg)
$ pacman -S xorg-server ttf-dejavu
$ pacman -S xterm (or rxvt-unicode, see https://wiki.archlinux.org/index.php/rxvt-unicode)
$ localectl set-x11-keymap pt

# install lightdm login/display manager, use F9 to change session
$ pacman -S xorg-server-xephyr lightdm lightdm-gtk2-greeter
$ systemctl enable lightdm.service
# see https://wiki.archlinux.org/index.php/LightDM#Missing_icons_with_GTK_greeter
$ pacman -S adwaita-icon-theme
$ nano /etc/lightdm/lightdm-gtk-greeter.conf
[greeter]
theme-name = TraditionalGreen
icon-theme-name = mate
font-name = Sans 10
background = /usr/share/backgrounds/mate/nature/Wood.jpg

# install desktops 
$ pacman -S i3 dmenu
$ pacman -S mate mate-extra (or just 'mate-panel')
$ pacman -S lxde (or just 'lxde-common openbox obconf obmenu lxappearance tint2')
$ pacman -S xfce4 xfce4-goodies
$ pacman -S cinnamon
$ pacman -S gnome gnome-extra (or just 'gnome-shell')
$ pacman -S kde (or just 'kdebase')

# generate openbox menus, see http://trizenx.blogspot.co.uk/2012/02/obmenu-generator.html
$ yaourt obmenu-generator
$ obmenu-generator -i -p
$ openbox --reconfigure

from arch install

Using Arch Linux’s pacman/ABS/AUR

  • pacman combines a simple binary package format with an easy-to-use build system. Written in the C programming language and uses the .pkg.tar.xz package format.
# update package databases
$ pacman -Sy

# search all package, or just installed
$ pacman -Ss <package> or pacman -Qs <package>
(add color, either use 'pacsearch <package>' a perl wrapper for 'pacman -Ss' or)
$ nano /etc/pacman.conf
Color

# query all package info, or just installed package info
$ pacman -Si <package> or pacman -Qi <package>
# lists all files associated with a package
$ pacman -Ql <package>
# list package disk usage
$ pacsysclean

# download/install
$ sudo pacman -S <package>
# just download
$ sudo pacman -Sw <package>
# install locally, used in AUR
$ sudo pacman -U <package_path>

# list packages out of date
$ pacman -Qu
# install packages out of date
$ sudo pacman -Syu

# list downloaded packages
$ ls /var/cache/pacman/pkg | grep <package>
# revert to a package in your cache
$ pacman -U <path_to_cached_file>
# rollback using https://wiki.archlinux.org/index.php/Arch_Rollback_Machine
$ pacman -U http://seblu.net/a/arm/2013/08/31/extra/os/x86_64/apache-2.2.25-1-x86_64.pkg.tar.xz
# same using downgrade/downgrader
$ downgrade <package> | downgrader <package>

# remove a package, leaves dependencies
$ sudo pacman -R <package>
# remove packages and orphan dependencies
$ sudo pacman -Rs <package>

# mirrors by speed, see https://wiki.archlinux.org/index.php/Mirrors
$ sudo cp /etc/pacman.d/mirrorlist{,.backup}
$ sudo rankmirrors -n 6 /etc/pacman.d/mirrorlist.backup > /etc/pacman.d/mirrorlist
$ sudo pacman -Syy

# pacman frontends, https://wiki.archlinux.org/index.php/Pacman_GUI_Frontends
# note: if using putty change translation to latin1
$ sudo pacman -S pcurses 
$ yaourt yaourt-gui

# tips, see https://wiki.archlinux.org/index.php/Pacman_tips and https://wiki.archlinux.org/index.php/System_maintenance
# remove orphan packages
$ pacman -Rns $(pacman -Qtdq)
# reinstall all packages (except foreign)
# pacman -Qenq | pacman -S -
# remove all the cached packages not installed
$ sudo pacman -Sc

from howto use arch package management

While pacman is the specialized Arch tool for binary package management (including packages built with the ABS), ABS is a collection of tools for compiling source into installable .pkg.tar.xz packages.

ABS is not necessary to use Arch Linux, but it is useful for automating certain tasks of source compilation.

$ sudo pacman -S abs ; sudo abs
$ mkdir -p ~/abs ; cp /var/abs// ~/abs
$ $ cd ~/abs/ ; makepkg -s ; sudo pacman *.tar.xz 

It contains package descriptions PKGBUILDs that allow you to compile a package from source with makepkg and then install it via pacman.

# prerequisites
$ sudo pacman -S --needed base-devel

# manually 
$ mkdir ~/build ; cd $_
$ curl https://aur.archlinux.org/packages///.tar.gz | tar xvf
$ cd  ; makepkg -s ; pacman -U *.tar.xz ; cd -
# list foreign packages
$ pacman -Qm 

# using https://wiki.archlinux.org/index.php/Yaourt as a https://wiki.archlinux.org/index.php/AUR_Helpers
$ mkdir ~/build ; cd $_
$ curl https://aur.archlinux.org/packages/pa/package-query/package-query.tar.gz | tar xvf
$ cd package-query ; makepkg -si ; cd -
$ curl https://aur.archlinux.org/packages/ya/yaourt/yaourt.tar.gz | tar xvf
$ cd yaourt ; makepkg -si ; cd -

# install package
$ yaourt  or yaourt -Sa 
# sync database, upgrade packages, search aur and devel upgrades
$ yaourt -Syu --devel --aur
# build package from source
$ yaourt -Sb 

from yaourt

How to disable consistent naming rules for network interfaces in RHEL7

Consistent Network Device Naming

$ ip link show
2: ens192 ...

## disable consistent naming
$ nano /etc/default/grub
... net.ifnames=0
$ grub2-mkconfig -o /boot/grub2/grub.cfg

## add udev network naming rule, replace MAC with your macaddress
$ nano /etc/udev/rules.d/70-persistent-net.rules
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="08:00:27:a9:7a:e1", ATTR{type}=="1", KERNEL=="eth*", NAME="sushi"
$ reboot
$ ip link show
2: sushi ...

from How to change a network interface name on CentOS 7