Commit a8d08210 authored by anteater's avatar anteater
Browse files

fix mmsd to work with t-mobile (pending cleanup)

parent f4b8b324
......@@ -88,7 +88,8 @@ unit_test_wsputil_SOURCES = unit/test-wsputil.c src/wsputil.c src/wsputil.h
unit_test_wsputil_LDADD = @GLIB_LIBS@
unit_test_mmsutil_SOURCES = unit/test-mmsutil.c src/mmsutil.c src/mmsutil.h \
src/wsputil.c src/wsputil.h
src/wsputil.c src/wsputil.h \
src/log.c src/log.h
unit_test_mmsutil_LDADD = @GLIB_LIBS@
TESTS = unit/test-wsputil unit/test-mmsutil
......
......@@ -35,6 +35,7 @@
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <net/if.h>
#include <ifaddrs.h>
#include "gresolv.h"
......@@ -764,13 +765,15 @@ static int connect_udp_channel(struct resolv_nameserver *nameserver)
return -EINVAL;
sk = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
const int so_reuseaddr = 1;
setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &so_reuseaddr, sizeof so_reuseaddr);
if (sk < 0) {
freeaddrinfo(rp);
return -EIO;
}
/*
* If nameserver points to localhost ip, their is no need to
* If nameserver points to localhost ip, there is no need to
* bind the socket on any interface.
*/
if (nameserver->resolv->index > 0 &&
......@@ -780,12 +783,63 @@ static int connect_udp_channel(struct resolv_nameserver *nameserver)
memset(interface, 0, IF_NAMESIZE);
if (if_indextoname(nameserver->resolv->index,
interface) != NULL) {
if (setsockopt(sk, SOL_SOCKET, SO_BINDTODEVICE,
interface, IF_NAMESIZE) < 0) {
/* set up bind address */
struct sockaddr_storage bind_addr;
int addr_size = 0;
memset(&bind_addr, 0, sizeof(bind_addr));
bind_addr.ss_family = rp->ai_family;
struct ifaddrs *ifa, *ifa_tmp;
if (getifaddrs(&ifa) == -1) {
perror("getifaddrs failed");
return -errno;
}
ifa_tmp = ifa;
while (ifa_tmp) {
if (!strcmp(ifa_tmp->ifa_name, interface) &&
ifa_tmp->ifa_addr) {
if (ifa_tmp->ifa_addr->sa_family != rp->ai_family) {
printf("fam %d != expected %d\n", ifa_tmp->ifa_addr->sa_family, rp->ai_family);
ifa_tmp = ifa_tmp->ifa_next;
continue;
}
if (ifa_tmp->ifa_addr->sa_family == AF_INET) {
struct sockaddr_in *bind_addr4 = (struct sockaddr_in *)&bind_addr;
bind_addr4->sin_addr.s_addr = ((struct sockaddr_in *)ifa_tmp->ifa_addr)->sin_addr.s_addr;
bind_addr4->sin_port = 53;
printf("addr = %s\n", inet_ntoa(bind_addr4->sin_addr));
addr_size = sizeof(*bind_addr4);
} else if (ifa_tmp->ifa_addr->sa_family == AF_INET6) {
struct sockaddr_in6 *bind_addr6 = (struct sockaddr_in6 *)&bind_addr;
bind_addr6->sin6_addr = ((struct sockaddr_in6 *)ifa_tmp->ifa_addr)->sin6_addr;
bind_addr6->sin6_port = 53;
char buf[64];
inet_ntop(AF_INET6, bind_addr6->sin6_addr.s6_addr, buf, 64);
printf("addr = %s\n", buf);
addr_size = sizeof(*bind_addr6);
} else {
printf("unknown fam\n");
}
break;
}
ifa_tmp = ifa_tmp->ifa_next;
}
/* if (bind_addr. && bind_addr.sin_addr.s_addr == 0) {
printf("interface not found\n");
}
if (bind_addr.sin6_addr.s_addr == 0) {
printf("interface6 not found\n");
}*/
if (bind(sk, (struct sockaddr *)&bind_addr, addr_size) < 0) {
perror("bind failed");
close(sk);
freeaddrinfo(rp);
return -EIO;
}
freeifaddrs(ifa);
}
}
......@@ -896,6 +950,7 @@ void g_resolv_set_debug(GResolv *resolv, GResolvDebugFunc func,
gboolean g_resolv_add_nameserver(GResolv *resolv, const char *address,
uint16_t port, unsigned long flags)
{
printf ("adding nameserver %s\n", address);
struct resolv_nameserver *nameserver;
if (resolv == NULL)
......@@ -911,6 +966,7 @@ gboolean g_resolv_add_nameserver(GResolv *resolv, const char *address,
nameserver->resolv = resolv;
if (connect_udp_channel(nameserver) < 0) {
printf ("connect_udp_channel failed!\n");
free_nameserver(nameserver);
return FALSE;
}
......@@ -977,6 +1033,9 @@ guint g_resolv_lookup_hostname(GResolv *resolv, const char *hostname,
if (resolv->nameserver_list == NULL) {
int i;
printf("g_resolv_lookup_hostname: nameserver_list NULL\n");
printf("g_resolv_lookup_hostname: nscount=%d\n", resolv->res.nscount);
for (i = 0; i < resolv->res.nscount; i++) {
char buf[100];
......@@ -989,15 +1048,19 @@ guint g_resolv_lookup_hostname(GResolv *resolv, const char *hostname,
sa_addr = &resolv->res._u._ext.nsaddrs[i]->sin6_addr;
}
if (family != AF_INET && family != AF_INET6)
if (family != AF_INET && family != AF_INET6) {
printf("g_resolv_lookup_hostname: skipping b/c family=%d\n", family);
continue;
}
if (inet_ntop(family, sa_addr, buf, sizeof(buf)))
g_resolv_add_nameserver(resolv, buf, 53, 0);
}
if (resolv->nameserver_list == NULL)
if (resolv->nameserver_list == NULL) {
printf("g_resolv_lookup_hostname: nameserver_list *still* NULL\n");
g_resolv_add_nameserver(resolv, "127.0.0.1", 53, 0);
}
}
lookup = g_try_new0(struct resolv_lookup, 1);
......
......@@ -1008,6 +1008,7 @@ static inline int bind_socket(int sk, int index, int family)
if (if_indextoname(index, interface) == NULL)
return -1;
printf("binding %s\n", interface);
err = setsockopt(sk, SOL_SOCKET, SO_BINDTODEVICE,
interface, IF_NAMESIZE);
if (err < 0)
......
......@@ -396,11 +396,14 @@ static void check_context_active(struct modem_data *modem,
g_free(modem->context_proxy);
modem->context_proxy = NULL;
DBG("context_active = false");
mms_service_bearer_notify(modem->service, FALSE, NULL, NULL);
} else if (modem->context_proxy != NULL)
} else if (modem->context_proxy != NULL) {
DBG("nonnull proxy");
mms_service_bearer_notify(modem->service, TRUE,
modem->context_interface,
modem->context_proxy);
}
}
static void check_context_settings(struct modem_data *modem,
......@@ -452,6 +455,7 @@ static void check_context_settings(struct modem_data *modem,
if (modem->context_active == FALSE)
return;
DBG("about to bearer_notify");
mms_service_bearer_notify(modem->service, TRUE,
modem->context_interface,
modem->context_proxy);
......@@ -692,6 +696,7 @@ static void set_context_reply(DBusPendingCall *call, void *user_data)
dbus_error_init(&err);
if (dbus_set_error_from_message(&err, reply) == TRUE) {
DBG("set_ctx reply failure (%s: %s), about to bearer_notify", err.name, err.message);
dbus_error_free(&err);
mms_service_bearer_notify(modem->service, FALSE, NULL, NULL);
}
......@@ -739,15 +744,17 @@ static void bearer_handler(mms_bool_t active, void *user_data)
{
struct modem_data *modem = user_data;
DBG("path %s active %d", modem->path, active);
DBG("path %s active %d context_active %d", modem->path, active, modem->context_active);
if (active == TRUE && modem->context_active == TRUE) {
DBG("active and context_active, bearer_notify");
mms_service_bearer_notify(modem->service, TRUE,
modem->context_interface,
modem->context_proxy);
return;
}
DBG("checking for failure");
if (active == FALSE && modem->context_active == FALSE) {
mms_service_bearer_notify(modem->service, FALSE, NULL, NULL);
return;
......
......@@ -32,6 +32,7 @@
#include "wsputil.h"
#include "mmsutil.h"
#include "mms.h"
#define MAX_ENC_VALUE_BYTES 6
......@@ -75,7 +76,11 @@ enum mms_header {
MMS_HEADER_SUBJECT = 0x16,
MMS_HEADER_TO = 0x17,
MMS_HEADER_TRANSACTION_ID = 0x18,
__MMS_HEADER_MAX = 0x19,
MMS_HEADER_RETRIEVE_STATUS = 0x19,
MMS_HEADER_RETRIEVE_TEXT = 0x20,
MMS_HEADER_READ_STATUS = 0x21,
MMS_HEADER_LAST_HANDLED = 0x21,
__MMS_HEADER_MAX = 0x22,
MMS_HEADER_INVALID = 0x80,
};
......@@ -159,13 +164,18 @@ static gboolean extract_short(struct wsp_header_iter *iter, void *user)
static const char *decode_text(struct wsp_header_iter *iter)
{
const unsigned char *p;
unsigned int l;
unsigned int l=32;
if (wsp_header_iter_get_val_type(iter) != WSP_VALUE_TYPE_TEXT)
if (wsp_header_iter_get_val_type(iter) != WSP_VALUE_TYPE_TEXT) {
p = wsp_header_iter_get_val(iter);
DBG("could not decode text of (dummy) length %u: %*s", l-1, l-1, p+1);
return NULL;
}
p = wsp_header_iter_get_val(iter);
l = wsp_header_iter_get_val_len(iter);
DBG("claimed len: %u", l);
DBG("val: %*s", l - 1, p);
return wsp_decode_text(p, l, NULL);
}
......@@ -184,31 +194,14 @@ static gboolean extract_text(struct wsp_header_iter *iter, void *user)
return TRUE;
}
static gboolean extract_text_array_element(struct wsp_header_iter *iter,
void *user)
{
char **out = user;
const char *element;
char *tmp;
element = decode_text(iter);
if (element == NULL)
return FALSE;
if (*out == NULL) {
*out = g_strdup(element);
return TRUE;
}
tmp = g_strjoin(",", *out, element, NULL);
if (tmp == NULL)
return FALSE;
g_free(*out);
*out = tmp;
return TRUE;
static char* remove_address_type_suffix(const char* addr, size_t len) {
return g_strdup(addr);
/* #define MMS_ADDR_SUFFIX_PUBLIC_LAND_MOBILE_NUMBER "/TYPE=PLMN"
if(g_str_has_suffix(addr, MMS_ADDR_SUFFIX_PUBLIC_LAND_MOBILE_NUMBER)) {
return g_strndup(addr, len - strlen(MMS_ADDR_SUFFIX_PUBLIC_LAND_MOBILE_NUMBER));
} else {
return g_strdup(addr);
}*/
}
static char *decode_encoded_string_with_mib_enum(const unsigned char *p,
......@@ -242,6 +235,57 @@ static char *decode_encoded_string_with_mib_enum(const unsigned char *p,
&bytes_read, &bytes_written, NULL);
}
static gboolean extract_text_array_element(struct wsp_header_iter *iter,
void *user)
{
char **out = user;
const char *element = NULL;
char *tmp;
DBG("");
const unsigned char *p;
unsigned int l;
p = wsp_header_iter_get_val(iter);
l = wsp_header_iter_get_val_len(iter);
switch (wsp_header_iter_get_val_type(iter)) {
case WSP_VALUE_TYPE_TEXT:
/* Text-string */
element = wsp_decode_text(p, l, NULL);
break;
case WSP_VALUE_TYPE_LONG:
/* (Value-len) Char-set Text-string */
element = decode_encoded_string_with_mib_enum(p, l);
break;
case WSP_VALUE_TYPE_SHORT:
element = NULL;
break;
}
if (element == NULL) {
DBG("failed, type=%d", wsp_header_iter_get_val_type(iter));
return FALSE;
}
if (*out == NULL) {
*out = g_strdup(element);
return TRUE;
}
tmp = g_strjoin(",", *out, element, NULL);
if (tmp == NULL) {
DBG("join failed");
return FALSE;
}
g_free(*out);
*out = tmp;
return TRUE;
}
static gboolean extract_encoded_text(struct wsp_header_iter *iter, void *user)
{
char **out = user;
......@@ -361,26 +405,62 @@ static gboolean extract_from(struct wsp_header_iter *iter, void *user)
const unsigned char *p;
unsigned int l;
const char *text;
unsigned char char_set = 0;
if (wsp_header_iter_get_val_type(iter) != WSP_VALUE_TYPE_LONG)
if (wsp_header_iter_get_val_type(iter) != WSP_VALUE_TYPE_LONG) {
DBG("val_type not LONG");
return FALSE;
}
p = wsp_header_iter_get_val(iter);
l = wsp_header_iter_get_val_len(iter);
if (p[0] != 128 && p[0] != 129)
/* From-value = Value-length (Address-present-token=128 Encoded-string-value | Insert-address-token=129) */
/* Encoded-string-value = Text-string | Value-length Char-set Text-string */
/* Value-length = Short-length | (Length-quote Length) */
/* Short-length = val 0-30 */
/* Length-quote = val 31 */
/* Length = Uintvar-integer */
if (p[0] != 128 && p[0] != 129) {
DBG("not 128 or 129");
return FALSE;
}
if (p[0] == 129) {
*out = NULL;
return TRUE;
}
p += 1; l -= 1; /* token has been handled */
unsigned int val_len = l;
unsigned int str_len;
if (p[0] < 31) { /*short-length */
val_len = p[0];
char_set = p[1];
p += 2;
val_len -= 1; /* count encoding against val_len */
} else if (p[0] == 31) /* length quote then long length */ {
unsigned int consumed = 0;
gboolean ok = wsp_decode_uintvar(p, l, &val_len, &consumed);
if (!ok)
return FALSE;
char_set = p[1];
p += consumed;
val_len -= 1; /* count encoding against val_len */
}
str_len = val_len - 1; /* NUL at the end is not counted by strlen() */
DBG("trying to decode text of length %u: %*s", str_len, str_len, p);
text = wsp_decode_text(p, val_len, NULL);
DBG("text=\"%s\"", text);
text = wsp_decode_text(p + 1, l - 1, NULL);
if (text == NULL)
if (text == NULL) {
DBG("could not decode text of length %u: %*s", str_len, str_len, p);
return FALSE;
}
*out = g_strdup(text);
*out = remove_address_type_suffix(text, str_len);
return TRUE;
}
......@@ -473,6 +553,50 @@ static gboolean extract_priority(struct wsp_header_iter *iter, void *user)
return TRUE;
}
static gboolean extract_read_status(struct wsp_header_iter *iter, void *user)
{
enum mms_message_read_status *out = user;
const unsigned char *p;
if (wsp_header_iter_get_val_type(iter) != WSP_VALUE_TYPE_SHORT)
return FALSE;
p = wsp_header_iter_get_val(iter);
if (p[0] == MMS_MESSAGE_READ_STATUS_READ ||
p[0] == MMS_MESSAGE_READ_STATUS_DELETED_UNREAD) {
*out = p[0];
return TRUE;
}
return FALSE;
}
static gboolean extract_retr_status(struct wsp_header_iter *iter, void *user)
{
enum mms_message_retr_status *out = user;
const unsigned char *p;
if (wsp_header_iter_get_val_type(iter) != WSP_VALUE_TYPE_SHORT)
return FALSE;
p = wsp_header_iter_get_val(iter);
switch (p[0]) {
case MMS_MESSAGE_RETR_STATUS_OK:
case MMS_MESSAGE_RETR_STATUS_ERR_TRANS_FAILURE:
case MMS_MESSAGE_RETR_STATUS_ERR_TRANS_MESSAGE_NOT_FOUND:
case MMS_MESSAGE_RETR_STATUS_ERR_PERM_FAILURE:
case MMS_MESSAGE_RETR_STATUS_ERR_PERM_SERVICE_DENIED:
case MMS_MESSAGE_RETR_STATUS_ERR_PERM_MESSAGE_NOT_FOUND:
case MMS_MESSAGE_RETR_STATUS_ERR_PERM_CONTENT_UNSUPPORTED:
*out = p[0];
return TRUE;
}
return FALSE;
}
static gboolean extract_rsp_status(struct wsp_header_iter *iter, void *user)
{
unsigned char *out = user;
......@@ -559,7 +683,7 @@ static header_handler handler_for_type(enum mms_header header)
case MMS_HEADER_CONTENT_LOCATION:
return extract_text;
case MMS_HEADER_CONTENT_TYPE:
return extract_text;
return extract_text; /* extract_encoded_text? */
case MMS_HEADER_DATE:
return extract_date;
case MMS_HEADER_DELIVERY_REPORT:
......@@ -590,6 +714,12 @@ static header_handler handler_for_type(enum mms_header header)
return extract_rsp_status;
case MMS_HEADER_RESPONSE_TEXT:
return extract_encoded_text;
case MMS_HEADER_RETRIEVE_STATUS:
return extract_retr_status;
case MMS_HEADER_RETRIEVE_TEXT:
return extract_encoded_text;
case MMS_HEADER_READ_STATUS:
return extract_read_status;
case MMS_HEADER_SENDER_VISIBILITY:
return extract_sender_visibility;
case MMS_HEADER_STATUS:
......@@ -650,8 +780,12 @@ static gboolean mms_parse_headers(struct wsp_header_iter *iter,
h = p[0] & 0x7f;
handler = handler_for_type(h);
if (handler == NULL)
if (handler == NULL) {
DBG("no handler for type %u", h);
return FALSE;
}
DBG("saw header of type %u", h);
/* Unsupported header, skip */
if (entries[h].data == NULL)
......@@ -662,9 +796,15 @@ static gboolean mms_parse_headers(struct wsp_header_iter *iter,
!(entries[h].flags & HEADER_FLAG_ALLOW_MULTI))
continue;
DBG("running handler for type %u", h);
/* Parse the header */
if (handler(iter, entries[h].data) == FALSE)
if (handler(iter, entries[h].data) == FALSE) {
DBG("handler %p for type %u returned false", handler, h);
return FALSE;
}
DBG("handler for type %u was success", h);
entries[h].pos = i;
entries[h].flags |= HEADER_FLAG_MARKED;
......@@ -672,8 +812,10 @@ static gboolean mms_parse_headers(struct wsp_header_iter *iter,
for (i = 0; i < __MMS_HEADER_MAX + 1; i++) {
if ((entries[i].flags & HEADER_FLAG_MANDATORY) &&
!(entries[i].flags & HEADER_FLAG_MARKED))
!(entries[i].flags & HEADER_FLAG_MARKED)) {
DBG("header %u was mandatory but not marked", i);
return FALSE;
}
}
/*
......@@ -704,8 +846,10 @@ static gboolean mms_parse_headers(struct wsp_header_iter *iter,
va_end(args);
if (entries[i].pos != expected_pos)
if (entries[i].pos != expected_pos) {
DBG("header %u was in position %u but expected in position %u", i, entries[i].pos, expected_pos);
return FALSE;
}
}
return TRUE;
......@@ -770,6 +914,7 @@ static gboolean extract_content_id(struct wsp_header_iter *iter, void *user)
return FALSE;
*out = g_strdup(text);
DBG("extracted content-id %s\n", *out);
return TRUE;
}
......@@ -991,11 +1136,17 @@ gboolean mms_message_decode(const unsigned char *pdu,
flags |= WSP_HEADER_ITER_FLAG_DETECT_MMS_MULTIPART;
wsp_header_iter_init(&iter, pdu, len, flags);
DBG("about to check well known");
CHECK_WELL_KNOWN_HDR(MMS_HEADER_MESSAGE_TYPE);
DBG("about to extract short");
if (extract_short(&iter, &octet) == FALSE)
return FALSE;
DBG("octet %u", octet);
if (octet < MMS_MESSAGE_TYPE_SEND_REQ ||
octet > MMS_MESSAGE_TYPE_DELIVERY_IND)
return FALSE;
......@@ -1422,6 +1573,12 @@ static header_encoder encoder_for_type(enum mms_header header)
return NULL;
case MMS_HEADER_RESPONSE_TEXT:
return NULL;
case MMS_HEADER_RETRIEVE_STATUS:
return NULL;
case MMS_HEADER_RETRIEVE_TEXT:
return NULL;
case MMS_HEADER_READ_STATUS:
return NULL;
case MMS_HEADER_SENDER_VISIBILITY:
return NULL;
case MMS_HEADER_STATUS:
......
......@@ -50,6 +50,23 @@ enum mms_message_rsp_status {
MMS_MESSAGE_RSP_STATUS_ERR_PERM_LACK_OF_PREPAID = 235,
};
enum mms_message_retr_status {
MMS_MESSAGE_RETR_STATUS_OK = 128,
MMS_MESSAGE_RETR_STATUS_ERR_TRANS_MIN = 192,
MMS_MESSAGE_RETR_STATUS_ERR_TRANS_FAILURE = 192,
MMS_MESSAGE_RETR_STATUS_ERR_TRANS_MESSAGE_NOT_FOUND = 194,
MMS_MESSAGE_RETR_STATUS_ERR_PERM_MIN = 224,
MMS_MESSAGE_RETR_STATUS_ERR_PERM_FAILURE = 224,
MMS_MESSAGE_RETR_STATUS_ERR_PERM_SERVICE_DENIED = 225,
MMS_MESSAGE_RETR_STATUS_ERR_PERM_MESSAGE_NOT_FOUND = 226,
MMS_MESSAGE_RETR_STATUS_ERR_PERM_CONTENT_UNSUPPORTED = 227,
};
enum mms_message_read_status {
MMS_MESSAGE_READ_STATUS_READ = 128,
MMS_MESSAGE_READ_STATUS_DELETED_UNREAD = 129,
};
enum mms_message_notify_status {
MMS_MESSAGE_NOTIFY_STATUS_RETRIEVED = 129,
MMS_MESSAGE_NOTIFY_STATUS_REJECTED = 130,
......
......@@ -609,7 +609,7 @@ static void emit_message_added(const struct mms_service *service,
static void activate_bearer(struct mms_service *service)
{
DBG("service %p", service);
DBG("service %p setup %d active %d", service, service->bearer_setup, service->bearer_active);
if (service->bearer_setup == TRUE)
return;
......@@ -622,7 +622,7 @@ static void activate_bearer(struct mms_service *service)
if (service->bearer_handler == NULL)
return;
DBG("service %p", service);
DBG("service %p waiting for %d seconds", service, BEARER_SETUP_TIMEOUT);
service->bearer_setup = TRUE;
......@@ -736,9 +736,12 @@ static DBusMessage *get_messages(DBusConnection *conn,
GHashTableIter table_iter;
gpointer key, value;
DBG("");
reply = dbus_message_new_method_return(dbus_msg);
if (reply == NULL)
return NULL;
//return reply;
dbus_message_iter_init_append(reply, &iter);
......@@ -1632,6 +1635,7 @@ static void append_attachment_properties(struct mms_attachment *part,
dbus_message_iter_open_container(part_array, DBUS_TYPE_STRUCT,
NULL, &entry);
DBG("content-id: %s\n", part->content_id);
dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING,