BAF's Ramblings » #programming

BAFIRC: CTCP Layer

October 8, 2010bafirc

So, I was working on the CTCP layer tonight. I had planned to keep it a separate entity, and then debate ensued over how to actually implement ‘CtcpMessage’ - whether it should subclass IrcMessage, or be composed of it. After a lengthy discussion, I decided to just add it into the core IRC layer, with two new pseudo IRC Commands - CTCP and NCTCP, CTCP being for requests/extended data messages (like ACTION) sent via privmsg, and NCTCP being for replies sent via NOTICE.

I’m not totally sure if I like how I actually implemented this, I’ll have to sleep on it and see in the morning. I created a CtcpHelper class that looks at IrcMessage objects and maps back and forth the commands. When parsing a message, it checks if it’s actually CTCP, and if it is, forges the command type appropriately (it also rebuilds the parameter list, privmsg/notice only have two parameters, a destination and a message, but CTCP/NCTCP have three, destination, ctcp command, and ctcp data). This isn’t too bad.

The part I’m still not totally sure on is constructing it back to a string that can be sent to the IRC server. In here, I added another path to my if statements that maps the command back if it’s a CTCP message, and then when I actually print the parameters out, it calls another function in CtcpHelper to “unbuild” the array, dumping it back to destination/message and formatting the message into CTCP format.

Anyway, this is probably about as clear as mud. I’m pretty tired right now, and I was even making some stupid mistakes while coding. I’m going to go to bed and sleep a good long while (until I wake up, rather than until the alarm wakes me). If need be, I’ll revise or rewrite this post tomorrow.

Music Generation

October 7, 2010

I am taking an media arts class at school right now. In two weeks, I have an assignment due, some sort of musical composition that involves form. The short of it is that software that generates music via some sort of algorithm is acceptable.

This idea intrigued me when it was mentioned, maybe because I’m a coder (not an artist/composer). My idea is to find some sort of algorithm to auralize various data sources - e.g., the current system clock, the US Debt Clock, the latest trending topics on twitter, or whatever. That is, take a raw bitsream, and… transform it into audio.

The code should be easy to produce once I come up with an algorithm. At any rate, this may be competing with BAFIRC for my time at various points over the next two weeks, but either way, I’ll blog about what I’m working on.

BAFIRC: IRC Layer Complete?

October 6, 2010bafirc

So, I think the IRC layer is pretty much complete at this point. I’ve added options to enable/disable auto-reconnect, added error reporting/handling, and added configurable message throttling/flood control (with defaults that match the suggestions in RFC2813).

I did come across one bug while testing the throttling, where messages were being sent out of order. This was a bug in the way I was inserting messages into the prioritized queue. Just one character made the difference - I was determining the index at which to insert by counting the number of messages with a priority greater than the message being sent. What I meant to do was count the number of messages with a priority greater than or equal to the message being sent. The result was that when you sent a message, it was put in the queue in front of any other message with the same priority, instead of behind them all. Adding one tiny little equals sign to the code fixed that one.

As far as throttling goes, it is accomplished with a rolling timer. The connection processor is signaled that there is data waiting in the send queue by an event that is waited on along with the incoming data. Before, it would just dump the whole queue to the server whenever this flag was set. With the flood control now, it will dump one message at a time, until the throttle has been hit. At that point, it makes note of when sending can be re-enabled, and leaves early, before sending everything in the queue. On the next pass, if sending shouldn’t be re-enabled yet, we block the send-queue-has-data flag, such that we will only respond to incoming data. When throttling is occurring, a wait timeout is observed, so we can loop back around and re-enable the send-queue-has-data flag. Once this is re-enabled, we will hit the flag (if data is waiting) and keep sending data and repeating this process until the queue is emptied out. When sending is enabled, we revert to an infinite timeout, waiting on both receiving and sending.

