static void stateless_send_transport_cb( void *token,
					 pjsip_tx_data *tdata,
					 pj_ssize_t sent )
{
    pjsip_send_state *stateless_data = (pjsip_send_state*) token;
    pj_status_t need_update_via = PJ_TRUE;

    PJ_UNUSED_ARG(tdata);
    pj_assert(tdata == stateless_data->tdata);

    for (;;) {
	pj_status_t status;
	pj_bool_t cont;

	pj_sockaddr_t *cur_addr;
	pjsip_transport_type_e cur_addr_type;
	int cur_addr_len;

	pjsip_via_hdr *via;

	if (sent == -PJ_EPENDING) {
	    /* This is the initial process.
	     * When the process started, this function will be called by
	     * stateless_send_resolver_callback() with sent argument set to
	     * -PJ_EPENDING.
	     */
	    cont = PJ_TRUE;
	} else {
	    /* There are two conditions here:
	     * (1) Message is sent (i.e. sent > 0),
	     * (2) Failure (i.e. sent <= 0)
	     */
	    cont = (sent > 0) ? PJ_FALSE :
		   (tdata->dest_info.cur_addr<tdata->dest_info.addr.count-1);
	    if (stateless_data->app_cb) {
		(*stateless_data->app_cb)(stateless_data, sent, &cont);
	    } else {
		/* Doesn't have application callback.
		 * Terminate the process.
		 */
		cont = PJ_FALSE;
	    }
	}

	/* Finished with this transport. */
	if (stateless_data->cur_transport) {
	    pjsip_transport_dec_ref(stateless_data->cur_transport);
	    stateless_data->cur_transport = NULL;
	}

	/* Done if application doesn't want to continue. */
	if (sent > 0 || !cont) {
	    pjsip_tx_data_dec_ref(tdata);
	    return;
	}

	/* Try next address, if any, and only when this is not the 
	 * first invocation. 
	 */
	if (sent != -PJ_EPENDING) {
	    tdata->dest_info.cur_addr++;
	}

	/* Have next address? */
	if (tdata->dest_info.cur_addr >= tdata->dest_info.addr.count) {
	    /* This only happens when a rather buggy application has
	     * sent 'cont' to PJ_TRUE when the initial value was PJ_FALSE.
	     * In this case just stop the processing; we don't need to
	     * call the callback again as application has been informed
	     * before.
	     */
	    pjsip_tx_data_dec_ref(tdata);
	    return;
	}

	/* Keep current server address information handy. */
	cur_addr = &tdata->dest_info.addr.entry[tdata->dest_info.cur_addr].addr;
	cur_addr_type = tdata->dest_info.addr.entry[tdata->dest_info.cur_addr].type;
	cur_addr_len = tdata->dest_info.addr.entry[tdata->dest_info.cur_addr].addr_len;

	/* Acquire transport. */
	status = pjsip_endpt_acquire_transport2(stateless_data->endpt,
						cur_addr_type,
						cur_addr,
						cur_addr_len,
						&tdata->tp_sel,
						tdata,
						&stateless_data->cur_transport);
	if (status != PJ_SUCCESS) {
	    sent = -status;
	    continue;
	}

	/* Modify Via header. */
	via = (pjsip_via_hdr*) pjsip_msg_find_hdr( tdata->msg,
						   PJSIP_H_VIA, NULL);
	if (!via) {
	    /* Shouldn't happen if request was created with PJSIP API! 
	     * But we handle the case anyway for robustness.
	     */
	    pj_assert(!"Via header not found!");
	    via = pjsip_via_hdr_create(tdata->pool);
	    pjsip_msg_insert_first_hdr(tdata->msg, (pjsip_hdr*)via);
	}

	if (tdata->msg->line.req.method.id == PJSIP_CANCEL_METHOD) {
	    if (via->sent_by.host.slen > 0) {
		/* Don't update Via header on a CANCEL request if the sent-by
		 * parameter is already set since it needs to match the 
		 * original request. */
		need_update_via = PJ_FALSE;
	    }
	}

	if (via->branch_param.slen == 0) {
	    pj_str_t tmp;
	    via->branch_param.ptr = (char*)pj_pool_alloc(tdata->pool,
						  	 PJSIP_MAX_BRANCH_LEN);
	    via->branch_param.slen = PJSIP_MAX_BRANCH_LEN;
	    pj_memcpy(via->branch_param.ptr, PJSIP_RFC3261_BRANCH_ID,
		      PJSIP_RFC3261_BRANCH_LEN);
	    tmp.ptr = via->branch_param.ptr + PJSIP_RFC3261_BRANCH_LEN + 2;
	    *(tmp.ptr-2) = 80; *(tmp.ptr-1) = 106;
	    pj_generate_unique_string(&tmp);
	}

	if (need_update_via) {
	    via->transport = pj_str(stateless_data->cur_transport->type_name);

	    if (tdata->via_addr.host.slen > 0 &&
		(!tdata->via_tp ||
		 tdata->via_tp == (void *)stateless_data->cur_transport))
	    {
		via->sent_by = tdata->via_addr;

		/* Better also update tdata via_tp, e.g: CANCEL may need to
		 * refer to original INVITE tdata.
		 */
		tdata->via_tp = stateless_data->cur_transport;
	    } else {
		via->sent_by = stateless_data->cur_transport->local_name;

		/* Better also update tdata via_tp & via_addr, e.g: CANCEL
		 * may need to refer to original INVITE tdata.
		 */
		tdata->via_tp = stateless_data->cur_transport;
		tdata->via_addr = via->sent_by;
	    }
	    
	    via->rport_param = pjsip_cfg()->endpt.disable_rport ? -1 : 0;

	    /* Add/remove "alias" param to/from Via header on connection 
	     * oriented/less transport, if configured.
	     */
	    if (pjsip_cfg()->endpt.req_has_via_alias &&
		tdata->msg->type == PJSIP_REQUEST_MSG)
	    {
		const pj_str_t ALIAS_STR = {"alias", 5};
		pjsip_param *alias_param;
		pj_bool_t is_datagram;

		alias_param = pjsip_param_find(&via->other_param, &ALIAS_STR);
		is_datagram = (stateless_data->cur_transport->flag & 
			       PJSIP_TRANSPORT_DATAGRAM);
		if (!is_datagram && !alias_param) {
		    alias_param = PJ_POOL_ZALLOC_T(tdata->pool, pjsip_param);
		    alias_param->name = ALIAS_STR;
		    pj_list_push_back(&via->other_param, alias_param);
		} else if (is_datagram && alias_param) {
		    pj_list_erase(alias_param);
		}
	    }
	}

	pjsip_tx_data_invalidate_msg(tdata);

	/* Send message using this transport. */
	status = pjsip_transport_send( stateless_data->cur_transport,
				       tdata,
				       cur_addr,
				       cur_addr_len,
				       stateless_data,
				       &stateless_send_transport_cb);
	if (status == PJ_SUCCESS) {
	    /* Recursively call this function. */
	    sent = tdata->buf.cur - tdata->buf.start;
	    stateless_send_transport_cb( stateless_data, tdata, sent );
	    return;
	} else if (status == PJ_EPENDING) {
	    /* This callback will be called later. */
	    return;
	} else {
	    /* Recursively call this function. */
	    sent = -status;
	    stateless_send_transport_cb( stateless_data, tdata, sent );
	    return;
	}
    }

}
static void stateless_send_transport_cb( void *token,
					 pjsip_tx_data *tdata,
					 pj_ssize_t sent )
{
    pjsip_send_state *stateless_data = (pjsip_send_state*) token;
    pj_status_t need_update_via = PJ_TRUE;

    PJ_UNUSED_ARG(tdata);
    pj_assert(tdata == stateless_data->tdata);

    for (;;) {
	pj_status_t status;
	pj_bool_t cont;

	pj_sockaddr_t *cur_addr;
	pjsip_transport_type_e cur_addr_type;
	int cur_addr_len;

	pjsip_via_hdr *via;

	if (sent == -PJ_EPENDING) {
	     
	    cont = PJ_TRUE;
	} else {
	     
	    cont = (sent > 0) ? PJ_FALSE :
		   (tdata->dest_info.cur_addr<tdata->dest_info.addr.count-1);
	    if (stateless_data->app_cb) {
		(*stateless_data->app_cb)(stateless_data, sent, &cont);
	    } else {
		 
		cont = PJ_FALSE;
	    }
	}

	 
	if (stateless_data->cur_transport) {
	    pjsip_transport_dec_ref(stateless_data->cur_transport);
	    stateless_data->cur_transport = NULL;
	}

	 
	if (sent > 0 || !cont) {
	    pjsip_tx_data_dec_ref(tdata);
	    return;
	}

	 
	if (sent != -PJ_EPENDING) {
	    tdata->dest_info.cur_addr++;
	}

	 
	if (tdata->dest_info.cur_addr >= tdata->dest_info.addr.count) {
	     
	    pjsip_tx_data_dec_ref(tdata);
	    return;
	}

	 
	cur_addr = &tdata->dest_info.addr.entry[tdata->dest_info.cur_addr].addr;
	cur_addr_type = tdata->dest_info.addr.entry[tdata->dest_info.cur_addr].type;
	cur_addr_len = tdata->dest_info.addr.entry[tdata->dest_info.cur_addr].addr_len;

	 
	status = pjsip_endpt_acquire_transport2(stateless_data->endpt,
						cur_addr_type,
						cur_addr,
						cur_addr_len,
						&tdata->tp_sel,
						tdata,
						&stateless_data->cur_transport);
	if (status != PJ_SUCCESS) {
	    sent = -status;
	    continue;
	}

	 
	via = (pjsip_via_hdr*) pjsip_msg_find_hdr( tdata->msg,
						   PJSIP_H_VIA, NULL);
	if (!via) {
	     
	    pj_assert(!"Via header not found!");
	    via = pjsip_via_hdr_create(tdata->pool);
	    pjsip_msg_insert_first_hdr(tdata->msg, (pjsip_hdr*)via);
	}

	if (tdata->msg->line.req.method.id == PJSIP_CANCEL_METHOD) {
	    if (via->sent_by.host.slen > 0) {
		 
		need_update_via = PJ_FALSE;
	    }
	}

	if (via->branch_param.slen == 0) {
	    pj_str_t tmp;
	    via->branch_param.ptr = (char*)pj_pool_alloc(tdata->pool,
						  	 PJSIP_MAX_BRANCH_LEN);
	    via->branch_param.slen = PJSIP_MAX_BRANCH_LEN;
	    pj_memcpy(via->branch_param.ptr, PJSIP_RFC3261_BRANCH_ID,
		      PJSIP_RFC3261_BRANCH_LEN);
	    tmp.ptr = via->branch_param.ptr + PJSIP_RFC3261_BRANCH_LEN + 2;
	    *(tmp.ptr-2) = 80; *(tmp.ptr-1) = 106;
	    pj_generate_unique_string(&tmp);
	}

	if (need_update_via) {
	    via->transport = pj_str(stateless_data->cur_transport->type_name);

	    if (tdata->via_addr.host.slen > 0 &&
		(!tdata->via_tp ||
		 tdata->via_tp == (void *)stateless_data->cur_transport))
	    {
		via->sent_by = tdata->via_addr;

		 
		tdata->via_tp = stateless_data->cur_transport;
	    } else {
		via->sent_by = stateless_data->cur_transport->local_name;

		 
		tdata->via_tp = stateless_data->cur_transport;
		tdata->via_addr = via->sent_by;
	    }
	    
	    via->rport_param = pjsip_cfg()->endpt.disable_rport ? -1 : 0;

	     
	    if (pjsip_cfg()->endpt.req_has_via_alias &&
		tdata->msg->type == PJSIP_REQUEST_MSG)
	    {
		const pj_str_t ALIAS_STR = {"alias", 5};
		pjsip_param *alias_param;
		pj_bool_t is_datagram;

		alias_param = pjsip_param_find(&via->other_param, &ALIAS_STR);
		is_datagram = (stateless_data->cur_transport->flag & 
			       PJSIP_TRANSPORT_DATAGRAM);
		if (!is_datagram && !alias_param) {
		    alias_param = PJ_POOL_ZALLOC_T(tdata->pool, pjsip_param);
		    alias_param->name = ALIAS_STR;
		    pj_list_push_back(&via->other_param, alias_param);
		} else if (is_datagram && alias_param) {
		    pj_list_erase(alias_param);
		}
	    }
	}

	pjsip_tx_data_invalidate_msg(tdata);

	 
	status = pjsip_transport_send( stateless_data->cur_transport,
				       tdata,
				       cur_addr,
				       cur_addr_len,
				       stateless_data,
				       &stateless_send_transport_cb);
	if (status == PJ_SUCCESS) {
	     
	    sent = tdata->buf.cur - tdata->buf.start;
	    stateless_send_transport_cb( stateless_data, tdata, sent );
	    return;
	} else if (status == PJ_EPENDING) {
	     
	    return;
	} else {
	     
	    sent = -status;
	    stateless_send_transport_cb( stateless_data, tdata, sent );
	    return;
	}
    }

}