Cisco 911 Monitoring Without the $40K+ Price Tag

Actually I think the final price we were quoted was $20,000 on one product that did this, but initially we were told $40,000 (Hell, I think the product from Cisco was $60k)... Anyway, one of the things we were tasked with at work was setting up a system to monitor when 911 was called. When it was called we were to notify a set of individuals based on which office it was. It turns out this is incredibly simple. All we need to do is set up an SFTP server, set some info on the Cisco Call Manager, and parse the data with a couple lines of code.

The first step that we need to do is set up our SFTP server. If you search for SFTP, you'll notice a lot of references to SSH. SSH is a network protocol that allows for secure content exchange. Well, mostly secure anyway. Last vulnerability that I remember reading about was 2008 and I would have hoped that they would have fixed it by now. That being said, SFTP is simply an FTP server that uses SSH (yay, secure file transfers). Now all we have to do is set up SSH and we have an SFTP server. Now if we were a Linux shop at work, it would have been literally 5 minutes to set up the user login (SSH is already installed). On Windows, we have to install it ourselves. On the bright side this is fairly simple as there are 20+ versions out there. The one that I recommend is freeSSHd though as it's just incredibly simple (sadly we found it after setting up another SSH server at work). It's literally run the install app, follow directions, set up a user using their tray icon app, and you're done (note that on Windows Server 2008, there seems to be a bug where it saves your changes to the user's directory, which causes the service to not be able to find your changes. But you can simply do a search for the duplicate with the actual changes and simply copy it over the one in the app's directory. Just make sure to restart the service).

Once you have the SFTP server up and running, you simply go into the Cisco CallManager, go to Navigation->Cisco Unified CallManager Serviceability->click Go. The go to the Tools menu and select CDR Management. In the Billing Application Server Parameters section, click Add New. This is where you're tell it where your SFTP server is. So just enter the IP address of the server, username/password that you set up, directory that you want them to save to, and set the protocol to SFTP. Once that's done click save and you're done with the second step.

At this point you should have a folder on your SFTP server filling with files. These come in two flavors, files that start with cmr and those that start with cdr. The cmr files deal with call quality (packets sent, received, etc.). If you wanted, you could probably do some nice metrics of your system using that. The cdr files, on the other hand, actually give you information about who made the call, to whom, etc. If you open up one of these cdr files, you'll notice some info with a bunch of commas... It's a CSV file! Yay, parsing those is always fun... Thankfully I have some code that does that already. Although you may want the one from my utility library as I can't remember if the code there is updated or not (where as the utility library code is always up to date).

Anyway in the CSV we really only want a couple of fields. The first is the person calling (we can either use the extension, which is the 9th field, or the IP address if you have that nicely mapped out, which is the 80th field), the person being called (in this case we only care about 911 but we could monitor for anything really, but the field we want is the 30th), and maybe the time (which is the 48th field, and done as the number of seconds since 1/1/1970). So all of that being said, our code is going to look something like this:

    class Program

    {

        static void Main(string[] args)

        {

            try

            {

                EmailSender Sender = new EmailSender();

                Sender.To = "MyEmailAddress";

                Sender.From = "AGenericSystemEmailAddress";

                Sender.Server = "Your SMTP Server";

                Sender.Priority = MailPriority.High;

                Sender.Subject = "911 was called";

                Sender.Body = "";

 

                DateTime Start=new DateTime(1970,1,1);

                List<FileInfo> Files = Utilities.IO.FileManager.FileList("Directory of your call logs", true);

                foreach (FileInfo File in Files)

                {

                    bool Found = false;

                    string IPAddress = "";

                    string Extension="";

                    if (File.Name.ToLower().StartsWith("cdr"))

                    {

                        try

                        {

                            Utilities.FileFormats.CSV.CSV CSVFile = new Utilities.FileFormats.CSV.CSV(Utilities.IO.FileManager.GetFileContents(File.FullName));

                            for (int x = 2; x < CSVFile.NumberOfRows; ++x)

                            {

                                if (CSVFile[x][29].Value == "911" || CSVFile[x][29].Value == "8911")

                                {

                                    IPAddress = CSVFile[x][80].Value;

                                    Extension = CSVFile[x][8].Value;

                                    Found = true;

                                }

                                if (Found)

                                {

                                    DateTime TimeCalled = Start.AddSeconds(int.Parse(CSVFile[x][47].Value)).AddHours(-4);

                                    Sender.Body = "911 was called<br />";

                                    Sender.Body += "Time Called: " + TimeCalled.ToString() + "<br />";

                                    Sender.Body += "Extension: " + Extension + "<br />";

                                    Sender.Body += "IP Address: " + IPAddress + "<br />";

                                    Sender.SendMail();

                                    Found = false;

                                }

                            }

                        }

                        catch { }

                    }

                }

 

                for (int x = 0; x < Files.Count; ++x)

                {

                    try

                    {

                        Files[x].Delete();

                    }

                    catch { }

                }

            }

            catch { throw; }

        }

    }

