Improve the build system to *properly* remove unnecessary symbols from the runtime global namespace. Along the way, change the prefixes on some internal-only API calls to use a common prefix.

With these changes, for a module to export symbols into the global namespace, it must have *both* the AST_MODFLAG_GLOBAL_SYMBOLS flag and a linker script that allows the linker to leave the symbols exposed in the module's .so file (see res_odbc.exports for an example).



git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.4@182802 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Kevin P. Fleming
2009-03-18 01:28:42 +00:00
parent 62fbf19157
commit f1f417a9d8
33 changed files with 511 additions and 247 deletions

View File

@@ -51,8 +51,13 @@ endif
# per-target settings will be applied
CC_CFLAGS=$(PTHREAD_CFLAGS) $(ASTCFLAGS)
CXX_CFLAGS=$(PTHREAD_CFLAGS) $(filter-out -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations $(AST_DECLARATION_AFTER_STATEMENT),$(ASTCFLAGS))
CC_LDFLAGS_SO=$(PTHREAD_CFLAGS) $(ASTLDFLAGS) $(SOLINK)
CXX_LDFLAGS_SO=$(PTHREAD_CFLAGS) $(ASTLDFLAGS) $(SOLINK)
ifeq ($(GNU_LD),1)
SO_SUPPRESS_SYMBOLS=-Wl,--version-script,$(if $(wildcard $(subst .so,.exports,$@)),$(subst .so,.exports,$@),$(ASTTOPDIR)/default.exports)
endif
CC_LDFLAGS_SO=$(PTHREAD_CFLAGS) $(ASTLDFLAGS) $(SOLINK) $(SO_SUPPRESS_SYMBOLS)
CXX_LDFLAGS_SO=$(PTHREAD_CFLAGS) $(ASTLDFLAGS) $(SOLINK) $(SO_SUPPRESS_SYMBOLS)
CC_LIBS=$(PTHREAD_LIBS) $(LIBS)
CXX_LIBS=$(PTHREAD_LIBS) $(LIBS)

View File

@@ -171,7 +171,7 @@ static void spy_release(struct ast_channel *chan, void *data)
static int spy_generate(struct ast_channel *chan, void *data, int len, int samples)
{
struct chanspy_translation_helper *csth = data;
struct ast_frame *f;
struct ast_frame *f, *cur;
ast_audiohook_lock(&csth->spy_audiohook);
if (csth->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
@@ -186,14 +186,16 @@ static int spy_generate(struct ast_channel *chan, void *data, int len, int sampl
if (!f)
return 0;
if (ast_write(chan, f)) {
ast_frfree(f);
return -1;
}
for (cur = f; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
if (ast_write(chan, cur)) {
ast_frfree(f);
return -1;
}
if (csth->fd) {
if (write(csth->fd, f->data, f->datalen) < 0) {
ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
if (csth->fd) {
if (write(csth->fd, cur->data, cur->datalen) < 0) {
ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
}
}
}

View File

@@ -2338,9 +2338,19 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int c
}
}
if (conf->transframe[index]) {
if (conf->transframe[index]->frametype != AST_FRAME_NULL) {
if (can_write(chan, confflags) && ast_write(chan, conf->transframe[index]))
ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
if ((conf->transframe[index]->frametype != AST_FRAME_NULL) &&
can_write(chan, confflags)) {
struct ast_frame *cur;
/* the translator may have returned a list of frames, so
write each one onto the channel
*/
for (cur = conf->transframe[index]; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
if (ast_write(chan, cur)) {
ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
break;
}
}
}
} else {
ast_mutex_unlock(&conf->listenlock);

View File

@@ -229,9 +229,14 @@ static void *mixmonitor_thread(void *obj)
}
}
/* Write out the frame */
if (fs)
ast_writestream(fs, fr);
/* Write out the frame(s) */
if (fs) {
struct ast_frame *cur;
for (cur = fr; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
ast_writestream(fs, cur);
}
}
} else {
ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
}

View File

@@ -12,6 +12,4 @@
</member>
<member name="MTX_PROFILE" displayname="Enable Code Profiling Using TSC Counters">
</member>
<member name="TRACE_FRAMES" displayname="Trace Frame Allocations">
</member>
</category>

View File

@@ -1,37 +0,0 @@
#!/bin/sh -e
# This script is designed to remove all non-API global symbols from an object
# file. The only global symbols that should be retained are those that belong
# to the official namespace. Unfortunately doing this is platform-specific, as
# the object file manipulation tools are not consistent across platforms.
#
# On platforms where this script does not know what to do, the object file
# will retain non-API global symbols, and this may have unpleasant side effects.
#
# Prefixes that belong to the official namespace are:
# ast_
# _ast_
# __ast_
# astman_
# pbx_
case "${PROC}" in
powerpc64)
TEXTSYM=" D "
;;
*)
TEXTSYM=" T "
;;
esac
FILTER="${GREP} -v -e ^ast_ -e ^_ast_ -e ^__ast_ -e ^astman_ -e ^pbx_"
case "${OSARCH}" in
linux-gnu)
nm ${1} | ${GREP} -e "$TEXTSYM" | cut -d" " -f3 | ${FILTER} > striplist
sed -e "s/^/-N /" striplist | xargs -n 40 ${STRIP} ${1}
rm -f striplist
;;
*)
;;
esac

4
default.exports Normal file
View File

@@ -0,0 +1,4 @@
{
local:
*;
};

View File

