# HG changeset patch # User Thomas Butter # Date 1123146611 0 # Node ID 5f79dfde334c66f38222b744151796ff5da4d94f # Parent 12fc7a3fbc88ad64e6fb6bca8be8f956c77a22d1 [gaim-migrate @ 13307] added UDP transport for SIP/SIMPLE committer: Tailor Script diff -r 12fc7a3fbc88 -r 5f79dfde334c src/protocols/simple/simple.c --- a/src/protocols/simple/simple.c Thu Aug 04 01:08:01 2005 +0000 +++ b/src/protocols/simple/simple.c Thu Aug 04 09:10:11 2005 +0000 @@ -33,6 +33,7 @@ #include "version.h" #include "network.h" #include "xmlnode.h" +#include "stun.h" #include "simple.h" #include "sipmsg.h" @@ -259,7 +260,7 @@ struct simple_account_data *sip = gc->proto_data; int error = 0; if(!sip->connecting) { - serveradr = getserver(sip->servername); + serveradr = getserver(sip->servername, "_sip._tcp"); gaim_debug_info("simple","connecting to %s port %d", serveradr->name, serveradr->port); error = gaim_proxy_connect(sip->account, serveradr->name, serveradr->port, send_later_cb, gc); if(error) { @@ -278,17 +279,23 @@ static int sendout_pkt(GaimConnection *gc, const char *buf) { struct simple_account_data *sip = gc->proto_data; time_t currtime = time(NULL); - int ret; + int ret = 0; gaim_debug(GAIM_DEBUG_MISC, "simple", "\n\nsending - %s\n######\n%s\n######\n\n", ctime(&currtime), buf); - if(sip->fd <0 ) { - sendlater(gc, buf); - return 0; - } - ret = write(sip->fd, buf, strlen(buf)); - if(ret < 0) { - sendlater(gc,buf); - return 0; + if(sip->udp) { + if(sendto(sip->fd, buf, strlen(buf), 0, (struct sockaddr*)&sip->serveraddr, sizeof(struct sockaddr_in)) < strlen(buf)) { + gaim_debug_info("simple", "could not send packet\n"); + } + } else { + if(sip->fd <0 ) { + sendlater(gc, buf); + return 0; + } + ret = write(sip->fd, buf, strlen(buf)); + if(ret < 0) { + sendlater(gc,buf); + return 0; + } } return ret; } @@ -416,7 +423,7 @@ char *uri = g_strdup_printf("sip:%s",sip->servername); char *to = g_strdup_printf("sip:%s@%s",sip->username,sip->servername); - char *contact = g_strdup_printf("Contact: ;methods=\"MESSAGE, SUBSCRIBE, NOTIFY\"\r\nExpires: 900\r\n", sip->username, sip->ip, sip->listenport); + char *contact = g_strdup_printf("Contact: ;methods=\"MESSAGE, SUBSCRIBE, NOTIFY\"\r\nExpires: 900\r\n", sip->username, sip->ip, sip->listenport, sip->udp ? "udp" : "tcp"); // allow one auth try per register sip->proxy.fouroseven = 0; @@ -804,13 +811,78 @@ send_notify(sip, watcher); } +static void process_input_message(struct simple_account_data *sip, struct sipmsg *msg) { + int found = 0; + if( msg->response == 0 ) { // request + if(!strcmp(msg->method, "MESSAGE")) { + process_incoming_message(sip, msg); + found = 1; + } + if(!strcmp(msg->method, "NOTIFY")) { + process_incoming_notify(sip, msg); + found = 1; + } + if(!strcmp(msg->method, "SUBSCRIBE")) { + process_incoming_subscribe(sip, msg); + found = 1; + } + } else { // response + struct transaction *trans = transactions_find(sip, msg); + if(trans) { + if(msg->response == 407) { + if(sip->proxy.fouroseven>3) return; + sip->proxy.fouroseven++; + // do proxy authentication + + gchar *ptmp = sipmsg_find_header(msg,"Proxy-Authenticate"); + gchar *resend; + gchar *auth; + + HASHHEX HA2; + HASHHEX response; + gchar noncecount[90]; + fill_auth(sip, ptmp, &sip->proxy); + sprintf(noncecount, "%08d", sip->proxy.nc++); + + DigestCalcResponse(sip->proxy.HA1, sip->proxy.nonce, noncecount, "", "", trans->msg->method, trans->msg->target, HA2, response); + gaim_debug(GAIM_DEBUG_MISC, "simple", "response %s\n", response); + auth = g_strdup_printf("Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", nc=\"%s\", response=\"%s\"\r\n",sip->username, sip->proxy.realm, sip->proxy.nonce, trans->msg->target, noncecount, response); + sipmsg_remove_header(msg, "Proxy-Authorization"); + sipmsg_add_header(trans->msg, "Proxy-Authorization", auth); + g_free(auth); + resend = sipmsg_to_string(trans->msg); + // resend request + sendout_pkt(sip->gc, resend); + g_free(resend); + } else { + sip->proxy.fouroseven = 0; + if(msg->response == 401) sip->registrar.fouroseven++; + else sip->registrar.fouroseven = 0; + if(trans->callback) { + // call the callback to process response + (trans->callback)(sip, msg, trans); + sip->transactions = g_slist_remove(sip->transactions, trans); + } else { + // transaction has no callback - just remove it + sip->transactions = g_slist_remove(sip->transactions, trans); + } + } + found = 1; + } else { + gaim_debug(GAIM_DEBUG_MISC, "simple", "received response to unknown transaction"); + } + } + if(!found) { + gaim_debug(GAIM_DEBUG_MISC, "simple", "received a unknown sip message with method %sand response %d\n",msg->method, msg->response); + } +} + static void process_input(struct simple_account_data *sip, struct sip_connection *conn) { char *cur; char *dummy; struct sipmsg *msg; int restlen; - int found=0; cur = conn->inbuf; @@ -846,75 +918,28 @@ return; } // sipmsg_print(msg); - gaim_debug(GAIM_DEBUG_MISC, "simple", "in process response response: %d\n", msg->response); - if( msg->response == 0 ) { // request - if(!strcmp(msg->method, "MESSAGE")) { - process_incoming_message(sip, msg); - found = 1; - } - if(!strcmp(msg->method, "NOTIFY")) { - process_incoming_notify(sip, msg); - found = 1; - } - if(!strcmp(msg->method, "SUBSCRIBE")) { - process_incoming_subscribe(sip, msg); - found = 1; - } - } else { // response - struct transaction *trans = transactions_find(sip, msg); - if(trans) { - if(msg->response == 407) { - if(sip->proxy.fouroseven>3) return; - sip->proxy.fouroseven++; - // do proxy authentication - - gchar *ptmp = sipmsg_find_header(msg,"Proxy-Authenticate"); - gchar *resend; - gchar *auth; - - HASHHEX HA2; - HASHHEX response; - gchar noncecount[90]; - fill_auth(sip, ptmp, &sip->proxy); - sprintf(noncecount, "%08d", sip->proxy.nc++); - - DigestCalcResponse(sip->proxy.HA1, sip->proxy.nonce, noncecount, "", "", trans->msg->method, trans->msg->target, HA2, response); - gaim_debug(GAIM_DEBUG_MISC, "simple", "response %s\n", response); - auth = g_strdup_printf("Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", nc=\"%s\", response=\"%s\"\r\n",sip->username, sip->proxy.realm, sip->proxy.nonce, trans->msg->target, noncecount, response); - sipmsg_remove_header(msg, "Proxy-Authorization"); - sipmsg_add_header(trans->msg, "Proxy-Authorization", auth); - g_free(auth); - resend = sipmsg_to_string(trans->msg); - // resend request - sendout_pkt(sip->gc, resend); - g_free(resend); - } else { - sip->proxy.fouroseven = 0; - if(msg->response == 401) sip->registrar.fouroseven++; - else sip->registrar.fouroseven = 0; - if(trans->callback) { - // call the callback to process response - (trans->callback)(sip, msg, trans); - - sip->transactions = g_slist_remove(sip->transactions, trans); - } else { - // transaction has no callback - just remove it - sip->transactions = g_slist_remove(sip->transactions, trans); - } - } - found = 1; - } else { - gaim_debug(GAIM_DEBUG_MISC, "simple", "received response to unknown transaction"); - } - } - if(!found) { - gaim_debug(GAIM_DEBUG_MISC, "simple", "received a unknown sip message with method %sand response %d\n",msg->method, msg->response); - } + gaim_debug(GAIM_DEBUG_MISC, "simple", "in process response response: %d\n", msg->response); + process_input_message(sip,msg); } else { gaim_debug(GAIM_DEBUG_MISC, "simple", "received a incomplete sip msg: %s\n", conn->inbuf); } } +static void simple_udp_process(gpointer data, gint source, GaimInputCondition con) { + GaimConnection *gc = data; + struct simple_account_data *sip = gc->proto_data; + struct sipmsg *msg; + int len; + time_t currtime; + + static char buffer[65536]; + len = recv(source, buffer, 65536, 0); + buffer[len] = 0; + gaim_debug_info("simple","\n\nreceived - %s\n######\n%s\n#######\n\n",ctime(&currtime), buffer); + msg = sipmsg_parse_msg(buffer); + if(msg) process_input_message(sip, msg); +} + static void simple_input_cb(gpointer data, gint source, GaimInputCondition cond) { GaimConnection *gc = data; @@ -1015,7 +1040,9 @@ gc->proto_data = sip = g_new0(struct simple_account_data,1); sip->gc=gc; - sip->account = account; + sip->account = account; + + sip->udp = gaim_account_get_bool(account, "udp", FALSE); if (strpbrk(username, " \t\v\r\n") != NULL) { gaim_connection_error(gc, _("SIP usernames may not contain whitespaces or @ symbols")); return; @@ -1034,26 +1061,58 @@ gaim_connection_update_progress(gc, _("Connecting"), 1, 2); sip->status = g_strdup("available"); - - // search for SRV record - serveradr = getserver(sip->servername); - gaim_debug_info("simple","connecting to %s port %d", serveradr->name, serveradr->port); + + // TCP case + if(! sip->udp) { + // search for SRV record + serveradr = getserver(sip->servername, "_sip._tcp"); + gaim_debug_info("simple","connecting to %s port %d", serveradr->name, serveradr->port); + + // open tcp connection to the server + error = gaim_proxy_connect(account, serveradr->name, serveradr->port, login_cb, gc); + if(error) { + gaim_connection_error(gc, _("Couldn't create socket")); + } - // open tcp connection to the server - error = gaim_proxy_connect(account, serveradr->name, serveradr->port, login_cb, gc); - if(error) { - gaim_connection_error(gc, _("Couldn't create socket")); + // create socket for incoming connections + sip->listenfd = gaim_network_listen_range(5060, 5080); + if(sip->listenfd == -1) { + gaim_connection_error(gc, _("Could not create listen socket")); + return; + } + sip->listenport = gaim_network_get_port_from_fd(sip->listenfd); + gaim_input_add(sip->listenfd, GAIM_INPUT_READ, simple_newconn_cb, gc); + } else { // UDP + // search for SRV record + struct sockaddr_in addr; + struct hostent *h; + + serveradr = getserver(sip->servername, "_sip._udp"); + gaim_debug_info("simple", "using udp with server %s and port %d", serveradr->name, serveradr->port); + sip->fd = socket(AF_INET, SOCK_DGRAM, 0); + + addr.sin_family = AF_INET; + addr.sin_port = htons(5060); + addr.sin_addr.s_addr = INADDR_ANY; + while((bind(sip->fd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) <0) && ntohs(addr.sin_port)<5160) { + addr.sin_port = htons(ntohs(addr.sin_port)+1); + } + sip->listenport = ntohs(addr.sin_port); + sip->listenfd = sip->fd; + + gaim_input_add(sip->fd, GAIM_INPUT_READ, simple_udp_process, gc); + // TODO - change to new SRV impl. + sip->serveraddr.sin_family = AF_INET; + sip->serveraddr.sin_port = htons(serveradr->port); + + h = gethostbyname(serveradr->name); + sip->serveraddr.sin_addr.s_addr = ((struct in_addr*)h->h_addr)->s_addr; + sip->ip = g_strdup(gaim_network_get_my_ip(sip->listenfd)); + + do_register(gc); + } - - // create socket for incoming connections - sip->listenfd = gaim_network_listen_range(5060, 5080); - if(sip->listenfd == -1) { - gaim_connection_error(gc, _("Could not create listen socket")); - return; - } - sip->listenport = gaim_network_get_port_from_fd(sip->listenfd); - gaim_input_add(sip->listenfd, GAIM_INPUT_READ, simple_newconn_cb, gc); - + // register timeout callback for register / subscribe renewal sip->registertimeout = gaim_timeout_add((rand()%10)+10*1000, (GSourceFunc)register_timeout, sip); } @@ -1175,12 +1234,15 @@ static void _init_plugin(GaimPlugin *plugin) { GaimAccountUserSplit *split; + GaimAccountOption *option; gaim_debug_register_category("simple"); split = gaim_account_user_split_new(_("Server"), "blubb.com", '@'); prpl_info.user_splits = g_list_append(prpl_info.user_splits, split); + option = gaim_account_option_bool_new(_("Use UDP"), "udp", FALSE); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); // _simple_plugin = plugin; } diff -r 12fc7a3fbc88 -r 5f79dfde334c src/protocols/simple/simple.h --- a/src/protocols/simple/simple.h Thu Aug 04 01:08:01 2005 +0000 +++ b/src/protocols/simple/simple.h Thu Aug 04 09:10:11 2005 +0000 @@ -80,6 +80,8 @@ GSList *transactions; GSList *watcher; GSList *openconns; + gboolean udp; + struct sockaddr_in serveraddr; }; struct sip_connection { diff -r 12fc7a3fbc88 -r 5f79dfde334c src/protocols/simple/srvresolve.c --- a/src/protocols/simple/srvresolve.c Thu Aug 04 01:08:01 2005 +0000 +++ b/src/protocols/simple/srvresolve.c Thu Aug 04 09:10:11 2005 +0000 @@ -27,7 +27,7 @@ u_char buf[1024]; } queryans; -struct getserver_return *getserver(const char *domain) { +struct getserver_return *getserver(const char *domain, const char *srv) { static struct getserver_return ret; queryans answer; int size; @@ -40,9 +40,8 @@ int bestport = 5060; int bestpri=99999; int type, dlen, pref, weight, port; - gchar *query = g_strdup_printf("_sip._tcp.%s",domain); + gchar *query = g_strdup_printf("%s.%s",srv,domain); - gaim_debug_info("simple","searching for %s\r\n",domain); size = res_query( query, C_IN, T_SRV, (u_char*)&answer, sizeof( answer)); @@ -51,7 +50,6 @@ qdcount = ntohs(answer.hdr.qdcount); ancount = ntohs(answer.hdr.ancount); - gaim_debug_info("simple","ancount %d\r\n",ancount); cp = (char*)&answer + sizeof(HEADER); end = (char*)&answer + size; diff -r 12fc7a3fbc88 -r 5f79dfde334c src/protocols/simple/srvresolve.h --- a/src/protocols/simple/srvresolve.h Thu Aug 04 01:08:01 2005 +0000 +++ b/src/protocols/simple/srvresolve.h Thu Aug 04 09:10:11 2005 +0000 @@ -36,6 +36,6 @@ int port; }; -struct getserver_return *getserver(const char *domain); +struct getserver_return *getserver(const char *domain, const char *srv); #endif /* _GAIM_SRVRESOLVE_H */