aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--main/manager.c471
1 files changed, 259 insertions, 212 deletions
diff --git a/main/manager.c b/main/manager.c
index d1b34629e..a42259dde 100644
--- a/main/manager.c
+++ b/main/manager.c
@@ -148,7 +148,39 @@ static struct {
{{ "restart", "gracefully", NULL }},
};
-struct mansession {
+/* In order to understand what the heck is going on with the
+ * mansession_session and mansession structs, we need to have a bit of a history
+ * lesson.
+ *
+ * In the beginning, there was the mansession. The mansession contained data that was
+ * intrinsic to a manager session, such as the time that it started, the name of the logged-in
+ * user, etc. In addition to these parameters were the f and fd parameters. For typical manager
+ * sessions, these were used to represent the TCP socket over which the AMI session was taking
+ * place. It makes perfect sense for these fields to be a part of the session-specific data since
+ * the session actually defines this information.
+ *
+ * Then came the HTTP AMI sessions. With these, the f and fd fields need to be opened and closed
+ * for every single action that occurs. Thus the f and fd fields aren't really specific to the session
+ * but rather to the action that is being executed. Because a single session may execute many commands
+ * at once, some sort of safety needed to be added in order to be sure that we did not end up with fd
+ * leaks from one action overwriting the f and fd fields used by a previous action before the previous action
+ * has had a chance to properly close its handles.
+ *
+ * The initial idea to solve this was to use thread synchronization, but this prevented multiple actions
+ * from being run at the same time in a single session. Some manager actions may block for a long time, thus
+ * creating a large queue of actions to execute. In addition, this fix did not address the basic architectural
+ * issue that for HTTP manager sessions, the f and fd variables are not really a part of the session, but are
+ * part of the action instead.
+ *
+ * The new idea was to create a structure on the stack for each HTTP Manager action. This structure would
+ * contain the action-specific information, such as which file to write to. In order to maintain expectations
+ * of action handlers and not have to change the public API of the manager code, we would need to name this
+ * new stacked structure 'mansession' and contain within it the old mansession struct that we used to use.
+ * We renamed the old mansession struct 'mansession_session' to hopefully convey that what is in this structure
+ * is session-specific data. The structure that it is wrapped in, called a 'mansession' really contains action-specific
+ * data.
+ */
+struct mansession_session {
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 */
@@ -173,12 +205,18 @@ struct mansession {
struct eventqent *last_ev; /*!< last event processed. */
int writetimeout; /*!< Timeout for ast_carefulwrite() */
int pending_event; /*!< Pending events indicator in case when waiting_thread is NULL */
- AST_LIST_ENTRY(mansession) list;
+ AST_LIST_ENTRY(mansession_session) list;
+};
+
+struct mansession {
+ struct mansession_session *session;
+ FILE *f;
+ int fd;
};
-#define NEW_EVENT(m) (AST_LIST_NEXT(m->last_ev, eq_next))
+#define NEW_EVENT(m) (AST_LIST_NEXT(m->session->last_ev, eq_next))
-static AST_LIST_HEAD_STATIC(sessions, mansession);
+static AST_LIST_HEAD_STATIC(sessions, mansession_session);
/*! \brief user descriptor, as read from the config file.
*
@@ -425,7 +463,7 @@ static int strings_to_mask(const char *string)
static int check_manager_session_inuse(const char *name)
{
- struct mansession *session = NULL;
+ struct mansession_session *session = NULL;
AST_LIST_LOCK(&sessions);
AST_LIST_TRAVERSE(&sessions, session, list) {
@@ -456,13 +494,13 @@ static struct ast_manager_user *get_manager_by_name_locked(const char *name)
* \param s manager session to get parameter from.
* \return displayconnects config option value.
*/
-static int manager_displayconnects (struct mansession *s)
+static int manager_displayconnects (struct mansession_session *session)
{
struct ast_manager_user *user = NULL;
int ret = 0;
AST_RWLIST_RDLOCK(&users);
- if ((user = get_manager_by_name_locked (s->username)))
+ if ((user = get_manager_by_name_locked (session->username)))
ret = user->displayconnects;
AST_RWLIST_UNLOCK(&users);
@@ -675,7 +713,7 @@ static char *handle_showmancmds(struct ast_cli_entry *e, int cmd, struct ast_cli
/*! \brief CLI command manager list connected */
static char *handle_showmanconn(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
- struct mansession *s;
+ struct mansession_session *session;
time_t now = time(NULL);
#define HSMCONN_FORMAT1 " %-15.15s %-15.15s %-10.10s %-10.10s %-8.8s %-8.8s %-5.5s %-5.5s\n"
#define HSMCONN_FORMAT2 " %-15.15s %-15.15s %-10d %-10d %-8d %-8d %-5.5d %-5.5d\n"
@@ -695,8 +733,8 @@ static char *handle_showmanconn(struct ast_cli_entry *e, int cmd, struct ast_cli
ast_cli(a->fd, HSMCONN_FORMAT1, "Username", "IP Address", "Start", "Elapsed", "FileDes", "HttpCnt", "Read", "Write");
AST_LIST_LOCK(&sessions);
- AST_LIST_TRAVERSE(&sessions, s, list) {
- ast_cli(a->fd, HSMCONN_FORMAT2, s->username, ast_inet_ntoa(s->sin.sin_addr), (int)(s->sessionstart), (int)(now - s->sessionstart), s->fd, s->inuse, s->readperm, s->writeperm);
+ AST_LIST_TRAVERSE(&sessions, session, list) {
+ ast_cli(a->fd, HSMCONN_FORMAT2, session->username, ast_inet_ntoa(session->sin.sin_addr), (int)(session->sessionstart), (int)(now - session->sessionstart), session->fd, session->inuse, session->readperm, session->writeperm);
count++;
}
AST_LIST_UNLOCK(&sessions);
@@ -784,22 +822,22 @@ static void ref_event(struct eventqent *e)
/*
* destroy a session, leaving the usecount
*/
-static void free_session(struct mansession *s)
+static void free_session(struct mansession_session *session)
{
- struct eventqent *eqe = s->last_ev;
- if (s->f != NULL)
- fclose(s->f);
- ast_mutex_destroy(&s->__lock);
- ast_free(s);
+ struct eventqent *eqe = session->last_ev;
+ if (session->f != NULL)
+ fclose(session->f);
+ ast_mutex_destroy(&session->__lock);
+ ast_free(session);
unref_event(eqe);
}
-static void destroy_session(struct mansession *s)
+static void destroy_session(struct mansession_session *session)
{
AST_LIST_LOCK(&sessions);
- AST_LIST_REMOVE(&sessions, s, list);
+ AST_LIST_REMOVE(&sessions, session, list);
ast_atomic_fetchadd_int(&num_sessions, -1);
- free_session(s);
+ free_session(session);
AST_LIST_UNLOCK(&sessions);
}
@@ -859,7 +897,11 @@ struct ast_variable *astman_get_variables(const struct message *m)
*/
static int send_string(struct mansession *s, char *string)
{
- return ast_careful_fwrite(s->f, s->fd, string, strlen(string), s->writetimeout);
+ if (s->f) {
+ return ast_careful_fwrite(s->f, s->fd, string, strlen(string), s->session->writetimeout);
+ } else {
+ return ast_careful_fwrite(s->session->f, s->session->fd, string, strlen(string), s->session->writetimeout);
+ }
}
/*!
@@ -890,7 +932,7 @@ void astman_append(struct mansession *s, const char *fmt, ...)
ast_str_set_va(&buf, 0, fmt, ap);
va_end(ap);
- if (s->f != NULL)
+ if (s->f != NULL || s->session->f != NULL)
send_string(s, buf->str);
else
ast_verbose("fd == -1 in astman_append, should not happen\n");
@@ -898,7 +940,7 @@ void astman_append(struct mansession *s, const char *fmt, ...)
/*! \note NOTE: XXX this comment is unclear and possibly wrong.
Callers of astman_send_error(), astman_send_response() or astman_send_ack() must EITHER
- hold the session lock _or_ be running in an action callback (in which case s->busy will
+ hold the session lock _or_ be running in an action callback (in which case s->session->busy will
be non-zero). In either of these cases, there is no need to lock-protect the session's
fd, since no other output will be sent (events will be queued), and no input will
be read until either the current action finishes or get_input() obtains the session
@@ -964,10 +1006,10 @@ static int set_eventmask(struct mansession *s, const char *eventmask)
{
int maskint = strings_to_mask(eventmask);
- ast_mutex_lock(&s->__lock);
+ ast_mutex_lock(&s->session->__lock);
if (maskint >= 0)
- s->send_events = maskint;
- ast_mutex_unlock(&s->__lock);
+ s->session->send_events = maskint;
+ ast_mutex_unlock(&s->session->__lock);
return maskint;
}
@@ -993,12 +1035,12 @@ static int authenticate(struct mansession *s, const struct message *m)
AST_RWLIST_WRLOCK(&users);
if (!(user = get_manager_by_name_locked(username))) {
- ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_inet_ntoa(s->sin.sin_addr), username);
- } else if (user->ha && !ast_apply_ha(user->ha, &(s->sin))) {
- ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_inet_ntoa(s->sin.sin_addr), username);
+ ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_inet_ntoa(s->session->sin.sin_addr), username);
+ } else if (user->ha && !ast_apply_ha(user->ha, &(s->session->sin))) {
+ ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_inet_ntoa(s->session->sin.sin_addr), username);
} else if (!strcasecmp(astman_get_header(m, "AuthType"), "MD5")) {
const char *key = astman_get_header(m, "Key");
- if (!ast_strlen_zero(key) && !ast_strlen_zero(s->challenge) && user->secret) {
+ if (!ast_strlen_zero(key) && !ast_strlen_zero(s->session->challenge) && user->secret) {
int x;
int len = 0;
char md5key[256] = "";
@@ -1006,7 +1048,7 @@ static int authenticate(struct mansession *s, const struct message *m)
unsigned char digest[16];
MD5Init(&md5);
- MD5Update(&md5, (unsigned char *) s->challenge, strlen(s->challenge));
+ MD5Update(&md5, (unsigned char *) s->session->challenge, strlen(s->session->challenge));
MD5Update(&md5, (unsigned char *) user->secret, strlen(user->secret));
MD5Final(digest, &md5);
for (x = 0; x < 16; x++)
@@ -1015,24 +1057,24 @@ static int authenticate(struct mansession *s, const struct message *m)
error = 0;
} else {
ast_debug(1, "MD5 authentication is not possible. challenge: '%s'\n",
- S_OR(s->challenge, ""));
+ S_OR(s->session->challenge, ""));
}
} else if (password && user->secret && !strcmp(password, user->secret))
error = 0;
if (error) {
- ast_log(LOG_NOTICE, "%s failed to authenticate as '%s'\n", ast_inet_ntoa(s->sin.sin_addr), username);
+ ast_log(LOG_NOTICE, "%s failed to authenticate as '%s'\n", ast_inet_ntoa(s->session->sin.sin_addr), username);
AST_RWLIST_UNLOCK(&users);
return -1;
}
/* auth complete */
- ast_copy_string(s->username, username, sizeof(s->username));
- s->readperm = user->readperm;
- s->writeperm = user->writeperm;
- s->writetimeout = user->writetimeout;
- s->sessionstart = time(NULL);
+ ast_copy_string(s->session->username, username, sizeof(s->session->username));
+ s->session->readperm = user->readperm;
+ s->session->writeperm = user->writeperm;
+ s->session->writetimeout = user->writetimeout;
+ s->session->sessionstart = time(NULL);
set_eventmask(s, astman_get_header(m, "Events"));
AST_RWLIST_UNLOCK(&users);
@@ -1458,76 +1500,76 @@ static int action_waitevent(struct mansession *s, const struct message *m)
/* XXX maybe put an upper bound, or prevent the use of 0 ? */
}
- ast_mutex_lock(&s->__lock);
- if (s->waiting_thread != AST_PTHREADT_NULL)
- pthread_kill(s->waiting_thread, SIGURG);
+ ast_mutex_lock(&s->session->__lock);
+ if (s->session->waiting_thread != AST_PTHREADT_NULL)
+ pthread_kill(s->session->waiting_thread, SIGURG);
- if (s->managerid) { /* AMI-over-HTTP session */
+ if (s->session->managerid) { /* AMI-over-HTTP session */
/*
* Make sure the timeout is within the expire time of the session,
* as the client will likely abort the request if it does not see
* data coming after some amount of time.
*/
time_t now = time(NULL);
- int max = s->sessiontimeout - now - 10;
+ int max = s->session->sessiontimeout - now - 10;
if (max < 0) /* We are already late. Strange but possible. */
max = 0;
if (timeout < 0 || timeout > max)
timeout = max;
- if (!s->send_events) /* make sure we record events */
- s->send_events = -1;
+ if (!s->session->send_events) /* make sure we record events */
+ s->session->send_events = -1;
}
- ast_mutex_unlock(&s->__lock);
+ ast_mutex_unlock(&s->session->__lock);
/* XXX should this go inside the lock ? */
- s->waiting_thread = pthread_self(); /* let new events wake up this thread */
+ s->session->waiting_thread = pthread_self(); /* let new events wake up this thread */
ast_debug(1, "Starting waiting for an event!\n");
for (x = 0; x < timeout || timeout < 0; x++) {
- ast_mutex_lock(&s->__lock);
+ ast_mutex_lock(&s->session->__lock);
if (NEW_EVENT(s))
needexit = 1;
/* We can have multiple HTTP session point to the same mansession entry.
* The way we deal with it is not very nice: newcomers kick out the previous
* HTTP session. XXX this needs to be improved.
*/
- if (s->waiting_thread != pthread_self())
+ if (s->session->waiting_thread != pthread_self())
needexit = 1;
- if (s->needdestroy)
+ if (s->session->needdestroy)
needexit = 1;
- ast_mutex_unlock(&s->__lock);
+ ast_mutex_unlock(&s->session->__lock);
if (needexit)
break;
- if (s->managerid == 0) { /* AMI session */
- if (ast_wait_for_input(s->fd, 1000))
+ if (s->session->managerid == 0) { /* AMI session */
+ if (ast_wait_for_input(s->session->fd, 1000))
break;
} else { /* HTTP session */
sleep(1);
}
}
ast_debug(1, "Finished waiting for an event!\n");
- ast_mutex_lock(&s->__lock);
- if (s->waiting_thread == pthread_self()) {
+ ast_mutex_lock(&s->session->__lock);
+ if (s->session->waiting_thread == pthread_self()) {
struct eventqent *eqe;
astman_send_response(s, m, "Success", "Waiting for Event completed.");
while ( (eqe = NEW_EVENT(s)) ) {
ref_event(eqe);
- if (((s->readperm & eqe->category) == eqe->category) &&
- ((s->send_events & eqe->category) == eqe->category)) {
+ if (((s->session->readperm & eqe->category) == eqe->category) &&
+ ((s->session->send_events & eqe->category) == eqe->category)) {
astman_append(s, "%s", eqe->eventdata);
}
- s->last_ev = unref_event(s->last_ev);
+ s->session->last_ev = unref_event(s->session->last_ev);
}
astman_append(s,
"Event: WaitEventComplete\r\n"
"%s"
"\r\n", idText);
- s->waiting_thread = AST_PTHREADT_NULL;
+ s->session->waiting_thread = AST_PTHREADT_NULL;
} else {
ast_debug(1, "Abandoning event request!\n");
}
- ast_mutex_unlock(&s->__lock);
+ ast_mutex_unlock(&s->session->__lock);
return 0;
}
@@ -1544,7 +1586,7 @@ static int action_listcommands(struct mansession *s, const struct message *m)
astman_start_ack(s, m);
AST_RWLIST_TRAVERSE(&actions, cur, list) {
- if (s->writeperm & cur->authority || cur->authority == 0)
+ if (s->session->writeperm & cur->authority || cur->authority == 0)
astman_append(s, "%s: %s (Priv: %s)\r\n",
cur->action, cur->synopsis, authority_to_str(cur->authority, &temp));
}
@@ -1593,10 +1635,10 @@ static int action_login(struct mansession *s, const struct message *m)
astman_send_error(s, m, "Authentication failed");
return -1;
}
- s->authenticated = 1;
- if (manager_displayconnects(s))
- ast_verb(2, "%sManager '%s' logged on from %s\n", (s->managerid ? "HTTP " : ""), s->username, ast_inet_ntoa(s->sin.sin_addr));
- ast_log(LOG_EVENT, "%sManager '%s' logged on from %s\n", (s->managerid ? "HTTP " : ""), s->username, ast_inet_ntoa(s->sin.sin_addr));
+ s->session->authenticated = 1;
+ if (manager_displayconnects(s->session))
+ ast_verb(2, "%sManager '%s' logged on from %s\n", (s->session->managerid ? "HTTP " : ""), s->session->username, ast_inet_ntoa(s->session->sin.sin_addr));
+ ast_log(LOG_EVENT, "%sManager '%s' logged on from %s\n", (s->session->managerid ? "HTTP " : ""), s->session->username, ast_inet_ntoa(s->session->sin.sin_addr));
astman_send_ack(s, m, "Authentication accepted");
return 0;
}
@@ -1606,12 +1648,12 @@ static int action_challenge(struct mansession *s, const struct message *m)
const char *authtype = astman_get_header(m, "AuthType");
if (!strcasecmp(authtype, "MD5")) {
- if (ast_strlen_zero(s->challenge))
- snprintf(s->challenge, sizeof(s->challenge), "%ld", ast_random());
- ast_mutex_lock(&s->__lock);
+ if (ast_strlen_zero(s->session->challenge))
+ snprintf(s->session->challenge, sizeof(s->session->challenge), "%ld", ast_random());
+ ast_mutex_lock(&s->session->__lock);
astman_start_ack(s, m);
- astman_append(s, "Challenge: %s\r\n\r\n", s->challenge);
- ast_mutex_unlock(&s->__lock);
+ astman_append(s, "Challenge: %s\r\n\r\n", s->session->challenge);
+ ast_mutex_unlock(&s->session->__lock);
} else {
astman_send_error(s, m, "Must specify AuthType");
}
@@ -2222,7 +2264,7 @@ static int action_originate(struct mansession *s, const struct message *m)
}
} else if (!ast_strlen_zero(app)) {
/* To run the System application (or anything else that goes to shell), you must have the additional System privilege */
- if (!(s->writeperm & EVENT_FLAG_SYSTEM)
+ if (!(s->session->writeperm & EVENT_FLAG_SYSTEM)
&& (
strcasestr(app, "system") == 0 || /* System(rm -rf /)
TrySystem(rm -rf /) */
@@ -2389,22 +2431,22 @@ static int process_events(struct mansession *s)
{
int ret = 0;
- ast_mutex_lock(&s->__lock);
- if (s->f != NULL) {
+ ast_mutex_lock(&s->session->__lock);
+ if (s->session->f != NULL) {
struct eventqent *eqe;
while ( (eqe = NEW_EVENT(s)) ) {
ref_event(eqe);
- if (!ret && s->authenticated &&
- (s->readperm & eqe->category) == eqe->category &&
- (s->send_events & eqe->category) == eqe->category) {
+ if (!ret && s->session->authenticated &&
+ (s->session->readperm & eqe->category) == eqe->category &&
+ (s->session->send_events & eqe->category) == eqe->category) {
if (send_string(s, eqe->eventdata) < 0)
ret = -1; /* don't send more */
}
- s->last_ev = unref_event(s->last_ev);
+ s->session->last_ev = unref_event(s->session->last_ev);
}
}
- ast_mutex_unlock(&s->__lock);
+ ast_mutex_unlock(&s->session->__lock);
return ret;
}
@@ -2728,26 +2770,26 @@ static int process_message(struct mansession *s, const struct message *m)
ast_debug(1, "Manager received command '%s'\n", action);
if (ast_strlen_zero(action)) {
- ast_mutex_lock(&s->__lock);
+ ast_mutex_lock(&s->session->__lock);
astman_send_error(s, m, "Missing action in request");
- ast_mutex_unlock(&s->__lock);
+ ast_mutex_unlock(&s->session->__lock);
return 0;
}
- if (!s->authenticated && strcasecmp(action, "Login") && strcasecmp(action, "Logoff") && strcasecmp(action, "Challenge")) {
- ast_mutex_lock(&s->__lock);
+ if (!s->session->authenticated && strcasecmp(action, "Login") && strcasecmp(action, "Logoff") && strcasecmp(action, "Challenge")) {
+ ast_mutex_lock(&s->session->__lock);
astman_send_error(s, m, "Permission denied");
- ast_mutex_unlock(&s->__lock);
+ ast_mutex_unlock(&s->session->__lock);
return 0;
}
- if (!allowmultiplelogin && !s->authenticated && user &&
+ if (!allowmultiplelogin && !s->session->authenticated && user &&
(!strcasecmp(action, "Login") || !strcasecmp(action, "Challenge"))) {
if (check_manager_session_inuse(user)) {
sleep(1);
- ast_mutex_lock(&s->__lock);
+ ast_mutex_lock(&s->session->__lock);
astman_send_error(s, m, "Login Already In Use");
- ast_mutex_unlock(&s->__lock);
+ ast_mutex_unlock(&s->session->__lock);
return -1;
}
}
@@ -2756,7 +2798,7 @@ static int process_message(struct mansession *s, const struct message *m)
AST_RWLIST_TRAVERSE(&actions, tmp, list) {
if (strcasecmp(action, tmp->action))
continue;
- if (s->writeperm & tmp->authority || tmp->authority == 0)
+ if (s->session->writeperm & tmp->authority || tmp->authority == 0)
ret = tmp->func(s, m);
else
astman_send_error(s, m, "Permission denied");
@@ -2767,9 +2809,9 @@ static int process_message(struct mansession *s, const struct message *m)
if (!tmp) {
char buf[512];
snprintf(buf, sizeof(buf), "Invalid/unknown command: %s. Use Action: ListCommands to show available commands.", action);
- ast_mutex_lock(&s->__lock);
+ ast_mutex_lock(&s->session->__lock);
astman_send_error(s, m, buf);
- ast_mutex_unlock(&s->__lock);
+ ast_mutex_unlock(&s->session->__lock);
}
if (ret)
return ret;
@@ -2789,16 +2831,16 @@ static int process_message(struct mansession *s, const struct message *m)
static int get_input(struct mansession *s, char *output)
{
int res, x;
- int maxlen = sizeof(s->inbuf) - 1;
- char *src = s->inbuf;
+ int maxlen = sizeof(s->session->inbuf) - 1;
+ char *src = s->session->inbuf;
/*
* Look for \r\n within the buffer. If found, copy to the output
* buffer and return, trimming the \r\n (not used afterwards).
*/
- for (x = 0; x < s->inlen; x++) {
+ for (x = 0; x < s->session->inlen; x++) {
int cr; /* set if we have \r */
- if (src[x] == '\r' && x+1 < s->inlen && src[x+1] == '\n')
+ if (src[x] == '\r' && x+1 < s->session->inlen && src[x+1] == '\n')
cr = 2; /* Found. Update length to include \r\n */
else if (src[x] == '\n')
cr = 1; /* also accept \n only */
@@ -2807,32 +2849,32 @@ static int get_input(struct mansession *s, char *output)
memmove(output, src, x); /*... but trim \r\n */
output[x] = '\0'; /* terminate the string */
x += cr; /* number of bytes used */
- s->inlen -= x; /* remaining size */
- memmove(src, src + x, s->inlen); /* remove used bytes */
+ s->session->inlen -= x; /* remaining size */
+ memmove(src, src + x, s->session->inlen); /* remove used bytes */
return 1;
}
- if (s->inlen >= maxlen) {
+ if (s->session->inlen >= maxlen) {
/* no crlf found, and buffer full - sorry, too long for us */
- ast_log(LOG_WARNING, "Dumping long line with no return from %s: %s\n", ast_inet_ntoa(s->sin.sin_addr), src);
- s->inlen = 0;
+ ast_log(LOG_WARNING, "Dumping long line with no return from %s: %s\n", ast_inet_ntoa(s->session->sin.sin_addr), src);
+ s->session->inlen = 0;
}
res = 0;
while (res == 0) {
/* XXX do we really need this locking ? */
- ast_mutex_lock(&s->__lock);
- if (s->pending_event) {
- s->pending_event = 0;
- ast_mutex_unlock(&s->__lock);
+ ast_mutex_lock(&s->session->__lock);
+ if (s->session->pending_event) {
+ s->session->pending_event = 0;
+ ast_mutex_unlock(&s->session->__lock);
return 0;
}
- s->waiting_thread = pthread_self();
- ast_mutex_unlock(&s->__lock);
+ s->session->waiting_thread = pthread_self();
+ ast_mutex_unlock(&s->session->__lock);
- res = ast_wait_for_input(s->fd, -1); /* return 0 on timeout ? */
+ res = ast_wait_for_input(s->session->fd, -1); /* return 0 on timeout ? */
- ast_mutex_lock(&s->__lock);
- s->waiting_thread = AST_PTHREADT_NULL;
- ast_mutex_unlock(&s->__lock);
+ ast_mutex_lock(&s->session->__lock);
+ s->session->waiting_thread = AST_PTHREADT_NULL;
+ ast_mutex_unlock(&s->session->__lock);
}
if (res < 0) {
/* If we get a signal from some other thread (typically because
@@ -2843,23 +2885,23 @@ static int get_input(struct mansession *s, char *output)
ast_log(LOG_WARNING, "poll() returned error: %s\n", strerror(errno));
return -1;
}
- ast_mutex_lock(&s->__lock);
- res = fread(src + s->inlen, 1, maxlen - s->inlen, s->f);
+ ast_mutex_lock(&s->session->__lock);
+ res = fread(src + s->session->inlen, 1, maxlen - s->session->inlen, s->session->f);
if (res < 1)
res = -1; /* error return */
else {
- s->inlen += res;
- src[s->inlen] = '\0';
+ s->session->inlen += res;
+ src[s->session->inlen] = '\0';
res = 0;
}
- ast_mutex_unlock(&s->__lock);
+ ast_mutex_unlock(&s->session->__lock);
return res;
}
static int do_message(struct mansession *s)
{
struct message m = { 0 };
- char header_buf[sizeof(s->inbuf)] = { '\0' };
+ char header_buf[sizeof(s->session->inbuf)] = { '\0' };
int res;
for (;;) {
@@ -2891,15 +2933,16 @@ static int do_message(struct mansession *s)
static void *session_do(void *data)
{
struct ast_tcptls_session_instance *ser = data;
- struct mansession *s = ast_calloc(1, sizeof(*s));
+ struct mansession_session *session = ast_calloc(1, sizeof(*session));
+ struct mansession s = {.session = NULL, };
int flags;
int res;
- if (s == NULL)
+ if (session == NULL)
goto done;
- s->writetimeout = 100;
- s->waiting_thread = AST_PTHREADT_NULL;
+ session->writetimeout = 100;
+ session->waiting_thread = AST_PTHREADT_NULL;
flags = fcntl(ser->fd, F_GETFL);
if (!block_sockets) /* make sure socket is non-blocking */
@@ -2908,34 +2951,35 @@ static void *session_do(void *data)
flags &= ~O_NONBLOCK;
fcntl(ser->fd, F_SETFL, flags);
- ast_mutex_init(&s->__lock);
- s->send_events = -1;
+ ast_mutex_init(&session->__lock);
+ session->send_events = -1;
/* these fields duplicate those in the 'ser' structure */
- s->fd = ser->fd;
- s->f = ser->f;
- s->sin = ser->requestor;
+ session->fd = ser->fd;
+ session->f = ser->f;
+ session->sin = ser->requestor;
AST_LIST_LOCK(&sessions);
- AST_LIST_INSERT_HEAD(&sessions, s, list);
+ AST_LIST_INSERT_HEAD(&sessions, session, list);
ast_atomic_fetchadd_int(&num_sessions, 1);
AST_LIST_UNLOCK(&sessions);
/* Hook to the tail of the event queue */
- s->last_ev = grab_last();
- s->f = ser->f;
- astman_append(s, "Asterisk Call Manager/%s\r\n", AMI_VERSION); /* welcome prompt */
+ session->last_ev = grab_last();
+ session->f = ser->f;
+ s.session = session;
+ astman_append(&s, "Asterisk Call Manager/%s\r\n", AMI_VERSION); /* welcome prompt */
for (;;) {
- if ((res = do_message(s)) < 0)
+ if ((res = do_message(&s)) < 0)
break;
}
/* session is over, explain why and terminate */
- if (s->authenticated) {
- if (manager_displayconnects(s))
- ast_verb(2, "Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(s->sin.sin_addr));
- ast_log(LOG_EVENT, "Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(s->sin.sin_addr));
+ if (session->authenticated) {
+ if (manager_displayconnects(session))
+ ast_verb(2, "Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
+ ast_log(LOG_EVENT, "Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
} else {
if (displayconnects)
- ast_verb(2, "Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(s->sin.sin_addr));
- ast_log(LOG_EVENT, "Failed attempt from %s\n", ast_inet_ntoa(s->sin.sin_addr));
+ ast_verb(2, "Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(session->sin.sin_addr));
+ ast_log(LOG_EVENT, "Failed attempt from %s\n", ast_inet_ntoa(session->sin.sin_addr));
}
/* It is possible under certain circumstances for this session thread
@@ -2951,7 +2995,7 @@ static void *session_do(void *data)
*/
usleep(1);
- destroy_session(s);
+ destroy_session(session);
done:
ao2_ref(ser, -1);
@@ -2962,19 +3006,19 @@ done:
/*! \brief remove at most n_max stale session from the list. */
static void purge_sessions(int n_max)
{
- struct mansession *s;
+ struct mansession_session *session;
time_t now = time(NULL);
AST_LIST_LOCK(&sessions);
- AST_LIST_TRAVERSE_SAFE_BEGIN(&sessions, s, list) {
- if (s->sessiontimeout && (now > s->sessiontimeout) && !s->inuse) {
+ AST_LIST_TRAVERSE_SAFE_BEGIN(&sessions, session, list) {
+ if (session->sessiontimeout && (now > session->sessiontimeout) && !session->inuse) {
AST_LIST_REMOVE_CURRENT(list);
ast_atomic_fetchadd_int(&num_sessions, -1);
- if (s->authenticated && (VERBOSITY_ATLEAST(2)) && manager_displayconnects(s)) {
+ if (session->authenticated && (VERBOSITY_ATLEAST(2)) && manager_displayconnects(session)) {
ast_verb(2, "HTTP Manager '%s' timed out from %s\n",
- s->username, ast_inet_ntoa(s->sin.sin_addr));
+ session->username, ast_inet_ntoa(session->sin.sin_addr));
}
- free_session(s); /* XXX outside ? */
+ free_session(session); /* XXX outside ? */
if (--n_max <= 0)
break;
}
@@ -3017,7 +3061,7 @@ AST_THREADSTORAGE(manager_event_buf);
int __manager_event(int category, const char *event,
const char *file, int line, const char *func, const char *fmt, ...)
{
- struct mansession *s;
+ struct mansession_session *session;
struct manager_custom_hook *hook;
struct ast_str *auth = ast_str_alloca(80);
const char *cat_str;
@@ -3062,18 +3106,18 @@ int __manager_event(int category, const char *event,
/* Wake up any sleeping sessions */
AST_LIST_LOCK(&sessions);
- AST_LIST_TRAVERSE(&sessions, s, list) {
- ast_mutex_lock(&s->__lock);
- if (s->waiting_thread != AST_PTHREADT_NULL)
- pthread_kill(s->waiting_thread, SIGURG);
+ AST_LIST_TRAVERSE(&sessions, session, list) {
+ ast_mutex_lock(&session->__lock);
+ if (session->waiting_thread != AST_PTHREADT_NULL)
+ pthread_kill(session->waiting_thread, SIGURG);
else
/* We have an event to process, but the mansession is
* not waiting for it. We still need to indicate that there
* is an event waiting so that get_input processes the pending
* event instead of polling.
*/
- s->pending_event = 1;
- ast_mutex_unlock(&s->__lock);
+ session->pending_event = 1;
+ ast_mutex_unlock(&session->__lock);
}
AST_LIST_UNLOCK(&sessions);
@@ -3199,38 +3243,38 @@ static char *contenttype[] = {
* the value of the mansession_id cookie (0 is not valid and means
* a session on the AMI socket).
*/
-static struct mansession *find_session(uint32_t ident, int incinuse)
+static struct mansession_session *find_session(uint32_t ident, int incinuse)
{
- struct mansession *s;
+ struct mansession_session *session;
if (ident == 0)
return NULL;
AST_LIST_LOCK(&sessions);
- AST_LIST_TRAVERSE(&sessions, s, list) {
- ast_mutex_lock(&s->__lock);
- if (s->managerid == ident && !s->needdestroy) {
- ast_atomic_fetchadd_int(&s->inuse, incinuse ? 1 : 0);
+ AST_LIST_TRAVERSE(&sessions, session, list) {
+ ast_mutex_lock(&session->__lock);
+ if (session->managerid == ident && !session->needdestroy) {
+ ast_atomic_fetchadd_int(&session->inuse, incinuse ? 1 : 0);
break;
}
- ast_mutex_unlock(&s->__lock);
+ ast_mutex_unlock(&session->__lock);
}
AST_LIST_UNLOCK(&sessions);
- return s;
+ return session;
}
int astman_is_authed(uint32_t ident)
{
int authed;
- struct mansession *s;
+ struct mansession_session *session;
- if (!(s = find_session(ident, 0)))
+ if (!(session = find_session(ident, 0)))
return 0;
- authed = (s->authenticated != 0);
+ authed = (session->authenticated != 0);
- ast_mutex_unlock(&s->__lock);
+ ast_mutex_unlock(&session->__lock);
return authed;
}
@@ -3238,17 +3282,17 @@ int astman_is_authed(uint32_t ident)
int astman_verify_session_readpermissions(uint32_t ident, int perm)
{
int result = 0;
- struct mansession *s;
+ struct mansession_session *session;
AST_LIST_LOCK(&sessions);
- AST_LIST_TRAVERSE(&sessions, s, list) {
- ast_mutex_lock(&s->__lock);
- if ((s->managerid == ident) && (s->readperm & perm)) {
+ AST_LIST_TRAVERSE(&sessions, session, list) {
+ ast_mutex_lock(&session->__lock);
+ if ((session->managerid == ident) && (session->readperm & perm)) {
result = 1;
- ast_mutex_unlock(&s->__lock);
+ ast_mutex_unlock(&session->__lock);
break;
}
- ast_mutex_unlock(&s->__lock);
+ ast_mutex_unlock(&session->__lock);
}
AST_LIST_UNLOCK(&sessions);
return result;
@@ -3257,17 +3301,17 @@ int astman_verify_session_readpermissions(uint32_t ident, int perm)
int astman_verify_session_writepermissions(uint32_t ident, int perm)
{
int result = 0;
- struct mansession *s;
+ struct mansession_session *session;
AST_LIST_LOCK(&sessions);
- AST_LIST_TRAVERSE(&sessions, s, list) {
- ast_mutex_lock(&s->__lock);
- if ((s->managerid == ident) && (s->writeperm & perm)) {
+ AST_LIST_TRAVERSE(&sessions, session, list) {
+ ast_mutex_lock(&session->__lock);
+ if ((session->managerid == ident) && (session->writeperm & perm)) {
result = 1;
- ast_mutex_unlock(&s->__lock);
+ ast_mutex_unlock(&session->__lock);
break;
}
- ast_mutex_unlock(&s->__lock);
+ ast_mutex_unlock(&session->__lock);
}
AST_LIST_UNLOCK(&sessions);
return result;
@@ -3508,7 +3552,8 @@ static struct ast_str *generic_http_callback(enum output_format format,
struct ast_variable *params, int *status,
char **title, int *contentlength)
{
- struct mansession *s = NULL;
+ struct mansession s = {.session = NULL, };
+ struct mansession_session *session = NULL;
uint32_t ident = 0;
int blastaway = 0;
struct ast_variable *v;
@@ -3525,44 +3570,46 @@ static struct ast_str *generic_http_callback(enum output_format format,
}
}
- if (!(s = find_session(ident, 1))) {
+ if (!(session = find_session(ident, 1))) {
/* Create new session.
* While it is not in the list we don't need any locking
*/
- if (!(s = ast_calloc(1, sizeof(*s)))) {
+ if (!(session = ast_calloc(1, sizeof(*session)))) {
*status = 500;
goto generic_callback_out;
}
- 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;
+ session->sin = *requestor;
+ session->fd = -1;
+ session->waiting_thread = AST_PTHREADT_NULL;
+ session->send_events = 0;
+ ast_mutex_init(&session->__lock);
+ ast_mutex_lock(&session->__lock);
+ session->inuse = 1;
/*!\note There is approximately a 1 in 1.8E19 chance that the following
* calculation will produce 0, which is an invalid ID, but due to the
* properties of the rand() function (and the constantcy of s), that
* won't happen twice in a row.
*/
- while ((s->managerid = rand() ^ (unsigned long) s) == 0);
- s->last_ev = grab_last();
+ while ((session->managerid = rand() ^ (unsigned long) session) == 0);
+ session->last_ev = grab_last();
AST_LIST_LOCK(&sessions);
- AST_LIST_INSERT_HEAD(&sessions, s, list);
+ AST_LIST_INSERT_HEAD(&sessions, session, list);
ast_atomic_fetchadd_int(&num_sessions, 1);
AST_LIST_UNLOCK(&sessions);
}
- ast_mutex_unlock(&s->__lock);
+ s.session = session;
+
+ ast_mutex_unlock(&session->__lock);
if (!(out = ast_str_create(1024))) {
*status = 500;
goto generic_callback_out;
}
- s->fd = mkstemp(template); /* create a temporary file for command output */
+ s.fd = mkstemp(template); /* create a temporary file for command output */
unlink(template);
- s->f = fdopen(s->fd, "w+");
+ s.f = fdopen(s.fd, "w+");
for (x = 0, v = params; v && (x < AST_MAX_MANHEADERS); x++, v = v->next) {
hdrlen = strlen(v->name) + strlen(v->value) + 3;
@@ -3571,17 +3618,17 @@ static struct ast_str *generic_http_callback(enum output_format format,
m.hdrcount = x + 1;
}
- if (process_message(s, &m)) {
- if (s->authenticated) {
- if (manager_displayconnects(s))
- ast_verb(2, "HTTP Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(s->sin.sin_addr));
- ast_log(LOG_EVENT, "HTTP Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(s->sin.sin_addr));
+ if (process_message(&s, &m)) {
+ if (session->authenticated) {
+ if (manager_displayconnects(session))
+ ast_verb(2, "HTTP Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
+ ast_log(LOG_EVENT, "HTTP Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
} else {
if (displayconnects)
- ast_verb(2, "HTTP Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(s->sin.sin_addr));
- ast_log(LOG_EVENT, "HTTP Failed attempt from %s\n", ast_inet_ntoa(s->sin.sin_addr));
+ ast_verb(2, "HTTP Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(session->sin.sin_addr));
+ ast_log(LOG_EVENT, "HTTP Failed attempt from %s\n", ast_inet_ntoa(session->sin.sin_addr));
}
- s->needdestroy = 1;
+ session->needdestroy = 1;
}
ast_str_append(&out, 0,
@@ -3590,7 +3637,7 @@ static struct ast_str *generic_http_callback(enum output_format format,
"Set-Cookie: mansession_id=\"%08x\"; Version=\"1\"; Max-Age=%d\r\n"
"\r\n",
contenttype[format],
- s->managerid, httptimeout);
+ session->managerid, httptimeout);
if (format == FORMAT_XML) {
ast_str_append(&out, 0, "<ajax-response>\n");
@@ -3608,12 +3655,12 @@ static struct ast_str *generic_http_callback(enum output_format format,
ast_str_append(&out, 0, ROW_FMT, TEST_STRING);
}
- if (s->f != NULL) { /* have temporary output */
+ if (s.f != NULL) { /* have temporary output */
char *buf;
- size_t l = ftell(s->f);
+ size_t l = ftell(s.f);
if (l) {
- if ((buf = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_SHARED, s->fd, 0))) {
+ if ((buf = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_SHARED, s.fd, 0))) {
if (format == FORMAT_XML || format == FORMAT_HTML)
xml_translate(&out, buf, params, format);
else
@@ -3623,9 +3670,9 @@ static struct ast_str *generic_http_callback(enum output_format format,
} else if (format == FORMAT_XML || format == FORMAT_HTML) {
xml_translate(&out, "", params, format);
}
- fclose(s->f);
- s->f = NULL;
- s->fd = -1;
+ fclose(s.f);
+ s.f = NULL;
+ s.fd = -1;
}
if (format == FORMAT_XML) {
@@ -3633,26 +3680,26 @@ static struct ast_str *generic_http_callback(enum output_format format,
} else if (format == FORMAT_HTML)
ast_str_append(&out, 0, "</table></body>\r\n");
- ast_mutex_lock(&s->__lock);
+ ast_mutex_lock(&session->__lock);
/* Reset HTTP timeout. If we're not authenticated, keep it extremely short */
- s->sessiontimeout = time(NULL) + ((s->authenticated || httptimeout < 5) ? httptimeout : 5);
+ session->sessiontimeout = time(NULL) + ((session->authenticated || httptimeout < 5) ? httptimeout : 5);
- if (s->needdestroy) {
- if (s->inuse == 1) {
+ if (session->needdestroy) {
+ if (session->inuse == 1) {
ast_debug(1, "Need destroy, doing it now!\n");
blastaway = 1;
} else {
ast_debug(1, "Need destroy, but can't do it yet!\n");
- if (s->waiting_thread != AST_PTHREADT_NULL)
- pthread_kill(s->waiting_thread, SIGURG);
- s->inuse--;
+ if (session->waiting_thread != AST_PTHREADT_NULL)
+ pthread_kill(session->waiting_thread, SIGURG);
+ session->inuse--;
}
} else
- s->inuse--;
- ast_mutex_unlock(&s->__lock);
+ session->inuse--;
+ ast_mutex_unlock(&session->__lock);
if (blastaway)
- destroy_session(s);
+ destroy_session(session);
generic_callback_out:
if (*status != 200)
return ast_http_error(500, "Server Error", NULL, "Internal Server Error (out of memory)\n");