@@ -188,15 +188,15 @@ int ao2_ref(void *o, int delta);
#ifndef DEBUG_THREADS
int ao2_lock(void *a);
#else
#define ao2_lock(a) _ao2_lock(a, __FILE__, __PRETTY_FUNCTION__, __LINE__, #a)
int _ao2_lock(void *a, const char *file, const char *func, int line, const char *var);
#define ao2_lock(a) __ao2_lock(a, __FILE__, __PRETTY_FUNCTION__, __LINE__, #a)
int __ao2_lock(void *a, const char *file, const char *func, int line, const char *var);
#endif
#ifndef DEBUG_THREADS
int ao2_trylock(void *a);
#else
#define ao2_trylock(a) _ao2_trylock(a, __FILE__, __PRETTY_FUNCTION__, __LINE__, #a)
int _ao2_trylock(void *a, const char *file, const char *func, int line, const char *var);
#define ao2_trylock(a) __ao2_trylock(a, __FILE__, __PRETTY_FUNCTION__, __LINE__, #a)
int __ao2_trylock(void *a, const char *file, const char *func, int line, const char *var);
#endif
/*!
@@ -208,8 +208,8 @@ int _ao2_trylock(void *a, const char *file, const char *func, int line, const ch
#ifndef DEBUG_THREADS
int ao2_unlock(void *a);
#else
#define ao2_unlock(a) _ao2_unlock(a, __FILE__, __PRETTY_FUNCTION__, __LINE__, #a)
int _ao2_unlock(void *a, const char *file, const char *func, int line, const char *var);
#define ao2_unlock(a) __ao2_unlock(a, __FILE__, __PRETTY_FUNCTION__, __LINE__, #a)
int __ao2_unlock(void *a, const char *file, const char *func, int line, const char *var);
#endif
/*!

View File

@@ -399,9 +399,9 @@ struct ast_frame *ast_fralloc(char *source, int len);
#endif
/*!
* \brief Frees a frame
* \brief Frees a frame or list of frames
*
* \param fr Frame to free
* \param fr Frame to free, or head of list to free
* \param cache Whether to consider this frame for frame caching
*/
void ast_frame_free(struct ast_frame *fr, int cache);
@@ -415,6 +415,11 @@ void ast_frame_free(struct ast_frame *fr, int cache);
* data malloc'd. If you need to store frames, say for queueing, then
* you should call this function.
* \return Returns a frame on success, NULL on error
* \note This function may modify the frame passed to it, so you must
* not assume the frame will be intact after the isolated frame has
* been produced. In other words, calling this function on a frame
* should be the last operation you do with that frame before freeing
* it (or exiting the block, if the frame is on the stack.)
*/
struct ast_frame *ast_frisolate(struct ast_frame *fr);

View File