Note that I'm using stuff from my utility library to make things shorter/simpler. Specifically the EmailSender is nothing but a wrapper for the built in .Net SMTP code, the FileManager is used to get the list of files in the directory and also an individual file's contents, and I'm using the CSV parser that I mentioned earlier (feel free to switch any of this stuff out for your own code). But that's it. With that bit of code (once you fill in the needed fields, etc.) you're good to go. Just set that up as a task to run on the server every minute or two and you have yourself a 911 notifier that only costs you a little bit of time. Plus going this route opens up a whole bunch of potential things that you could look for and do. So take a look, try it out, and happy coding.

kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 8/27/2010 at 8:17 AM
Tags: , ,
Categories: General
Post Information: Permalink | Comments (1) | Post RSSRSS comment feed

Using Unsafe Code for Faster Image Manipulation

Over the past couple months, I've had a lot of traffic (well a lot for me anyway) going toward my various image editing posts. While the general concepts are there, I get a decent number of people complaining that they're a bit slow. They are slow when the image gets to be rather large. The reason for this is because I intentionally use two functions that are incredibly slow, GetPixel and SetPixel... These functions have to figure out the format that the image is actually displayed in, and give us/set the individual pixel in the image. To say the least that's a slow process (safe but slow). So why would I use them if they're so slow? Because they're easy to understand. Most of my code was designed such that someone who didn't know much about images or maybe even that much about C# could see what was going on and get something together for their needs. The alternative gets much more complicated, much faster...

That alternative is by using unsafe code. I can honestly say that there are only a couple times that I've ever seen someone use unsafe code (usually when doing image manipulation). So if you're a C# developer, there is a good chance that you've never (or at least rarely) seen the keyword used. So what the heck is the unsafe keyword? The unsafe keyword is used to define a section of code that uses pointers.  You can define it on a function, encapsulate a small bit of code with it, etc. You're just saying this bit of code uses pointers. If you've done C++ programming, you've dealt with pointers enough that this should be rather simple. For everyone else, well I'm not going to explain pointers that much other than to say that they point to things in memory.

OK, well maybe a little bit more is needed. In our case, think of our image as an array of bytes in memory. When we create a pointer and point it to our image, it does not hold our image. The pointer is simply an int (actually it depends on the language/architecture as to what the type is) that says we can find this image at location X in memory. On top of this we can change where the pointer points. For instance if we add 1 to it, we get the next byte in memory (1 pixel in on our image, assuming 1 pixel=1 byte). It's referred to as pointer arithmetic. That's all you need to know for our purposes, but If you want to know more Google is your friend.

Getting back to the unsafe keyword, the advantages of using pointers and unsafe code is it gets rid of a lot of bounds checks, etc. that slow down your code. The downside is that it can introduce potential security flaws if it's not written correctly... Not to mention they tend to increase the number of bugs that come about (especially with people who have limited experience with them). That being said, we're going to use unsafe code to speed up our image manipulation.

The two functions that were slowing us down were GetPixel and SetPixel. So let's create our own. So how do we do this? Well with images there are a couple steps that you need to do to get at the data so that we can set/get a pixel. The first step (after loading the image) is to lock it. I've written a function to do this step for me:

 

        internal static BitmapData LockImage(Bitmap Image)

        {

            try

            {

                return Image.LockBits(new Rectangle(0, 0, Image.Width, Image.Height),

                    ImageLockMode.ReadWrite, Image.PixelFormat);

            }

            catch { throw; }

        }

