On Thu, Jun 20, 2013 at 10:54 PM, Steve Edwards <asterisk....@sedwards.com>wrote:
> On Thu, 20 Jun 2013, Satish Barot wrote: > > Would you mind sharing a sample of your pthread-ed C AGI? This will help >> someone like me who has written AGI in Perl/PHP and now exploring C AGI. >> > > The source code for this particular AGI is about 600 lines and uses my own > AGI library (written before other C AGI libraries were available) so I > don't think it has a whole lot of value to other programmers. > > First a little background on why I used pthreads in this AGI... > > The application was an adult chat platform. (Mostly) guys call in to chat > to (mostly) women and pay $1 to $4 per minute. At the end of the call, the > accumulated charges are billed to their their credit card. > > Charges to credit cards usually take 2 transactions. The first transaction > ('OPEN') places a temporary 'hold' on the card for $XXX. At the end of the > call, a second transaction ('SALE') finalizes the billing for the actual > charges for the call. > > (This '2 step' process is why you may have trouble charging an expensive > dinner after checking into a hotel -- the hotel may have placed a 'hold' > against your credit limit for the expected charge for your entire stay.) > > As originally implemented, Asterisk would play a prompt asking the caller > to enter their card details. After the caller entered a 'valid' card number > (that passes Luhn mod 10) and expiration date (between the current month & > current year and current year + 7). My AGI would then play a prompt > ('Please wait while your card is being verified') and then transmit the > card details to our card processor. Getting a response from the card > processor takes a second or so. My AGI returned the card processor response > code as the 'priority' so the dialplan could continue to the main menu or > play a prompt indicating why the card details failed. After 3 failures, a > caller was played a prompt instructing them on alternative billing methods > (high rate NPAs, check by phone, etc). > > This client was extremely particular about the 'caller experience' and > thought the 'second or so' of silence while the card was being verified was > excessive and had to be eliminated. > > Since the card processing time was not under my control, my solution was > to change my AGI to create a second thread to play the 'please wait' prompt > while the 'main line' code shipped off the card details to the processor. > > When I got the processor's response (which was usually before the prompt > finished playing), the 'main line' code would 'join' the prompt thread. If > the prompt thread was finished playing the prompt, execution continued > immediately. If the prompt thread was still playing the prompt, execution > continued as soon as the prompt thread received the AGI response from > Asterisk. None of this took any special programming or synchronizing from > me. It all 'just worked' because of the way pthreads are implemented. > > So, what did I learn that would be of value to you? Really understand the > AGI protocol and you won't make a bunch of silly mistakes. > > The AGI protocol is very simple: > > 1) Read the AGI environment from stdin before you do anything in your AGI > that interacts with Asterisk. > > 2) Write your AGI request to stdout. > > 3) Read Asterisk's AGI response from stdin. > > 4) Rinse, lather, repeat (steps 2 & 3). > > If you use an established AGI library (like you really, really should), > this should be taken care of automagically, but understanding what's really > going on will help when things don't work as expected. > > The number 1 mistake new AGI programmers make is not reading the AGI > environment. Sometimes they 'get away' with it, some times they don't. > > The number 2 mistake is not reading the responses (step 3). Again, > sometimes it works, sometimes it doesn't > > The number 3 mistake new (and old salts like me still make on occasion) is > doing any I/O on stdin or stdout. A lot of bad debugging centers around > 'throw in a printf somewhere to see what's going on' instead of using 'real > programmer' tools like gdb*. > > If you're using an established AGI library, the crucial relationship > between steps 2 and 3 will be take care of -- unless you're using multiple > threads. > > If thread 1 issues an AGI request (writing to stdout) and then thread 2 > issues an AGI request (also writing to stdout) before thread 1 reads it's > response, you've broken the protocol and bad things will happen. Maybe not > immediately, but certainly when you're demonstrating the system to your > boss. > > So my first suggestion (after using an established library and without > knowing what your use case is) would be to 'designate' a single thread as > 'the Asterisk' thread and only interact (via stdin and stdout) with > Asterisk in that thread. If that's not feasible, you're going to need some > sort of 'semaphore' mechanism so you don't 'intermingle' your AGI requests > and responses and thereby violate the AGI protocol. > > Another couple of suggestions unrelated to threads, but are best (IMNSHO) > practices for AGIs in general: > > 1) Use getopt_long(). Most (everybody but me?) seems to like vague, > conflicting, and impossible to document or remember AGI command line > options. Seriously, which would you rather see in "the other guy's" > dialplan 5 years after he's gone: > > exten = *,n,agi(foo|5555551212|10255|**d) > > or > > exten = *,n,agi(foo,--debug,--ani=**5555551212,--charge=10255) > > 2) Use syslog() to say what's going on in your AGI. You can vary the level > of 'verbosity' by signals or by command line options (see #1). > > Sheesh I'm long winded :) > > If you still think it would have value to you after reading this email, > please let me know. > > *) A valuable debugging technique is to enable AGI debugging in the > Asterisk CLI and capture the session when your AGI executes. This file can > be munged into a file of the AGI environment and the AGI responses. Then, > when you have your AGI loaded into gdb you can 'run' it specifying this > file as input ('r <my-agi-input') and step through your AGI with some > serious debugging horsepower behind you. Note that this technique is > completely separate from Asterisk and can even take place on a separate > computer that doesn't even have Asterisk installed. > > > -- > Thanks in advance, > ------------------------------**------------------------------** > ------------- > Steve Edwards sedwa...@sedwards.com Voice: +1-760-468-3867 PST > Newline Fax: +1-760-731-3000 > > :) You reminded me of my teacher of old school days. Very well explained. I have somewhat similar requirement where I need to play some announcements to entertain a caller while passing/processing some data through webservice call (). Thanks a lot for your response. --Satish Barot
-- _____________________________________________________________________ -- Bandwidth and Colocation Provided by http://www.api-digital.com -- New to Asterisk? Join us for a live introductory webinar every Thurs: http://www.asterisk.org/hello asterisk-users mailing list To UNSUBSCRIBE or update options visit: http://lists.digium.com/mailman/listinfo/asterisk-users