@@ -685,7 +685,7 @@ struct { \
\param head This is a pointer to the list head structure
\param list This is a pointer to the list to be appended.
\param field This is the name of the field (declared using AST_LIST_ENTRY())
used to link entries of this list together.
used to link entries of the lists together.
Note: The source list (the \a list parameter) will be empty after
calling this macro (the list entries are \b moved to the target list).
@@ -704,6 +704,30 @@ struct { \
#define AST_RWLIST_APPEND_LIST AST_LIST_APPEND_LIST
/*!
\brief Inserts a whole list after a specific entry in a list
\param head This is a pointer to the list head structure
\param list This is a pointer to the list to be inserted.
\param elm This is a pointer to the entry after which the new list should
be inserted.
\param field This is the name of the field (declared using AST_LIST_ENTRY())
used to link entries of the lists together.
Note: The source list (the \a list parameter) will be empty after
calling this macro (the list entries are \b moved to the target list).
*/
#define AST_LIST_INSERT_LIST_AFTER(head, list, elm, field) do { \
(list)->last->field.next = (elm)->field.next; \
(elm)->field.next = (list)->first; \
if ((head)->last == elm) { \
(head)->last = (list)->last; \
} \
(list)->first = NULL; \
(list)->last = NULL; \
} while(0)
#define AST_RWLIST_INSERT_LIST_AFTER AST_LIST_INSERT_LIST_AFTER
/*!
\brief Removes and returns the head entry from a list.
\param head This is a pointer to the list head structure

View File

@@ -94,6 +94,10 @@ ifeq ($(OSARCH),SunOS)
ASTLINK=
endif
ifeq ($(GNU_LD),1)
ASTLINK+=-Wl,--version-script,asterisk.exports
endif
editline/libedit.a:
cd editline && test -f config.h || CFLAGS="$(PTHREAD_CFLAGS) $(subst $(ASTTOPDIR),../../,$(ASTCFLAGS:-Werror=))" LDFLAGS="$(ASTLDFLAGS)" ./configure --build=$(BUILD_PLATFORM) --host=$(HOST_PLATFORM) --with-ncurses=$(NCURSES_DIR) --with-curses=$(CURSES_DIR) --with-termcap=$(TERMCAP_DIR) --with-tinfo=$(TINFO_DIR)
$(MAKE) -C editline libedit.a
@@ -133,20 +137,19 @@ else
H323LDLIBS=
endif
asterisk: $(OBJS) editline/libedit.a db1-ast/libdb1.a $(AST_EMBED_LDSCRIPTS)
asterisk: $(OBJS) editline/libedit.a db1-ast/libdb1.a $(AST_EMBED_LDSCRIPTS) asterisk.exports
@$(ASTTOPDIR)/build_tools/make_build_h > $(ASTTOPDIR)/include/asterisk/build.h.tmp
@if cmp -s $(ASTTOPDIR)/include/asterisk/build.h.tmp $(ASTTOPDIR)/include/asterisk/build.h ; then echo ; else \
mv $(ASTTOPDIR)/include/asterisk/build.h.tmp $(ASTTOPDIR)/include/asterisk/build.h ; \
fi
@rm -f $(ASTTOPDIR)/include/asterisk/build.h.tmp
@$(CC) -c -o buildinfo.o $(ASTCFLAGS) buildinfo.c
$(ECHO_PREFIX) echo " [LD] $^ -> $@"
$(ECHO_PREFIX) echo " [LD] $(OBJS) editline/libedit.a db1-ast/libdb1.a $(AST_EMBED_LDSCRIPTS) -> $@"
ifneq ($(findstring chan_h323,$(MENUSELECT_CHANNELS)),)
$(CMD_PREFIX) $(CC) $(STATIC_BUILD) -o $@ $(ASTLINK) $(AST_EMBED_LDFLAGS) $(ASTLDFLAGS) $^ buildinfo.o $(AST_LIBS) $(AST_EMBED_LIBS)
$(CMD_PREFIX) $(CC) $(STATIC_BUILD) -o $@ $(ASTLINK) $(AST_EMBED_LDFLAGS) $(ASTLDFLAGS) $(OBJS) editline/libedit.a db1-ast/libdb1.a $(AST_EMBED_LDSCRIPTS) buildinfo.o $(AST_LIBS) $(AST_EMBED_LIBS)
else
$(CMD_PREFIX) $(CXX) $(STATIC_BUILD) -o $@ $(ASTLINK) $(AST_EMBED_LDFLAGS) $(ASTLDFLAGS) $(H323LDFLAGS) $^ buildinfo.o $(AST_LIBS) $(AST_EMBED_LIBS) $(H323LDLIBS)
$(CMD_PREFIX) $(CXX) $(STATIC_BUILD) -o $@ $(ASTLINK) $(AST_EMBED_LDFLAGS) $(ASTLDFLAGS) $(H323LDFLAGS) $(OBJS) editline/libedit.a db1-ast/libdb1.a $(AST_EMBED_LDSCRIPTS) buildinfo.o $(AST_LIBS) $(AST_EMBED_LIBS) $(H323LDLIBS)
endif
$(CMD_PREFIX) $(ASTTOPDIR)/build_tools/strip_nonapi $@ || rm $@
clean::
rm -f asterisk

28
main/asterisk.exports Normal file
View File

@@ -0,0 +1,28 @@
{
global:
ast_*;
_ast_*;
__ast_*;
pbx_*;
astman_*;
ao2_*;
__ao2_*;
option_debug;
option_verbose;
dahdi_chan_name;
dahdi_chan_name_len;
dahdi_chan_mode;
cid_di;
cid_dr;
clidsb;
MD5*;
sched_*;
io_*;
jb_*;
channelreloadreason2txt;
devstate2str;
manager_event;
dialed_interface_info;
local:
*;
};

View File

@@ -128,7 +128,7 @@ static inline struct astobj2 *INTERNAL_OBJ(void *user_data)
#ifndef DEBUG_THREADS
int ao2_lock(void *user_data)
#else
int _ao2_lock(void *user_data, const char *file, const char *func, int line, const char *var)
int __ao2_lock(void *user_data, const char *file, const char *func, int line, const char *var)
#endif
{
struct astobj2 *p = INTERNAL_OBJ(user_data);
@@ -150,7 +150,7 @@ int _ao2_lock(void *user_data, const char *file, const char *func, int line, con
#ifndef DEBUG_THREADS
int ao2_trylock(void *user_data)
#else
int _ao2_trylock(void *user_data, const char *file, const char *func, int line, const char *var)
int __ao2_trylock(void *user_data, const char *file, const char *func, int line, const char *var)
#endif
{
struct astobj2 *p = INTERNAL_OBJ(user_data);
@@ -177,7 +177,7 @@ int _ao2_trylock(void *user_data, const char *file, const char *func, int line,
#ifndef DEBUG_THREADS
int ao2_unlock(void *user_data)
#else
int _ao2_unlock(void *user_data, const char *file, const char *func, int line, const char *var)
int __ao2_unlock(void *user_data, const char *file, const char *func, int line, const char *var)
#endif
{
struct astobj2 *p = INTERNAL_OBJ(user_data);

View File

@@ -168,15 +168,22 @@ static void *autoservice_run(void *ign)
continue;
}
if ((dup_f = ast_frdup(defer_frame))) {
AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
if (defer_frame != f) {
if ((dup_f = ast_frdup(defer_frame))) {
AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
}
} else {
if ((dup_f = ast_frisolate(defer_frame))) {
if (dup_f != defer_frame) {
ast_frfree(defer_frame);
}
AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
}
}
break;
}
}
if (f) {
} else if (f) {
ast_frfree(f);
}
}

View File

@@ -895,60 +895,90 @@ alertpipe_failed:
}
/*! \brief Queue an outgoing media frame */
static int __ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, int head)
static int __ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, int head, struct ast_frame *after)
{
struct ast_frame *f;
struct ast_frame *cur;
int blah = 1;
int qlen = 0;
unsigned int new_frames = 0;
unsigned int new_voice_frames = 0;
unsigned int queued_frames = 0;
unsigned int queued_voice_frames = 0;
/* Build us a copy and free the original one */
if (!(f = ast_frdup(fin))) {
return -1;
AST_LIST_HEAD_NOLOCK(, ast_frame) frames;
/* Build copies of all the frames and count them */
AST_LIST_HEAD_INIT_NOLOCK(&frames);
for (cur = fin; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
if (!(f = ast_frdup(cur))) {
ast_frfree(AST_LIST_FIRST(&frames));
return -1;
}
AST_LIST_INSERT_TAIL(&frames, f, frame_list);
new_frames++;
if (f->frametype == AST_FRAME_VOICE) {
new_voice_frames++;
}
}
ast_channel_lock(chan);
/* See if the last frame on the queue is a hangup, if so don't queue anything */
if ((cur = AST_LIST_LAST(&chan->readq)) && (cur->frametype == AST_FRAME_CONTROL) && (cur->subclass == AST_CONTROL_HANGUP)) {
ast_frfree(f);
while ((f = AST_LIST_REMOVE_HEAD(&frames, frame_list))) {
ast_frfree(f);
}
ast_channel_unlock(chan);
return 0;
}
/* Count how many frames exist on the queue */
AST_LIST_TRAVERSE(&chan->readq, cur, frame_list) {
qlen++;
}
/* Allow up to 96 voice frames outstanding, and up to 128 total frames */
if (((fin->frametype == AST_FRAME_VOICE) && (qlen > 96)) || (qlen > 128)) {
if (fin->frametype != AST_FRAME_VOICE) {
ast_log(LOG_WARNING, "Exceptionally long queue length queuing to %s\n", chan->name);
ast_assert(fin->frametype == AST_FRAME_VOICE);
} else {
if (option_debug)
ast_log(LOG_DEBUG, "Dropping voice to exceptionally long queue on %s\n", chan->name);
ast_frfree(f);
ast_channel_unlock(chan);
return 0;
queued_frames++;
if (cur->frametype == AST_FRAME_VOICE) {
queued_voice_frames++;
}
}
if (head) {
AST_LIST_INSERT_HEAD(&chan->readq, f, frame_list);
if ((queued_frames + new_frames) > 128) {
ast_log(LOG_WARNING, "Exceptionally long queue length queuing to %s\n", chan->name);
while ((f = AST_LIST_REMOVE_HEAD(&frames, frame_list))) {
ast_frfree(f);
}
ast_channel_unlock(chan);
return 0;
}
if ((queued_voice_frames + new_voice_frames) > 96) {
ast_log(LOG_WARNING, "Exceptionally long voice queue length queuing to %s\n", chan->name);
while ((f = AST_LIST_REMOVE_HEAD(&frames, frame_list))) {
ast_frfree(f);
}
ast_channel_unlock(chan);
return 0;
}
if (after) {
AST_LIST_INSERT_LIST_AFTER(&chan->readq, &frames, after, frame_list);
} else {
AST_LIST_INSERT_TAIL(&chan->readq, f, frame_list);
if (head) {
AST_LIST_APPEND_LIST(&frames, &chan->readq, frame_list);
AST_LIST_HEAD_INIT_NOLOCK(&chan->readq);
}
AST_LIST_APPEND_LIST(&chan->readq, &frames, frame_list);
}
if (chan->alertpipe[1] > -1) {
if (write(chan->alertpipe[1], &blah, sizeof(blah)) != sizeof(blah)) {
ast_log(LOG_WARNING, "Unable to write to alert pipe on %s, frametype/subclass %d/%d (qlen = %d): %s!\n",
chan->name, f->frametype, f->subclass, qlen, strerror(errno));
if (write(chan->alertpipe[1], &blah, new_frames * sizeof(blah)) != (new_frames * sizeof(blah))) {
ast_log(LOG_WARNING, "Unable to write to alert pipe on %s (qlen = %d): %s!\n",
chan->name, queued_frames, strerror(errno));
}
#ifdef HAVE_DAHDI
} else if (chan->timingfd > -1) {
ioctl(chan->timingfd, DAHDI_TIMERPING, &blah);
while (new_frames--) {
ioctl(chan->timingfd, DAHDI_TIMERPING, &blah);
}
#endif
} else if (ast_test_flag(chan, AST_FLAG_BLOCKING)) {
pthread_kill(chan->blocker, SIGURG);
@@ -961,12 +991,12 @@ static int __ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, in
int ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin)
{
return __ast_queue_frame(chan, fin, 0);
return __ast_queue_frame(chan, fin, 0, NULL);
}
int ast_queue_frame_head(struct ast_channel *chan, struct ast_frame *fin)
{
return __ast_queue_frame(chan, fin, 1);
return __ast_queue_frame(chan, fin, 1, NULL);
}
/*! \brief Queue a hangup frame for channel */
@@ -2150,7 +2180,7 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
AST_LIST_REMOVE_CURRENT(&chan->readq, frame_list);
break;
}
AST_LIST_TRAVERSE_SAFE_END
AST_LIST_TRAVERSE_SAFE_END;
if (!f) {
/* There were no acceptable frames on the readq. */
@@ -2195,13 +2225,14 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
chan->fdno = -1;
if (f) {
struct ast_frame *readq_tail = AST_LIST_LAST(&chan->readq);
/* if the channel driver returned more than one frame, stuff the excess
into the readq for the next ast_read call (note that we can safely assume
that the readq is empty, because otherwise we would not have called into
the channel driver and f would be only a single frame)
into the readq for the next ast_read call
*/
if (AST_LIST_NEXT(f, frame_list)) {
AST_LIST_HEAD_SET_NOLOCK(&chan->readq, AST_LIST_NEXT(f, frame_list));
ast_queue_frame(chan, AST_LIST_NEXT(f, frame_list));
ast_frfree(AST_LIST_NEXT(f, frame_list));
AST_LIST_NEXT(f, frame_list) = NULL;
}
@@ -2410,8 +2441,26 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
}
}
if (chan->readtrans && (f = ast_translate(chan->readtrans, f, 1)) == NULL)
if (chan->readtrans && (f = ast_translate(chan->readtrans, f, 1)) == NULL) {
f = &ast_null_frame;
}
/* it is possible for the translation process on chan->readtrans to have
produced multiple frames from the single input frame we passed it; if
this happens, queue the additional frames *before* the frames we may
have queued earlier. if the readq was empty, put them at the head of
the queue, and if it was not, put them just after the frame that was
at the end of the queue.
*/
if (AST_LIST_NEXT(f, frame_list)) {
if (!readq_tail) {
ast_queue_frame_head(chan, AST_LIST_NEXT(f, frame_list));
} else {
__ast_queue_frame(chan, AST_LIST_NEXT(f, frame_list), 0, readq_tail);
}
ast_frfree(AST_LIST_NEXT(f, frame_list));
AST_LIST_NEXT(f, frame_list) = NULL;
}
/* Run generator sitting on the line if timing device not available
* and synchronous generation of outgoing frames is necessary */
@@ -2742,7 +2791,7 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
{
int res = -1;
int count = 0;
struct ast_frame *f = NULL, *f2 = NULL;
struct ast_frame *f = NULL;
/*Deadlock avoidance*/
while(ast_channel_trylock(chan)) {
@@ -2813,10 +2862,12 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
break;
case AST_FRAME_DTMF_END:
if (chan->audiohooks) {
struct ast_frame *old_frame = fr;
fr = ast_audiohook_write_list(chan, chan->audiohooks, AST_AUDIOHOOK_DIRECTION_WRITE, fr);
if (old_frame != fr)
f = fr;
struct ast_frame *new_frame = fr;
new_frame = ast_audiohook_write_list(chan, chan->audiohooks, AST_AUDIOHOOK_DIRECTION_WRITE, fr);
if (new_frame != fr) {
ast_frfree(new_frame);
}
}
ast_clear_flag(chan, AST_FLAG_BLOCKING);
ast_channel_unlock(chan);
@@ -2845,13 +2896,6 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
if (chan->tech->write == NULL)
break; /*! \todo XXX should return 0 maybe ? */
if (chan->audiohooks) {
struct ast_frame *old_frame = fr;
fr = ast_audiohook_write_list(chan, chan->audiohooks, AST_AUDIOHOOK_DIRECTION_WRITE, fr);
if (old_frame != fr)
f2 = fr;
}
/* If the frame is in the raw write format, then it's easy... just use the frame - otherwise we will have to translate */
if (fr->subclass == chan->rawwriteformat)
f = fr;
@@ -2864,37 +2908,82 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
break;
}
if (chan->audiohooks) {
struct ast_frame *new_frame, *cur;
for (cur = f; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
new_frame = ast_audiohook_write_list(chan, chan->audiohooks, AST_AUDIOHOOK_DIRECTION_WRITE, cur);
if (new_frame != cur) {
ast_frfree(new_frame);
}
}
}
/* If Monitor is running on this channel, then we have to write frames out there too */
/* the translator on chan->writetrans may have returned multiple frames
from the single frame we passed in; if so, feed each one of them to the
monitor */
if (chan->monitor && chan->monitor->write_stream) {
struct ast_frame *cur;
for (cur = f; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
/* XXX must explain this code */
#ifndef MONITOR_CONSTANT_DELAY
int jump = chan->insmpl - chan->outsmpl - 4 * f->samples;
if (jump >= 0) {
jump = chan->insmpl - chan->outsmpl;
if (ast_seekstream(chan->monitor->write_stream, jump, SEEK_FORCECUR) == -1)
ast_log(LOG_WARNING, "Failed to perform seek in monitoring write stream, synchronization between the files may be broken\n");
chan->outsmpl += jump + f->samples;
} else
chan->outsmpl += f->samples;
int jump = chan->insmpl - chan->outsmpl - 4 * cur->samples;
if (jump >= 0) {
jump = chan->insmpl - chan->outsmpl;
if (ast_seekstream(chan->monitor->write_stream, jump, SEEK_FORCECUR) == -1)
ast_log(LOG_WARNING, "Failed to perform seek in monitoring write stream, synchronization between the files may be broken\n");
chan->outsmpl += jump + cur->samples;
} else {
chan->outsmpl += cur->samples;
}
#else
int jump = chan->insmpl - chan->outsmpl;
if (jump - MONITOR_DELAY >= 0) {
if (ast_seekstream(chan->monitor->write_stream, jump - f->samples, SEEK_FORCECUR) == -1)
ast_log(LOG_WARNING, "Failed to perform seek in monitoring write stream, synchronization between the files may be broken\n");
chan->outsmpl += jump;
} else
chan->outsmpl += f->samples;
int jump = chan->insmpl - chan->outsmpl;
if (jump - MONITOR_DELAY >= 0) {
if (ast_seekstream(chan->monitor->write_stream, jump - cur->samples, SEEK_FORCECUR) == -1)
ast_log(LOG_WARNING, "Failed to perform seek in monitoring write stream, synchronization between the files may be broken\n");
chan->outsmpl += jump;
} else {
chan->outsmpl += cur->samples;
}
#endif
if (chan->monitor->state == AST_MONITOR_RUNNING) {
if (ast_writestream(chan->monitor->write_stream, f) < 0)
ast_log(LOG_WARNING, "Failed to write data to channel monitor write stream\n");
if (chan->monitor->state == AST_MONITOR_RUNNING) {
if (ast_writestream(chan->monitor->write_stream, cur) < 0)
ast_log(LOG_WARNING, "Failed to write data to channel monitor write stream\n");
}
}
}
if (f)
res = chan->tech->write(chan,f);
else
res = 0;
/* the translator on chan->writetrans may have returned multiple frames
from the single frame we passed in; if so, feed each one of them to the
channel, freeing each one after it has been written */
if ((f != fr) && AST_LIST_NEXT(f, frame_list)) {
struct ast_frame *cur, *next;
unsigned int skip = 0;
for (cur = f, next = AST_LIST_NEXT(cur, frame_list);
cur;
cur = next, next = cur ? AST_LIST_NEXT(cur, frame_list) : NULL) {
if (!skip) {
if ((res = chan->tech->write(chan, cur)) < 0) {
chan->_softhangup |= AST_SOFTHANGUP_DEV;
skip = 1;
} else if (next) {
/* don't do this for the last frame in the list,
as the code outside the loop will do it once
*/
chan->fout = FRAMECOUNT_INC(chan->fout);
}
}
ast_frfree(cur);
}
/* reset f so the code below doesn't attempt to free it */
f = NULL;
} else {
res = chan->tech->write(chan, f);
}
break;
case AST_FRAME_NULL:
case AST_FRAME_IAX:
@@ -2911,13 +3000,12 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
if (f && f != fr)
ast_frfree(f);
if (f2)
ast_frfree(f2);
ast_clear_flag(chan, AST_FLAG_BLOCKING);
/* Consider a write failure to force a soft hangup */
if (res < 0)
if (res < 0) {
chan->_softhangup |= AST_SOFTHANGUP_DEV;
else {
} else {
chan->fout = FRAMECOUNT_INC(chan->fout);
}
done:

View File

@@ -203,14 +203,20 @@ int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
struct ast_frame *trf;
fs->lastwriteformat = f->subclass;
/* Get the translated frame but don't consume the original in case they're using it on another stream */
trf = ast_translate(fs->trans, f, 0);
if (trf) {
res = fs->fmt->write(fs, trf);
if ((trf = ast_translate(fs->trans, f, 0))) {
struct ast_frame *cur;
/* the translator may have returned multiple frames, so process them */
for (cur = trf; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
if ((res = fs->fmt->write(fs, trf))) {
ast_log(LOG_WARNING, "Translated frame write failed\n");
break;
}
}
ast_frfree(trf);
if (res)
ast_log(LOG_WARNING, "Translated frame write failed\n");
} else
} else {
res = 0;
}
}
}
return res;

View File

@@ -47,11 +47,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/dsp.h"
#include "asterisk/file.h"
#ifdef TRACE_FRAMES
static int headers;
static AST_LIST_HEAD_STATIC(headerlist, ast_frame);
#endif
#if !defined(LOW_MEMORY)
static void frame_cache_cleanup(void *data);
@@ -291,7 +286,7 @@ struct ast_frame *ast_smoother_read(struct ast_smoother *s)
memmove(s->data, s->data + len, s->len);
if (!ast_tvzero(s->delivery)) {
/* If we have delivery time, increment it, otherwise, leave it at 0 */
s->delivery = ast_tvadd(s->delivery, ast_samp2tv(s->f.samples, 8000));
s->delivery = ast_tvadd(s->delivery, ast_samp2tv(s->f.samples, ast_format_rate(s->format)));
}
}
/* Return frame */
@@ -328,12 +323,6 @@ static struct ast_frame *ast_frame_header_new(void)
#endif
f->mallocd_hdr_len = sizeof(*f);
#ifdef TRACE_FRAMES
AST_LIST_LOCK(&headerlist);
headers++;
AST_LIST_INSERT_HEAD(&headerlist, f, frame_list);
AST_LIST_UNLOCK(&headerlist);
#endif
return f;
}
@@ -351,7 +340,7 @@ static void frame_cache_cleanup(void *data)
}
#endif
void ast_frame_free(struct ast_frame *fr, int cache)
static void __frame_free(struct ast_frame *fr, int cache)
{
if (ast_test_flag(fr, AST_FRFLAG_FROM_TRANSLATOR)) {
ast_translate_frame_freed(fr);
@@ -370,8 +359,8 @@ void ast_frame_free(struct ast_frame *fr, int cache)
* to keep things simple... */
struct ast_frame_cache *frames;
if ((frames = ast_threadstorage_get(&frame_cache, sizeof(*frames)))
&& frames->size < FRAME_CACHE_MAX_SIZE) {
if ((frames = ast_threadstorage_get(&frame_cache, sizeof(*frames))) &&
(frames->size < FRAME_CACHE_MAX_SIZE)) {
AST_LIST_INSERT_HEAD(&frames->list, fr, frame_list);
frames->size++;
return;
@@ -385,19 +374,25 @@ void ast_frame_free(struct ast_frame *fr, int cache)
}
if (fr->mallocd & AST_MALLOCD_SRC) {
if (fr->src)
free((char *)fr->src);
free((void *)fr->src);
}
if (fr->mallocd & AST_MALLOCD_HDR) {
#ifdef TRACE_FRAMES
AST_LIST_LOCK(&headerlist);
headers--;
AST_LIST_REMOVE(&headerlist, fr, frame_list);
AST_LIST_UNLOCK(&headerlist);
#endif
free(fr);
}
}
void ast_frame_free(struct ast_frame *frame, int cache)
{
struct ast_frame *next;
for (next = AST_LIST_NEXT(frame, frame_list);
frame;
frame = next, next = frame ? AST_LIST_NEXT(frame, frame_list) : NULL) {
__frame_free(frame, cache);
}
}
/*!
* \brief 'isolates' a frame by duplicating non-malloc'ed components
* (header, src, data).
@@ -408,19 +403,29 @@ struct ast_frame *ast_frisolate(struct ast_frame *fr)
struct ast_frame *out;
void *newdata;
ast_clear_flag(fr, AST_FRFLAG_FROM_TRANSLATOR);
ast_clear_flag(fr, AST_FRFLAG_FROM_DSP);
/* if none of the existing frame is malloc'd, let ast_frdup() do it
since it is more efficient
*/
if (fr->mallocd == 0) {
return ast_frdup(fr);
}
/* if everything is already malloc'd, we are done */
if ((fr->mallocd & (AST_MALLOCD_HDR | AST_MALLOCD_SRC | AST_MALLOCD_DATA)) ==
(AST_MALLOCD_HDR | AST_MALLOCD_SRC | AST_MALLOCD_DATA)) {
return fr;
}
if (!(fr->mallocd & AST_MALLOCD_HDR)) {
/* Allocate a new header if needed */
if (!(out = ast_frame_header_new()))
if (!(out = ast_frame_header_new())) {
return NULL;
}
out->frametype = fr->frametype;
out->subclass = fr->subclass;
out->datalen = fr->datalen;
out->samples = fr->samples;
out->offset = fr->offset;
out->data = fr->data;
/* Copy the timing data */
ast_copy_flags(out, fr, AST_FRFLAG_HAS_TIMING_INFO);
if (ast_test_flag(fr, AST_FRFLAG_HAS_TIMING_INFO)) {
@@ -428,26 +433,34 @@ struct ast_frame *ast_frisolate(struct ast_frame *fr)
out->len = fr->len;
out->seqno = fr->seqno;
}
} else
} else {
ast_clear_flag(fr, AST_FRFLAG_FROM_TRANSLATOR);
ast_clear_flag(fr, AST_FRFLAG_FROM_DSP);
ast_clear_flag(fr, AST_FRFLAG_FROM_FILESTREAM);
out = fr;
}
if (!(fr->mallocd & AST_MALLOCD_SRC)) {
if (fr->src) {
if (!(out->src = ast_strdup(fr->src))) {
if (out != fr)
free(out);
return NULL;
if (!(fr->mallocd & AST_MALLOCD_SRC) && fr->src) {
if (!(out->src = ast_strdup(fr->src))) {
if (out != fr) {
free(out);
}
return NULL;
}
} else
} else {
out->src = fr->src;
fr->src = NULL;
fr->mallocd &= ~AST_MALLOCD_SRC;
}
if (!(fr->mallocd & AST_MALLOCD_DATA)) {
if (!(newdata = ast_malloc(fr->datalen + AST_FRIENDLY_OFFSET))) {
if (out->src != fr->src)
if (out->src != fr->src) {
free((void *) out->src);
if (out != fr)
}
if (out != fr) {
free(out);
}
return NULL;
}
newdata += AST_FRIENDLY_OFFSET;
@@ -455,6 +468,10 @@ struct ast_frame *ast_frisolate(struct ast_frame *fr)
out->datalen = fr->datalen;
memcpy(newdata, fr->data, fr->datalen);
out->data = newdata;
} else {
out->data = fr->data;
fr->data = NULL;
fr->mallocd &= ~AST_MALLOCD_DATA;
}
out->mallocd = AST_MALLOCD_HDR | AST_MALLOCD_SRC | AST_MALLOCD_DATA;
@@ -497,7 +514,7 @@ struct ast_frame *ast_frdup(const struct ast_frame *f)
break;
}
}
AST_LIST_TRAVERSE_SAFE_END
AST_LIST_TRAVERSE_SAFE_END;
}
#endif
@@ -970,29 +987,6 @@ void ast_frame_dump(const char *name, struct ast_frame *f, char *prefix)
}
#ifdef TRACE_FRAMES
static int show_frame_stats(int fd, int argc, char *argv[])
{
struct ast_frame *f;
int x=1;
if (argc != 4)
return RESULT_SHOWUSAGE;
AST_LIST_LOCK(&headerlist);
ast_cli(fd, " Framer Statistics \n");
ast_cli(fd, "---------------------------\n");
ast_cli(fd, "Total allocated headers: %d\n", headers);
ast_cli(fd, "Queue Dump:\n");
AST_LIST_TRAVERSE(&headerlist, f, frame_list)
ast_cli(fd, "%d. Type %d, subclass %d from %s\n", x++, f->frametype, f->subclass, f->src ? f->src : "<Unknown>");
AST_LIST_UNLOCK(&headerlist);
return RESULT_SUCCESS;
}
static char frame_stats_usage[] =
"Usage: core show frame stats\n"
" Displays debugging statistics from framer\n";
#endif
/* Builtin Asterisk CLI-commands for debugging */
static struct ast_cli_entry cli_show_codecs = {
{ "show", "codecs", NULL },
@@ -1019,13 +1013,6 @@ static struct ast_cli_entry cli_show_codec = {
show_codec_n_deprecated, NULL,
NULL };
#ifdef TRACE_FRAMES
static struct ast_cli_entry cli_show_frame_stats = {
{ "show", "frame", "stats", NULL },
show_frame_stats, NULL,
NULL };
#endif
static struct ast_cli_entry my_clis[] = {
{ { "core", "show", "codecs", NULL },
show_codecs, "Displays a list of codecs",
@@ -1046,12 +1033,6 @@ static struct ast_cli_entry my_clis[] = {
{ { "core", "show", "codec", NULL },
show_codec_n, "Shows a specific codec",
frame_show_codec_n_usage, NULL, &cli_show_codec },
#ifdef TRACE_FRAMES
{ { "core", "show", "frame", "stats", NULL },
show_frame_stats, "Shows frame statistics",
frame_stats_usage, NULL, &cli_show_frame_stats },
#endif
};
int init_framer(void)

View File

@@ -57,7 +57,7 @@ void ast_slinfactory_destroy(struct ast_slinfactory *sf)
int ast_slinfactory_feed(struct ast_slinfactory *sf, struct ast_frame *f)
{
struct ast_frame *begin_frame = f, *duped_frame = NULL, *frame_ptr;
unsigned int x;
unsigned int x = 0;
/* In some cases, we can be passed a frame which has no data in it, but
* which has a positive number of samples defined. Once such situation is
@@ -84,27 +84,33 @@ int ast_slinfactory_feed(struct ast_slinfactory *sf, struct ast_frame *f)
}
}
if (!(begin_frame = ast_translate(sf->trans, f, 0)))
if (!(begin_frame = ast_translate(sf->trans, f, 0))) {
return 0;
}
duped_frame = ast_frdup(begin_frame);
ast_frfree(begin_frame);
if (!duped_frame)
if (!(duped_frame = ast_frisolate(begin_frame))) {
return 0;
}
if (duped_frame != begin_frame) {
ast_frfree(begin_frame);
}
} else {
if (!(duped_frame = ast_frdup(f)))
return 0;
}
x = 0;
AST_LIST_TRAVERSE(&sf->queue, frame_ptr, frame_list)
AST_LIST_TRAVERSE(&sf->queue, frame_ptr, frame_list) {
x++;
}
AST_LIST_INSERT_TAIL(&sf->queue, duped_frame, frame_list);
sf->size += duped_frame->samples;
/* if the frame was translated, the translator may have returned multiple
frames, so process each of them
*/
for (begin_frame = duped_frame; begin_frame; begin_frame = AST_LIST_NEXT(begin_frame, frame_list)) {
AST_LIST_INSERT_TAIL(&sf->queue, begin_frame, frame_list);
sf->size += begin_frame->samples;
}
return x;
}

View File

@@ -43,6 +43,8 @@ GC_LDFLAGS=@GC_LDFLAGS@
PTHREAD_CFLAGS=@PTHREAD_CFLAGS@
PTHREAD_LIBS=@PTHREAD_LIBS@
GNU_LD=@GNU_LD@
prefix = @prefix@
exec_prefix = @exec_prefix@

33
res/res_adsi.exports Normal file
View File

@@ -0,0 +1,33 @@
{
global:
ast_adsi_available;
ast_adsi_begin_download;
ast_adsi_channel_restore;
ast_adsi_clear_screen;
ast_adsi_clear_soft_keys;
ast_adsi_connect_session;
ast_adsi_data_mode;
ast_adsi_disconnect_session;
ast_adsi_display;
ast_adsi_download_connect;
ast_adsi_download_disconnect;
ast_adsi_end_download;
ast_adsi_get_cpeid;
ast_adsi_get_cpeinfo;
ast_adsi_input_control;
ast_adsi_input_format;
ast_adsi_load_session;
ast_adsi_load_soft_key;
ast_adsi_print;
ast_adsi_query_cpeid;
ast_adsi_query_cpeinfo;
ast_adsi_read_encoded_dtmf;
ast_adsi_set_keys;
ast_adsi_set_line;
ast_adsi_transmit_message;
ast_adsi_transmit_message_full;
ast_adsi_unload_session;
ast_adsi_voice_mode;
local:
*;
};

7
res/res_agi.exports Normal file
View File

@@ -0,0 +1,7 @@
{
global:
ast_agi_register;
ast_agi_unregister;
local:
*;
};

View File

@@ -558,7 +558,7 @@ static int load_module (void)
return 0;
}
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "ODBC Configuration",
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "ODBC Configuration",
.load = load_module,
.unload = unload_module,
);

View File

@@ -835,7 +835,7 @@ static int realtime_pgsql_status(int fd, int argc, char **argv)
}
/* needs usecount semantics defined */
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "PostgreSQL RealTime Configuration Driver",
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "PostgreSQL RealTime Configuration Driver",
.load = load_module,
.unload = unload_module,
.reload = reload

View File

@@ -624,7 +624,7 @@ static int unload_module(void)
}
/* needs usecount semantics defined */
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Cryptographic Digital Signatures",
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Cryptographic Digital Signatures",
.load = load_module,
.unload = unload_module,
.reload = reload

