Use a dynamically sized array to store the list of files for moh "files" mode

- Instead of always allocating 64KB of memory for every MOH class, this has
   been reduced to only a single pointer per class, with more memory only
   allocatted when using "files" mode, as needed
 - Instead of imposing a length limit on the full filename, including full
   path, of 127 characters, use PATH_MAX, the maximum length that the system
   can handle
 - There is no longer a limit on the number of files than can be used for a
   single MOH class using "files" mode


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@31953 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Russell Bryant
2006-06-04 06:21:43 +00:00
parent 998eacf17f
commit 006989cbe2

View File

@@ -72,8 +72,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/stringfields.h" #include "asterisk/stringfields.h"
#include "asterisk/linkedlists.h" #include "asterisk/linkedlists.h"
#define MAX_MOHFILES 512 #define INITIAL_NUM_FILES 8
#define MAX_MOHFILE_LEN 128
static char *app0 = "MusicOnHold"; static char *app0 = "MusicOnHold";
static char *app1 = "WaitMusicOnHold"; static char *app1 = "WaitMusicOnHold";
@@ -133,17 +132,22 @@ struct mohclass {
char dir[256]; char dir[256];
char args[256]; char args[256];
char mode[80]; char mode[80];
/* XXX This means that we are allocating 64KB of memory for every musiconhold class XXX */ /*! A dynamically sized array to hold the list of filenames in "files" mode */
char filearray[MAX_MOHFILES][MAX_MOHFILE_LEN]; char **filearray;
unsigned int flags; /*! The current size of the filearray */
int allowed_files;
/*! The current number of files loaded into the filearray */
int total_files; int total_files;
unsigned int flags;
/*! The format from the MOH source, not applicable to "files" mode */
int format; int format;
int pid; /* PID of mpg123 */ /*! The pid of the external application delivering MOH */
int pid;
time_t start; time_t start;
pthread_t thread; pthread_t thread;
/* Source of audio */ /*! Source of audio */
int srcfd; int srcfd;
/* FD for timing source */ /*! FD for timing source */
int pseudofd; int pseudofd;
AST_LIST_HEAD_NOLOCK(, mohdata) members; AST_LIST_HEAD_NOLOCK(, mohdata) members;
AST_LIST_ENTRY(mohclass) list; AST_LIST_ENTRY(mohclass) list;
@@ -164,20 +168,28 @@ AST_LIST_HEAD_STATIC(mohclasses, mohclass);
#define MAX_MP3S 256 #define MAX_MP3S 256
static void ast_moh_free_class(struct mohclass **class) static void ast_moh_free_class(struct mohclass **mohclass)
{ {
struct mohdata *member; struct mohdata *member;
struct mohclass *class = *mohclass;
int i;
while ((member = AST_LIST_REMOVE_HEAD(&((*class)->members), list))) while ((member = AST_LIST_REMOVE_HEAD(&class->members, list)))
free(member); free(member);
if ((*class)->thread) { if (class->thread) {
pthread_cancel((*class)->thread); pthread_cancel(class->thread);
(*class)->thread = 0; class->thread = 0;
} }
free(*class); if (class->filearray) {
*class = NULL; for (i = 0; i < class->total_files; i++)
free(class->filearray[i]);
free(class->filearray);
}
free(class);
*mohclass = NULL;
} }
@@ -402,14 +414,6 @@ static int spawn_mp3(struct mohclass *class)
ast_log(LOG_WARNING, "Pipe failed\n"); ast_log(LOG_WARNING, "Pipe failed\n");
return -1; return -1;
} }
#if 0
printf("%d files total, %d args total\n", files, argc);
{
int x;
for (x=0;argv[x];x++)
printf("arg%d: %s\n", x, argv[x]);
}
#endif
if (!files) { if (!files) {
ast_log(LOG_WARNING, "Found no files in '%s'\n", class->dir); ast_log(LOG_WARNING, "Found no files in '%s'\n", class->dir);
close(fds[0]); close(fds[0]);
@@ -721,12 +725,35 @@ static struct ast_generator mohgen =
generate: moh_generate, generate: moh_generate,
}; };
static int moh_add_file(struct mohclass *class, const char *filepath)
{
if (!class->allowed_files) {
if (!(class->filearray = ast_calloc(1, INITIAL_NUM_FILES * sizeof(*class->filearray))))
return -1;
class->allowed_files = INITIAL_NUM_FILES;
} else if (class->total_files == class->allowed_files) {
if (!(class->filearray = ast_realloc(class->filearray, class->allowed_files * sizeof(*class->filearray) * 2))) {
class->allowed_files = 0;
class->total_files = 0;
return -1;
}
class->allowed_files *= 2;
}
if (!(class->filearray[class->total_files] = ast_strdup(filepath)))
return -1;
class->total_files++;
return 0;
}
static int moh_scan_files(struct mohclass *class) { static int moh_scan_files(struct mohclass *class) {
DIR *files_DIR; DIR *files_DIR;
struct dirent *files_dirent; struct dirent *files_dirent;
char path[512]; char path[512];
char filepath[MAX_MOHFILE_LEN]; char filepath[PATH_MAX];
char *ext; char *ext;
struct stat statbuf; struct stat statbuf;
int dirnamelen; int dirnamelen;
@@ -738,16 +765,19 @@ static int moh_scan_files(struct mohclass *class) {
return -1; return -1;
} }
for (i = 0; i < class->total_files; i++)
free(class->filearray[i]);
class->total_files = 0; class->total_files = 0;
dirnamelen = strlen(class->dir) + 2; dirnamelen = strlen(class->dir) + 2;
getcwd(path, 512); getcwd(path, 512);
chdir(class->dir); chdir(class->dir);
memset(class->filearray, 0, MAX_MOHFILES*MAX_MOHFILE_LEN);
while ((files_dirent = readdir(files_DIR))) { while ((files_dirent = readdir(files_DIR))) {
if ((strlen(files_dirent->d_name) < 4) || ((strlen(files_dirent->d_name) + dirnamelen) >= MAX_MOHFILE_LEN)) /* The file name must be at least long enough to have the file type extension */
if ((strlen(files_dirent->d_name) < 4))
continue; continue;
snprintf(filepath, MAX_MOHFILE_LEN, "%s/%s", class->dir, files_dirent->d_name); snprintf(filepath, sizeof(filepath), "%s/%s", class->dir, files_dirent->d_name);
if (stat(filepath, &statbuf)) if (stat(filepath, &statbuf))
continue; continue;
@@ -765,13 +795,10 @@ static int moh_scan_files(struct mohclass *class) {
if (!strcmp(filepath, class->filearray[i])) if (!strcmp(filepath, class->filearray[i]))
break; break;
if (i == class->total_files) if (i == class->total_files) {
strcpy(class->filearray[class->total_files++], filepath); if (moh_add_file(class, filepath))
break;
/* If the new total files is equal to the maximum allowed, stop adding new ones */ }
if (class->total_files == MAX_MOHFILES)
break;
} }
closedir(files_DIR); closedir(files_DIR);