Mon May 14 04:43:00 2007

Asterisk developer's documentation


res_smdi.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- A telephony toolkit for Linux.
00003  *
00004  * Copyright (C) 2005-2006, Digium, Inc.
00005  *
00006  * Matthew A. Nicholson <mnicholson@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*!
00020  * \file
00021  * \brief SMDI support for Asterisk.
00022  * \author Matthew A. Nicholson <mnicholson@digium.com>
00023  */
00024 
00025 #include "asterisk.h"
00026 
00027 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
00028 
00029 #include <stdio.h>
00030 #include <stdlib.h>
00031 #include <errno.h>
00032 #include <termios.h>
00033 #include <sys/time.h>
00034 #include <time.h>
00035 #include <ctype.h>
00036 
00037 #include "asterisk/module.h"
00038 #include "asterisk/lock.h"
00039 #include "asterisk/utils.h"
00040 #include "asterisk/smdi.h"
00041 #include "asterisk/config.h"
00042 #include "asterisk/astobj.h"
00043 #include "asterisk/io.h"
00044 #include "asterisk/logger.h"
00045 #include "asterisk/utils.h"
00046 #include "asterisk/options.h"
00047 
00048 /* Message expiry time in milliseconds */
00049 #define SMDI_MSG_EXPIRY_TIME  30000 /* 30 seconds */
00050 
00051 static const char config_file[] = "smdi.conf";
00052 
00053 static void ast_smdi_md_message_push(struct ast_smdi_interface *iface, struct ast_smdi_md_message *msg);
00054 static void ast_smdi_mwi_message_push(struct ast_smdi_interface *iface, struct ast_smdi_mwi_message *msg);
00055 
00056 static void *smdi_read(void *iface_p);
00057 static int smdi_load(int reload);
00058 
00059 struct module_symbols *me; /* initialized in load_module() */
00060 
00061 /*! \brief SMDI interface container. */
00062 struct ast_smdi_interface_container {
00063    ASTOBJ_CONTAINER_COMPONENTS(struct ast_smdi_interface);
00064 } smdi_ifaces;
00065 
00066 /*! 
00067  * \internal
00068  * \brief Push an SMDI message to the back of an interface's message queue.
00069  * \param iface a pointer to the interface to use.
00070  * \param md_msg a pointer to the message to use.
00071  */
00072 static void ast_smdi_md_message_push(struct ast_smdi_interface *iface, struct ast_smdi_md_message *md_msg)
00073 {
00074    ASTOBJ_CONTAINER_LINK_END(&iface->md_q, md_msg);
00075 }
00076 
00077 /*!
00078  * \internal
00079  * \brief Push an SMDI message to the back of an interface's message queue.
00080  * \param iface a pointer to the interface to use.
00081  * \param mwi_msg a pointer to the message to use.
00082  */
00083 static void ast_smdi_mwi_message_push(struct ast_smdi_interface *iface, struct ast_smdi_mwi_message *mwi_msg)
00084 {
00085    ASTOBJ_CONTAINER_LINK_END(&iface->mwi_q, mwi_msg);
00086 }
00087 
00088 /*!
00089  * \brief Set the MWI indicator for a mailbox.
00090  * \param iface the interface to use.
00091  * \param mailbox the mailbox to use.
00092  */
00093 int ast_smdi_mwi_set(struct ast_smdi_interface *iface, const char *mailbox)
00094 {
00095    FILE *file;
00096    int i;
00097    
00098    file = fopen(iface->name, "w");
00099    if(!file) {
00100       ast_log(LOG_ERROR, "Error opening SMDI interface %s (%s) for writing\n", iface->name, strerror(errno));
00101       return 1;
00102    }  
00103 
00104    ASTOBJ_WRLOCK(iface);
00105 
00106    fprintf(file, "OP:MWI ");
00107 
00108    for(i = 0; i < iface->msdstrip; i++)
00109       fprintf(file, "0");
00110 
00111    fprintf(file, "%s!\x04", mailbox);
00112    fclose(file);
00113 
00114    ASTOBJ_UNLOCK(iface);
00115    ast_log(LOG_DEBUG, "Sent MWI set message for %s on %s\n", mailbox, iface->name);
00116    return 0;
00117 }
00118 
00119 /*! 
00120  * \brief Unset the MWI indicator for a mailbox.
00121  * \param iface the interface to use.
00122  * \param mailbox the mailbox to use.
00123  */
00124 int ast_smdi_mwi_unset(struct ast_smdi_interface *iface, const char *mailbox)
00125 {
00126    FILE *file;
00127    int i;
00128    
00129    file = fopen(iface->name, "w");
00130    if(!file) {
00131       ast_log(LOG_ERROR, "Error opening SMDI interface %s (%s) for writing\n", iface->name, strerror(errno));
00132       return 1;
00133    }  
00134 
00135    ASTOBJ_WRLOCK(iface);
00136 
00137    fprintf(file, "RMV:MWI ");
00138 
00139    for(i = 0; i < iface->msdstrip; i++)
00140       fprintf(file, "0");
00141 
00142    fprintf(file, "%s!\x04", mailbox);
00143    fclose(file);
00144 
00145    ASTOBJ_UNLOCK(iface);
00146    ast_log(LOG_DEBUG, "Sent MWI unset message for %s on %s\n", mailbox, iface->name);
00147    return 0;
00148 }
00149 
00150 /*!
00151  * \brief Put an SMDI message back in the front of the queue.
00152  * \param iface a pointer to the interface to use.
00153  * \param md_msg a pointer to the message to use.
00154  *
00155  * This function puts a message back in the front of the specified queue.  It
00156  * should be used if a message was popped but is not going to be processed for
00157  * some reason, and the message needs to be returned to the queue.
00158  */
00159 void ast_smdi_md_message_putback(struct ast_smdi_interface *iface, struct ast_smdi_md_message *md_msg)
00160 {
00161    ASTOBJ_CONTAINER_LINK_START(&iface->md_q, md_msg);
00162 }
00163 
00164 /*!
00165  * \brief Put an SMDI message back in the front of the queue.
00166  * \param iface a pointer to the interface to use.
00167  * \param mwi_msg a pointer to the message to use.
00168  *
00169  * This function puts a message back in the front of the specified queue.  It
00170  * should be used if a message was popped but is not going to be processed for
00171  * some reason, and the message needs to be returned to the queue.
00172  */
00173 void ast_smdi_mwi_message_putback(struct ast_smdi_interface *iface, struct ast_smdi_mwi_message *mwi_msg)
00174 {
00175    ASTOBJ_CONTAINER_LINK_START(&iface->mwi_q, mwi_msg);
00176 }
00177 
00178 /*! 
00179  * \brief Get the next SMDI message from the queue.
00180  * \param iface a pointer to the interface to use.
00181  *
00182  * This function pulls the first unexpired message from the SMDI message queue
00183  * on the specified interface.  It will purge all expired SMDI messages before
00184  * returning.
00185  *
00186  * \return the next SMDI message, or NULL if there were no pending messages.
00187  */
00188 struct ast_smdi_md_message *ast_smdi_md_message_pop(struct ast_smdi_interface *iface)
00189 {
00190    struct ast_smdi_md_message *md_msg = ASTOBJ_CONTAINER_UNLINK_START(&iface->md_q);
00191    struct timeval now;
00192    long elapsed = 0;
00193 
00194    /* purge old messages */
00195    now = ast_tvnow();
00196    while (md_msg) {
00197       elapsed = ast_tvdiff_ms(now, md_msg->timestamp);
00198 
00199       if (elapsed > iface->msg_expiry) {
00200          /* found an expired message */
00201          ASTOBJ_UNREF(md_msg, ast_smdi_md_message_destroy);
00202          ast_log(LOG_NOTICE, "Purged expired message from %s SMDI MD message queue.  Message was %ld milliseconds too old.\n",
00203             iface->name, elapsed - iface->msg_expiry);
00204          md_msg = ASTOBJ_CONTAINER_UNLINK_START(&iface->md_q);
00205       }
00206       else {
00207          /* good message, return it */
00208          break;
00209       }
00210    }
00211 
00212    return md_msg;
00213 }
00214 
00215 /*!
00216  * \brief Get the next SMDI message from the queue.
00217  * \param iface a pointer to the interface to use.
00218  * \param timeout the time to wait before returning in milliseconds.
00219  *
00220  * This function pulls a message from the SMDI message queue on the specified
00221  * interface.  If no message is available this function will wait the specified
00222  * amount of time before returning.
00223  *
00224  * \return the next SMDI message, or NULL if there were no pending messages and
00225  * the timeout has expired.
00226  */
00227 extern struct ast_smdi_md_message *ast_smdi_md_message_wait(struct ast_smdi_interface *iface, int timeout)
00228 {
00229    struct timeval start;
00230    long diff = 0;
00231    struct ast_smdi_md_message *msg;
00232 
00233    start = ast_tvnow();
00234    while (diff < timeout) {
00235 
00236       if ((msg = ast_smdi_md_message_pop(iface)))
00237          return msg;
00238 
00239       /* check timeout */
00240       diff = ast_tvdiff_ms(ast_tvnow(), start);
00241    }
00242 
00243    return (ast_smdi_md_message_pop(iface));
00244 }
00245 
00246 /*!
00247  * \brief Get the next SMDI message from the queue.
00248  * \param iface a pointer to the interface to use.
00249  *
00250  * This function pulls the first unexpired message from the SMDI message queue
00251  * on the specified interface.  It will purge all expired SMDI messages before
00252  * returning.
00253  *
00254  * \return the next SMDI message, or NULL if there were no pending messages.
00255  */
00256 extern struct ast_smdi_mwi_message *ast_smdi_mwi_message_pop(struct ast_smdi_interface *iface)
00257 {
00258    struct ast_smdi_mwi_message *mwi_msg = ASTOBJ_CONTAINER_UNLINK_START(&iface->mwi_q);
00259    struct timeval now;
00260    long elapsed = 0;
00261 
00262    /* purge old messages */
00263    now = ast_tvnow();
00264    while (mwi_msg)   {
00265       elapsed = ast_tvdiff_ms(now, mwi_msg->timestamp);
00266 
00267       if (elapsed > iface->msg_expiry) {
00268          /* found an expired message */
00269          ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
00270          ast_log(LOG_NOTICE, "Purged expired message from %s SMDI MWI message queue.  Message was %ld milliseconds too old.\n",
00271             iface->name, elapsed - iface->msg_expiry);
00272          mwi_msg = ASTOBJ_CONTAINER_UNLINK_START(&iface->mwi_q);
00273       }
00274       else {
00275          /* good message, return it */
00276          break;
00277       }
00278    }
00279 
00280    return mwi_msg;
00281 }
00282 
00283 /*!
00284  * \brief Get the next SMDI message from the queue.
00285  * \param iface a pointer to the interface to use.
00286  * \param timeout the time to wait before returning in milliseconds.
00287  *
00288  * This function pulls a message from the SMDI message queue on the specified
00289  * interface.  If no message is available this function will wait the specified
00290  * amount of time before returning.
00291  *
00292  * \return the next SMDI message, or NULL if there were no pending messages and
00293  * the timeout has expired.
00294  */
00295 extern struct ast_smdi_mwi_message *ast_smdi_mwi_message_wait(struct ast_smdi_interface *iface, int timeout)
00296 {
00297    struct timeval start;
00298    long diff = 0;
00299    struct ast_smdi_mwi_message *msg;
00300 
00301    start = ast_tvnow();
00302    while (diff < timeout) {
00303 
00304       if ((msg = ast_smdi_mwi_message_pop(iface)))
00305          return msg;
00306 
00307       /* check timeout */
00308       diff = ast_tvdiff_ms(ast_tvnow(), start);
00309    }
00310 
00311    return (ast_smdi_mwi_message_pop(iface));
00312 }
00313 
00314 /*!
00315  * \brief Find an SMDI interface with the specified name.
00316  * \param iface_name the name/port of the interface to search for.
00317  *
00318  * \return a pointer to the interface located or NULL if none was found.  This
00319  * actually returns an ASTOBJ reference and should be released using
00320  * #ASTOBJ_UNREF(iface, ast_smdi_interface_destroy).
00321  */
00322 extern struct ast_smdi_interface *ast_smdi_interface_find(const char *iface_name)
00323 {
00324    return (ASTOBJ_CONTAINER_FIND(&smdi_ifaces, iface_name));
00325 }
00326 
00327 /*! \brief Read an SMDI message.
00328  *
00329  * \param iface_p the SMDI interface to read from.
00330  *
00331  * This function loops and reads from and SMDI interface.  It must be stopped
00332  * using pthread_cancel().
00333  */
00334 static void *smdi_read(void *iface_p)
00335 {
00336    struct ast_smdi_interface *iface = iface_p;
00337    struct ast_smdi_md_message *md_msg;
00338    struct ast_smdi_mwi_message *mwi_msg;
00339    char c = '\0';
00340    char *cp = NULL;
00341    int i;
00342    int start = 0;
00343       
00344    /* read an smdi message */
00345    while ((c = fgetc(iface->file))) {
00346 
00347       /* check if this is the start of a message */
00348       if (!start) {
00349          if (c == 'M')
00350             start = 1;
00351       }
00352       else { /* Determine if this is a MD or MWI message */
00353          if(c == 'D') { /* MD message */
00354             start = 0;
00355 
00356             if (!(md_msg = ast_calloc(1, sizeof(*md_msg)))) {
00357                ASTOBJ_UNREF(iface,ast_smdi_interface_destroy);
00358                return NULL;
00359             }
00360             
00361             ASTOBJ_INIT(md_msg);
00362 
00363             /* read the message desk number */
00364             for(i = 0; i < SMDI_MESG_DESK_NUM_LEN; i++)
00365                md_msg->mesg_desk_num[i] = fgetc(iface->file);
00366 
00367             md_msg->mesg_desk_num[SMDI_MESG_DESK_NUM_LEN] = '\0';
00368 
00369             /* read the message desk terminal number */
00370             for(i = 0; i < SMDI_MESG_DESK_TERM_LEN; i++)
00371                md_msg->mesg_desk_term[i] = fgetc(iface->file);
00372 
00373             md_msg->mesg_desk_term[SMDI_MESG_DESK_TERM_LEN] = '\0';
00374 
00375             /* read the message type */
00376             md_msg->type = fgetc(iface->file);
00377             
00378             /* read the forwarding station number (may be blank) */
00379             cp = &md_msg->fwd_st[0];
00380             for (i = 0; i < SMDI_MAX_STATION_NUM_LEN + 1; i++) {
00381                if((c = fgetc(iface->file)) == ' ') {
00382                   *cp = '\0';
00383                   break;
00384                }
00385 
00386                /* store c in md_msg->fwd_st */
00387                if( i >= iface->msdstrip)
00388                   *cp++ = c;
00389             }
00390 
00391             /* make sure the value is null terminated, even if this truncates it */
00392             md_msg->fwd_st[SMDI_MAX_STATION_NUM_LEN] = '\0';
00393             cp = NULL;
00394             
00395             /* read the calling station number (may be blank) */
00396             cp = &md_msg->calling_st[0];
00397             for (i = 0; i < SMDI_MAX_STATION_NUM_LEN + 1; i++) {
00398                if (!isdigit((c = fgetc(iface->file)))) {
00399                   *cp = '\0';
00400                   break;
00401                }
00402 
00403                /* store c in md_msg->calling_st */
00404                if (i >= iface->msdstrip)
00405                   *cp++ = c;
00406             }
00407 
00408             /* make sure the value is null terminated, even if this truncates it */
00409             md_msg->calling_st[SMDI_MAX_STATION_NUM_LEN] = '\0';
00410             cp = NULL;
00411 
00412             /* add the message to the message queue */
00413             md_msg->timestamp = ast_tvnow();
00414             ast_smdi_md_message_push(iface, md_msg);
00415             ast_log(LOG_DEBUG, "Recieved SMDI MD message on %s\n", iface->name);
00416             
00417             ASTOBJ_UNREF(md_msg, ast_smdi_md_message_destroy);
00418 
00419          } else if(c == 'W') { /* MWI message */
00420             start = 0;
00421 
00422             if (!(mwi_msg = ast_calloc(1, sizeof(*mwi_msg)))) {
00423                ASTOBJ_UNREF(iface,ast_smdi_interface_destroy);
00424                return NULL;
00425             }
00426 
00427             ASTOBJ_INIT(mwi_msg);
00428 
00429             /* discard the 'I' (from 'MWI') */
00430             fgetc(iface->file);
00431             
00432             /* read the forwarding station number (may be blank) */
00433             cp = &mwi_msg->fwd_st[0];
00434             for (i = 0; i < SMDI_MAX_STATION_NUM_LEN + 1; i++) {
00435                if ((c = fgetc(iface->file)) == ' ') {
00436                   *cp = '\0';
00437                   break;
00438                }
00439 
00440                /* store c in md_msg->fwd_st */
00441                if (i >= iface->msdstrip)
00442                   *cp++ = c;
00443             }
00444 
00445             /* make sure the station number is null terminated, even if this will truncate it */
00446             mwi_msg->fwd_st[SMDI_MAX_STATION_NUM_LEN] = '\0';
00447             cp = NULL;
00448             
00449             /* read the mwi failure cause */
00450             for (i = 0; i < SMDI_MWI_FAIL_CAUSE_LEN; i++)
00451                mwi_msg->cause[i] = fgetc(iface->file);
00452 
00453             mwi_msg->cause[SMDI_MWI_FAIL_CAUSE_LEN] = '\0';
00454 
00455             /* add the message to the message queue */
00456             mwi_msg->timestamp = ast_tvnow();
00457             ast_smdi_mwi_message_push(iface, mwi_msg);
00458             ast_log(LOG_DEBUG, "Recieved SMDI MWI message on %s\n", iface->name);
00459             
00460             ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
00461          } else {
00462             ast_log(LOG_ERROR, "Unknown SMDI message type recieved on %s (M%c).\n", iface->name, c);
00463             start = 0;
00464          }
00465       }
00466    }
00467 
00468    ast_log(LOG_ERROR, "Error reading from SMDI interface %s, stopping listener thread\n", iface->name);
00469    ASTOBJ_UNREF(iface,ast_smdi_interface_destroy);
00470    return NULL;
00471 }
00472 
00473 /*! \brief ast_smdi_md_message destructor. */
00474 void ast_smdi_md_message_destroy(struct ast_smdi_md_message *msg)
00475 {
00476    free(msg);
00477 }
00478 
00479 /*! \brief ast_smdi_mwi_message destructor. */
00480 void ast_smdi_mwi_message_destroy(struct ast_smdi_mwi_message *msg)
00481 {
00482    free(msg);
00483 }
00484 
00485 /*! \brief ast_smdi_interface destructor. */
00486 void ast_smdi_interface_destroy(struct ast_smdi_interface *iface)
00487 {
00488    if (iface->thread != AST_PTHREADT_NULL && iface->thread != AST_PTHREADT_STOP) {
00489       pthread_cancel(iface->thread);
00490       pthread_join(iface->thread, NULL);
00491    }
00492    
00493    iface->thread = AST_PTHREADT_STOP;
00494    
00495    if(iface->file) 
00496       fclose(iface->file);
00497    
00498    ASTOBJ_CONTAINER_DESTROYALL(&iface->md_q, ast_smdi_md_message_destroy);
00499    ASTOBJ_CONTAINER_DESTROYALL(&iface->mwi_q, ast_smdi_mwi_message_destroy);
00500    ASTOBJ_CONTAINER_DESTROY(&iface->md_q);
00501    ASTOBJ_CONTAINER_DESTROY(&iface->mwi_q);
00502    free(iface);
00503 
00504    ast_module_unref(ast_module_info->self);
00505 }
00506 
00507 /*!
00508  * \internal
00509  * \brief Load and reload SMDI configuration.
00510  * \param reload this should be 1 if we are reloading and 0 if not.
00511  *
00512  * This function loads/reloads the SMDI configuration and starts and stops
00513  * interfaces accordingly.
00514  *
00515  * \return zero on success, -1 on failure, and 1 if no smdi interfaces were started.
00516  */
00517 static int smdi_load(int reload)
00518 {
00519    struct ast_config *conf;
00520    struct ast_variable *v;
00521    struct ast_smdi_interface *iface = NULL;
00522    int res = 0;
00523 
00524    /* Config options */
00525    speed_t baud_rate = B9600;     /* 9600 baud rate */
00526    tcflag_t paritybit = PARENB;   /* even parity checking */
00527    tcflag_t charsize = CS7;       /* seven bit characters */
00528    int stopbits = 0;              /* One stop bit */
00529    
00530    int msdstrip = 0;              /* strip zero digits */
00531    long msg_expiry = SMDI_MSG_EXPIRY_TIME;
00532    
00533    conf = ast_config_load(config_file);
00534 
00535    if (!conf) {
00536       if (reload)
00537          ast_log(LOG_NOTICE, "Unable to reload config %s: SMDI untouched\n", config_file);
00538       else
00539          ast_log(LOG_NOTICE, "Unable to load config %s: SMDI disabled\n", config_file);
00540       return 1;
00541    }
00542 
00543    /* Mark all interfaces that we are listening on.  We will unmark them
00544     * as we find them in the config file, this way we know any interfaces
00545     * still marked after we have finished parsing the config file should
00546     * be stopped.
00547     */
00548    if (reload)
00549       ASTOBJ_CONTAINER_MARKALL(&smdi_ifaces);
00550 
00551    for (v = ast_variable_browse(conf, "interfaces"); v; v = v->next) {
00552       if (!strcasecmp(v->name, "baudrate")) {
00553          if (!strcasecmp(v->value, "9600"))
00554             baud_rate = B9600;
00555          else if(!strcasecmp(v->value, "4800"))
00556             baud_rate = B4800;
00557          else if(!strcasecmp(v->value, "2400"))
00558             baud_rate = B2400;
00559          else if(!strcasecmp(v->value, "1200"))
00560             baud_rate = B1200;
00561          else {
00562             ast_log(LOG_NOTICE, "Invalid baud rate '%s' specified in %s (line %d), using default\n", v->value, config_file, v->lineno);
00563             baud_rate = B9600;
00564          }
00565       } else if (!strcasecmp(v->name, "msdstrip")) {
00566          if (!sscanf(v->value, "%d", &msdstrip)) {
00567             ast_log(LOG_NOTICE, "Invalid msdstrip value in %s (line %d), using default\n", config_file, v->lineno);
00568             msdstrip = 0;
00569          } else if (0 > msdstrip || msdstrip > 9) {
00570             ast_log(LOG_NOTICE, "Invalid msdstrip value in %s (line %d), using default\n", config_file, v->lineno);
00571             msdstrip = 0;
00572          }
00573       } else if (!strcasecmp(v->name, "msgexpirytime")) {
00574          if (!sscanf(v->value, "%ld", &msg_expiry)) {
00575             ast_log(LOG_NOTICE, "Invalid msgexpirytime value in %s (line %d), using default\n", config_file, v->lineno);
00576             msg_expiry = SMDI_MSG_EXPIRY_TIME;
00577          }
00578       } else if (!strcasecmp(v->name, "paritybit")) {
00579          if (!strcasecmp(v->value, "even"))
00580             paritybit = PARENB;
00581          else if (!strcasecmp(v->value, "odd"))
00582             paritybit = PARENB | PARODD;
00583          else if (!strcasecmp(v->value, "none"))
00584             paritybit = ~PARENB;
00585          else {
00586             ast_log(LOG_NOTICE, "Invalid parity bit setting in %s (line %d), using default\n", config_file, v->lineno);
00587             paritybit = PARENB;
00588          }
00589       } else if (!strcasecmp(v->name, "charsize")) {
00590          if (!strcasecmp(v->value, "7"))
00591             charsize = CS7;
00592          else if (!strcasecmp(v->value, "8"))
00593             charsize = CS8;
00594          else {
00595             ast_log(LOG_NOTICE, "Invalid character size setting in %s (line %d), using default\n", config_file, v->lineno);
00596             charsize = CS7;
00597          }
00598       } else if (!strcasecmp(v->name, "twostopbits")) {
00599          stopbits = ast_true(v->name);
00600       } else if (!strcasecmp(v->name, "smdiport")) {
00601          if (reload) {
00602             /* we are reloading, check if we are already
00603              * monitoring this interface, if we are we do
00604              * not want to start it again.  This also has
00605              * the side effect of not updating different
00606              * setting for the serial port, but it should
00607              * be trivial to rewrite this section so that
00608              * options on the port are changed without
00609              * restarting the interface.  Or the interface
00610              * could be restarted with out emptying the
00611              * queue. */
00612             if ((iface = ASTOBJ_CONTAINER_FIND(&smdi_ifaces, v->value))) {
00613                ast_log(LOG_NOTICE, "SMDI interface %s already running, not restarting\n", iface->name);
00614                ASTOBJ_UNMARK(iface);
00615                ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
00616                continue;
00617             }
00618          }
00619                      
00620          if (!(iface = ast_calloc(1, sizeof(*iface))))
00621             continue;
00622 
00623          ASTOBJ_INIT(iface);
00624          ASTOBJ_CONTAINER_INIT(&iface->md_q);
00625          ASTOBJ_CONTAINER_INIT(&iface->mwi_q);
00626 
00627          ast_copy_string(iface->name, v->value, sizeof(iface->name));
00628 
00629          if (!(iface->file = fopen(iface->name, "r"))) {
00630             ast_log(LOG_ERROR, "Error opening SMDI interface %s (%s)\n", iface->name, strerror(errno));
00631             ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
00632             continue;
00633          }
00634 
00635          iface->fd = fileno(iface->file);
00636 
00637          /* Set the proper attributes for our serial port. */
00638 
00639          /* get the current attributes from the port */
00640          if (tcgetattr(iface->fd, &iface->mode)) {
00641             ast_log(LOG_ERROR, "Error getting atributes of %s (%s)\n", iface->name, strerror(errno));
00642             ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
00643             continue;
00644          }
00645 
00646          /* set the desired speed */
00647          if (cfsetispeed(&iface->mode, baud_rate) || cfsetospeed(&iface->mode, baud_rate)) {
00648             ast_log(LOG_ERROR, "Error setting baud rate on %s (%s)\n", iface->name, strerror(errno));
00649             ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
00650             continue;
00651          }
00652          
00653          /* set the stop bits */
00654          if (stopbits)
00655             iface->mode.c_cflag = iface->mode.c_cflag | CSTOPB;   /* set two stop bits */
00656          else
00657             iface->mode.c_cflag = iface->mode.c_cflag & ~CSTOPB;  /* set one stop bit */
00658 
00659          /* set the parity */
00660          iface->mode.c_cflag = (iface->mode.c_cflag & ~PARENB & ~PARODD) | paritybit;
00661 
00662          /* set the character size */
00663          iface->mode.c_cflag = (iface->mode.c_cflag & ~CSIZE) | charsize;
00664          
00665          /* commit the desired attributes */
00666          if (tcsetattr(iface->fd, TCSAFLUSH, &iface->mode)) {
00667             ast_log(LOG_ERROR, "Error setting attributes on %s (%s)\n", iface->name, strerror(errno));
00668             ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
00669             continue;
00670          }
00671 
00672          /* set the msdstrip */
00673          iface->msdstrip = msdstrip;
00674 
00675          /* set the message expiry time */
00676          iface->msg_expiry = msg_expiry;
00677 
00678                         /* start the listner thread */
00679          if (option_verbose > 2)
00680             ast_verbose(VERBOSE_PREFIX_3 "Starting SMDI monitor thread for %s\n", iface->name);
00681          if (ast_pthread_create_background(&iface->thread, NULL, smdi_read, iface)) {
00682             ast_log(LOG_ERROR, "Error starting SMDI monitor thread for %s\n", iface->name);
00683             ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
00684             continue;
00685          }
00686 
00687          ASTOBJ_CONTAINER_LINK(&smdi_ifaces, iface);
00688          ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
00689          ast_module_ref(ast_module_info->self);
00690       } else {
00691          ast_log(LOG_NOTICE, "Ignoring unknown option %s in %s\n", v->name, config_file);
00692       }
00693    }
00694    ast_config_destroy(conf);
00695 
00696    /* Prune any interfaces we should no longer monitor. */
00697    if (reload)
00698       ASTOBJ_CONTAINER_PRUNE_MARKED(&smdi_ifaces, ast_smdi_interface_destroy);
00699    
00700    ASTOBJ_CONTAINER_RDLOCK(&smdi_ifaces);
00701    /* TODO: this is bad, we need an ASTOBJ method for this! */
00702    if (!smdi_ifaces.head)
00703       res = 1;
00704    ASTOBJ_CONTAINER_UNLOCK(&smdi_ifaces);
00705          
00706    return res;
00707 }
00708 
00709 static int load_module(void)
00710 {
00711    int res;
00712 
00713    /* initialize our containers */
00714    memset(&smdi_ifaces, 0, sizeof(smdi_ifaces));
00715    ASTOBJ_CONTAINER_INIT(&smdi_ifaces);
00716 
00717    /* load the config and start the listener threads*/
00718    res = smdi_load(0);
00719    if (res < 0) {
00720       return res;
00721    } else if (res == 1) {
00722       ast_log(LOG_WARNING, "No SMDI interfaces are available to listen on, not starting SDMI listener.\n");
00723       return AST_MODULE_LOAD_DECLINE;;
00724    } else
00725       return 0;
00726 }
00727 
00728 static int unload_module(void)
00729 {
00730    /* this destructor stops any running smdi_read threads */
00731    ASTOBJ_CONTAINER_DESTROYALL(&smdi_ifaces, ast_smdi_interface_destroy);
00732    ASTOBJ_CONTAINER_DESTROY(&smdi_ifaces);
00733 
00734    return 0;
00735 }
00736 
00737 static int reload(void)
00738 {
00739    int res;
00740 
00741    res = smdi_load(1);
00742 
00743    if (res < 0) {
00744       return res;
00745    } else if (res == 1) {
00746       ast_log(LOG_WARNING, "No SMDI interfaces were specified to listen on, not starting SDMI listener.\n");
00747       return 0;
00748    } else
00749       return 0;
00750 }
00751 
00752 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Simplified Message Desk Interface (SMDI) Resource",
00753       .load = load_module,
00754       .unload = unload_module,
00755       .reload = reload,
00756           );

Generated on Mon May 14 04:43:00 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1