Beispiel #1
0
/*
 * 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);
}
Beispiel #2
0
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);
}
Beispiel #3
0
/* 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;
		}
	}
}
Beispiel #4
0
/* 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);
}