webconference: roomDelete and time for roomCreate

added config items (webconference.conf):
 private_rooms
 support_rooms_timeout

implements bugs #0000048 and #0000049
sayer/1.4-spce2.6
Stefan Sayer 16 years ago
parent 9d4fa937aa
commit f5846bfa27

@ -80,6 +80,16 @@ AmArg ConferenceRoom::asArgArray() {
return res;
}
vector<string> ConferenceRoom::participantLtags() {
cleanExpired();
vector<string> res;
for (list<ConferenceRoomParticipant>::iterator it=participants.begin();
it != participants.end(); it++) {
res.push_back(it->localtag);
}
return res;
}
void ConferenceRoom::newParticipant(const string& localtag,
const string& number) {
gettimeofday(&last_access_time, NULL);
@ -149,3 +159,7 @@ bool ConferenceRoom::expired(const struct timeval& now) {
return (diff.tv_sec > 0) &&
(unsigned int)diff.tv_sec > (unsigned int)WebConferenceFactory::RoomExpiredDelay;
}
bool ConferenceRoom::hard_expired(const struct timeval& now) {
return expiry_time && (now.tv_sec > expiry_time);
}

@ -8,6 +8,9 @@ using std::string;
#include <list>
using std::list;
#include <vector>
using std::vector;
#include <sys/time.h>
@ -54,6 +57,7 @@ struct ConferenceRoom {
string adminpin;
struct timeval last_access_time;
time_t expiry_time;
list<ConferenceRoomParticipant> participants;
@ -64,6 +68,8 @@ struct ConferenceRoom {
AmArg asArgArray();
vector<string> participantLtags();
void newParticipant(const string& localtag, const string& number);
bool updateStatus(const string& part_tag,
@ -76,6 +82,8 @@ struct ConferenceRoom {
bool expired(const struct timeval& now);
bool expired();
bool hard_expired(const struct timeval& now);
};

@ -70,6 +70,8 @@ int WebConferenceFactory::RoomExpiredDelay;
int WebConferenceFactory::RoomSweepInterval;
bool WebConferenceFactory::ignore_pin = false;
bool WebConferenceFactory::PrivateRoomsMode = false;
int WebConferenceFactory::onLoad()
{
return getInstance()->load();
@ -95,6 +97,7 @@ int WebConferenceFactory::load()
AM_PROMPT_ADD(DROP_SOUND, WEBCONF_ANNOUNCE_PATH "beep.wav");
AM_PROMPT_ADD(ENTER_PIN, WEBCONF_ANNOUNCE_PATH "enter_pin.wav");
AM_PROMPT_ADD(WRONG_PIN, WEBCONF_ANNOUNCE_PATH "wrong_pin.wav");
AM_PROMPT_ADD(WRONG_PIN_BYE, WEBCONF_ANNOUNCE_PATH "wrong_pin_bye.wav");
AM_PROMPT_ADD(ENTERING_CONFERENCE, WEBCONF_ANNOUNCE_PATH "entering_conference.wav");
AM_PROMPT_END(prompts, cfg, APP_NAME);
@ -207,6 +210,16 @@ int WebConferenceFactory::load()
}
}
if (cfg.getParameter("private_rooms") == "yes")
PrivateRoomsMode = true;
DBG("Private rooms mode %sabled.\n", PrivateRoomsMode ? "en":"dis");
if (cfg.getParameter("support_rooms_timeout") == "yes") {
cleaner = new WebConferenceCleaner(this);
cleaner->start();
}
if(cfg.hasParameter("enable_session_timer") &&
(cfg.getParameter("enable_session_timer") == string("yes")) ){
DBG("enabling session timers\n");
@ -219,12 +232,27 @@ int WebConferenceFactory::load()
return 0;
}
void WebConferenceFactory::newParticipant(const string& conf_id,
bool WebConferenceFactory::isValidConference(const string& conf_id) {
if (!PrivateRoomsMode)
return true;
rooms_mut.lock();
bool res = rooms.find(conf_id) != rooms.end();
rooms_mut.unlock();
return res;
}
bool WebConferenceFactory::newParticipant(const string& conf_id,
const string& localtag,
const string& number) {
rooms_mut.lock();
if (PrivateRoomsMode && rooms.find(conf_id) == rooms.end()) {
rooms_mut.unlock();
return false;
}
rooms[conf_id].newParticipant(localtag, number);
rooms_mut.unlock();
return true;
}
void WebConferenceFactory::updateStatus(const string& conf_id,
@ -232,7 +260,9 @@ void WebConferenceFactory::updateStatus(const string& conf_id,
ConferenceRoomParticipant::ParticipantStatus status,
const string& reason) {
rooms_mut.lock();
rooms[conf_id].updateStatus(localtag, status, reason);
if (!PrivateRoomsMode || rooms.find(conf_id) != rooms.end()) {
rooms[conf_id].updateStatus(localtag, status, reason);
}
rooms_mut.unlock();
}
@ -247,16 +277,21 @@ string WebConferenceFactory::getAdminpin(const string& room) {
}
ConferenceRoom* WebConferenceFactory::getRoom(const string& room,
const string& adminpin) {
const string& adminpin,
bool ignore_adminpin = false) {
ConferenceRoom* res = NULL;
map<string, ConferenceRoom>::iterator it = rooms.find(room);
if (it == rooms.end()) {
if (PrivateRoomsMode)
return NULL;
// (re)open room
rooms[room] = ConferenceRoom();
rooms[room].adminpin = adminpin;
res = &rooms[room];
} else {
if ((!ignore_pin) &&
(!ignore_adminpin) &&
(!it->second.adminpin.empty()) &&
(it->second.adminpin != adminpin)) {
// wrong pin
@ -372,7 +407,7 @@ void WebConferenceFactory::invoke(const string& method,
{
if(method == "roomCreate"){
if (method == "roomCreate"){
args.assertArrayFmt("s");
roomCreate(args, ret);
ret.push(getServerInfoString().c_str());
@ -380,6 +415,10 @@ void WebConferenceFactory::invoke(const string& method,
args.assertArrayFmt("ss");
roomInfo(args, ret);
ret.push(getServerInfoString().c_str());
} else if(method == "roomDelete"){
args.assertArrayFmt("ss");
roomDelete(args, ret);
ret.push(getServerInfoString().c_str());
} else if(method == "dialout"){
args.assertArrayFmt("sssssss");
dialout(args, ret);
@ -434,6 +473,7 @@ void WebConferenceFactory::invoke(const string& method,
ret.push(getServerInfoString().c_str());
} else if(method == "_list"){
ret.push("roomCreate");
ret.push("roomDelete");
ret.push("roomInfo");
ret.push("dialout");
ret.push("mute");
@ -492,6 +532,13 @@ void WebConferenceFactory::sweepRooms() {
void WebConferenceFactory::roomCreate(const AmArg& args, AmArg& ret) {
string room = args.get(0).asCStr();
time_t expiry_time = 0;
if (args.size() > 1 && (args.get(1).asInt() > 0)) {
struct timeval now;
gettimeofday(&now, NULL);
expiry_time = now.tv_sec + args.get(1).asInt();
}
rooms_mut.lock();
// sweep rooms (if necessary)
@ -501,6 +548,7 @@ void WebConferenceFactory::roomCreate(const AmArg& args, AmArg& ret) {
if (it == rooms.end()) {
rooms[room] = ConferenceRoom();
rooms[room].adminpin = getRandomPin();
rooms[room].expiry_time = expiry_time;
ret.push(0);
ret.push("OK");
ret.push(rooms[room].adminpin.c_str());
@ -523,21 +571,76 @@ void WebConferenceFactory::roomInfo(const AmArg& args, AmArg& ret) {
string room = args.get(0).asCStr();
string adminpin = args.get(1).asCStr();
rooms_mut.lock();
ConferenceRoom* r = getRoom(room, adminpin);
if (NULL == r) {
rooms_mut.lock();
ConferenceRoom* r = getRoom(room, adminpin);
if (NULL == r) {
ret.push(1);
ret.push("wrong adminpin");
ret.push("wrong adminpin or inexisting room");
// for consistency, add an empty array
AmArg a;
a.assertArray(0);
ret.push(a);
} else {
ret.push(0);
ret.push("OK");
ret.push(r->asArgArray());
}
rooms_mut.unlock();
} else {
ret.push(0);
ret.push("OK");
ret.push(r->asArgArray());
}
rooms_mut.unlock();
}
void WebConferenceFactory::roomDelete(const string& room, const string& adminpin,
AmArg& ret, bool ignore_adminpin = false) {
rooms_mut.lock();
map<string, ConferenceRoom>::iterator it = rooms.find(room);
if (it == rooms.end()) {
rooms_mut.unlock();
ret.push(2);
ret.push("room does not exist\n");
return;
}
rooms_mut.unlock();
postAllConfEvent(room, adminpin, ret,
WebConferenceEvent::Kick, ignore_adminpin);
if (ret.get(0).asInt()==0) {
DBG("erasing room '%s'\n", room.c_str());
rooms_mut.lock();
rooms.erase(room);
rooms_mut.unlock();
}
}
void WebConferenceFactory::roomDelete(const AmArg& args, AmArg& ret) {
rooms_mut.lock();
string room = args.get(0).asCStr();
string adminpin = args.get(1).asCStr();
roomDelete(room, adminpin, ret);
}
void WebConferenceFactory::closeExpiredRooms() {
struct timeval now;
gettimeofday(&now, NULL);
vector<string> expired_rooms;
rooms_mut.lock();
for (map<string, ConferenceRoom>::iterator it =
rooms.begin(); it !=rooms.end(); it++) {
if (it->second.hard_expired(now))
expired_rooms.push_back(it->first);
}
rooms_mut.unlock();
for (vector<string>::iterator it=
expired_rooms.begin(); it != expired_rooms.end(); it++) {
DBG("deleting expired room '%s'\n", it->c_str());
AmArg ret;
roomDelete(*it, "", ret, true);
}
}
void WebConferenceFactory::dialout(const AmArg& args, AmArg& ret) {
@ -587,11 +690,12 @@ void WebConferenceFactory::dialout(const AmArg& args, AmArg& ret) {
// sweep rooms (if necessary)
sweepRooms();
ConferenceRoom* r = getRoom(room, adminpin);
bool is_valid_room = getRoom(room, adminpin) != NULL;
rooms_mut.unlock();
if (NULL == r) {
if (!is_valid_room) {
ret.push(1);
ret.push("wrong adminpin");
ret.push("wrong adminpin or inexisting room");
ret.push("");
return;
}
@ -624,6 +728,29 @@ void WebConferenceFactory::dialout(const AmArg& args, AmArg& ret) {
}
}
void WebConferenceFactory::postAllConfEvent(const string& room, const string& adminpin,
AmArg& ret, int id, bool ignore_adminpin = false) {
vector<string> ltags;
rooms_mut.lock(); {
ConferenceRoom* r = getRoom(room, adminpin, ignore_adminpin);
if (NULL == r) {
rooms_mut.unlock();
return;
}
ltags = r->participantLtags();
} rooms_mut.unlock();
for (vector<string>::iterator it =
ltags.begin(); it != ltags.end(); it++) {
AmSessionContainer::instance()->postEvent(*it,
new WebConferenceEvent(id));
}
ret.push(0);
ret.push("OK");
}
void WebConferenceFactory::postConfEvent(const AmArg& args, AmArg& ret,
int id, int mute) {
string room = args.get(0).asCStr();
@ -635,16 +762,15 @@ void WebConferenceFactory::postConfEvent(const AmArg& args, AmArg& ret,
rooms_mut.lock();
ConferenceRoom* r = getRoom(room, adminpin);
if (NULL == r) {
ret.push(1);
ret.push("wrong adminpin");
rooms_mut.unlock();
return;
ret.push(1);
ret.push("wrong adminpin or inexisting room");
rooms_mut.unlock();
return;
}
bool p_exists = r->hasParticipant(call_tag);
if (p_exists && (mute >= 0))
r->setMuted(call_tag, mute);
rooms_mut.unlock();
rooms_mut.unlock();
if (p_exists) {
AmSessionContainer::instance()->postEvent(call_tag,
@ -681,7 +807,7 @@ void WebConferenceFactory::getRoomPassword(const AmArg& args, AmArg& ret) {
if ((!MasterPassword.length()) ||
pwd != MasterPassword) {
ret.push(403);
ret.push("Wrong Master Password.\n");
ret.push("Wrong Master Password.");
return;
}
int res_code = 404;
@ -707,7 +833,7 @@ void WebConferenceFactory::changeRoomAdminpin(const AmArg& args, AmArg& ret) {
ConferenceRoom* r = getRoom(room, adminpin);
if (NULL == r) {
ret.push(1);
ret.push("wrong adminpin");
ret.push("wrong adminpin or inexisting room");
} else {
r->adminpin = new_adminpin;
ret.push(0);
@ -724,13 +850,14 @@ void WebConferenceFactory::listRooms(const AmArg& args, AmArg& ret) {
pwd != MasterPassword) {
ret.push(407);
AmArg res;
res.push("Wrong Master Password.\n");
res.push("Wrong Master Password.");
ret.push(res);
return;
}
AmArg room_list;
room_list.assertArray();
rooms_mut.lock();
for (map<string, ConferenceRoom>::iterator it =
rooms.begin(); it != rooms.end(); it++) {
@ -822,3 +949,14 @@ void WebConferenceFactory::callStats(bool success, unsigned int connect_t) {
}
}
void WebConferenceCleaner::on_stop() {
is_stopped.set(true);
}
void WebConferenceCleaner::run(){
sleep(1);
while (!is_stopped.get()) {
factory->closeExpiredRooms();
sleep(1);
}
}

@ -54,6 +54,7 @@ class ConferenceStatusContainer;
#define DROP_SOUND "drop_sound"
#define ENTER_PIN "enter_pin"
#define WRONG_PIN "wrong_pin"
#define WRONG_PIN_BYE "wrong_pin_bye"
// default path for files
#define WEBCONF_ANNOUNCE_PATH "/usr/local/lib/sems/audio/webconference/"
@ -68,6 +69,8 @@ public:
};
};
class WebConferenceCleaner;
class WebConferenceFactory
: public AmSessionFactory,
public AmDynInvokeFactory,
@ -82,6 +85,8 @@ class WebConferenceFactory
AmSessionEventHandlerFactory* session_timer_f;
WebConferenceCleaner* cleaner;
// for DI
static WebConferenceFactory* _instance;
bool configured;
@ -91,9 +96,13 @@ class WebConferenceFactory
string getRandomPin();
/** @return NULL if adminpin wrong */
ConferenceRoom* getRoom(const string& room,
const string& adminpin);
const string& adminpin,
bool ignore_adminpin);
void postConfEvent(const AmArg& args, AmArg& ret,
int id, int mute);
/** broadcast conf event to all */
void postAllConfEvent(const string& room, const string& adminpin,
AmArg& ret, int id, bool ignore_adminpin);
regex_t direct_room_re;
bool use_direct_room;
@ -126,13 +135,16 @@ public:
static bool ignore_pin;
static bool PrivateRoomsMode;
WebConferenceFactory(const string& _app_name);
AmSession* onInvite(const AmSipRequest&);
AmSession* onInvite(const AmSipRequest& req,
AmArg& session_params);
int onLoad();
void newParticipant(const string& conf_id,
bool isValidConference(const string& conf_id);
bool newParticipant(const string& conf_id,
const string& localtag,
const string& number);
void updateStatus(const string& conf_id,
@ -142,33 +154,58 @@ public:
void callStats(bool success, unsigned int connect_t);
void closeExpiredRooms();
// DI API
WebConferenceFactory* getInstance(){
return _instance;
}
void invoke(const string& method, const AmArg& args, AmArg& ret);
void roomDelete(const string& room, const string& adminpin,
AmArg& ret, bool ignore_adminpin);
// DI functions
void roomCreate(const AmArg& args, AmArg& ret);
void roomInfo(const AmArg& args, AmArg& ret);
void roomDelete(const AmArg& args, AmArg& ret);
void changeRoomAdminpin(const AmArg& args, AmArg& ret);
void dialout(const AmArg& args, AmArg& ret);
void kickout(const AmArg& args, AmArg& ret);
void mute(const AmArg& args, AmArg& ret);
void unmute(const AmArg& args, AmArg& ret);
void changeRoomAdminpin(const AmArg& args, AmArg& ret);
void serverInfo(const AmArg& args, AmArg& ret);
void vqRoomFeedback(const AmArg& args, AmArg& ret);
void vqCallFeedback(const AmArg& args, AmArg& ret);
void vqConferenceFeedback(const AmArg& args, AmArg& ret);
void resetFeedback(const AmArg& args, AmArg& ret);
void flushFeedback(const AmArg& args, AmArg& ret);
void getRoomPassword(const AmArg& args, AmArg& ret);
void listRooms(const AmArg& args, AmArg& ret);
};
class WebConferenceCleaner
: public AmThread
{
WebConferenceFactory* factory;
AmCondition<bool> is_stopped;
public:
WebConferenceCleaner(WebConferenceFactory* factory)
: factory(factory), is_stopped(false) { }
void run();
void on_stop();
};
#endif
// Local Variables:
// mode:C++
// End:

@ -114,16 +114,23 @@ void WebConferenceDialog::onSessionStart(const AmSipRequest& req) {
// direct room access?
if (conf_id.empty()) {
state = EnteringPin;
state = EnteringPin;
prompts.addToPlaylist(ENTER_PIN, (long)this, play_list);
// set the playlist as input and output
setInOut(&play_list,&play_list);
} else {
DBG("########## direct connect conference #########\n");
factory->newParticipant(conf_id,
getLocalTag(),
dlg.remote_party);
factory->updateStatus(conf_id,
DBG("########## direct connect conference #########\n");
if (!factory->newParticipant(conf_id,
getLocalTag(),
dlg.remote_party)) {
DBG("inexisting conference room\n");
state = PlayErrorFinish;
setInOut(&play_list,&play_list);
prompts.addToPlaylist(WRONG_PIN_BYE, (long)this, play_list);
return;
}
factory->updateStatus(conf_id,
getLocalTag(),
ConferenceRoomParticipant::Connected,
"direct access: entered");
@ -266,21 +273,36 @@ void WebConferenceDialog::process(AmEvent* ev)
if (EnteringConference == state) {
state = InConference;
DBG("########## connectConference after pin entry #########\n");
if (!factory->newParticipant(pin_str,
getLocalTag(),
dlg.remote_party)) {
DBG("inexisting conference room\n");
state = PlayErrorFinish;
setInOut(&play_list,&play_list);
prompts.addToPlaylist(WRONG_PIN_BYE, (long)this, play_list);
return;
}
connectConference(pin_str);
factory->newParticipant(pin_str,
getLocalTag(),
dlg.remote_party);
factory->updateStatus(pin_str,
getLocalTag(),
ConferenceRoomParticipant::Connected,
"entered");
}
}
}
// audio events
AmAudioEvent* audio_ev = dynamic_cast<AmAudioEvent*>(ev);
if (audio_ev &&
audio_ev->event_id == AmAudioEvent::noAudio) {
DBG("########## noAudio event #########\n");
if (PlayErrorFinish == state) {
DBG("Finished playing bye message, ending call.\n");
dlg.bye();
setStopped();
return;
}
return;
}
@ -312,10 +334,9 @@ void WebConferenceDialog::onDtmf(int event, int duration)
play_list.close(false);
} else if (event==10 || event==11) {
// pound and star key
// if required add checking of pin here...
if (!pin_str.length()) {
if (!pin_str.length() || !factory->isValidConference(pin_str)) {
prompts.addToPlaylist(WRONG_PIN, (long)this, play_list, true);
pin_str.clear();
} else {
state = EnteringConference;
setInOut(NULL, NULL);

@ -48,7 +48,8 @@ public:
EnteringConference,
InConference,
InConferenceRinging,
InConferenceEarly
InConferenceEarly,
PlayErrorFinish
};
private:

@ -5,6 +5,7 @@ join_sound=/usr/local/lib/sems/audio/webconference/beep.wav
drop_sound=/usr/local/lib/sems/audio/webconference/beep.wav
enter_pin=/usr/local/lib/sems/audio/webconference/pin_prompt.wav
wrong_pin=/usr/local/lib/sems/audio/webconference/wrong_pin.wav
wrong_pin_bye=/usr/local/lib/sems/audio/webconference/wrong_pin_bye.wav
entering_conference=/usr/local/lib/sems/audio/webconference/entering_conference.wav
#
@ -65,6 +66,23 @@ stats_dir=/var/log/sems-webconference/
#
#webconference_urlbase=https://webconference.iptel.org/openRoom.py?action=openRoom
# private_rooms = [yes |no]
#
# In private rooms mode, participants can join rooms only if they have been
# opened before.
#
# Default: no
#
# private_rooms=yes
# support_rooms_timeout = [yes |no]
#
# Support timeout for rooms? If rooms are timed out, they will be closed and
# all participants disconnected.
#
# Default: no
#
# support_rooms_timeout=yes
#
# participants_expire = [yes | no]

Loading…
Cancel
Save