Esempio n. 1
0
PJ_DEF(pj_ioqueue_t*) pj_ioqueue_create(pj_pool_t *pool, pj_size_t max_fd)
{
    pj_ioqueue_t *ioque;

    if (max_fd > PJ_IOQUEUE_MAX_HANDLES) {
	PJ_LOG(1,("ioqueue", "max_fd too large! Can't create ioqueue."));
	return NULL;
    }

    ioque = pj_pool_alloc(pool, sizeof(pj_ioqueue_t));
    ioque->max = max_fd;
    ioque->count = 0;
    PJ_FD_ZERO(&ioque->rfdset);
    PJ_FD_ZERO(&ioque->wfdset);
#if PJ_HAS_TCP
    PJ_FD_ZERO(&ioque->xfdset);
#endif
    pj_list_init(&ioque->hlist);

    ioque->mutex = pj_mutex_create(pool, "ioq%p", PJ_MUTEX_SIMPLE);
    if (!ioque->mutex) {
	PJ_LOG(1,("ioqueue", "Mutex creation failed!"));
	return NULL;
    }

    PJ_LOG(4, ("pjlib", "select() I/O Queue created (%p)", ioque));
    return ioque;
}
Esempio n. 2
0
/*
 * Module initialization.
 * This will be called by endpoint when it initializes all modules.
 */
static pj_status_t mod_init( pjsip_endpoint *endpt,
			     struct pjsip_module *mod, pj_uint32_t id )
{
    pj_pool_t *pool;

    pool = pjsip_endpt_create_pool(endpt, "esubmgr", MGR_POOL_SIZE, MGR_POOL_INC);
    if (!pool)
	return -1;

    /* Manager initialization: create hash table and mutex. */
    mgr.pool = pool;
    mgr.endpt = endpt;
    mgr.ht = pj_hash_create(pool, HASH_TABLE_SIZE);
    if (!mgr.ht)
	return -1;

    mgr.mutex = pj_mutex_create(pool, "esubmgr", PJ_MUTEX_SIMPLE);
    if (!mgr.mutex)
	return -1;

    /* Attach manager to module. */
    mod->mod_data = &mgr;

    /* Init package list. */
    pj_list_init(&mgr.pkg_list);

    /* Init Allow-Events header. */
    mgr.allow_events = pjsip_allow_events_hdr_create(mgr.pool);

    /* Save the module ID. */
    mod_id = id;

    pjsip_event_notify_init_parser();
    return 0;
}
Esempio n. 3
0
/* Test witn non-recursive mutex. */
static int simple_mutex_test(pj_pool_t *pool)
{
    pj_status_t rc;
    pj_mutex_t *mutex;

    PJ_LOG(3,("", "...testing simple mutex"));
    
    /* Create mutex. */
    TRACE_(("", "....create mutex"));
    rc = pj_mutex_create( pool, "", PJ_MUTEX_SIMPLE, &mutex);
    if (rc != PJ_SUCCESS) {
	app_perror("...error: pj_mutex_create", rc);
	return -10;
    }

    /* Normal lock/unlock cycle. */
    TRACE_(("", "....lock mutex"));
    rc = pj_mutex_lock(mutex);
    if (rc != PJ_SUCCESS) {
	app_perror("...error: pj_mutex_lock", rc);
	return -20;
    }
    TRACE_(("", "....unlock mutex"));
    rc = pj_mutex_unlock(mutex);
    if (rc != PJ_SUCCESS) {
	app_perror("...error: pj_mutex_unlock", rc);
	return -30;
    }
    
    /* Lock again. */
    TRACE_(("", "....lock mutex"));
    rc = pj_mutex_lock(mutex);
    if (rc != PJ_SUCCESS) return -40;

    /* Try-lock should fail. It should not deadlocked. */
    TRACE_(("", "....trylock mutex"));
    rc = pj_mutex_trylock(mutex);
    if (rc == PJ_SUCCESS)
	PJ_LOG(3,("", "...info: looks like simple mutex is recursive"));

    /* Unlock and done. */
    TRACE_(("", "....unlock mutex"));
    rc = pj_mutex_unlock(mutex);
    if (rc != PJ_SUCCESS) return -50;

    TRACE_(("", "....destroy mutex"));
    rc = pj_mutex_destroy(mutex);
    if (rc != PJ_SUCCESS) return -60;

    TRACE_(("", "....done"));
    return PJ_SUCCESS;
}
Esempio n. 4
0
PJ_DEF(pj_atomic_t*) pj_atomic_create( pj_pool_t *pool, long value)
{
    pj_atomic_t *t = pj_pool_calloc(pool, 1, sizeof(pj_atomic_t));
    if (!t)
	return NULL;
#if PJ_HAS_THREADS
    t->mutex = pj_mutex_create(pool, "atm%p", PJ_MUTEX_SIMPLE);
    if (t->mutex == NULL)
	return NULL;
#endif
    t->value = value;
    return t;
}
Esempio n. 5
0
/*
 * pj_atomic_create()
 */
PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool, 
				      pj_atomic_value_t initial,
				      pj_atomic_t **ptr_atomic)
{
    pj_status_t rc;
    pj_atomic_t *atomic_var;

    atomic_var = PJ_POOL_ZALLOC_T(pool, pj_atomic_t);

    PJ_ASSERT_RETURN(atomic_var, PJ_ENOMEM);
    
#if PJ_HAS_THREADS
    rc = pj_mutex_create(pool, "atm%p", PJ_MUTEX_SIMPLE, &atomic_var->mutex);
    if (rc != PJ_SUCCESS)
	return rc;
#endif
    atomic_var->value = initial;

    *ptr_atomic = atomic_var;
    return PJ_SUCCESS;
}
Esempio n. 6
0
static pj_status_t create_mutex_lock( pj_pool_t *pool,
				      const char *name,
				      int type,
				      pj_lock_t **lock )
{
    pj_lock_t *p_lock;
    pj_mutex_t *mutex;
    pj_status_t rc;

    PJ_ASSERT_RETURN(pool && lock, PJ_EINVAL);

    p_lock = PJ_POOL_ALLOC_T(pool, pj_lock_t);
    if (!p_lock)
	return PJ_ENOMEM;

    pj_memcpy(p_lock, &mutex_lock_template, sizeof(pj_lock_t));
    rc = pj_mutex_create(pool, name, type, &mutex);
    if (rc != PJ_SUCCESS)
	return rc;

    p_lock->lock_object = mutex;
    *lock = p_lock;
    return PJ_SUCCESS;
}
Esempio n. 7
0
/* Test with recursive mutex. */
static int recursive_mutex_test(pj_pool_t *pool)
{
    pj_status_t rc;
    pj_mutex_t *mutex;

    PJ_LOG(3,("", "...testing recursive mutex"));

    /* Create mutex. */
    TRACE_(("", "....create mutex"));
    rc = pj_mutex_create( pool, "", PJ_MUTEX_RECURSE, &mutex);
    if (rc != PJ_SUCCESS) {
	app_perror("...error: pj_mutex_create", rc);
	return -10;
    }

    /* Normal lock/unlock cycle. */
    TRACE_(("", "....lock mutex"));
    rc = pj_mutex_lock(mutex);
    if (rc != PJ_SUCCESS) {
	app_perror("...error: pj_mutex_lock", rc);
	return -20;
    }
    TRACE_(("", "....unlock mutex"));
    rc = pj_mutex_unlock(mutex);
    if (rc != PJ_SUCCESS) {
	app_perror("...error: pj_mutex_unlock", rc);
	return -30;
    }
    
    /* Lock again. */
    TRACE_(("", "....lock mutex"));
    rc = pj_mutex_lock(mutex);
    if (rc != PJ_SUCCESS) return -40;

    /* Try-lock should NOT fail. . */
    TRACE_(("", "....trylock mutex"));
    rc = pj_mutex_trylock(mutex);
    if (rc != PJ_SUCCESS) {
	app_perror("...error: recursive mutex is not recursive!", rc);
	return -40;
    }

    /* Locking again should not fail. */
    TRACE_(("", "....lock mutex"));
    rc = pj_mutex_lock(mutex);
    if (rc != PJ_SUCCESS) {
	app_perror("...error: recursive mutex is not recursive!", rc);
	return -45;
    }

    /* Unlock several times and done. */
    TRACE_(("", "....unlock mutex 3x"));
    rc = pj_mutex_unlock(mutex);
    if (rc != PJ_SUCCESS) return -50;
    rc = pj_mutex_unlock(mutex);
    if (rc != PJ_SUCCESS) return -51;
    rc = pj_mutex_unlock(mutex);
    if (rc != PJ_SUCCESS) return -52;

    TRACE_(("", "....destroy mutex"));
    rc = pj_mutex_destroy(mutex);
    if (rc != PJ_SUCCESS) return -60;

    TRACE_(("", "....done"));
    return PJ_SUCCESS;
}
Esempio n. 8
0
PJ_DEF(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool,
					       const char *name,
					       pj_mutex_t **mutex )
{
    return pj_mutex_create( pool, name, PJ_MUTEX_RECURSE, mutex);
}
Esempio n. 9
0
PJ_DEF(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool, const char *name,
					    pj_mutex_t **mutex )
{
    return pj_mutex_create(pool, name, PJ_MUTEX_SIMPLE, mutex);
}
Esempio n. 10
0
    //
    // Create mutex.
    //
    pj_status_t create( Pj_Pool *pool, Type type, const char *name = NULL)
    {
        destroy();
	return pj_mutex_create( pool->pool_(), name, type,
                                &mutex_ );
    }