With this function we're telling the image to lock all of it (since the rectangle is the entire image) for both reading and writing. The last item is the pixel format of the image. In our case we're using the image's own pixel format, because we don't exactly know what the format is suppose to be. That being said, in later code we're going to limit ourselves to 24 and 32 bit images (expanding this for 48 or 64 bit is actually fairly simple but not something that I needed). In return the function returns a BitmapData class. This class contains our actual bits of data, but we still aren't quite ready to edit it yet. The next step is we need to figure out the actual size of each pixel (luckily for us, they tell us):

 

        internal static int GetPixelSize(BitmapData Data)

        {

            if (Data.PixelFormat == PixelFormat.Format24bppRgb)

                return 3;

            else if (Data.PixelFormat == PixelFormat.Format32bppArgb 

                || Data.PixelFormat == PixelFormat.Format32bppPArgb 

                || Data.PixelFormat == PixelFormat.Format32bppRgb)

                return 4;

            return 0;

        }

As I said earlier, we're only really going to handle 24 and 32 bit images. Once we have our data and know our pixel size, we can actually get/set our needed pixel:

 

        internal static unsafe Color GetPixel(BitmapData Data, int x, int y,int PixelSizeInBytes)

        {

            try

            {

                byte* DataPointer = (byte*)Data.Scan0;

                DataPointer = DataPointer + (y * Data.Stride) + (x * PixelSizeInBytes);

                if (PixelSizeInBytes == 3)

                {

                    return Color.FromArgb(DataPointer[2], DataPointer[1], DataPointer[0]);

                }

                return Color.FromArgb(DataPointer[3], DataPointer[2], DataPointer[1], DataPointer[0]);

            }

            catch { throw; }

        }

 

        internal static unsafe void SetPixel(BitmapData Data, int x, int y,Color PixelColor,int PixelSizeInBytes)

        {

            try

            {

                byte* DataPointer = (byte*)Data.Scan0;

                DataPointer = DataPointer + (y * Data.Stride) + (x * PixelSizeInBytes);

                if (PixelSizeInBytes == 3)

                {

                    DataPointer[2] = PixelColor.R;

                    DataPointer[1] = PixelColor.G;

                    DataPointer[0] = PixelColor.B;

                    return;

                }

                DataPointer[3] = PixelColor.A;

                DataPointer[2] = PixelColor.R;

                DataPointer[1] = PixelColor.G;

                DataPointer[0] = PixelColor.B;

            }

            catch { throw; }

        }

That code gets/sets our individual pixels respectively. In it you'll notice that we finally use the unsafe keyword. Up until now we didn't use any pointers, but here we're using them to point to the actual data. The BitmapData class contains an IntPtr called Scan0. This is the actual data of our image... Well the pointer to our actual data. The Stride property tells us the actual width of the image. You see, if we have an image that is 207 pixels wide, it might not actually be 207 pixels wide. Images, to make them faster to manipulate and load, tend to have actual widths that are multiple of 4s (although with 64 bit processors, I wonder if it would be a multiple of 8...). So in reality the image would request enough memory such that the width was 208. The extra pixel would just be sitting out there, not doing anything. And in normal managed code, it wouldn't matter, but in unsafe pointer land we need to know about it. So using some pointer arithmetic (y*ActualWidthInBytes+x*PixelSizeInBytes), we can get the actual location of the pixel that we want. From here, you'll notice that we're accessing it in reverse order (BGR instead of RGB). I don't know why this is done in memory, but I do remember that bitmaps are actually stored in reverse order. The bottom right pixel is the first one that you come to, stored in BGR order, and you end with the upper left (no idea why this is the case though). Anyway, we get our R, G, B, and potentially A values and create a Color object and return it.

The last thing that we have to do, once we're done manipulating our image, is unlock the Bitmap object. Once again I've built a function to help with that:

 

        internal static void UnlockImage(Bitmap Image,BitmapData ImageData)

        {

            try

            {

                Image.UnlockBits(ImageData);

            }

            catch { throw; }

        }

 

That's all there is to it really. Once unlocked, we're done. We can simply replace our functions from before with these and we end up with a much faster system. For instance we can do a median filter like this:

 

        public static Bitmap MedianFilter(Bitmap OriginalImage, int Size)

        {

            try

            {

                System.Drawing.Bitmap NewBitmap = new System.Drawing.Bitmap(OriginalImage.Width, OriginalImage.Height);

                BitmapData NewData = Image.LockImage(NewBitmap);

                BitmapData OldData = Image.LockImage(OriginalImage);

                int NewPixelSize = Image.GetPixelSize(NewData);

                int OldPixelSize = Image.GetPixelSize(OldData);

                Random.Random TempRandom = new Random.Random();

                int ApetureMin = -(Size / 2);

                int ApetureMax = (Size / 2);

                for (int x = 0; x < NewBitmap.Width; ++x)

                {

                    for (int y = 0; y < NewBitmap.Height; ++y)

                    {

                        List<int> RValues = new List<int>();

                        List<int> GValues = new List<int>();

                        List<int> BValues = new List<int>();

                        for (int x2 = ApetureMin; x2 < ApetureMax; ++x2)

                        {

                            int TempX = x + x2;

                            if (TempX >= 0 && TempX < NewBitmap.Width)

                            {

                                for (int y2 = ApetureMin; y2 < ApetureMax; ++y2)

                                {

                                    int TempY = y + y2;

                                    if (TempY >= 0 && TempY < NewBitmap.Height)

                                    {

                                        Color TempColor = Image.GetPixel(OldData, TempX, TempY, OldPixelSize);

                                        RValues.Add(TempColor.R);

                                        GValues.Add(TempColor.G);

                                        BValues.Add(TempColor.B);

                                    }

                                }

                            }

                        }

                        Color MedianPixel = Color.FromArgb(Math.MathHelper.Median<int>(RValues),

                            Math.MathHelper.Median<int>(GValues),

                            Math.MathHelper.Median<int>(BValues));

                        Image.SetPixel(NewData, x, y, MedianPixel, NewPixelSize);

                    }

                }

                Image.UnlockImage(NewBitmap, NewData);

                Image.UnlockImage(OriginalImage, OldData);

                return NewBitmap;

            }

            catch { throw; }

        }

The Math.MathHelper.Median function simply sorts the list and gets the middle item. But it's not that different from the code before (although a bit cleaned up). The speed difference though is rather amazing. For a small 274x350 image we go from 8 seconds to about 2 seconds. And that's with a simple update. If you wanted, you could increase this further by breaking out the GetPixel and SetPixel functions and doing the pointer arithmetic in the function itself (doing 1 add and 1 assignment instead of 2 multiplications, 2 adds, and an assignment and Color object creation makes things run a bit faster). But still, for a simple update that's a big speed increase.

So try it out. Copy it into your IDE and compile it (you may want to set up a function call, load up an image, save it, etc. so it's at least a somewhat interesting test), I'll wait... Oh, it failed didn't it? The reason for this is because you must compile unsafe code using /unsafe (just go into the properties of the project, build tab, and check the Allow unsafe code box). OK, now try compiling it and you should see a nice, much faster, median filter applied to your image. So try it out, leave feedback, and happy coding.

 

 

 

 

kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 8/20/2010 at 8:34 AM
Tags: , , ,
Categories: C#
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

HaterAide ORM updated to 1.6

I've been quite for a while. The reason for this is two fold. First, I've been on vacation for a while with minimal access to the internet. The second reason is I've been working a lot on HaterAide ORM. For those that never read the series, HaterAide was a learning project for me. I wanted to see how difficult it was to create a basic ORM, what the "magic" was behind them, etc. I find that recreating the wheel is the best way for me to learn something and I've definitely learned a lot thus far from working on it. Since the initial postings and release it has added a number of features that put it up to the level of half way decent (we're even using it at my work now). This release added a number of features including:

1) Added transaction support
2) Added paging support
3) Added ability to override the default table and column names
4) Added ability to mark the database read only or write only
5) Added ability to do batch saving (calling Save when sending in a list of objects will save the entire list in one transaction).
6) Speed increases for all IEnumerables.
7) General speed increases for saving items.
8) Non int/GUID primary keys now work.
9) Size of DLLs reduced considerably.
10) Added the ability to save an object as a sub type.
11) Solution is now Visual Studio 2010
12) Separated database config data so that in the future multiple databases can be supported
13) Added switch so you can auto update the database or manually update the structure of the database.
14) DotCache, Aspectus, and Gestalt are integrated to make the system more modular.
15) Added better checks for null values/non existant objects in the database

Plus a number of fixes. I still need to add features like multiple databases, composite keys, etc. but it's coming along. So give it a look, try it out (usage documentation is included in this release), and happy coding.

Edit: It helps if I put a link to the new download...

kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 8/17/2010 at 5:16 PM
Tags: , ,
Categories: General
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed