Posts Tagged Code

Natural order sorting strings with numbers

The following python code makes natural sorting sequences of lexical and numerical values a little easier. It supports any iterable containing strings which have embedded numbers. In short it would give you this:

foo1 < foo2 < foo10

instead of this:

foo1 < foo10 < foo2

As an example, if you have this sequence:

>>> seq = ['foo', 'foo1', 'foo2', 'foo10', 'foobar10', '20', '100', '1', '3', 'bar1']

a regular sort would produce this:

>>> sorted(seq)
['1', '100', '20', '3', 'bar1', 'foo', 'foo1', 'foo10', 'foo2', 'foobar10']

whereas a natural sort would produce this:

>>> natural_sort(seq)
['1', '3', '20', '100', 'bar1', 'foo', 'foo1', 'foo2', 'foo10', 'foobar10']

Here is the code:

import re

def natsort_key(item):
    chunks = re.split('(\d+(?:\.\d+)?)', item)
    for ii in range(len(chunks)):
        if chunks[ii] and chunks[ii][0] in '0123456789':
            if '.' in chunks[ii]: numtype = float
            else: numtype = int
            chunks[ii] = (0, numtype(chunks[ii]))
        else:
            chunks[ii] = (1, chunks[ii])
    return (chunks, item)

def natural_sort(seq):
    sortlist = [item for item in seq]
    sortlist.sort(key=natsort_key)
    return sortlist

, ,

No Comments

Simple HTTP POST in Java

Today I was helping a friend debug a web service they had implemented. Their side was working correctly but the developer who was trying to interface with it seemed to be running into many problems. Since they were integrating an application written in Java, I whipped up a simple test for them. All we really needed to do was to send a few variables using HTTP POST to this resource and make sure it returned exactly what we were expecting.

This uses standard libraries only, and doesn’t require anything third party. It does nothing fancy at all, just simply posts data to a URL. Hopefully you find this useful at some point.

src/postit/Main.java

/*
 * Java POST Example
 */

package postit;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.net.URLEncoder;
import java.io.DataOutputStream;
import java.io.DataInputStream;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Greg
 */
public class Main {

    /**
     * Pretend you're a script...
     */
    public static void main(String[] args) {
        final String server = "somewhere.ontheinter.net";

        URL url = null;
        try {
            url = new URL("http://" + server + "/we-expect-post/data");
        } catch (MalformedURLException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }

        HttpURLConnection urlConn = null;
        try {
            // URL connection channel.
            urlConn = (HttpURLConnection) url.openConnection();
        } catch (IOException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }

        // Let the run-time system (RTS) know that we want input.
        urlConn.setDoInput (true);

        // Let the RTS know that we want to do output.
        urlConn.setDoOutput (true);

        // No caching, we want the real thing.
        urlConn.setUseCaches (false);

        try {
            urlConn.setRequestMethod("POST");
        } catch (ProtocolException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }

        try {
            urlConn.connect();
        } catch (IOException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }

        DataOutputStream output = null;
        DataInputStream input = null;

        try {
            output = new DataOutputStream(urlConn.getOutputStream());
        } catch (IOException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }

        // Specify the content type if needed.
        //urlConn.setRequestProperty("Content-Type",
        //  "application/x-www-form-urlencoded");

        // Construct the POST data.
        String content =
          "name=" + URLEncoder.encode("Greg") +
          "&email=" + URLEncoder.encode("greg at code dot geek dot sh");

        // Send the request data.
        try {
            output.writeBytes(content);
            output.flush();
            output.close();
        } catch (IOException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }

        // Get response data.
        String str = null;
        try {
            input = new DataInputStream (urlConn.getInputStream());
            while (null != ((str = input.readLine()))) {
                System.out.println(str);
            }
            input.close ();
        } catch (IOException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

, ,

6 Comments

Simple OpenVPN Server Statistics

Ever wondered what the status of your OpenVPN server is, or wanted some simple stats ?

Here is a really simple script to give you some info. The output looks like this:

greg@leonis:~$ vpnstatus
Common Name   Virtual Address    Real Address          Sent      Received             Connected Since
greg.vpn      10.8.142.6         196.9.23.59        1.11 MB     282.50 KB    Thu Jul 16 09:07:15 2009

Firstly, ensure your server is actually saving the stats somewhere (/etc/openvpn/openvpn.status in my example):

greg@leonis:~$ grep status /etc/openvpn/server.conf
status openvpn.status

Once that is happening, drop this code into a file and make it executable.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

STATUS = "/etc/openvpn/openvpn.status"

status_file = open(STATUS, 'r')
stats = status_file.readlines()
status_file.close()

hosts = []

headers = {
    'cn':    'Common Name',
    'virt':  'Virtual Address',
    'real':  'Real Address',
    'sent':  'Sent',
    'recv':  'Received',
    'since': 'Connected Since'
}

sizes = [
    (1<<50L, 'PB'),
    (1<<40L, 'TB'),
    (1<<30L, 'GB'),
    (1<<20L, 'MB'),
    (1<<10L, 'KB'),
    (1,       'B')
]

def byte2str(size):
    for f, suf in sizes:
        if size >= f:
            break

    return "%.2f %s" % (size / float(f), suf)

for line in stats:
    cols = line.split(',')

    if len(cols) == 5 and not line.startswith('Common Name'):
        host  = {}
        host['cn']    = cols[0]
        host['real']  = cols[1].split(':')[0]
        host['recv']  = byte2str(int(cols[2]))
        host['sent']  = byte2str(int(cols[3]))
        host['since'] = cols[4].strip()
        hosts.append(host)

    if len(cols) == 4 and not line.startswith('Virtual Address'):
        for h in hosts:
            if h['cn'] == cols[1]:
                h['virt'] = cols[0]

fmt = "%(cn)-25s %(virt)-18s %(real)-15s %(sent)13s %(recv)13s %(since)25s"
print fmt % headers
print "\n".join([fmt % h for h in hosts])

,

No Comments

Run something as another user

Here is a simple way to run something on UNIX / Linux as another user, without having to resort to weird sudo incantations. The Makefile is left as an exercise for the reader.

This has only been tested on FreeBSD, Debian Linux and OpenSolaris so far.

Compile with: cc -o setuid setuid.c

#include <stdio.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h> 

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

    /* Check command line */
    if (argc < 3) {
        fprintf(stderr, "Usage: %s user cmd\n", argv[0]);
        return 1;
    }

    struct passwd *pw;
    pw = getpwnam(argv[1]);

    if (pw==NULL) {
        fprintf(stderr, "User not found\n");
        return 1;
    }

    if (initgroups(argv[1], pw->pw_gid)==-1) {
        perror("initgroups");
        return 1;
    }

    if (setregid(pw->pw_gid, pw->pw_gid)==0 &&
        setreuid(pw->pw_uid, pw->pw_uid)==0) {
        argv += 2;
        execvp(argv[0], argv);
        perror("exec");
        return 1;
    }

    perror("setre[gu]id");
    return 1;

}

, ,

No Comments