There are three configuration values for the throttling - enabled, burst limit, and time per message. You are allowed to a number of messages, up to the burst limit, before you begin being throttled. After then, you can send one message every (time per message). The default values are derived from the algorithm described in RFC2813, section 5.8 - burst limit of 5, and time per message of 2 seconds. So, unless overridden (or disabled), you will be allowed to send 5 messages without being throttled (assuming you haven’t sent anything for the 10 seconds preceding that). Once you begin being throttled, a message will make it out to the server roughly once every 2 seconds (give or take a few ms, of course, depending on the OS scheduler, timer accuracy, etc.). Actually, I lied a tiny bit, it doesn’t actually wait 2 seconds per message in this case - with a burst allowance of 5, 5*2 = 10 seconds, so it will wait until 10 seconds after the first message in the ‘flood’ was sent (then 12, then 14, etc).

Error reporting and handling was added as well. If any uncaught exceptions are thrown on the message processor or connection processor thread, they will be swallowed and reported via an event. One change I may make later is to put some limits on this, that is, if you receive a configurable number of exceptions within a given time frame, then you give up and stop trying to reconnect or process messages (rather than potentially hammering the server if you keep being disconnected for some reason). I could also implement back-off into this, whereas it will try to reconnect instantly at first, then slowly back-off and wait longer and longer for a reconnect, until it finally gives up.

At any rate, I think that about does it for this portion of the project. It did run all night last night and all day today without disconnecting or throwing any exceptions, and I’ve tested out the throttling algorithm. SSL connections work. Everything seems to work great, so it’s time to move on. Still need to decide what I’ll start next… CTCP/DCC support or the plugin system. Decisions, decisions.

BAFIRC: Tonight's Plan

October 5, 2010bafirc

This post is mostly a short plan to myself, but I don’t think I have any pressing school work that needs to be done tonight. Being so, I’d like to get some more code going on BAFIRC.

I plan to finish the IRC connection layer and write a short test to play with it a bit. I will probably borrow a bit from the cbots IRC layer, at least as far as the queue management and connection loop go, just because it’s solid code that’s seen several iterations and works well already. That’s all I’m aiming for tonight though, I don’t want to spend too much time on it. After that, I need to plan out the DCC and CTCP support modules, and begin figuring out the plugin system and API for that. After that, I can begin building the core.

Look for my nightly update/status report later!

BAFIRC: IRC Layer Progress

October 5, 2010bafirc

I spent a chunk of time working on my IRC layer some more tonight. I did the busy work of ensuring my list of commands and replies was fairly exhaustive according to the RFCs, and implemented static functions for almost every possible command/parameter combination allowed by the RFC. This was not strictly necessary, just more of syntactic sugar for use in plugins/etc, but it makes the interface a lot nicer - i.e., rather than calling ‘new IrcMessage(IrcCommand.Privmsg, “#channel”, “hi”);’ you can call ‘IrcMessage.Privmsg(“#channel”, “hi”);’). This makes it easier to use without any knowledge of the RFC, and less error prone.

After completing that, I moved on to begin laying the framework for the IrcConnection class. I did a rough layout of the class and its members and methods, and began implementing a little. The guts of the connection management thread still need to be filled in, as do the relevant chunks of code to handle the management thread itself. Other than that, I wrote the event management system. So far, there are only four events (remember, this is a very thin layer above the IRC protocol) - ConnectionStateChanged, MessageReceived, MessageSent, and MessageSending. Note the difference between the sent and sending events - MessageSent is fired after a message is queued for sending, whereas MessageSending is fired before the message is queued, giving plugins the chance to review the message, possibly editing it or throwing it away all together. This may sound risky from a security standpoint, but remember, plugins should already be trusted by you anyway. They’re compiled code running on your machine, and have access to all messages sent and received anyway.

Hopefully I will have time tomorrow night to finish implementing what needs to be done on the connection class. It will support SSL and binding to a particular local IP, and will have configurable queuing settings. I haven’t figured out what these configurations will consist of, but likely will involve a flag to turn on or off queuing, and some values to specify what the maximum sustained rate of sending and burst rates are. I’m thinking number of messages (or bytes?) per second will be the values. It will track how much you are sending, and once you exceed the burst rate, it will kick in and throttle messages back to the sustained rate, until the queue is empty (and perhaps, a configurable penalty time has passed).

That’s all for now! Once I’ve implemented my IRC layer (and implementing, or at least stubbing out, the CTCP and DCC layers) and tested it a bunch, I will begin building the plugin system, implementing the pieces required for dealing with IRC.