📄 chan_gtalk.c
字号:
ast_find_ourip(&us, bindaddr); /* Setup our gtalk candidates */ ast_copy_string(ours1->name, "rtp", sizeof(ours1->name)); ours1->port = ntohs(sin.sin_port); ours1->preference = 1; snprintf(user, sizeof(user), "%08lx%08lx", ast_random(), ast_random()); snprintf(pass, sizeof(pass), "%08lx%08lx", ast_random(), ast_random()); ast_copy_string(ours1->username, user, sizeof(ours1->username)); ast_copy_string(ours1->password, pass, sizeof(ours1->password)); ast_copy_string(ours1->ip, ast_inet_ntoa(us), sizeof(ours1->ip)); ours1->protocol = AJI_PROTOCOL_UDP; ours1->type = AJI_CONNECT_LOCAL; ours1->generation = 0; p->ourcandidates = ours1; if (!ast_strlen_zero(externip)) { /* XXX We should really stun for this one not just go with externip XXX */ snprintf(user, sizeof(user), "%08lx%08lx", ast_random(), ast_random()); snprintf(pass, sizeof(pass), "%08lx%08lx", ast_random(), ast_random()); ast_copy_string(ours2->username, user, sizeof(ours2->username)); ast_copy_string(ours2->password, pass, sizeof(ours2->password)); ast_copy_string(ours2->ip, externip, sizeof(ours2->ip)); ast_copy_string(ours2->name, "rtp", sizeof(ours1->name)); ours2->port = ntohs(sin.sin_port); ours2->preference = 0.9; ours2->protocol = AJI_PROTOCOL_UDP; ours2->type = AJI_CONNECT_STUN; ours2->generation = 0; ours1->next = ours2; ours2 = NULL; } ours1 = NULL; dest.sin_addr = __ourip; dest.sin_port = sin.sin_port; for (tmp = p->ourcandidates; tmp; tmp = tmp->next) { snprintf(port, sizeof(port), "%d", tmp->port); snprintf(preference, sizeof(preference), "%.2f", tmp->preference); iks_insert_attrib(iq, "from", to); iks_insert_attrib(iq, "to", from); iks_insert_attrib(iq, "type", "set"); iks_insert_attrib(iq, "id", c->mid); ast_aji_increment_mid(c->mid); iks_insert_attrib(gtalk, "type", "transport-info"); iks_insert_attrib(gtalk, "id", sid); iks_insert_attrib(gtalk, "initiator", (p->initiator) ? to : from); iks_insert_attrib(gtalk, "xmlns", GOOGLE_NS); iks_insert_attrib(candidate, "name", tmp->name); iks_insert_attrib(candidate, "address", tmp->ip); iks_insert_attrib(candidate, "port", port); iks_insert_attrib(candidate, "username", tmp->username); iks_insert_attrib(candidate, "password", tmp->password); iks_insert_attrib(candidate, "preference", preference); if (tmp->protocol == AJI_PROTOCOL_UDP) iks_insert_attrib(candidate, "protocol", "udp"); if (tmp->protocol == AJI_PROTOCOL_SSLTCP) iks_insert_attrib(candidate, "protocol", "ssltcp"); if (tmp->type == AJI_CONNECT_STUN) iks_insert_attrib(candidate, "type", "stun"); if (tmp->type == AJI_CONNECT_LOCAL) iks_insert_attrib(candidate, "type", "local"); if (tmp->type == AJI_CONNECT_RELAY) iks_insert_attrib(candidate, "type", "relay"); iks_insert_attrib(candidate, "network", "0"); iks_insert_attrib(candidate, "generation", "0"); iks_send(c->p, iq); } p->laststun = 0;safeout: if (ours1) free(ours1); if (ours2) free(ours2); if (iq) iks_delete(iq); if (gtalk) iks_delete(gtalk); if (candidate) iks_delete(candidate); if(transport) iks_delete(transport); return 1;}static struct gtalk_pvt *gtalk_alloc(struct gtalk *client, const char *us, const char *them, const char *sid){ struct gtalk_pvt *tmp = NULL; struct aji_resource *resources = NULL; struct aji_buddy *buddy; char idroster[200]; char *data, *exten = NULL; if (option_debug) ast_log(LOG_DEBUG, "The client is %s for alloc\n", client->name); if (!sid && !strchr(them, '/')) { /* I started call! */ if (!strcasecmp(client->name, "guest")) { buddy = ASTOBJ_CONTAINER_FIND(&client->connection->buddies, them); if (buddy) resources = buddy->resources; } else if (client->buddy) resources = client->buddy->resources; while (resources) { if (resources->cap->jingle) { break; } resources = resources->next; } if (resources) snprintf(idroster, sizeof(idroster), "%s/%s", them, resources->resource); else { ast_log(LOG_ERROR, "no gtalk capable clients to talk to.\n"); return NULL; } } if (!(tmp = ast_calloc(1, sizeof(*tmp)))) { return NULL; } if (sid) { ast_copy_string(tmp->sid, sid, sizeof(tmp->sid)); ast_copy_string(tmp->them, them, sizeof(tmp->them)); ast_copy_string(tmp->us, us, sizeof(tmp->us)); } else { snprintf(tmp->sid, sizeof(tmp->sid), "%08lx%08lx", ast_random(), ast_random()); ast_copy_string(tmp->them, idroster, sizeof(tmp->them)); ast_copy_string(tmp->us, us, sizeof(tmp->us)); tmp->initiator = 1; } /* clear codecs */ tmp->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr); ast_rtp_pt_clear(tmp->rtp); /* add user configured codec capabilites */ if (client->capability) tmp->capability = client->capability; else if (global_capability) tmp->capability = global_capability; tmp->parent = client; if (!tmp->rtp) { ast_log(LOG_WARNING, "Out of RTP sessions?\n"); free(tmp); return NULL; } /* Set CALLERID(name) to the full JID of the remote peer */ ast_copy_string(tmp->cid_name, tmp->them, sizeof(tmp->cid_name)); if(strchr(tmp->us, '/')) { data = ast_strdupa(tmp->us); exten = strsep(&data, "/"); } else exten = tmp->us; ast_copy_string(tmp->exten, exten, sizeof(tmp->exten)); ast_mutex_init(&tmp->lock); ast_mutex_lock(>alklock); tmp->next = client->p; client->p = tmp; ast_mutex_unlock(>alklock); return tmp;}/*! \brief Start new gtalk channel */static struct ast_channel *gtalk_new(struct gtalk *client, struct gtalk_pvt *i, int state, const char *title){ struct ast_channel *tmp; int fmt; int what; const char *n2; if (title) n2 = title; else n2 = i->us; tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, client->accountcode, i->exten, client->context, client->amaflags, "Gtalk/%s-%04lx", n2, ast_random() & 0xffff); if (!tmp) { ast_log(LOG_WARNING, "Unable to allocate Gtalk channel structure!\n"); return NULL; } tmp->tech = >alk_tech; /* Select our native format based on codec preference until we receive something from another device to the contrary. */ if (i->jointcapability) what = i->jointcapability; else if (i->capability) what = i->capability; else what = global_capability; tmp->nativeformats = ast_codec_choose(&i->prefs, what, 1) | (i->jointcapability & AST_FORMAT_VIDEO_MASK); fmt = ast_best_codec(tmp->nativeformats); if (i->rtp) { ast_rtp_setstun(i->rtp, 1); tmp->fds[0] = ast_rtp_fd(i->rtp); tmp->fds[1] = ast_rtcp_fd(i->rtp); } if (i->vrtp) { ast_rtp_setstun(i->rtp, 1); tmp->fds[2] = ast_rtp_fd(i->vrtp); tmp->fds[3] = ast_rtcp_fd(i->vrtp); } if (state == AST_STATE_RING) tmp->rings = 1; tmp->adsicpe = AST_ADSI_UNAVAILABLE; tmp->writeformat = fmt; tmp->rawwriteformat = fmt; tmp->readformat = fmt; tmp->rawreadformat = fmt; tmp->tech_pvt = i; tmp->callgroup = client->callgroup; tmp->pickupgroup = client->pickupgroup; tmp->cid.cid_pres = client->callingpres; if (!ast_strlen_zero(client->accountcode)) ast_string_field_set(tmp, accountcode, client->accountcode); if (client->amaflags) tmp->amaflags = client->amaflags; if (!ast_strlen_zero(client->language)) ast_string_field_set(tmp, language, client->language); if (!ast_strlen_zero(client->musicclass)) ast_string_field_set(tmp, musicclass, client->musicclass); i->owner = tmp; ast_module_ref(ast_module_info->self); ast_copy_string(tmp->context, client->context, sizeof(tmp->context)); ast_copy_string(tmp->exten, i->exten, sizeof(tmp->exten)); if (!ast_strlen_zero(i->exten) && strcmp(i->exten, "s")) tmp->cid.cid_dnid = ast_strdup(i->exten); tmp->priority = 1; if (i->rtp) ast_jb_configure(tmp, &global_jbconf); if (state != AST_STATE_DOWN && ast_pbx_start(tmp)) { ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name); tmp->hangupcause = AST_CAUSE_SWITCH_CONGESTION; ast_hangup(tmp); tmp = NULL; } return tmp;}static int gtalk_action(struct gtalk *client, struct gtalk_pvt *p, const char *action){ iks *request, *session = NULL; int res = -1; request = iks_new("iq"); if (request) { iks_insert_attrib(request, "type", "set"); iks_insert_attrib(request, "from", p->us); iks_insert_attrib(request, "to", p->them); iks_insert_attrib(request, "id", client->connection->mid); ast_aji_increment_mid(client->connection->mid); session = iks_new("session"); if (session) { iks_insert_attrib(session, "type", action); iks_insert_attrib(session, "id", p->sid); iks_insert_attrib(session, "initiator", p->initiator ? p->us : p->them); iks_insert_attrib(session, "xmlns", "http://www.google.com/session"); iks_insert_node(request, session); iks_send(client->connection->p, request); iks_delete(session); res = 0; } iks_delete(request); } return res;}static void gtalk_free_candidates(struct gtalk_candidate *candidate){ struct gtalk_candidate *last; while (candidate) { last = candidate; candidate = candidate->next; free(last); }}static void gtalk_free_pvt(struct gtalk *client, struct gtalk_pvt *p){ struct gtalk_pvt *cur, *prev = NULL; cur = client->p; while (cur) { if (cur == p) { if (prev) prev->next = p->next; else client->p = p->next; break; } prev = cur; cur = cur->next; } if (p->ringrule) iks_filter_remove_rule(p->parent->connection->f, p->ringrule); if (p->owner) ast_log(LOG_WARNING, "Uh oh, there's an owner, this is going to be messy.\n"); if (p->rtp) ast_rtp_destroy(p->rtp); if (p->vrtp) ast_rtp_destroy(p->vrtp); gtalk_free_candidates(p->theircandidates); free(p);}static int gtalk_newcall(struct gtalk *client, ikspak *pak){ struct gtalk_pvt *p, *tmp = client->p; struct ast_channel *chan; int res; iks *codec; char *from = NULL; char s1[BUFSIZ], s2[BUFSIZ], s3[BUFSIZ]; int peernoncodeccapability; /* Make sure our new call doesn't exist yet */ from = iks_find_attrib(pak->x,"to"); if(!from) from = client->connection->jid->full; while (tmp) { if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) { ast_log(LOG_NOTICE, "Ignoring duplicate call setup on SID %s\n", tmp->sid); gtalk_response(client, from, pak, "out-of-order", NULL); return -1; } tmp = tmp->next; } if (!strcasecmp(client->name, "guest")){ /* the guest account is not tied to any configured XMPP client, let's set it now */ client->connection = ast_aji_get_client(from); if (!client->connection) { ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", from); return -1; } } p = gtalk_alloc(client, from, pak->from->full, iks_find_attrib(pak->query, "id")); if (!p) { ast_log(LOG_WARNING, "Unable to allocate gtalk structure!\n"); return -1; } chan = gtalk_new(client, p, AST_STATE_DOWN, pak->from->user); if (!chan) { gtalk_free_pvt(client, p); return -1; } ast_mutex_lock(&p->lock); ast_copy_string(p->them, pak->from->full, sizeof(p->them)); if (iks_find_attrib(pak->query, "id")) { ast_copy_string(p->sid, iks_find_attrib(pak->query, "id"), sizeof(p->sid)); } /* codec points to the first <payload-type/> tag */ codec = iks_child(iks_child(iks_child(pak->x))); while (codec) { ast_rtp_set_m_type(p->rtp, atoi(iks_find_attrib(codec, "id"))); ast_rtp_set_rtpmap_type(p->rtp, atoi(iks_find_attrib(codec, "id")), "audio", iks_find_attrib(codec, "name"), 0); codec = iks_next(codec); } /* Now gather all of the codecs that we are asked for */ ast_rtp_get_current_formats(p->rtp, &p->peercapability, &peernoncodeccapability); p->jointcapability = p->capability & p->peercapability; ast_mutex_unlock(&p->lock); ast_setstate(chan, AST_STATE_RING); if (!p->jointcapability) { ast_log(LOG_WARNING, "Capabilities don't match : us - %s, peer - %s, combined - %s \n", ast_getformatname_multiple(s1, BUFSIZ, p->capability), ast_getformatname_multiple(s2, BUFSIZ, p->peercapability), ast_getformatname_multiple(s3, BUFSIZ, p->jointcapability)); /* close session if capabilities don't match */ gtalk_action(client, p, "reject"); p->alreadygone = 1; gtalk_hangup(chan); ast_channel_free(chan); return -1; } res = ast_pbx_start(chan); switch (res) { case AST_PBX_FAILED: ast_log(LOG_WARNING, "Failed to start PBX :(\n"); gtalk_response(client, from, pak, "service-unavailable", NULL); break; case AST_PBX_CALL_LIMIT: ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n"); gtalk_response(client, from, pak, "service-unavailable", NULL); break; case AST_PBX_SUCCESS: gtalk_response(client, from, pak, NULL, NULL); gtalk_invite_response(p, p->them, p->us,p->sid, 0); gtalk_create_candidates(client, p, p->sid, p->them, p->us); /* nothing to do */ break; } return 1;}static int gtalk_update_stun(struct gtalk *client, struct gtalk_pvt *p){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -