+ move output_format variables in the http section of the file;
authorLuigi Rizzo <rizzo@icir.org>
Wed, 18 Oct 2006 21:30:21 +0000 (21:30 +0000)
committerLuigi Rizzo <rizzo@icir.org>
Wed, 18 Oct 2006 21:30:21 +0000 (21:30 +0000)
+ more comments on struct mansession and global variables;
+ small improvements to the session matching code so it supports
  multiple sessions from the same IP

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@45597 65c4cc65-6c06-0410-ace0-fbb531ad65f3

main/manager.c

index 6e55db6..d3026ba 100644 (file)
@@ -83,26 +83,14 @@ struct eventqent {
        char eventdata[1];      /* really variable size, allocated by append_event() */
 };
 
-enum output_format {
-       FORMAT_RAW,
-       FORMAT_HTML,
-       FORMAT_XML,
-};
-
-static char *contenttype[] = {
-       [FORMAT_RAW] = "plain",
-       [FORMAT_HTML] = "html",
-       [FORMAT_XML] =  "xml",
-};
-
 static int enabled = 0;
 static int portno = DEFAULT_MANAGER_PORT;
-static int asock = -1;
+static int asock = -1; /* the accept socket */
 static int displayconnects = 1;
 static int timestampevents = 0;
 static int httptimeout = 60;
 
-static pthread_t t;
+static pthread_t accept_thread_ptr;    /* the accept thread */
 static int block_sockets = 0;
 static int num_sessions = 0;
 
