/* * join descructor */ JoinPBX::~JoinPBX() { struct join_relation *relation, *rtemp; relation = j_relation; while(relation) { rtemp = relation->next; FREE(relation, sizeof(struct join_relation)); cmemuse--; relation = rtemp; } /* remove 3PTY from other join */ if (j_3pty) { class Join *join; class JoinPBX *joinpbx; join = find_join_id(j_3pty); if (join && join->j_type == JOIN_TYPE_PBX) { joinpbx = (class JoinPBX *)join; joinpbx->j_3pty = 0; trigger_work(&joinpbx->j_updatebridge); } } del_work(&j_updatebridge); }
void * thread_trigger(void *c_handle) { struct radclock_handle *handle; int err; JDEBUG /* Deal with UNIX signal catching */ init_thread_signal_mgt(); /* Clock handle to be able to read global data */ handle = (struct radclock_handle *) c_handle; /* Initialise the trigger thread. * If this fails, we commit a collective suicide */ err = trigger_init(handle); if (err) handle->pthread_flag_stop = PTH_STOP_ALL; while ((handle->pthread_flag_stop & PTH_TRIGGER_STOP) != PTH_TRIGGER_STOP) { /* * Check if processing thread did grab the lock, we don't want to lock * repeatidly for ever. If we marked data ready to be processed, then * the processing thread has to do his job. We signal again in case the * processing thread hadn't be listening before (at startup for * example), then we sleep a little and probably get rescheduled. */ if (handle->wakeup_data_ready == 1 && !VM_SLAVE(handle)) { pthread_cond_signal(&handle->wakeup_cond); usleep(50); continue; } /* Lock the pthread_mutex we share with the processing thread */ pthread_mutex_lock(&handle->wakeup_mutex); /* Do our job */ trigger_work(handle); /* Raise wakeup_dat_ready flag. * Signal the processing thread, and unlock mutex to give the processing * thread a chance at it. To be sure it grabs the lock we sleep for a * little while ... */ handle->wakeup_data_ready = 1; pthread_cond_signal(&handle->wakeup_cond); pthread_mutex_unlock(&handle->wakeup_mutex); } /* Thread exit * In case we pass into the continue statement but then ordered to die, make * sure we release the lock (and maybe silently fail) */ verbose(LOG_NOTICE, "Thread trigger is terminating."); pthread_exit(NULL); }
/* epoint sends a message to a join * */ void JoinPBX::message_epoint(unsigned int epoint_id, int message_type, union parameter *param) { class Join *cl; struct join_relation *relation, *reltemp; int num; int new_state; struct lcr_msg *message; // int size, writesize, oldpointer; char *number, *numbers; if (!epoint_id) { PERROR("software error, epoint == NULL\n"); return; } // if (options.deb & DEBUG_JOIN) { // PDEBUG(DEBUG_JOIN, "message %d received from ep%d.\n", message, epoint->ep_serial); // joinpbx_debug(join,"Join::message_epoint"); // } if (options.deb & DEBUG_JOIN) { if (message_type) { cl = join_first; while(cl) { if (cl->j_type == JOIN_TYPE_PBX) joinpbx_debug((class JoinPBX *)cl, "Join::message_epoint{all joins before processing}"); cl = cl->next; } } } /* check relation */ relation = j_relation; while(relation) { if (relation->epoint_id == epoint_id) break; relation = relation->next; } if (!relation) { PDEBUG(DEBUG_JOIN, "no relation back to the endpoint found, ignoring (join=%d, endpoint=%d)\n", j_serial, epoint_id); return; } /* count relations */ num=joinpbx_countrelations(j_serial); /* process party line */ if (message_type == MESSAGE_SETUP) if (param->setup.partyline && !j_partyline) { j_partyline = param->setup.partyline; j_partyline_jingle = param->setup.partyline_jingle; } if (j_partyline) { switch(message_type) { case MESSAGE_SETUP: PDEBUG(DEBUG_JOIN, "respsone with connect in partyline mode.\n"); relation->type = RELATION_TYPE_CONNECT; message = message_create(j_serial, epoint_id, JOIN_TO_EPOINT, MESSAGE_CONNECT); SPRINT(message->param.connectinfo.id, "%d", j_partyline); message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN; message_put(message); trigger_work(&j_updatebridge); if (j_partyline_jingle) play_jingle(1); break; case MESSAGE_AUDIOPATH: PDEBUG(DEBUG_JOIN, "join received channel message: %d.\n", param->audiopath); if (relation->channel_state != param->audiopath) { relation->channel_state = param->audiopath; trigger_work(&j_updatebridge); if (options.deb & DEBUG_JOIN) joinpbx_debug(this, "Join::message_epoint{after setting new channel state}"); } break; /* track notify */ case MESSAGE_NOTIFY: switch(param->notifyinfo.notify) { case INFO_NOTIFY_USER_SUSPENDED: case INFO_NOTIFY_USER_RESUMED: case INFO_NOTIFY_REMOTE_HOLD: case INFO_NOTIFY_REMOTE_RETRIEVAL: case INFO_NOTIFY_CONFERENCE_ESTABLISHED: case INFO_NOTIFY_CONFERENCE_DISCONNECTED: new_state = track_notify(relation->rx_state, param->notifyinfo.notify); if (new_state != relation->rx_state) { relation->rx_state = new_state; trigger_work(&j_updatebridge); if (options.deb & DEBUG_JOIN) joinpbx_debug(this, "Join::message_epoint{after setting new rx state}"); } break; } break; case MESSAGE_DISCONNECT: PDEBUG(DEBUG_JOIN, "releasing after receiving disconnect, because join in partyline mode.\n"); message = message_create(j_serial, epoint_id, JOIN_TO_EPOINT, MESSAGE_RELEASE); message->param.disconnectinfo.cause = CAUSE_NORMAL; message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL; message_put(message); // fall through case MESSAGE_RELEASE: PDEBUG(DEBUG_JOIN, "releasing from join\n"); release(relation, 0, 0); if (j_partyline_jingle) play_jingle(0); break; default: PDEBUG(DEBUG_JOIN, "ignoring message, because join in partyline mode.\n"); } return; } /* process messages */ switch(message_type) { /* process audio path message */ case MESSAGE_AUDIOPATH: PDEBUG(DEBUG_JOIN, "join received channel message: audiopath=%d, current relation's channel_state=%d\n", param->audiopath, relation->channel_state); if (relation->channel_state != param->audiopath) { relation->channel_state = param->audiopath; trigger_work(&j_updatebridge); if (options.deb & DEBUG_JOIN) joinpbx_debug(this, "Join::message_epoint{after setting new channel state}"); } return; /* track notify */ case MESSAGE_NOTIFY: switch(param->notifyinfo.notify) { case INFO_NOTIFY_USER_SUSPENDED: case INFO_NOTIFY_USER_RESUMED: case INFO_NOTIFY_REMOTE_HOLD: case INFO_NOTIFY_REMOTE_RETRIEVAL: case INFO_NOTIFY_CONFERENCE_ESTABLISHED: case INFO_NOTIFY_CONFERENCE_DISCONNECTED: new_state = track_notify(relation->rx_state, param->notifyinfo.notify); if (new_state != relation->rx_state) { relation->rx_state = new_state; trigger_work(&j_updatebridge); if (options.deb & DEBUG_JOIN) joinpbx_debug(this, "Join::message_epoint{after setting new rx state}"); } break; default: /* send notification to all other endpoints */ reltemp = j_relation; while(reltemp) { if (reltemp->epoint_id!=epoint_id && reltemp->epoint_id) { message = message_create(j_serial, reltemp->epoint_id, JOIN_TO_EPOINT, MESSAGE_NOTIFY); memcpy(&message->param, param, sizeof(union parameter)); message_put(message); } reltemp = reltemp->next; } } return; /* relations sends a connect */ case MESSAGE_CONNECT: /* outgoing setup type becomes connected */ if (relation->type == RELATION_TYPE_SETUP) relation->type = RELATION_TYPE_CONNECT; /* release other relations in setup state */ release_again: reltemp = j_relation; while(reltemp) { //printf("connect, checking relation %d\n", reltemp->epoint_id); if (reltemp->type == RELATION_TYPE_SETUP) { //printf("relation %d is of type setup, releasing\n", reltemp->epoint_id); /* send release to endpoint */ message = message_create(j_serial, reltemp->epoint_id, JOIN_TO_EPOINT, MESSAGE_RELEASE); message->param.disconnectinfo.cause = CAUSE_NONSELECTED; message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL; message_put(message); if (release(reltemp, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL)) // dummy cause, should not be used, since calling and connected endpoint still exist afterwards. return; // must return, because join IS destroyed goto release_again; } if (reltemp->type == RELATION_TYPE_CALLING) reltemp->type = RELATION_TYPE_CONNECT; reltemp = reltemp->next; } break; // continue with our message /* release is sent by endpoint */ case MESSAGE_RELEASE: switch(relation->type) { case RELATION_TYPE_SETUP: /* by called */ /* collect cause and send collected cause */ collect_cause(&j_multicause, &j_multilocation, param->disconnectinfo.cause, param->disconnectinfo.location); if (j_multicause) release(relation, j_multilocation, j_multicause); else release(relation, LOCATION_PRIVATE_LOCAL, CAUSE_UNSPECIFIED); break; case RELATION_TYPE_CALLING: /* by calling */ /* remove us, if we don't have a called releation yet */ if (!j_relation->next) { release(j_relation, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); return; // must return, because join IS destroyed } /* in a conf, we don't kill the other members */ if (num > 2 && !joinpbx_onecalling_othersetup(j_relation)) { release(relation, 0, 0); return; } /* remove all relations that are of called type */ release_again2: reltemp = j_relation; while(reltemp) { if (reltemp->type == RELATION_TYPE_SETUP) { /* send release to endpoint */ message = message_create(j_serial, reltemp->epoint_id, JOIN_TO_EPOINT, message_type); memcpy(&message->param, param, sizeof(union parameter)); message_put(message); if (release(reltemp, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL)) return; // must return, because join IS destroyed goto release_again2; } reltemp = reltemp->next; } PERROR("we are still here, this should not happen\n"); break; default: /* by connected */ /* send current cause */ release(relation, param->disconnectinfo.location, param->disconnectinfo.cause); } return; // must return, because join may be destroyed } /* check number of relations */ if (num > 2 && !joinpbx_onecalling_othersetup(j_relation) && message_type != MESSAGE_CONNECT) { PDEBUG(DEBUG_JOIN, "we are in a conference, so we ignore the messages, except MESSAGE_CONNECT.\n"); return; } /* if join has no other relation, we process the setup message */ if (num == 1) { switch(message_type) { case MESSAGE_SETUP: if (param->setup.dialinginfo.itype == INFO_ITYPE_ISDN_EXTENSION) { /* in case of keypad */ numbers = param->setup.dialinginfo.keypad; if (numbers[0]) { while((number = strsep(&numbers, ","))) { if (out_setup(epoint_id, message_type, param, NULL, number)) return; // join destroyed } /* after keypad finish dialing */ break; } /* dialed number */ numbers = param->setup.dialinginfo.id; while((number = strsep(&numbers, ","))) { if (out_setup(epoint_id, message_type, param, number, NULL)) return; // join destroyed } break; } if (out_setup(epoint_id, message_type, param, param->setup.dialinginfo.id, param->setup.dialinginfo.keypad)) return; // join destroyed break; default: PDEBUG(DEBUG_JOIN, "no need to send a message because there is no other endpoint than the calling one.\n"); } } else { /* sending message to other relation(s) */ relation = j_relation; while(relation) { if (relation->epoint_id != epoint_id) { PDEBUG(DEBUG_JOIN, "sending message ep%ld -> ep%ld.\n", epoint_id, relation->epoint_id); message = message_create(j_serial, relation->epoint_id, JOIN_TO_EPOINT, message_type); memcpy(&message->param, param, sizeof(union parameter)); message_put(message); PDEBUG(DEBUG_JOIN, "message sent.\n"); } relation = relation->next; } } }
/* release join from endpoint * if the join has two relations, all relations are freed and the join will be * destroyed * on outgoing relations, the cause is collected, if not connected * returns if join has been destroyed */ int JoinPBX::release(struct join_relation *relation, int location, int cause) { struct join_relation *reltemp, **relationpointer; struct lcr_msg *message; class Join *join; int destroy = 0; /* remove from bridge */ if (relation->channel_state != 0) { relation->channel_state = 0; trigger_work(&j_updatebridge); // note: if join is not released, bridge must be updated } /* detach given interface */ reltemp = j_relation; relationpointer = &j_relation; while(reltemp) { /* endpoint of function call */ if (relation == reltemp) break; relationpointer = &reltemp->next; reltemp = reltemp->next; } if (!reltemp) FATAL("relation not in list of our relations. this must not happen.\n"); //printf("releasing relation %d\n", reltemp->epoint_id); *relationpointer = reltemp->next; FREE(reltemp, sizeof(struct join_relation)); cmemuse--; relation = reltemp = NULL; // just in case of reuse fault; /* if no more relation */ if (!j_relation) { PDEBUG(DEBUG_JOIN, "join is completely removed.\n"); /* there is no more endpoint related to the join */ destroy = 1; delete this; // end of join object! PDEBUG(DEBUG_JOIN, "join completely removed!\n"); } else /* if join is a party line */ if (j_partyline) { PDEBUG(DEBUG_JOIN, "join is a conference room, so we keep it alive until the last party left.\n"); } else /* if only one relation left */ if (!j_relation->next) { PDEBUG(DEBUG_JOIN, "join has one relation left, so we send it a release with the given cause %d.\n", cause); message = message_create(j_serial, j_relation->epoint_id, JOIN_TO_EPOINT, MESSAGE_RELEASE); message->param.disconnectinfo.cause = cause; message->param.disconnectinfo.location = location; message_put(message); destroy = 1; delete this; // end of join object! PDEBUG(DEBUG_JOIN, "join completely removed!\n"); } join = join_first; while(join) { if (options.deb & DEBUG_JOIN && join->j_type==JOIN_TYPE_PBX) joinpbx_debug((class JoinPBX *)join, "join_release{all joins left}"); join = join->next; } PDEBUG(DEBUG_JOIN, "join_release(): ended.\n"); return(destroy); }