void nw_changed_cb(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info) { su_network_changed_t *snc = (su_network_changed_t *) info; su_network_changed_t *snc2; su_msg_r rmsg = SU_MSG_R_INIT; SU_DEBUG_7(("nw_changed_cb: entering.\n")); if (su_msg_create(rmsg, su_root_task(snc->su_root), su_root_task(snc->su_root), su_nw_changed_msg_recv, sizeof *snc) == SU_FAILURE) { return; } snc2 = su_msg_data(rmsg); assert(snc2); snc2->su_root = snc->su_root; snc2->su_home = snc->su_home; memcpy(snc2->su_storeRef, snc->su_storeRef, sizeof(SCDynamicStoreRef)); memcpy(snc2->su_sourceRef, snc->su_sourceRef, sizeof(CFRunLoopSourceRef)); snc2->su_os_thread = snc->su_os_thread; snc2->su_network_changed_cb = snc->su_network_changed_cb; snc2->su_network_changed_magic = snc->su_network_changed_magic; if (su_msg_send(rmsg) == SU_FAILURE) { su_msg_destroy(rmsg); return; } return; }
/** Wait for the pthread clone to exit. * @internal * * Called by su_port_wait() and su_clone_wait(). */ void su_pthread_port_wait(su_clone_r rclone) { su_port_t *clone, *parent; struct su_pthread_port_waiting_parent mom[1]; pthread_t tid; assert(*rclone); clone = su_msg_to(rclone)->sut_port; parent = su_msg_from(rclone)->sut_port; if (clone == parent) { su_base_port_wait(rclone); return; } assert(parent); assert(clone); assert(rclone[0]->sum_func == su_pthread_port_clone_break); #if 0 assert(!clone->sup_paused); #endif tid = clone->sup_tid; if (!clone->sup_thread) { /* Already died */ su_msg_destroy(rclone); pthread_join(tid, NULL); return; } pthread_mutex_init(mom->deinit, NULL); pthread_mutex_lock(mom->deinit); pthread_cond_init(mom->cv, NULL); pthread_mutex_init(mom->mutex, NULL); pthread_mutex_lock(mom->mutex); mom->waiting = 1; clone->sup_waiting_parent = mom; su_msg_send(rclone); while (mom->waiting) pthread_cond_wait(mom->cv, mom->mutex); /* Run all messages from clone */ while (su_port_getmsgs_from(parent, clone)) ; /* Allow clone thread to exit */ pthread_mutex_unlock(mom->deinit); pthread_join(tid, NULL); pthread_mutex_destroy(mom->deinit); pthread_mutex_unlock(mom->mutex); pthread_mutex_destroy(mom->mutex); pthread_cond_destroy(mom->cv); }
/** Send message to the @a to_task and mark @a from_task as sender. * * @NEW_1_12_8 */ SOFIAPUBFUN int su_msg_send_to(su_msg_r rmsg, su_task_r const to_task, su_msg_f wakeup) { assert(rmsg); assert(to_task); if (rmsg[0]) { su_msg_t *msg = rmsg[0]; if (wakeup) msg->sum_func = wakeup; if (msg->sum_to->sut_port && msg->sum_to->sut_port != to_task->sut_port) { SU_TASK_ZAP(msg->sum_to, "su_msg_send_to"); } if (to_task->sut_port != NULL) { msg->sum_to->sut_port = NULL; msg->sum_to->sut_root = to_task->sut_root; return su_port_send(to_task->sut_port, rmsg); } su_msg_destroy(rmsg); errno = EINVAL; return -1; } return 0; }
int su_base_port_start_shared(su_root_t *parent, su_clone_r return_clone, su_root_magic_t *magic, su_root_init_f init, su_root_deinit_f deinit) { su_port_t *self = parent->sur_task->sut_port; su_root_t *child; child = su_salloc(su_port_home(self), sizeof *child); if (!child) return -1; child->sur_magic = magic; child->sur_deinit = deinit; child->sur_threading = parent->sur_threading; SU_TASK_COPY(child->sur_parent, su_root_task(parent), su_base_port_clone_start); SU_TASK_COPY(child->sur_task, child->sur_parent, su_base_port_clone_start); child->sur_task->sut_root = child; if (su_msg_create(return_clone, child->sur_task, su_root_task(parent), su_base_port_clone_break, 0) == 0 && init(child, magic) == 0) return 0; su_msg_destroy(return_clone); su_root_destroy(child); return -1; }
/*# Receive event from protocol machine and hand it over to application */ static void nua_application_event(nua_t *dummy, su_msg_r sumsg, nua_ee_data_t *ee) { nua_t *nua = ee->ee_nua; nua_event_data_t *e = ee->ee_data; nua_handle_t *nh = e->e_nh; enter; ee->ee_nua = NULL; e->e_nh = NULL; if (nh == NULL) { /* Xyzzy */ } else if (nh->nh_valid) { if (!nh->nh_ref_by_user) { /* Application must now call nua_handle_destroy() */ nh->nh_ref_by_user = 1; nua_handle_ref(nh); } } else if (!nh->nh_valid) { /* Handle has been destroyed */ if (nua_log->log_level >= 7) { char const *name = nua_event_name((enum nua_event_e)e->e_event) + 4; SU_DEBUG_7(("nua(%p): event %s dropped\n", (void *)nh, name)); } nua_handle_unref(nh); nua_stack_unref(nua); return; } if (e->e_event == nua_r_shutdown && e->e_status >= 200) nua->nua_shutdown_final = 1; if (nua->nua_callback) { nua_event_frame_t frame[1]; su_msg_save(frame->nf_saved, sumsg); frame->nf_next = nua->nua_current, nua->nua_current = frame; nua->nua_callback((enum nua_event_e)e->e_event, e->e_status, e->e_phrase, nua, nua->nua_magic, nh, nh ? nh->nh_magic : NULL, e->e_msg ? sip_object(e->e_msg) : NULL, e->e_tags); su_msg_destroy(frame->nf_saved); nua->nua_current = frame->nf_next; } nua_handle_unref(nh); nua_stack_unref(nua); }
/** Execute the @a function by a pthread @a task. * * @retval 0 if successful * @retval -1 upon an error * * @sa su_task_execute() * * @internal */ int su_pthread_port_execute(su_task_r const task, int (*function)(void *), void *arg, int *return_value) { int success; su_msg_r m = SU_MSG_R_INIT; #if HAVE_OPEN_C struct su_pthread_port_execute frame = { { PTHREAD_MUTEX_INITIALIZER }, { _ENeedsNormalInit, NULL }, NULL, NULL, 0 }; frame.function = function; frame.arg = arg; #else struct su_pthread_port_execute frame = { { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_COND_INITIALIZER }, function, arg, 0 }; #endif if (su_msg_create(m, task, su_task_null, _su_pthread_port_execute, (sizeof &frame)) < 0) return -1; *(struct su_pthread_port_execute **)su_msg_data(m) = &frame; pthread_mutex_lock(frame.mutex); success = su_msg_send(m); if (success == 0) while (frame.function) pthread_cond_wait(frame.cond, frame.mutex); else su_msg_destroy(m); pthread_mutex_unlock(frame.mutex); pthread_mutex_destroy(frame.mutex); pthread_cond_destroy(frame.cond); if (return_value) *return_value = frame.value; return success; }
/**Send a message. * * The function @c su_msg_send() sends the message. The message is added to * the recipients message queue, and recipient is waken up. The caller may * not alter the message or the data associated with it after the message * has been sent. * * @param rmsg message handle * * @retval 0 if signal was sent successfully or handle was @c NULL, * @retval -1 otherwise. */ int su_msg_send(su_msg_r rmsg) { assert(rmsg); if (rmsg[0]) { su_msg_t *msg = rmsg[0]; if (msg->sum_to->sut_port) return su_port_send(msg->sum_to->sut_port, rmsg); su_msg_destroy(rmsg); errno = EINVAL; return -1; } return 0; }
/**Wait for the clone to exit. * @internal * * Called by su_port_wait() and su_clone_wait() */ void su_base_port_wait(su_clone_r rclone) { su_port_t *self; su_root_t *root_to_wait; assert(*rclone); self = su_msg_from(rclone)->sut_port; assert(self == su_msg_to(rclone)->sut_port); root_to_wait = su_msg_to(rclone)->sut_root; assert(rclone[0]->sum_func == su_base_port_clone_break); while (su_base_port_getmsgs_of_root(self, root_to_wait)) ; su_root_destroy(root_to_wait); su_msg_destroy(rclone); }
static void delayed_auth_method(auth_mod_t *am, auth_status_t *as, msg_auth_t *auth, auth_challenger_t const *ach) { auth_plugin_t *ap = AUTH_PLUGIN(am); su_msg_r mamc = SU_MSG_R_INIT; auth_splugin_t *asp; if (su_msg_create(mamc, su_root_task(ap->ap_root), su_root_task(ap->ap_root), delayed_auth_method_recv, sizeof *asp) == SU_FAILURE) { as->as_status = 500; as->as_phrase = "Asynchronous authentication failure"; return; } asp = su_msg_data(mamc); assert(asp); asp->asp_cookie = delayed_asp_cookie; asp->asp_am = am; asp->asp_as = as; asp->asp_header = auth; asp->asp_ach = ach; asp->asp_canceled = 0; if (su_msg_send(mamc) == SU_FAILURE) { su_msg_destroy(mamc); as->as_status = 500; as->as_phrase = "Asynchronous authentication failure"; return; } as->as_plugin = asp; as->as_status = 100; as->as_phrase = "Trying"; return; }
/** Send a delivery report. * * If the sender has attached a delivery report function to message with * su_msg_report(), the message is returned to the message queue of the * sending task. The sending task calls the delivery report function when it * has received the message. */ void su_msg_delivery_report(su_msg_r rmsg) { su_task_r swap; if (!rmsg || !rmsg[0]) return; if (!rmsg[0]->sum_report) { su_msg_destroy(rmsg); return; } *swap = *rmsg[0]->sum_from; *rmsg[0]->sum_from = *rmsg[0]->sum_to; *rmsg[0]->sum_to = *swap; rmsg[0]->sum_func = rmsg[0]->sum_report; rmsg[0]->sum_report = NULL; su_msg_send(rmsg); }
/** @internal Send a message to the port. * * @retval 0 if there are other messages in queue, too * @retval -1 upon an error */ int su_base_port_send(su_port_t *self, su_msg_r rmsg) { if (self) { int wakeup; su_port_lock(self, "su_port_send"); wakeup = self->sup_head == NULL; *self->sup_tail = rmsg[0]; rmsg[0] = NULL; self->sup_tail = &(*self->sup_tail)->sum_next; su_port_unlock(self, "su_port_send"); if (wakeup > 0) su_port_wakeup(self); return 0; } else { su_msg_destroy(rmsg); return -1; } }
void nua_destroy_signal(nua_saved_signal_t saved[1]) { if (saved) su_msg_destroy(saved); }
/** Destroy saved event. * * @sa #nua_event_e, nua_event_save(), nua_event_data(), nua_saved_event_request(). */ void nua_destroy_event(nua_saved_event_t saved[1]) { if (saved && saved[0]) su_msg_destroy(saved); }
/* ---------------------------------------------------------------------- * Receiving events from client */ static void nua_stack_signal(nua_t *nua, su_msg_r msg, nua_ee_data_t *ee) { nua_event_data_t *e = ee->ee_data; nua_handle_t *nh = e->e_nh; tagi_t *tags = e->e_tags; nua_event_t event; int error = 0; if (nh) { if (!nh->nh_prev) nh_append(nua, nh); if (!nh->nh_ref_by_stack) { /* Mark handle as used by stack */ nh->nh_ref_by_stack = 1; nua_handle_ref(nh); } } if (nua_log->log_level >= 5) { char const *name = nua_event_name((enum nua_event_e)e->e_event); if (e->e_status == 0) SU_DEBUG_5(("nua(%p): %s signal %s\n", (void *)nh, "recv", name + 4)); else SU_DEBUG_5(("nua(%p): recv signal %s %u %s\n", (void *)nh, name + 4, e->e_status, e->e_phrase ? e->e_phrase : "")); } su_msg_save(nua->nua_signal, msg); event = (enum nua_event_e)e->e_event; if (nua->nua_shutdown && !e->e_always) { /* Shutting down */ nua_stack_event(nua, nh, NULL, event, 901, "Stack is going down", NULL); } else switch (event) { case nua_r_get_params: nua_stack_get_params(nua, nh ? nh : nua->nua_dhandle, event, tags); break; case nua_r_set_params: nua_stack_set_params(nua, nh ? nh : nua->nua_dhandle, event, tags); break; case nua_r_shutdown: nua_stack_shutdown(nua); break; case nua_r_register: case nua_r_unregister: nua_stack_register(nua, nh, event, tags); break; case nua_r_invite: error = nua_stack_invite(nua, nh, event, tags); break; case nua_r_cancel: error = nua_stack_cancel(nua, nh, event, tags); break; case nua_r_bye: error = nua_stack_bye(nua, nh, event, tags); break; case nua_r_options: error = nua_stack_options(nua, nh, event, tags); break; case nua_r_refer: error = nua_stack_refer(nua, nh, event, tags); break; case nua_r_publish: case nua_r_unpublish: error = nua_stack_publish(nua, nh, event, tags); break; case nua_r_info: error = nua_stack_info(nua, nh, event, tags); break; case nua_r_prack: error = nua_stack_prack(nua, nh, event, tags); break; case nua_r_update: error = nua_stack_update(nua, nh, event, tags); break; case nua_r_message: error = nua_stack_message(nua, nh, event, tags); break; case nua_r_subscribe: case nua_r_unsubscribe: error = nua_stack_subscribe(nua, nh, event, tags); break; case nua_r_notify: error = nua_stack_notify(nua, nh, event, tags); break; case nua_r_notifier: nua_stack_notifier(nua, nh, event, tags); break; case nua_r_terminate: nua_stack_terminate(nua, nh, event, tags); break; case nua_r_method: error = nua_stack_method(nua, nh, event, tags); break; case nua_r_authenticate: nua_stack_authenticate(nua, nh, event, tags); break; case nua_r_authorize: nua_stack_authorize(nua, nh, event, tags); break; case nua_r_ack: error = nua_stack_ack(nua, nh, event, tags); break; case nua_r_respond: nua_stack_respond(nua, nh, e->e_status, e->e_phrase, tags); break; case nua_r_destroy: nua_stack_destroy_handle(nua, nh, tags); su_msg_destroy(nua->nua_signal); return; default: break; } if (error < 0) { nua_stack_event(nh->nh_nua, nh, NULL, event, NUA_ERROR_AT(__FILE__, __LINE__), NULL); } su_msg_destroy(nua->nua_signal); }
/** Main function for clone thread. * * @internal */ static void *su_pthread_port_clone_main(void *varg) { struct clone_args *arg = (struct clone_args *)varg; su_task_r task; int zap = 1; #if SU_HAVE_WINSOCK su_init(); #endif task->sut_port = arg->create(); if (task->sut_port) { task->sut_root = su_salloc(su_port_home(task->sut_port), sizeof *task->sut_root); if (task->sut_root) { task->sut_root->sur_threading = 1; /* By default */ SU_TASK_COPY(task->sut_root->sur_parent, su_root_task(arg->parent), su_pthread_port_clone_main); SU_TASK_COPY(task->sut_root->sur_task, task, su_pthread_port_clone_main); if (su_msg_create(arg->clone, task, su_root_task(arg->parent), su_pthread_port_clone_break, 0) == 0) { task->sut_root->sur_magic = arg->magic; task->sut_root->sur_deinit = arg->deinit; su_root_set_max_defer(task->sut_root, su_root_get_max_defer(arg->parent)); if (arg->init(task->sut_root, arg->magic) == 0) { su_pthread_port_return_to_parent(arg, 0), arg = NULL; su_root_run(task->sut_root); /* Do the work */ /* Cleanup */ if (task->sut_port->sup_waiting_parent) { struct su_pthread_port_waiting_parent *mom; mom = task->sut_port->sup_waiting_parent; pthread_mutex_lock(mom->mutex); mom->waiting = 0; pthread_cond_signal(mom->cv); pthread_mutex_unlock(mom->mutex); pthread_mutex_lock(mom->deinit); su_port_getmsgs(task->sut_port); pthread_mutex_unlock(mom->deinit); } else zap = 0; } else su_msg_destroy(arg->clone); su_root_destroy(task->sut_root); } } task->sut_port->sup_base->sup_vtable-> su_port_decref(task->sut_port, zap, "su_pthread_port_clone_main"); } #if SU_HAVE_WINSOCK su_deinit(); #endif if (arg) su_pthread_port_return_to_parent(arg, -1); return NULL; /* Exit from thread */ }
/* * test su_timer functionality: * * Create a timer, executing print_stamp() in every 20 ms */ int main(int argc, char *argv[]) { su_root_t *root; su_timer_t *t, *t1, *t_end; su_timer_t **timers; su_duration_t interval = 60; char *argv0 = argv[0]; char *s; int use_t1 = 0; su_time_t now, started; intptr_t i, N = 500; GSource *source; struct timing timing[1] = {{ 0 }}; struct tester tester[1] = {{ 0 }}; while (argv[1] && argv[1][0] == '-') { char *o = argv[1] + 1; while (*o) { if (*o == '1') o++, use_t1 = 1; else if (*o == 'r') o++, timing->t_run = 1; else if (*o == 'N') { if (o[1]) N = strtoul(o + 1, &o, 0); else if (argv[2]) N = strtoul(argv++[2], &o, 0); break; } else break; } if (*o) usage(argv0); argv++; } if (argv[1]) { interval = strtoul(argv[1], &s, 10); if (interval == 0 || s == argv[1]) usage(argv0); } su_init(); atexit(su_deinit); tester->root = root = su_glib_root_create(tester); source = su_root_gsource(tester->root); g_source_attach(source, NULL /*g_main_context_default ()*/); su_msg_create(intr_msg, su_root_task(root), su_root_task(root), test_break, 0); signal(SIGINT, intr_handler); #if HAVE_SIGPIPE signal(SIGPIPE, intr_handler); signal(SIGQUIT, intr_handler); signal(SIGHUP, intr_handler); #endif t = su_timer_create(su_root_task(root), interval); t1 = su_timer_create(su_root_task(root), 1); t_end = su_timer_create(su_root_task(root), 20 * interval); if (t == NULL || t1 == NULL || t_end == NULL) su_perror("su_timer_create"), exit(1); tester->t = t, tester->t1 = t1; timing->t_prev = su_now(); if (timing->t_run) su_timer_run(t, print_stamp, timing); else su_timer_set(t, print_stamp, timing); if (use_t1) su_timer_set(t1, print_X, NULL); su_timer_set(t_end, end_test, NULL); su_root_run(root); su_msg_destroy(intr_msg); su_timer_destroy(t); su_timer_destroy(t1); if (timing->t_times != 10) { fprintf(stderr, "%s: t expired %d times (expecting 10)\n", argv0, timing->t_times); return 1; } /* Insert timers in order */ timers = calloc(N, sizeof *timers); if (!timers) { perror("calloc"); exit(1); } now = started = su_now(); for (i = 0; i < N; i++) { t = su_timer_create(su_root_task(root), 1000); if (!t) { perror("su_timer_create"); exit(1); } if (++now.tv_usec == 0) ++now.tv_sec; su_timer_set_at(t, increment, (void *)i, now); timers[i] = t; } tester->sentinel = (void*)(i - 1); su_root_run(root); printf("Processing %u timers took %f millisec (%f expected)\n", (unsigned)i, su_time_diff(su_now(), started) * 1000, (double)i / 1000); for (i = 0; i < N; i++) { su_timer_destroy(timers[i]); } su_root_destroy(root); su_deinit(); return 0; }