@@ -121,17 +109,19 @@ AST_THREADSTORAGE(astman_append_buf, astman_append_buf_init);
 
 /*! \brief Descriptor for an AMI session, either a regular one
  * or one over http.
+ * For AMI sessions, the entry is created upon a connect, and destroyed
+ * with the socket.
  */
 struct mansession {
-       pthread_t t;            /*! Execution thread */
+       pthread_t ms_t;         /*! Execution thread, basically useless */
        ast_mutex_t __lock;     /*! Thread lock -- don't use in action callbacks, it's already taken care of  */
                                /* XXX need to document which fields it is protecting */
-       struct sockaddr_in sin; /*! socket address */
+       struct sockaddr_in sin; /*! address we are connecting from */
        int fd;                 /*! descriptor used for output. Either the socket (AMI) or a temporary file (HTTP) */
-       int inuse;              /*! Whether an HTTP (XXX or AMI ?) manager is in use */
+       int inuse;              /*! number of HTTP sessions using this entry */
        int needdestroy;        /*! Whether an HTTP session should be destroyed */
        pthread_t waiting_thread;       /*! Whether an HTTP session has someone waiting on events */
-       unsigned long managerid;        /*! Unique manager identifer */
+       unsigned long managerid;        /*! Unique manager identifer, 0 for AMI sessions */
        time_t sessiontimeout;  /*! Session timeout if HTTP */
        struct ast_dynamic_str *outputstr;      /*! Output from manager interface */
        char username[80];      /*! Logged in username */
@@ -511,7 +501,7 @@ static struct ast_cli_entry cli_manager[] = {
 static void unuse_eventqent(struct eventqent *e)
 {
        if (ast_atomic_dec_and_test(&e->usecount) && e->next)
-               pthread_kill(t, SIGURG);
+               pthread_kill(accept_thread_ptr, SIGURG);
 }
 
 static void free_session(struct mansession *s)
@@ -532,6 +522,7 @@ static void free_session(struct mansession *s)
 static void destroy_session(struct mansession *s)
 {
        AST_LIST_LOCK(&sessions);
+       ast_verbose("destroy session %lx\n", s->managerid);
        AST_LIST_REMOVE(&sessions, s, list);
        AST_LIST_UNLOCK(&sessions);
 
@@ -1938,6 +1929,8 @@ static void *accept_thread(void *ignore)
                AST_LIST_LOCK(&sessions);
                AST_LIST_TRAVERSE_SAFE_BEGIN(&sessions, s, list) {
                        if (s->sessiontimeout && (now > s->sessiontimeout) && !s->inuse) {
+                               ast_verbose("destroy session[2] %lx now %lu to %lu\n",
+                                       s->managerid, now, s->sessiontimeout);
                                AST_LIST_REMOVE_CURRENT(&sessions, list);
                                ast_atomic_fetchadd_int(&num_sessions, -1);
                                if (s->authenticated && (option_verbose > 1) && displayconnects) {
@@ -2010,7 +2003,7 @@ static void *accept_thread(void *ignore)
                        s->eventq = s->eventq->next;
                AST_LIST_UNLOCK(&sessions);
                ast_atomic_fetchadd_int(&s->eventq->usecount, 1);
-               if (ast_pthread_create_background(&s->t, &attr, session_do, s))
+               if (ast_pthread_create_background(&s->ms_t, &attr, session_do, s))
                        destroy_session(s);
        }
        pthread_attr_destroy(&attr);
@@ -2189,15 +2182,31 @@ int ast_manager_register2(const char *action, int auth, int (*func)(struct manse
  * then fed back to the client over the original socket.
  */
 
+enum output_format {
+       FORMAT_RAW,
+       FORMAT_HTML,
+       FORMAT_XML,
+};
+
+static char *contenttype[] = {
+       [FORMAT_RAW] = "plain",
+       [FORMAT_HTML] = "html",
+       [FORMAT_XML] =  "xml",
+};
+
+/* locate an http session in the list using the cookie as a key */
 static struct mansession *find_session(unsigned long ident)
 {
        struct mansession *s;
 
+       if (ident == 0)
+               return NULL;
+
        AST_LIST_LOCK(&sessions);
        AST_LIST_TRAVERSE(&sessions, s, list) {
                ast_mutex_lock(&s->__lock);
                if (s->sessiontimeout && (s->managerid == ident) && !s->needdestroy) {
-                       s->inuse++;
+                       ast_atomic_fetchadd_int(&s->inuse, 1);
                        break;
                }
                ast_mutex_unlock(&s->__lock);
@@ -2408,25 +2417,26 @@ static char *generic_http_callback(enum output_format format,
        for (v = params; v; v = v->next) {
                if (!strcasecmp(v->name, "mansession_id")) {
                        sscanf(v->value, "%lx", &ident);
-                       ast_verbose("session is <%lx>\n", ident);
                        break;
                }
        }
-       
+
        if (!(s = find_session(ident))) {
-               /* Create new session */
+               /* Create new session.
+                * While it is not in the list we don't need any locking
+                */
                if (!(s = ast_calloc(1, sizeof(*s)))) {
                        *status = 500;
                        goto generic_callback_out;
                }
-               memcpy(&s->sin, requestor, sizeof(s->sin));
+               s->sin = *requestor;
                s->fd = -1;
                s->waiting_thread = AST_PTHREADT_NULL;
                s->send_events = 0;
                ast_mutex_init(&s->__lock);
                ast_mutex_lock(&s->__lock);
                s->inuse = 1;
-               s->managerid = rand() | (unsigned long)s;
+               s->managerid = rand() | 1;      /* make sure it is non-zero */
                AST_LIST_LOCK(&sessions);
                AST_LIST_INSERT_HEAD(&sessions, s, list);
                /* Hook into the last spot in the event queue */
@@ -2438,14 +2448,7 @@ static char *generic_http_callback(enum output_format format,
                ast_atomic_fetchadd_int(&num_sessions, 1);
        }
 
-       /* Reset HTTP timeout.  If we're not yet authenticated, keep it extremely short */
-       time(&s->sessiontimeout);
-       if (!s->authenticated && (httptimeout > 5))
-               s->sessiontimeout += 5;
-       else
-               s->sessiontimeout += httptimeout;
        ast_mutex_unlock(&s->__lock);
-       
        memset(&m, 0, sizeof(m));
        {
                char tmp[80];
@@ -2542,6 +2545,10 @@ static char *generic_http_callback(enum output_format format,
                ast_build_string(&c, &len, "</table></body>\r\n");
 
        ast_mutex_lock(&s->__lock);
+       /* Reset HTTP timeout.  If we're not authenticated, keep it extremely short */
+       s->sessiontimeout = time(NULL) + ((s->authenticated || httptimeout < 5) ? httptimeout : 5);
+       ast_verbose("die in %d seconds\n",
+               (int)(s->sessiontimeout - time(NULL)) );
        if (s->needdestroy) {
                if (s->inuse == 1) {
                        if (option_debug)
@@ -2831,7 +2838,7 @@ int init_manager(void)
                fcntl(asock, F_SETFL, flags | O_NONBLOCK);
                if (option_verbose)
                        ast_verbose("Asterisk Management interface listening on port %d\n", portno);
-               ast_pthread_create_background(&t, NULL, accept_thread, NULL);
+               ast_pthread_create_background(&accept_thread_ptr, NULL, accept_thread, NULL);
        }
        return 0;
 }