SDP client for myBlueUSB

Dependents:   mbed_TANK_Kinect ftusbClass

Files at this revision

API Documentation at this revision

Comitter:
networker
Date:
Mon Apr 04 16:45:20 2011 +0000
Child:
1:70ee392bcfd4
Commit message:
initial revision

Changed in this revision

sdp.cpp Show annotated file Show diff for this revision Revisions of this file
sdp.h Show annotated file Show diff for this revision Revisions of this file
sdp_data.cpp Show annotated file Show diff for this revision Revisions of this file
sdp_data.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sdp.cpp	Mon Apr 04 16:45:20 2011 +0000
@@ -0,0 +1,329 @@
+#include "mbed.h"
+#include "Utils.h"
+#include "hci.h"
+#include "sdp_data.h"
+#include "sdp.h"
+
+SDPManager SDP; //instance
+const unsigned char base_uuid[16] = { 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0, 0x07, 0x70, 0, 0x10, 0, 0};
+
+void attribHandler(serv_rec *r) {
+    printf("Service 0x%08X\n", (*r)[0x0000]->asUnsigned());
+    map<unsigned short, sdp_data*>::iterator it = r->begin();
+    for (;it != r->end();it++) {
+        printf("   0x%04X: %s\n", (*it).first, (*it).second->asString());
+    }
+}
+
+//this function is called when the L2CAP layer receives SDP packets (see SDPManager::Open), userdata is the sdpmanager instance
+void SDPManager::OnSdpRsp(int socket, SocketState state, const u8* data, int len, void* userData) {
+printf("\x1B[%dm", 34);
+    printf("OnSdpRsp(socket=%d, state=%d, len=%d)\n", socket, state, len);
+    //printfBytes("Got SDP Response from L2CAP: ", data, len);
+    SDPManager *self = (SDPManager*)userData;
+    if (state != SocketState_Open)
+      return;
+    sdp_data list(sdp_data::SEQUENCE);
+    if (data)
+        self->parseRsp(data, len);
+    if (len==0) {
+        sdp_data root(sdp_data::UUID, 0x1101);
+        sdp_data req(sdp_data::SEQUENCE);
+        req.add_element(&root);
+        self->ServiceSearchRequest(&req, 5);
+    } else if (data[0]==3) {
+        self->index = self->services.begin();
+        if (self->index != self->services.end()) {
+            unsigned handle = (*self->index).first;
+            //printf("req.: handle %#X\n", handle);
+            sdp_data all(0xffffU,4);
+            list.add_element(&all);
+            self->ServiceAttributeRequest(handle, 100, &list);//0x1001D
+            self->index++;
+        } else printf(" - empty list - \n");//should not happen
+    } else if (data[0]==5) {
+        if (self->index != self->services.end()) {
+            //printf("req.: handle %#X\n", (*self->index).first);
+            self->ServiceAttributeRequest((*self->index).first, 100, &list);
+            self->index++;
+        } else {
+            printf(" - end of list - \n");
+            Socket_Close(self->sdp_socket); //Note: socket=L2CAP, sdp_socket=SDP !!!
+        }
+    }
+printf("\x1B[%dm", 0);
+}
+
+//this function is called when the SDP sockets receives data (see HCICallback in TestShell),
+//currently does not happen because not forwarded from OnSdpRsp, can be used to handle multiple connections
+void SDPManager::OnSockCallback(int socket, SocketState state, const u8* data, int len, void* userData) {
+    printf("OnSockCallback(socket=%d, state=%d, len=%d)\n", socket, state, len);
+    printfBytes("Got SDP Response from socket: ", data, len);
+}
+
+void SDPManager::errorhandler(unsigned err) {//default error handler
+    switch (err) {
+        case 1:
+            printf("Unsupported version of SDP\n");
+            break;
+        case 2:
+            printf("Invalid SDP ServiceRecordHandle\n");
+            break;
+        case 3:
+            printf("SDP syntax error\n");
+            break;
+        case 4:
+            printf("PDU size was invalid\n");
+            break;
+        case 5:
+            printf("Continuation state was invalid\n");
+            break;
+        case 6:
+            printf("SDP server has insufficient resources\n");
+            break;
+        default:
+            printf("Unknown SDP error code\n");
+            break;
+    }
+}
+
+int SDPManager::ServiceSearchRequest(sdp_data *sp, unsigned count, unsigned cs) {
+    int parlen = sp->Size() + 3; //no continuation
+    buf[0] = 2; //pdu
+    buf[1] = txid>>8;
+    buf[2] = txid++;
+    buf[4] = parlen;
+    buf[3] = parlen>>8;
+    int p = sp->build(buf+5, 100-10);
+    buf[p+6] = count;
+    buf[p+5] = count>>8;
+    if (cs==0)
+        buf[p+7] = 0;
+    else
+        printf("Continuation not supported\n");
+    //printfBytes("SDP Send: ", buf, parlen+5);
+    return Socket_Send(_l2cap, l2cap_buf, parlen + 5 + OFFSET);
+}
+
+int SDPManager::ServiceAttributeRequest(unsigned handle, unsigned count, sdp_data* al, unsigned cs) {
+    int parlen = al->Size() + 7; //no continuation
+    buf[0] = 4; //pdu
+    buf[1] = txid>>8;
+    buf[2] = txid++;
+    buf[4] = parlen;
+    buf[3] = parlen>>8;
+    for (int i = 0; i < 4; i++)
+        buf[i+5] = ((char*)&handle)[3-i];
+    buf[9] = count>>8;
+    buf[10] = count;
+    int p = al->build(buf+11, 100-26);
+    if (cs==0)
+        buf[p+11] = 0;
+    else
+        printf("Continuation not supported\n");
+    //printfBytes("SDP Send: ", buf, parlen+5);
+    return Socket_Send(_l2cap, l2cap_buf, parlen + 5 + OFFSET);
+}
+
+int SDPManager::ServiceSearchAttributeRequest(sdp_data *sp, unsigned count, sdp_data* al, unsigned cs) {
+    int parlen = sp->Size() + al->Size() + 3; //no continuation (1 byte), count (2 bytes)
+    buf[0] = 6; //pdu
+    buf[1] = txid>>8;
+    buf[2] = txid++;
+    buf[4] = parlen;
+    buf[3] = parlen>>8;
+    int p = sp->build(buf+5, 30);
+    buf[p+6] = count;
+    buf[p+5] = count>>8;
+    p += al->build(buf+11, 100-38);
+    if (cs==0)
+        buf[p+7] = 0;
+    else
+        printf("Continuation not supported\n");
+    //printfBytes("SDP Send: ", buf, parlen+5);
+    return Socket_Send(_l2cap, l2cap_buf, parlen + 5 + OFFSET);
+}
+
+unsigned SDPManager::getval(const unsigned char *p, int n) {
+    unsigned ret = 0;
+    for (int i = 0; i < n; i++)
+        ret = (ret<<8) + (unsigned)p[i];
+    return ret;
+}
+
+unsigned SDPManager::length(const unsigned char *el, unsigned &p) {
+    unsigned len = 0;
+    switch (el[p++] & 7) {//length
+        case 0:
+            len = 1;
+            break;
+        case 1:
+            len = 2;
+            break;
+        case 2:
+            len = 4;
+            break;
+        case 3:
+            len = 8;
+            break;
+        case 4:
+            len = 16;
+            break;
+        case 7://4bytes
+            len= el[p++]<<24;
+            len += el[p++]<<16;
+        case 6://2bytes
+            len += el[p++]<<8;
+        case 5://1byte
+            len += el[p++];
+            break;
+    }
+    return len;
+}
+
+extern "C" void HardFault_Handler() { printf("Hard Fault!\n"); while(1); }
+
+
+unsigned SDPManager::parse (const unsigned char *el, unsigned count, sdp_data* &result, serv_rec* &record) {
+    unsigned p = 0;
+    unsigned len = length(el, p);
+    int end = p+len;//end is the index of the item just after the sequence
+    sdp_data *item = 0;
+    switch (el[0]>>3) {//type
+        case sdp_data::NULL_:
+            item = new sdp_data();
+            break;
+        case sdp_data::UNSIGNED:
+            item = new sdp_data((unsigned)getval(el+p, len), len);
+            break;
+        case sdp_data::SIGNED:
+            item = new sdp_data((int)getval(el+p, len), len);
+            break;
+        case sdp_data::UUID:
+            if (len==16) {
+                char rev[16];
+                for (int i = 0; i < 16; i++)
+                    rev[i] = el[p+15-i];
+                item = new sdp_data(sdp_data::UUID, rev, len);
+            } else
+                item = new sdp_data(sdp_data::UUID, getval(el+p, len), len);
+            break;
+        case sdp_data::STRING:
+            item = new sdp_data((char*)el+p, len);
+            break;
+        case sdp_data::BOOL:
+            item = new sdp_data((bool)getval(el+p, len), len);
+            break;
+        case sdp_data::SEQUENCE:
+            item = new sdp_data(sdp_data::SEQUENCE);
+            goto skip;
+        case sdp_data::ALTERNATIVE:
+            item = new sdp_data(sdp_data::ALTERNATIVE);
+skip: {//p points just after the length indicator, hence at the first item IN the sequence
+//               printf("SEQ%d{%p ", len, item);
+                int n = 0;
+                unsigned short key;
+                serv_rec *dummy = 0;
+                while (p < end) {
+                    sdp_data *elem = 0;
+                    p += parse(el + p, len-p, elem, dummy);//parse each element in the sequence, the second arg is as yet unused
+                    item->add_element(elem);
+                    if (record) {
+                        if (n & 1) { //value
+                            record->insert(pair<unsigned short, sdp_data*>(key, elem));
+                        } else //key
+                            key = elem->asUnsigned();
+                        n++;
+                    }
+                }
+            }
+//            printf("}\n");
+            break;
+        case 8:
+            item = new sdp_data(sdp_data::URL, (char*)el+p, len);
+            break;
+        default:
+            printf("Parse: Unknown type %d, len=%d (code=%#02X)\n", el[0]>>3, len, el[0]);
+    }
+    result = item;
+    return end;
+}
+
+int SDPManager::parseRsp(const unsigned char*rsp, int len) {
+    //unsigned tid = rsp[2] + ((unsigned)rsp[1]<<8);
+    unsigned parlen = rsp[4] + ((unsigned)rsp[3]<<8);
+//    printf("ParseRsp: tid=%04X, parlen=%d ", tid, parlen);
+    unsigned cont = 0;
+    switch (rsp[0]) {
+        case 1: {//errorRsp
+            unsigned errorcode = rsp[6] + ((unsigned)rsp[5]<<8);
+            if (parlen > 2) {
+                printf("ErrorInfo (%d bytes) for error %d is available\n", parlen-2, errorcode);
+            }
+            if (ErrorResponse)
+                ErrorResponse(errorcode);
+            return errorcode;
+        }
+        //break;
+        case 3: { //servicesearchRsp
+            //unsigned total = rsp[6] + ((unsigned)rsp[5]<<8);
+            unsigned current = rsp[8] + ((unsigned)rsp[7]<<8);
+            cont = rsp[9+4*current];
+//            printf("total=%d, current=%d, cont=%d\n", total, current, cont);
+            if (cont) break;
+            //linear list of 32bit service-handles
+            for (int i = 0; i < current; i++) {
+                unsigned result = 0;
+                for (int j = 0; j< 4; j++)
+                    result = (result<<8) + rsp[9 + 4*i + j];
+//                printf("SDP Search handle %08X\n", result);
+                services.insert(pair<unsigned, serv_rec*>(result, 0));
+            }
+            if (ServiceSearchResponse)
+                ServiceSearchResponse();
+        }
+        break;
+        case 5: { //serviceattributeRsp
+            if (tree) delete tree;
+            unsigned count = rsp[6] + ((unsigned)rsp[5]<<8);
+            cont = rsp[7+count];
+            if (cont)
+                break;
+//            printf("pos=%d, count=%d parsing...\n", 7, count);
+            serv_rec *serv = new serv_rec;
+            unsigned p = parse(rsp+7, count, tree, serv);
+            unsigned key = (*serv)[0]->asUnsigned();
+            services[key] = serv;
+//            printf("...parsing done, pos=%d, cont=%d\n", p, cont);
+            if (ServiceAttributeResponse)
+                ServiceAttributeResponse(serv);
+        }
+        break;
+        case 7: { //servicesearchattributeRsp
+            if (tree) delete tree;
+            unsigned count = rsp[6] + ((unsigned)rsp[5]<<8);
+            cont = rsp[7+count];
+            if (cont)
+                break;
+            unsigned pos = 7;
+            while (rsp[pos]>>3 == sdp_data::SEQUENCE) {
+                unsigned len = length(rsp, pos);
+                printf("pos=%d, count=%d, parsing...\n", pos, len);
+                serv_rec *serv = new serv_rec;
+                pos = parse(rsp+pos, len, tree, serv);
+                unsigned key = (*serv)[0]->asUnsigned();
+                services[key] = serv;
+            }
+            printf("...parsing done, pos=%d\n", pos);
+            if (ServiceSearchAttributeResponse)
+                ServiceSearchAttributeResponse();
+        }
+        break;
+        default:
+            printf("Unknown SDP response type %02X\n", rsp[0]);
+            break;
+    }
+    if (cont)
+        printf("Continuation not supported (yet)\n");
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sdp.h	Mon Apr 04 16:45:20 2011 +0000
@@ -0,0 +1,89 @@
+#ifndef SDP_H
+#define SDP_H
+
+#include <map>
+#define OFFSET  8
+
+class SDPManager;
+extern SDPManager SDP;
+typedef map<unsigned short, sdp_data*> serv_rec;
+
+void attribHandler(serv_rec *r);
+
+//at the moment, SDP can handle only one connection at a time
+class SDPManager: public SocketHandler {
+    int _l2cap;
+    int sdp_socket; //at the moment the only socket
+    unsigned char l2cap_buf[100+OFFSET];
+    unsigned char* buf;
+    unsigned txid;
+    sdp_data *tree;//root of the entire service tree
+    map<unsigned, serv_rec*> services;//the set of supported services <handle, service>
+    map<unsigned, serv_rec*>::iterator index;
+public:
+    SDPManager(): _l2cap(0), txid(1), tree(0) {
+        ErrorResponse=errorhandler;
+        ServiceSearchResponse=0;
+        ServiceAttributeResponse=attribHandler;
+        ServiceSearchAttributeResponse=0;
+        buf = l2cap_buf+OFFSET;
+    }
+
+    //Called as: Socket_Open(SOCKET_SDP, addr, callback, userdata(this))
+    virtual int Open(SocketInternal* sock, SocketAddrHdr* addr) {
+        L2CAPAddr* ad = (L2CAPAddr*)addr;
+        if (_l2cap) {
+          printf("This SDP supports only one connection at a time\n");
+          return 0;
+          }
+        //BD_ADDR* a = &ad->bdaddr;
+        sdp_socket = sock->ID;
+        for (index = services.begin(); index != services.end(); index++)
+           delete (*index).second;
+        services.clear();
+        ad->psm = L2CAP_PSM_SDP;//open the l2cap channel
+        _l2cap = Socket_Open(SOCKET_L2CAP, addr, OnSdpRsp, this);//this is the socket between SDP and the L2CAP layer
+        if (_l2cap <= 0) {
+            printf("Opening L2CAP channel failed\n");
+            return _l2cap;
+        }
+        printf("Successfully opened L2CAP channel for SDP on socket %d\n", _l2cap);
+        return sock->ID;
+    }
+
+    virtual int Send(SocketInternal* sock, const u8* data, int len) {
+        printf("SDPManager::Send should not be called directly\n");
+        return Socket_Send(_l2cap, data, len);
+    }
+
+    virtual int Close(SocketInternal* sock) {
+        printf("SDP socket %d and L2CAP socket %d closed\n", sock->ID, _l2cap);
+        return Socket_Close(_l2cap);
+    }
+
+    virtual char* Name() {
+        return "SDPManager SocketHandler";
+    }
+
+    //this function is called when the L2CAP layer receives SDP packets (see SDPManager::Open), userdata is the sdpmanager instance
+    static void OnSdpRsp(int socket, SocketState state, const u8* data, int len, void* userData) ;
+    //this function is called when the SDP sockets receives data (see HCICallback in TestShell),
+    //currently does not happen because not forwarded from OnSdpRsp, can be used to handle multiple connections
+    static void OnSockCallback(int socket, SocketState state, const u8* data, int len, void* userData) ;
+    static void errorhandler(unsigned err);
+
+    void (*ErrorResponse)(unsigned) ;
+    void (*ServiceSearchResponse)() ;
+    void (*ServiceAttributeResponse)(serv_rec*) ;
+    void (*ServiceSearchAttributeResponse)() ;
+    int ServiceSearchRequest(sdp_data *sp, unsigned count, unsigned cs=0);
+    int ServiceAttributeRequest(unsigned handle, unsigned count, sdp_data* al, unsigned cs=0) ;
+    int ServiceSearchAttributeRequest(sdp_data *sp, unsigned count, sdp_data* al, unsigned cs=0);
+private:
+    unsigned length(const unsigned char *el, unsigned &p);
+    unsigned getval(const unsigned char *p, int n) ;
+    unsigned parse (const unsigned char *el, unsigned count, sdp_data* &result, serv_rec* &record) ;
+    int parseRsp(const unsigned char*rsp, int len) ;
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sdp_data.cpp	Mon Apr 04 16:45:20 2011 +0000
@@ -0,0 +1,203 @@
+#include "mbed.h"
+#include "sdp_data.h"
+
+char sdp_data::ret[12];
+
+unsigned sdp_data::asUnsigned() {
+    switch (type) {
+        case NULL_:
+            return 0;
+        case UNSIGNED:
+        case SIGNED:
+        case BOOL:
+            return data;
+        case UUID:
+#ifdef LONGUUID
+            return uuid[6] + uuid[7]<<16;
+#else
+            return data;
+#endif
+        default:
+            return 0;
+    }
+}
+
+const char* sdp_data::asString(bool alt) {
+    char sep = ',';
+    switch (type) {
+        case NULL_:
+            return "NULL";
+        case UNSIGNED:
+            if (alt) sprintf(ret, "0x%0*X", size*2, data);
+            else sprintf(ret, "%u", data);
+            return ret;
+        case SIGNED:
+            sprintf(ret, "%d", data);
+            return ret;
+        case BOOL:
+            return data ? "TRUE" : "FALSE";
+        case STRING:
+        case URL:
+            return str;
+        case ALTERNATIVE:
+            sep = '|';
+        case SEQUENCE: {
+            if (longstr) delete[] longstr;
+            int n = sprintf(ret, "SEQ %d { ", size) + 1;
+            longstr = new char[n];
+            strcpy(longstr, ret);
+            for (int i = 0; i < sequence.size(); i++) {
+                const char *s = sequence[i]->asString(alt);
+                n = strlen(longstr) + strlen(s) + 2;
+                char *t = new char[n];
+                strcpy(t, longstr);
+                strcat(t, s);
+                t[n-2] = sep;
+                t[n-1]='\0';
+                //printf("[%s]+[%s]+%c=[%s]\n", longstr, s, sep, t);
+                delete[] longstr;
+                longstr = t;
+            }
+            longstr[n-2] = '}';
+        }
+        return longstr;
+        case UUID:
+#ifdef LONGUUID
+            switch (size) {
+                case 2:
+                    sprintf(ret, "0x%04X", uuid[6]);
+                    return ret;
+                case 4:
+                    sprintf(ret, "0x%04X%04X", uuid[7],uuid[6]);
+                    return ret;
+                case 16:
+                    longstr = new char[35];
+                    sprintf(longstr, "%04X%04X-%04X-%04X-%04X-%04X%04X%04X", uuid[7],uuid[6],uuid[5],uuid[4],uuid[3],uuid[2],uuid[1],uuid[0]);
+                    return longstr;
+            }
+#else
+            switch (size) {
+                case 2:
+                    sprintf(ret, "0x%04X", data & 0xffff);
+                    return ret;
+                case 4:
+                    sprintf(ret, "0x%08X", data);
+                    return ret;
+                case 16:
+                    longstr = new char[35];
+                    sprintf(longstr, "%08X-%04X-%04X-%04X-%04X%04X%04X", data,base_uuid[5],base_uuid[4],base_uuid[3],base_uuid[2],base_uuid[1],base_uuid[0]);
+                    return longstr;
+            }
+#endif
+    }
+    return "Unsupported";
+}
+
+unsigned sdp_data::Size() {
+    if (size<3 || size==4 || size==8 || size==16)
+        return size+1;//include descriptor
+    if (size < 256) return size+2; //1 extra byte
+    if (size < 65536) return size+3; //2 extra bytes
+    return size+5; //4 extra bytes
+}
+
+unsigned sdp_data::sizedesc(unsigned char *buf) {
+    int desc, extra=0;
+    switch (size) {
+        case 0:
+        case 1:
+            desc = 0;
+            break;
+        case 2:
+            desc = 1;
+            break;
+        case 4:
+            desc = 2;
+            break;
+        case 8:
+            desc = 3;
+            break;
+        case 16:
+            desc = 4;
+            break;
+        default:
+            if (size < 256) {
+                desc = 5;
+                extra = 1;
+                buf[1] = size;
+            } else if (size < 65536) {
+                desc = 6;
+                extra = 2;
+                *(unsigned short*)&buf[1] = size;
+            } else {
+                desc = 7;
+                extra = 4;
+                *(unsigned*)&buf[1] = size;
+            }
+    }
+    buf[0] |= desc;
+    return extra+1;
+}
+
+void sdp_data::revcpy(unsigned char*d, const unsigned char*s, int n) {
+    for (int i = 0; i < n; i++)
+        d[i] = s[n-i-1];
+}
+
+unsigned sdp_data::build(unsigned char *buf, unsigned max) {
+    int p = 0;
+    if (size+5 < max) {
+        buf[p] = type<<3;
+        switch (type) {
+            case NULL_:
+                p++;
+                break;
+            case UNSIGNED:
+            case SIGNED:
+            case BOOL:
+                p += sizedesc(buf+p);
+                revcpy(buf+p, (unsigned char*)&data, size);
+                break;
+            case UUID:
+                p += sizedesc(buf+p);
+#ifdef LONGUUID
+                switch (size) {
+                    case 2:
+                    case 4:
+                        revcpy(buf+p, (unsigned char*)&uuid[6], size);
+                        break;
+                    case 16:
+                        revcpy(buf+p, (unsigned char*)uuid, size);
+                        break;
+                }
+#else
+                switch (size) {
+                    case 2:
+                    case 4:
+                        revcpy(buf+p, (unsigned char*)&data, size);
+                        break;
+                    case 16:
+                        revcpy(buf+p, (unsigned char*)&data, 4);
+                        revcpy(buf+p+4, base_uuid, 12);
+                        break;
+                }
+#endif
+                break;
+            case STRING:
+            case URL:
+                p += sizedesc(buf+p);
+                memcpy(buf+p, str, size);
+                break;
+            case SEQUENCE:
+            case ALTERNATIVE:
+                p += sizedesc(buf+p);
+                for (int i = 0; i < sequence.size(); i++)
+                    sequence.at(i)->build(buf+p, max-p);
+                break;
+        }
+        p += size;
+    } else { //too big, make continuation
+        printf ("Data too large to fit\n");
+    }
+    return p;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sdp_data.h	Mon Apr 04 16:45:20 2011 +0000
@@ -0,0 +1,106 @@
+#ifndef SDP_DATA_H
+#define SDP_DATA_H
+
+#include <vector>
+
+extern const unsigned char base_uuid[16];// = { 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0, 0x07, 0x70, 0, 0x10, 0, 0};
+
+class sdp_data {
+public:
+    enum elements { NULL_, UNSIGNED, SIGNED, UUID, STRING, BOOL, SEQUENCE, ALTERNATIVE, URL};
+private:
+    enum elements type;
+    char size;
+    union {
+        unsigned data;
+        char *str;
+#ifdef LONGUUID
+        unsigned short uuid[8];
+#endif
+    };
+    static char ret[12];
+    char *longstr;
+    vector<sdp_data*> sequence;
+public:
+    sdp_data(): type(NULL_), size(0), longstr(0) {
+        //printf("NULL%d ", size);
+    }
+    sdp_data(unsigned d, unsigned sz=4): type(UNSIGNED), size(sz), longstr(0) {
+        data=d;
+        //printf("UINT%d=%u ", size, data);
+    }
+    sdp_data(signed d, unsigned sz=4): type(SIGNED), size(sz), longstr(0) {
+        data=d;
+        //   printf("INT%d=%d ", size, data);
+    }
+    sdp_data(bool d, unsigned sz=1): type(BOOL), size(sz), longstr(0) {
+        data=d;
+        //   printf("BOOL%d=%u ", size, data);
+    }
+    sdp_data(char*s, unsigned sz=0): type(STRING), longstr(0) {
+        if (sz) size = sz;
+        else size = strlen(s)+1;
+        str = new char[size];
+        strncpy(str, s, size);
+        //   printf("STR%d='%s' ", size, str);
+    }
+    sdp_data(enum elements t, unsigned d, unsigned sz=2): type(t), size(sz), longstr(0) {
+        if (t==UUID) {
+#ifdef LONGUUID
+            memcpy(uuid, base_uuid, 16);
+            uuid[6] = d;
+            uuid[7] = d>>16;
+            //       printf("UUID%d=%04X%04X ", size, uuid[7], uuid[6]);
+#else
+            data = d;
+#endif
+        } else printf("Please use other constructor for type %d\n", t);
+    }
+    sdp_data(enum elements t, char *d=0, unsigned sz=0): type(t), size(sz), longstr(0) {
+        switch (t) {
+#ifdef LONGUUID
+            case UUID:
+                memcpy(uuid, d, size);
+                //           printf("UUID%d=%08X ", size, uuid[6]);
+                break;
+#endif
+            case URL:
+                //size = strlen(d)+1;
+                str = new char[size+1];
+                strcpy(str, d);
+                //         printf("URL%d='%u' ", size, str);
+                break;
+            case SEQUENCE:
+            case ALTERNATIVE:
+                break;
+            default:
+                printf("Please use other constructor for type %d\n", t);
+        }
+    }
+    ~sdp_data() {
+        switch (type) {
+            case STRING:
+            case URL:
+                delete[] str;
+                break;
+            case SEQUENCE:
+            case ALTERNATIVE:
+                for (int i = 0; i < sequence.size(); i++)
+                    delete sequence.at(i);
+                break;
+        }
+        delete[] longstr;
+    }
+    void add_element(sdp_data *el) {
+        sequence.push_back(el);
+        size += el->Size();
+    }
+    unsigned asUnsigned() ;
+    const char* asString(bool alt=false) ;
+    unsigned Size() ;
+    unsigned sizedesc(unsigned char *buf) ;
+    void revcpy(unsigned char*d, const unsigned char*s, int n) ;
+    unsigned build(unsigned char *buf, unsigned max) ;
+};
+
+#endif
\ No newline at end of file