Esempio n. 11
0
/*
 * Create UAC subscription.
 */
PJ_DEF(pjsip_event_sub*) pjsip_event_sub_create( pjsip_endpoint *endpt,
						 const pj_str_t *from,
						 const pj_str_t *to,
						 const pj_str_t *event,
						 int expires,
						 int accept_cnt,
						 const pj_str_t accept[],
						 void *user_data,
						 const pjsip_event_sub_cb *cb)
{
    pjsip_tx_data *tdata;
    pj_pool_t *pool;
    const pjsip_hdr *hdr;
    pjsip_event_sub *sub;
    PJ_USE_EXCEPTION;

    PJ_LOG(5,(THIS_FILE, "Creating event subscription %.*s to %.*s",
			 event->slen, event->ptr, to->slen, to->ptr));

    /* Create pool for the event subscription. */
    pool = pjsip_endpt_create_pool(endpt, "esub", SUB_POOL_SIZE, SUB_POOL_INC);
    if (!pool) {
	return NULL;
    }

    /* Init subscription. */
    sub = pj_pool_calloc(pool, 1, sizeof(*sub));
    sub->pool = pool;
    sub->endpt = endpt;
    sub->role = PJSIP_ROLE_UAC;
    sub->state = PJSIP_EVENT_SUB_STATE_PENDING;
    sub->state_str = state[sub->state];
    sub->user_data = user_data;
    sub->timer.id = 0;
    sub->default_interval = expires;
    pj_memcpy(&sub->cb, cb, sizeof(*cb));
    pj_list_init(&sub->auth_sess);
    pj_list_init(&sub->route_set);
    sub->mutex = pj_mutex_create(pool, "esub", PJ_MUTEX_RECURSE);
    if (!sub->mutex) {
	pjsip_endpt_destroy_pool(endpt, pool);
	return NULL;
    }

    /* The easiest way to parse the parameters is to create a dummy request! */
    tdata = pjsip_endpt_create_request( endpt, &SUBSCRIBE, to, from, to, from,
					NULL, -1, NULL);
    if (!tdata) {
	pj_mutex_destroy(sub->mutex);
	pjsip_endpt_destroy_pool(endpt, pool);
	return NULL;
    }

    /* 
     * Duplicate headers in the request to our structure. 
     */
    PJ_TRY {
	int i;

	/* From */
	hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_FROM, NULL);
	pj_assert(hdr != NULL);
	sub->from = pjsip_hdr_clone(pool, hdr);
        
	/* To */
	hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_TO, NULL);
	pj_assert(hdr != NULL);
	sub->to = pjsip_hdr_clone(pool, hdr);

	/* Contact. */
	sub->contact = pjsip_contact_hdr_create(pool);
	sub->contact->uri = sub->from->uri;

	/* Call-ID */
	hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CALL_ID, NULL);
	pj_assert(hdr != NULL);
	sub->call_id = pjsip_hdr_clone(pool, hdr);

	/* CSeq */
	sub->cseq = pj_rand() % 0xFFFF;

	/* Event. */
	sub->event = pjsip_event_hdr_create(sub->pool);
	pj_strdup(pool, &sub->event->event_type, event);

	/* Expires. */
	sub->uac_expires = pjsip_expires_hdr_create(pool);
	sub->uac_expires->ivalue = expires;

	/* Accept. */
	sub->local_accept = pjsip_accept_hdr_create(pool);
	for (i=0; i<accept_cnt && i < PJSIP_MAX_ACCEPT_COUNT; ++i) {
	    sub->local_accept->count++;
	    pj_strdup(sub->pool, &sub->local_accept->values[i], &accept[i]);
	}

	/* Register to hash table. */
	create_subscriber_key( &sub->key, pool, PJSIP_ROLE_UAC, 
			       &sub->call_id->id, &sub->from->tag);
	pj_mutex_lock( mgr.mutex );
	pj_hash_set( pool, mgr.ht, sub->key.ptr, sub->key.slen, sub);
	pj_mutex_unlock( mgr.mutex );

    }
    PJ_DEFAULT {
	PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): caught exception %d during init", 
			     sub, state[sub->state].ptr, PJ_GET_EXCEPTION()));

	pjsip_tx_data_dec_ref(tdata);
	pj_mutex_destroy(sub->mutex);
	pjsip_endpt_destroy_pool(endpt, sub->pool);
	return NULL;
    }
    PJ_END;

    /* All set, delete temporary transmit data as we don't need it. */
    pjsip_tx_data_dec_ref(tdata);

    PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): client created, target=%.*s, event=%.*s",
			 sub, state[sub->state].ptr,
			 to->slen, to->ptr, event->slen, event->ptr));

    return sub;
}
Esempio n. 12
0
/* This function is called when we receive SUBSCRIBE request message for 
 * a new subscription.
 */