13
res/res_features.exports Normal file
View File

@@ -0,0 +1,13 @@
{
global:
ast_bridge_call;
ast_masq_park_call;
ast_park_call;
ast_parking_ext;
ast_pickup_call;
ast_pickup_ext;
ast_register_feature;
ast_unregister_feature;
local:
*;
};

View File

@@ -399,7 +399,7 @@ static int reload(void)
return ind_load_module();
}
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Indications Resource",
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Indications Resource",
.load = load_module,
.unload = unload_module,
.reload = reload,

13
res/res_jabber.exports Normal file
View File

@@ -0,0 +1,13 @@
{
global:
ast_aji_create_chat;
ast_aji_disconnect;
ast_aji_get_client;
ast_aji_get_clients;
ast_aji_increment_mid;
ast_aji_invite_chat;
ast_aji_join_chat;
ast_aji_send;
local:
*;
};

11
res/res_monitor.exports Normal file
View File

@@ -0,0 +1,11 @@
{
global:
ast_monitor_change_fname;
ast_monitor_pause;
ast_monitor_setjoinfiles;
ast_monitor_start;
ast_monitor_stop;
ast_monitor_unpause;
local:
*;
};

View File

@@ -1486,7 +1486,7 @@ static int unload_module(void)
return res;
}
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Music On Hold Resource",
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Music On Hold Resource",
.load = load_module,
.unload = unload_module,
.reload = reload,

11
res/res_odbc.exports Normal file
View File

@@ -0,0 +1,11 @@
{
global:
ast_odbc_backslash_is_escape;
ast_odbc_prepare_and_execute;
ast_odbc_release_obj;
ast_odbc_request_obj;
ast_odbc_sanity_check;
ast_odbc_smart_execute;
local:
*;
};

18
res/res_smdi.exports Normal file
View File

@@ -0,0 +1,18 @@
{
global:
ast_smdi_interface_find;
ast_smdi_interface_unref;
ast_smdi_md_message_destroy;
ast_smdi_md_message_pop;
ast_smdi_md_message_putback;
ast_smdi_md_message_wait;
ast_smdi_mwi_message_destroy;
ast_smdi_mwi_message_pop;
ast_smdi_mwi_message_putback;
ast_smdi_mwi_message_wait;
ast_smdi_mwi_message_wait_station;
ast_smdi_mwi_set;
ast_smdi_mwi_unset;
local:
*;
};

View File

@@ -109,7 +109,7 @@ static int unload_module(void)
return ((thread != AST_PTHREADT_NULL) ? pthread_join(thread, NULL) : 0);
}
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "SNMP [Sub]Agent for Asterisk",
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "SNMP [Sub]Agent for Asterisk",
.load = load_module,
.unload = unload_module,
);

21
res/res_speech.exports Normal file
View File

@@ -0,0 +1,21 @@
{
global:
ast_speech_change;
ast_speech_change_results_type;
ast_speech_change_state;
ast_speech_destroy;
ast_speech_dtmf;
ast_speech_grammar_activate;
ast_speech_grammar_deactivate;
ast_speech_grammar_load;
ast_speech_grammar_unload;
ast_speech_new;
ast_speech_register;
ast_speech_results_free;
ast_speech_results_get;
ast_speech_start;
ast_speech_unregister;
ast_speech_write;
local:
*;
};