static void on_new_subscription( pjsip_transaction *tsx, pjsip_rx_data *rdata )
{
    package *pkg;
    pj_pool_t *pool;
    pjsip_event_sub *sub = NULL;
    pj_str_t hname;
    int status = 200;
    pj_str_t reason = { NULL, 0 };
    pjsip_tx_data *tdata;
    pjsip_expires_hdr *expires;
    pjsip_accept_hdr *accept;
    pjsip_event_hdr *evhdr;

    /* Get the Event header. */
    hname = pj_str("Event");
    evhdr = pjsip_msg_find_hdr_by_name(rdata->msg, &hname, NULL);
    if (!evhdr) {
	status = 400;
	reason = pj_str("No Event header in request");
	goto send_response;
    }

    /* Find corresponding package. 
     * We don't lock the manager's mutex since we assume the package list
     * won't change once the application is running!
     */
    pkg = mgr.pkg_list.next;
    while (pkg != &mgr.pkg_list) {
	if (pj_stricmp(&pkg->event, &evhdr->event_type) == 0)
	    break;
	pkg = pkg->next;
    }

    if (pkg == &mgr.pkg_list) {
	/* Event type is not supported by any packages! */
	status = 489;
	reason = pj_str("Bad Event");
	goto send_response;
    }

    /* First check that the Accept specification matches the 
     * package's Accept types.
     */
    accept = pjsip_msg_find_hdr(rdata->msg, PJSIP_H_ACCEPT, NULL);
    if (accept) {
	unsigned i;
	pj_str_t *content_type = NULL;

	for (i=0; i<accept->count && !content_type; ++i) {
	    int j;
	    for (j=0; j<pkg->accept_cnt; ++j) {
		if (pj_stricmp(&accept->values[i], &pkg->accept[j])==0) {
		    content_type = &pkg->accept[j];
		    break;
		}
	    }
	}

	if (!content_type) {
	    status = PJSIP_SC_NOT_ACCEPTABLE_HERE;
	    goto send_response;
	}
    }

    /* Check whether the package wants to accept the subscription. */
    pj_assert(pkg->cb.on_query_subscribe != NULL);
    (*pkg->cb.on_query_subscribe)(rdata, &status);
    if (!PJSIP_IS_STATUS_IN_CLASS(status,200))
	goto send_response;

    /* Create new subscription record. */
    pool = pjsip_endpt_create_pool(tsx->endpt, "esub", 
				   SUB_POOL_SIZE, SUB_POOL_INC);
    if (!pool) {
	status = 500;
	goto send_response;
    }
    sub = pj_pool_calloc(pool, 1, sizeof(*sub));
    sub->pool = pool;
    sub->mutex = pj_mutex_create(pool, "esub", PJ_MUTEX_RECURSE);
    if (!sub->mutex) {
	status = 500;
	goto send_response;
    }

    PJ_LOG(4,(THIS_FILE, "event_sub%p: notifier is created.", sub));

    /* Start locking mutex. */
    pj_mutex_lock(sub->mutex);

    /* Init UAS subscription */
    sub->endpt = tsx->endpt;
    sub->role = PJSIP_ROLE_UAS;
    sub->state = PJSIP_EVENT_SUB_STATE_PENDING;
    sub->state_str = state[sub->state];
    pj_list_init(&sub->auth_sess);
    pj_list_init(&sub->route_set);
    sub->from = pjsip_hdr_clone(pool, rdata->to);
    pjsip_fromto_set_from(sub->from);
    if (sub->from->tag.slen == 0) {
	pj_create_unique_string(pool, &sub->from->tag);
	rdata->to->tag = sub->from->tag;
    }
    sub->to = pjsip_hdr_clone(pool, rdata->from);
    pjsip_fromto_set_to(sub->to);
    sub->contact = pjsip_contact_hdr_create(pool);
    sub->contact->uri = sub->from->uri;
    sub->call_id = pjsip_cid_hdr_create(pool);
    pj_strdup(pool, &sub->call_id->id, &rdata->call_id);
    sub->cseq = pj_rand() % 0xFFFF;
    
    expires = pjsip_msg_find_hdr( rdata->msg, PJSIP_H_EXPIRES, NULL);
    if (expires) {
	sub->default_interval = expires->ivalue;
	if (sub->default_interval > 0 && 
	    sub->default_interval < SECONDS_BEFORE_EXPIRY) 
	{
	    status = 423; /* Interval too short. */
	    goto send_response;
	}
    } else {
	sub->default_interval = 600;
    }

    /* Clone Event header. */
    sub->event = pjsip_hdr_clone(pool, evhdr);

    /* Register to hash table. */
    create_subscriber_key(&sub->key, pool, PJSIP_ROLE_UAS, &sub->call_id->id,
			  &sub->from->tag);
    pj_mutex_lock(mgr.mutex);
    pj_hash_set(pool, mgr.ht, sub->key.ptr, sub->key.slen, sub);
    pj_mutex_unlock(mgr.mutex);

    /* Set timer where subscription will expire only when expires<>0. 
     * Subscriber may send new subscription with expires==0.
     */
    if (sub->default_interval != 0) {
	sub_schedule_uas_expire( sub, sub->default_interval-SECONDS_BEFORE_EXPIRY);
    }

    /* Notify application. */
    if (pkg->cb.on_subscribe) {
	pjsip_event_sub_cb *cb = NULL;
	sub->pending_tsx++;
	(*pkg->cb.on_subscribe)(sub, rdata, &cb, &sub->default_interval);
	sub->pending_tsx--;
	if (cb == NULL)
	    pj_memset(&sub->cb, 0, sizeof(*cb));
	else
	    pj_memcpy(&sub->cb, cb, sizeof(*cb));
    }


send_response:
    PJ_LOG(4,(THIS_FILE, "event_sub%p (%s)(UAS): status=%d", 
			  sub, state[sub->state].ptr, status));

    tdata = pjsip_endpt_create_response( tsx->endpt, rdata, status);
    if (tdata) {
	if (reason.slen) {
	    /* Customize reason text. */
	    tdata->msg->line.status.reason = reason;
	}
	if (PJSIP_IS_STATUS_IN_CLASS(status,200)) {
	    /* Add Expires header. */
	    pjsip_expires_hdr *hdr;

	    hdr = pjsip_expires_hdr_create(tdata->pool);
	    hdr->ivalue = sub->default_interval;
	    pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)hdr );
	}
	if (status == 423) {
	    /* Add Min-Expires header. */
	    pjsip_min_expires_hdr *hdr;

	    hdr = pjsip_min_expires_hdr_create(tdata->pool);
	    hdr->ivalue = SECONDS_BEFORE_EXPIRY;
	    pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)hdr);
	}
	if (status == 489 || 
	    status==PJSIP_SC_NOT_ACCEPTABLE_HERE ||
	    PJSIP_IS_STATUS_IN_CLASS(status,200)) 
	{
	    /* Add Allow-Events header. */
	    pjsip_hdr *hdr;
	    hdr = pjsip_hdr_shallow_clone(tdata->pool, mgr.allow_events);
	    pjsip_msg_add_hdr(tdata->msg, hdr);

	    /* Should add Accept header?. */
	}

	pjsip_tsx_on_tx_msg(tsx, tdata);
    }

    /* If received new subscription with expires=0, terminate. */
    if (sub && sub->default_interval == 0) {
	pj_assert(sub->state == PJSIP_EVENT_SUB_STATE_TERMINATED);
	if (sub->cb.on_sub_terminated) {
	    pj_str_t reason = { "timeout", 7 };
	    (*sub->cb.on_sub_terminated)(sub, &reason);
	}
    }

    if (!PJSIP_IS_STATUS_IN_CLASS(status,200) || (sub && sub->delete_flag)) {
	if (sub && sub->mutex) {
	    pjsip_event_sub_destroy(sub);
	} else if (sub) {
	    pjsip_endpt_destroy_pool(tsx->endpt, sub->pool);
	}
    } else {
	pj_assert(status >= 200);
	pj_mutex_unlock(sub->mutex);
    }
}