SDP client for myBlueUSB

Dependents:   mbed_TANK_Kinect ftusbClass

Committer:
networker
Date:
Sat Jun 11 19:43:36 2011 +0000
Revision:
4:d5c3e499603d
Parent:
3:e8d2ebb7392e
added some further server functions

Who changed what in which revision?

UserRevisionLine numberNew contents of line
networker 0:7493bf6bb1b9 1 #include "mbed.h"
networker 0:7493bf6bb1b9 2 #include "Utils.h"
networker 0:7493bf6bb1b9 3 #include "hci.h"
networker 0:7493bf6bb1b9 4 #include "sdp_data.h"
networker 0:7493bf6bb1b9 5 #include "sdp.h"
networker 0:7493bf6bb1b9 6
networker 0:7493bf6bb1b9 7 SDPManager SDP; //instance
networker 0:7493bf6bb1b9 8 const unsigned char base_uuid[16] = { 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0, 0x07, 0x70, 0, 0x10, 0, 0};
networker 3:e8d2ebb7392e 9 map<unsigned, serv_rec*> SDPManager::server;
networker 3:e8d2ebb7392e 10 int SDPManager::serverSock = 0;
networker 0:7493bf6bb1b9 11
networker 0:7493bf6bb1b9 12 void attribHandler(serv_rec *r) {
networker 0:7493bf6bb1b9 13 printf("Service 0x%08X\n", (*r)[0x0000]->asUnsigned());
networker 0:7493bf6bb1b9 14 map<unsigned short, sdp_data*>::iterator it = r->begin();
networker 0:7493bf6bb1b9 15 for (;it != r->end();it++) {
networker 0:7493bf6bb1b9 16 printf(" 0x%04X: %s\n", (*it).first, (*it).second->asString());
networker 0:7493bf6bb1b9 17 }
networker 0:7493bf6bb1b9 18 }
networker 0:7493bf6bb1b9 19
networker 4:d5c3e499603d 20 #define BROWSEGROUP 0x1001
networker 1:70ee392bcfd4 21 #define BROWSEROOT 0x1002
networker 1:70ee392bcfd4 22 #define SERIALSERV 0x1101
networker 1:70ee392bcfd4 23
networker 3:e8d2ebb7392e 24 SDPHandler::SDPHandler(): txid(1), tree(0) {
networker 3:e8d2ebb7392e 25 ErrorResponse=errorhandler;
networker 3:e8d2ebb7392e 26 ServiceSearchResponse=0;
networker 3:e8d2ebb7392e 27 ServiceAttributeResponse=attribHandler;
networker 3:e8d2ebb7392e 28 ServiceSearchAttributeResponse=0;
networker 3:e8d2ebb7392e 29 buf = l2cap_buf+OFFSET;
networker 3:e8d2ebb7392e 30 contBuf = 0;
networker 3:e8d2ebb7392e 31 byteCount = 0;
networker 3:e8d2ebb7392e 32 contState[0] = 0;
networker 3:e8d2ebb7392e 33 _state = 0;
networker 3:e8d2ebb7392e 34 }
networker 3:e8d2ebb7392e 35
networker 3:e8d2ebb7392e 36 void SDPHandler::Clear() {
networker 3:e8d2ebb7392e 37 for (index = services.begin(); index != services.end(); index++) {//for all services
networker 3:e8d2ebb7392e 38 for (serv_rec::iterator it = index->second->begin(); it != index->second->end(); it++)//for all attributes
networker 3:e8d2ebb7392e 39 delete it->second; //delete the attribute value tree
networker 3:e8d2ebb7392e 40 delete (*index).second; //delete the attribute list
networker 3:e8d2ebb7392e 41 }
networker 3:e8d2ebb7392e 42 services.clear();//and empty the services list
networker 3:e8d2ebb7392e 43 }
networker 3:e8d2ebb7392e 44
networker 3:e8d2ebb7392e 45 //Called as: Socket_Open(SOCKET_SDP, addr, callback, userdata(this)) from SDPManager
networker 3:e8d2ebb7392e 46 //never called
networker 3:e8d2ebb7392e 47 int SDPHandler::Open(SocketInternal* sock, SocketAddrHdr* addr) {
networker 3:e8d2ebb7392e 48 printf("Successfully opened SDP socket %d\n", sock->ID);
networker 3:e8d2ebb7392e 49 sock->SetState(SocketState_Open);
networker 3:e8d2ebb7392e 50 sdp_socket = sock->ID;
networker 3:e8d2ebb7392e 51 return sdp_socket;
networker 3:e8d2ebb7392e 52 }
networker 3:e8d2ebb7392e 53
networker 3:e8d2ebb7392e 54 int SDPHandler::Send(SocketInternal* sock, const u8* data, int len) {
networker 3:e8d2ebb7392e 55 printf("SDPHandler::Send should not be called directly\n");
networker 3:e8d2ebb7392e 56 // return Socket_Send(_l2cap, data, len);
networker 3:e8d2ebb7392e 57 BTDevice *l2cap = (BTDevice*)sock->userData;
networker 3:e8d2ebb7392e 58 return l2cap->Send(sock, data, len);
networker 3:e8d2ebb7392e 59 }
networker 3:e8d2ebb7392e 60
networker 3:e8d2ebb7392e 61 int SDPHandler::Close(SocketInternal* sock) {
networker 3:e8d2ebb7392e 62 printf("SDPHandler::Close(%d)\n", sock->ID);
networker 3:e8d2ebb7392e 63 Clear();
networker 3:e8d2ebb7392e 64 // printf("SDP socket %d and L2CAP socket %d closed, freemem=%d\n", sock->ID, _l2cap, AvailableMemory(1));
networker 3:e8d2ebb7392e 65 int retval = 0;//Socket_Close(_l2cap);//could also keep it open for the next connection
networker 3:e8d2ebb7392e 66 return retval;
networker 3:e8d2ebb7392e 67 }
networker 3:e8d2ebb7392e 68
networker 3:e8d2ebb7392e 69 //this function is called when the L2CAP layer receives SDP packets (see SDPHandler::Open), userdata is the sdpmanager instance
networker 3:e8d2ebb7392e 70 void SDPHandler::OnSdpRsp(int socket, SocketState state, const u8* data, int len, void* userData) {
networker 3:e8d2ebb7392e 71 printf("\x1B[%dm", 35);
networker 3:e8d2ebb7392e 72 // printf("OnSdpRsp(socket=%d, state=%d, len=%d)\n", socket, state, len);
networker 3:e8d2ebb7392e 73 printf("SDPHandler::OnSdpRsp(socket=%d, state=%d, len=%d, freemem=%d\n", socket, state, len, AvailableMemory(1));
networker 3:e8d2ebb7392e 74 SDPHandler *self = (SDPHandler*)userData;
networker 3:e8d2ebb7392e 75 if (state == SocketState_Open) {
networker 3:e8d2ebb7392e 76 self->sdp_socket = socket;
networker 3:e8d2ebb7392e 77 self->OnSdpRsp(data, len);
networker 3:e8d2ebb7392e 78 } else if (state == SocketState_Closed) {
networker 3:e8d2ebb7392e 79 SDP.Destroy(socket);
networker 3:e8d2ebb7392e 80 }
networker 3:e8d2ebb7392e 81 printf("\x1B[%dm", 0);
networker 3:e8d2ebb7392e 82 }
networker 3:e8d2ebb7392e 83
networker 3:e8d2ebb7392e 84 //this function is called when the L2CAP layer receives SDP packets (see SDPHandler::Open), userdata is the sdpmanager instance
networker 3:e8d2ebb7392e 85 //void SDPHandler::OnSdpRsp(int socket, SocketState state, const u8* data, int len, void* userData) {
networker 3:e8d2ebb7392e 86 void SDPHandler::OnSdpRsp(const u8* data, int len) {
networker 3:e8d2ebb7392e 87 static sdp_data list(sdp_data::SEQUENCE);
networker 1:70ee392bcfd4 88 static sdp_data all(0x0000ffffU,4);
networker 2:d5a27b2d2e08 89 static sdp_data serviceID(0U, 2);
networker 2:d5a27b2d2e08 90 static sdp_data name(0x100U, 2);
networker 1:70ee392bcfd4 91 static sdp_data root(sdp_data::UUID, BROWSEROOT);
networker 1:70ee392bcfd4 92 static sdp_data req(sdp_data::SEQUENCE);
networker 1:70ee392bcfd4 93 static bool once = true;
networker 3:e8d2ebb7392e 94 // printf("_state=%d first=%d ", _state, once);
networker 1:70ee392bcfd4 95 if (once) {
networker 3:e8d2ebb7392e 96 list.add_element(&all);
networker 3:e8d2ebb7392e 97 //list.add_element(&serviceID);
networker 3:e8d2ebb7392e 98 //list.add_element(&name);
networker 3:e8d2ebb7392e 99 req.add_element(&root);
networker 3:e8d2ebb7392e 100 once = false;
networker 0:7493bf6bb1b9 101 }
networker 3:e8d2ebb7392e 102 if (data) {
networker 1:70ee392bcfd4 103 parseRsp(data, len);
networker 3:e8d2ebb7392e 104 }
networker 1:70ee392bcfd4 105 switch (_state) {
networker 1:70ee392bcfd4 106 case 0: //closed
networker 1:70ee392bcfd4 107 if (len==0) { //socket just opened
networker 1:70ee392bcfd4 108 //'Open' cleared the services list
networker 2:d5a27b2d2e08 109 ServiceSearchRequest(&req, 10);
networker 1:70ee392bcfd4 110 _state = 1; //wait for service handles
networker 1:70ee392bcfd4 111 }
networker 1:70ee392bcfd4 112 break;
networker 1:70ee392bcfd4 113 case 1: //service handles arriving
networker 1:70ee392bcfd4 114 if (contState[0]) {//continuation, repeat request
networker 1:70ee392bcfd4 115 ServiceSearchRequest(&req, 5);
networker 1:70ee392bcfd4 116 } else {
networker 1:70ee392bcfd4 117 if (data[0]==3) {
networker 1:70ee392bcfd4 118 index = services.begin();
networker 1:70ee392bcfd4 119 if (index != services.end()) {
networker 1:70ee392bcfd4 120 unsigned handle = (*index).first;
networker 2:d5a27b2d2e08 121 //printf("req.: handle %#X\n", handle);
networker 1:70ee392bcfd4 122 ServiceAttributeRequest(handle, 100, &list);//0x1001D
networker 3:e8d2ebb7392e 123 } else
networker 1:70ee392bcfd4 124 printf(" - empty list - \n");//should not happen
networker 1:70ee392bcfd4 125 _state = 2; //wait for attribute response
networker 3:e8d2ebb7392e 126 } else
networker 1:70ee392bcfd4 127 printf("Expected a ServiceSearchResponse 0x03, got %#x\n", data[0]);
networker 1:70ee392bcfd4 128 }
networker 1:70ee392bcfd4 129 break;
networker 1:70ee392bcfd4 130 case 2:
networker 1:70ee392bcfd4 131 if (contState[0])//repeat request
networker 1:70ee392bcfd4 132 ServiceAttributeRequest((*index).first, 100, &list);
networker 1:70ee392bcfd4 133 else {
networker 1:70ee392bcfd4 134 if (data[0]==5) {
networker 1:70ee392bcfd4 135 index++; //move to next service
networker 1:70ee392bcfd4 136 if (index != services.end()) {
networker 2:d5a27b2d2e08 137 //printf("req.: handle %#X\n", (*index).first);
networker 1:70ee392bcfd4 138 ServiceAttributeRequest((*index).first, 100, &list);
networker 1:70ee392bcfd4 139 } else {
networker 1:70ee392bcfd4 140 printf(" - end of list - \n");
networker 1:70ee392bcfd4 141 Socket_Close(sdp_socket); //Note: socket=L2CAP, sdp_socket=SDP !!!
networker 1:70ee392bcfd4 142 _state = 0;
networker 1:70ee392bcfd4 143 }
networker 3:e8d2ebb7392e 144 } else
networker 1:70ee392bcfd4 145 printf("Expected a ServiceAttributeResponse 0x05, got %#x\n", data[0]);
networker 1:70ee392bcfd4 146 }
networker 1:70ee392bcfd4 147 break;
networker 1:70ee392bcfd4 148 }
networker 0:7493bf6bb1b9 149 }
networker 0:7493bf6bb1b9 150
networker 0:7493bf6bb1b9 151 //this function is called when the SDP sockets receives data (see HCICallback in TestShell),
networker 0:7493bf6bb1b9 152 //currently does not happen because not forwarded from OnSdpRsp, can be used to handle multiple connections
networker 3:e8d2ebb7392e 153 void SDPHandler::OnSockCallback(int socket, SocketState state, const u8* data, int len, void* userData) {
networker 3:e8d2ebb7392e 154 printf("SDPHandler::OnSockCallback(socket=%d, state=%d, len=%d)\n", socket, state, len);
networker 0:7493bf6bb1b9 155 printfBytes("Got SDP Response from socket: ", data, len);
networker 0:7493bf6bb1b9 156 }
networker 0:7493bf6bb1b9 157
networker 3:e8d2ebb7392e 158 //void SDPHandler::errorhandler(unsigned err) {//default error handler
networker 3:e8d2ebb7392e 159 void errorhandler(unsigned err) {//default error handler
networker 0:7493bf6bb1b9 160 switch (err) {
networker 0:7493bf6bb1b9 161 case 1:
networker 0:7493bf6bb1b9 162 printf("Unsupported version of SDP\n");
networker 0:7493bf6bb1b9 163 break;
networker 0:7493bf6bb1b9 164 case 2:
networker 0:7493bf6bb1b9 165 printf("Invalid SDP ServiceRecordHandle\n");
networker 0:7493bf6bb1b9 166 break;
networker 0:7493bf6bb1b9 167 case 3:
networker 0:7493bf6bb1b9 168 printf("SDP syntax error\n");
networker 0:7493bf6bb1b9 169 break;
networker 0:7493bf6bb1b9 170 case 4:
networker 0:7493bf6bb1b9 171 printf("PDU size was invalid\n");
networker 0:7493bf6bb1b9 172 break;
networker 0:7493bf6bb1b9 173 case 5:
networker 0:7493bf6bb1b9 174 printf("Continuation state was invalid\n");
networker 0:7493bf6bb1b9 175 break;
networker 0:7493bf6bb1b9 176 case 6:
networker 0:7493bf6bb1b9 177 printf("SDP server has insufficient resources\n");
networker 0:7493bf6bb1b9 178 break;
networker 0:7493bf6bb1b9 179 default:
networker 0:7493bf6bb1b9 180 printf("Unknown SDP error code\n");
networker 0:7493bf6bb1b9 181 break;
networker 0:7493bf6bb1b9 182 }
networker 0:7493bf6bb1b9 183 }
networker 0:7493bf6bb1b9 184
networker 3:e8d2ebb7392e 185 int SDPHandler::ServiceSearchRequest(sdp_data *sp, unsigned count, unsigned cs) {
networker 1:70ee392bcfd4 186 int parlen = sp->Size() + contState[0] + 3;
networker 0:7493bf6bb1b9 187 buf[0] = 2; //pdu
networker 0:7493bf6bb1b9 188 buf[1] = txid>>8;
networker 0:7493bf6bb1b9 189 buf[2] = txid++;
networker 0:7493bf6bb1b9 190 buf[4] = parlen;
networker 0:7493bf6bb1b9 191 buf[3] = parlen>>8;
networker 0:7493bf6bb1b9 192 int p = sp->build(buf+5, 100-10);
networker 0:7493bf6bb1b9 193 buf[p+6] = count;
networker 0:7493bf6bb1b9 194 buf[p+5] = count>>8;
networker 1:70ee392bcfd4 195 buf[p+7] = contState[0];
networker 1:70ee392bcfd4 196 for (int j = 1; j <= contState[0]; j++)
networker 1:70ee392bcfd4 197 buf[p+j+7] = contState[j];
networker 0:7493bf6bb1b9 198 //printfBytes("SDP Send: ", buf, parlen+5);
networker 3:e8d2ebb7392e 199 return Socket_Send(sdp_socket, l2cap_buf, parlen + 5 + OFFSET);
networker 0:7493bf6bb1b9 200 }
networker 0:7493bf6bb1b9 201
networker 3:e8d2ebb7392e 202 int SDPHandler::ServiceAttributeRequest(unsigned handle, unsigned count, sdp_data* al, unsigned cs) {
networker 1:70ee392bcfd4 203 int parlen = al->Size() + contState[0] + 7;
networker 0:7493bf6bb1b9 204 buf[0] = 4; //pdu
networker 0:7493bf6bb1b9 205 buf[1] = txid>>8;
networker 0:7493bf6bb1b9 206 buf[2] = txid++;
networker 0:7493bf6bb1b9 207 buf[4] = parlen;
networker 0:7493bf6bb1b9 208 buf[3] = parlen>>8;
networker 0:7493bf6bb1b9 209 for (int i = 0; i < 4; i++)
networker 0:7493bf6bb1b9 210 buf[i+5] = ((char*)&handle)[3-i];
networker 0:7493bf6bb1b9 211 buf[9] = count>>8;
networker 0:7493bf6bb1b9 212 buf[10] = count;
networker 0:7493bf6bb1b9 213 int p = al->build(buf+11, 100-26);
networker 1:70ee392bcfd4 214 buf[p+11] = contState[0];
networker 1:70ee392bcfd4 215 for (int j = 1; j <= contState[0]; j++)
networker 1:70ee392bcfd4 216 buf[p+j+11] = contState[j];
networker 0:7493bf6bb1b9 217 //printfBytes("SDP Send: ", buf, parlen+5);
networker 3:e8d2ebb7392e 218 return Socket_Send(sdp_socket, l2cap_buf, parlen + 5 + OFFSET);
networker 0:7493bf6bb1b9 219 }
networker 0:7493bf6bb1b9 220
networker 3:e8d2ebb7392e 221 int SDPHandler::ServiceSearchAttributeRequest(sdp_data *sp, unsigned count, sdp_data* al, unsigned cs) {
networker 1:70ee392bcfd4 222 int parlen = sp->Size() + al->Size() + contState[0] + 3; // count (2 bytes) + at least 1 cont
networker 0:7493bf6bb1b9 223 buf[0] = 6; //pdu
networker 0:7493bf6bb1b9 224 buf[1] = txid>>8;
networker 0:7493bf6bb1b9 225 buf[2] = txid++;
networker 0:7493bf6bb1b9 226 buf[4] = parlen;
networker 0:7493bf6bb1b9 227 buf[3] = parlen>>8;
networker 0:7493bf6bb1b9 228 int p = sp->build(buf+5, 30);
networker 0:7493bf6bb1b9 229 buf[p+6] = count;
networker 0:7493bf6bb1b9 230 buf[p+5] = count>>8;
networker 0:7493bf6bb1b9 231 p += al->build(buf+11, 100-38);
networker 1:70ee392bcfd4 232 buf[p+7] = contState[0];
networker 1:70ee392bcfd4 233 for (int j = 1; j <= contState[0]; j++)
networker 1:70ee392bcfd4 234 buf[p+j+7] = contState[j];
networker 0:7493bf6bb1b9 235 //printfBytes("SDP Send: ", buf, parlen+5);
networker 3:e8d2ebb7392e 236 return Socket_Send(sdp_socket, l2cap_buf, parlen + 5 + OFFSET);
networker 0:7493bf6bb1b9 237 }
networker 0:7493bf6bb1b9 238
networker 4:d5c3e499603d 239 unsigned BE32(unsigned le) {
networker 4:d5c3e499603d 240 unsigned be=0;
networker 4:d5c3e499603d 241 for (int i = 0; i < 32; i+=8){
networker 4:d5c3e499603d 242 be |= ((le>>i)&0xFFU)<<(24-i);
networker 4:d5c3e499603d 243 }
networker 4:d5c3e499603d 244 return be;
networker 4:d5c3e499603d 245 }
networker 4:d5c3e499603d 246
networker 4:d5c3e499603d 247 int SDPManager::ServiceSearchReply(unsigned rxid, unsigned *handles, unsigned count, unsigned cs) {//'count' is number of matching handles and capped at the maximumservicerecordcount
networker 4:d5c3e499603d 248 unsigned size = count*4;
networker 4:d5c3e499603d 249 unsigned cont = 0;//outgoing continuation
networker 4:d5c3e499603d 250 unsigned char *_buf = new unsigned char[OFFSET+5+4+size+3];
networker 4:d5c3e499603d 251 unsigned char *buf = _buf+OFFSET;
networker 4:d5c3e499603d 252 unsigned current = count - cs; //remainder of data to send
networker 4:d5c3e499603d 253 unsigned parlen = 4 + 4*current + 1 ;// attributelistbytecount+payload+no_continuation
networker 4:d5c3e499603d 254 //never need a continuation unless other criterion like PDU size is used
networker 4:d5c3e499603d 255 if (current > count) {//still too large, need continuation
networker 4:d5c3e499603d 256 current = count; //limit at maximum
networker 4:d5c3e499603d 257 cont = cs + count; //start for next iteration
networker 4:d5c3e499603d 258 parlen = 4 + 4*current + 3; //adjusted for payload and continuation
networker 4:d5c3e499603d 259 printf("Need continuation, sending handles [%d, %d> of attributeList\n", cs, cont);
networker 4:d5c3e499603d 260 } else {
networker 4:d5c3e499603d 261 // printf("Final or only block, sending bytes [%d, %d> of attributeList\n", cs, cs+byteCount);
networker 4:d5c3e499603d 262 }
networker 4:d5c3e499603d 263 buf[0] = 3; //pdu
networker 4:d5c3e499603d 264 buf[1] = rxid>>8;
networker 4:d5c3e499603d 265 buf[2] = rxid;
networker 4:d5c3e499603d 266 buf[3] = parlen>>8;
networker 4:d5c3e499603d 267 buf[4] = parlen;
networker 4:d5c3e499603d 268 buf[5] = count>>8;
networker 4:d5c3e499603d 269 buf[6] = count;
networker 4:d5c3e499603d 270 buf[7] = current>>8;
networker 4:d5c3e499603d 271 buf[8] = current;
networker 4:d5c3e499603d 272 unsigned *p = (unsigned*)&buf[9];
networker 4:d5c3e499603d 273 for (int i = 0; i < current; i++)
networker 4:d5c3e499603d 274 p[i] = BE32(handles[i]);
networker 4:d5c3e499603d 275 //printf("'build' added %d bytes to the buffer\n", p);
networker 4:d5c3e499603d 276 if (cs == 0) { //this is not a continuation
networker 4:d5c3e499603d 277 buf[5+parlen-1] = 0;
networker 4:d5c3e499603d 278 } else { //this is a continuation
networker 4:d5c3e499603d 279 memcpy(buf+9, buf+9+cs*4, current*4);//move part of interrest to beginning of buffer
networker 4:d5c3e499603d 280 buf[5+parlen-3] = 2;
networker 4:d5c3e499603d 281 buf[5+parlen-2] = cont>>8;
networker 4:d5c3e499603d 282 buf[5+parlen-1] = cont;
networker 4:d5c3e499603d 283 }
networker 4:d5c3e499603d 284 //printfBytes("SDP Send: ", buf, parlen+5);
networker 4:d5c3e499603d 285 int retval = Socket_Send(serverSock, _buf, parlen + 5 + OFFSET);
networker 4:d5c3e499603d 286 delete[] _buf;
networker 4:d5c3e499603d 287 return retval;
networker 4:d5c3e499603d 288 }
networker 4:d5c3e499603d 289
networker 4:d5c3e499603d 290 int SDPManager::ServiceAttributeReply(unsigned rxid, sdp_data* al, unsigned count, unsigned cs) {
networker 4:d5c3e499603d 291 unsigned size = al->Size();
networker 4:d5c3e499603d 292 unsigned cont = 0;//outgoing continuation
networker 4:d5c3e499603d 293 unsigned char *_buf = new unsigned char[OFFSET+5+2+size+3];
networker 4:d5c3e499603d 294 unsigned char *buf = _buf+OFFSET;
networker 4:d5c3e499603d 295 unsigned byteCount = size - cs; //remainder of data to send
networker 4:d5c3e499603d 296 unsigned parlen = 2 + byteCount + 1 ;// attributelistbytecount+payload+no_continuation
networker 4:d5c3e499603d 297 if (byteCount > count) {//still too large, need continuation
networker 4:d5c3e499603d 298 byteCount = count; //limit at maximum
networker 4:d5c3e499603d 299 cont = cs + count; //start for next iteration
networker 4:d5c3e499603d 300 parlen = 2 + byteCount + 3; //adjusted for payload and continuation
networker 4:d5c3e499603d 301 printf("Need continuation, sending bytes [%d, %d> of attributeList\n", cs, cont);
networker 4:d5c3e499603d 302 } else {
networker 4:d5c3e499603d 303 // printf("Final or only block, sending bytes [%d, %d> of attributeList\n", cs, cs+byteCount);
networker 4:d5c3e499603d 304 }
networker 4:d5c3e499603d 305 buf[0] = 5; //pdu
networker 4:d5c3e499603d 306 buf[1] = rxid>>8;
networker 4:d5c3e499603d 307 buf[2] = rxid;
networker 4:d5c3e499603d 308 buf[3] = parlen>>8;
networker 4:d5c3e499603d 309 buf[4] = parlen;
networker 4:d5c3e499603d 310 buf[5] = byteCount>>8;
networker 4:d5c3e499603d 311 buf[6] = byteCount;
networker 4:d5c3e499603d 312 int p = al->build(buf+7, size);//limited only by buffersize
networker 4:d5c3e499603d 313 //printf("'build' added %d bytes to the buffer\n", p);
networker 4:d5c3e499603d 314 if (cs == 0) { //this is not a continuation
networker 4:d5c3e499603d 315 buf[byteCount+7] = 0;
networker 4:d5c3e499603d 316 } else { //this is a continuation
networker 4:d5c3e499603d 317 memcpy(buf+7, buf+7+cs, byteCount);//move part of interrest to beginning of buffer
networker 4:d5c3e499603d 318 buf[byteCount+7] = 2;
networker 4:d5c3e499603d 319 buf[byteCount+8] = cont>>8;
networker 4:d5c3e499603d 320 buf[byteCount+9] = cont;
networker 4:d5c3e499603d 321 }
networker 4:d5c3e499603d 322 //printfBytes("SDP Send: ", buf, parlen+5);
networker 4:d5c3e499603d 323 int retval = Socket_Send(serverSock, _buf, parlen + 5 + OFFSET);
networker 4:d5c3e499603d 324 delete[] _buf;
networker 4:d5c3e499603d 325 return retval;
networker 4:d5c3e499603d 326 }
networker 4:d5c3e499603d 327
networker 3:e8d2ebb7392e 328 int SDPManager::ServiceSearchAttributeReply(unsigned rxid, sdp_data* al, unsigned count, unsigned cs) {
networker 3:e8d2ebb7392e 329 unsigned size = al->Size();
networker 3:e8d2ebb7392e 330 unsigned cont = 0;//outgoing continuation
networker 3:e8d2ebb7392e 331 unsigned char *_buf = new unsigned char[OFFSET+5+2+size+3];
networker 3:e8d2ebb7392e 332 unsigned char *buf = _buf+OFFSET;
networker 3:e8d2ebb7392e 333 unsigned byteCount = size - cs; //remainder of data to send
networker 3:e8d2ebb7392e 334 unsigned parlen = 2 + byteCount + 1 ;// attributelistbytecount+payload+no_continuation
networker 3:e8d2ebb7392e 335 if (byteCount > count) {//still too large, need continuation
networker 3:e8d2ebb7392e 336 byteCount = count; //limit at maximum
networker 3:e8d2ebb7392e 337 cont = cs + count; //start for next iteration
networker 3:e8d2ebb7392e 338 parlen = 2 + byteCount + 3; //adjusted for payload and continuation
networker 3:e8d2ebb7392e 339 printf("Need continuation, sending bytes [%d, %d> of attributeList\n", cs, cont);
networker 3:e8d2ebb7392e 340 } else {
networker 4:d5c3e499603d 341 // printf("Final or only block, sending bytes [%d, %d> of attributeList\n", cs, cs+byteCount);
networker 3:e8d2ebb7392e 342 }
networker 3:e8d2ebb7392e 343 buf[0] = 7; //pdu
networker 3:e8d2ebb7392e 344 buf[1] = rxid>>8;
networker 3:e8d2ebb7392e 345 buf[2] = rxid;
networker 3:e8d2ebb7392e 346 buf[3] = parlen>>8;
networker 3:e8d2ebb7392e 347 buf[4] = parlen;
networker 3:e8d2ebb7392e 348 buf[5] = byteCount>>8;
networker 3:e8d2ebb7392e 349 buf[6] = byteCount;
networker 3:e8d2ebb7392e 350 int p = al->build(buf+7, size);//limited only by buffersize
networker 3:e8d2ebb7392e 351 //printf("'build' added %d bytes to the buffer\n", p);
networker 3:e8d2ebb7392e 352 if (cs == 0) { //this is not a continuation
networker 3:e8d2ebb7392e 353 buf[byteCount+7] = 0;
networker 3:e8d2ebb7392e 354 } else { //this is a continuation
networker 3:e8d2ebb7392e 355 memcpy(buf+7, buf+7+cs, byteCount);//move part of interrest to beginning of buffer
networker 3:e8d2ebb7392e 356 buf[byteCount+7] = 2;
networker 3:e8d2ebb7392e 357 buf[byteCount+8] = cont>>8;
networker 3:e8d2ebb7392e 358 buf[byteCount+9] = cont;
networker 3:e8d2ebb7392e 359 }
networker 3:e8d2ebb7392e 360 //printfBytes("SDP Send: ", buf, parlen+5);
networker 3:e8d2ebb7392e 361 int retval = Socket_Send(serverSock, _buf, parlen + 5 + OFFSET);
networker 3:e8d2ebb7392e 362 delete[] _buf;
networker 3:e8d2ebb7392e 363 return retval;
networker 3:e8d2ebb7392e 364 }
networker 3:e8d2ebb7392e 365
networker 3:e8d2ebb7392e 366 //unsigned SDPHandler::getval(const unsigned char *p, int n) {
networker 3:e8d2ebb7392e 367 unsigned getval(const unsigned char *p, int n) {
networker 0:7493bf6bb1b9 368 unsigned ret = 0;
networker 0:7493bf6bb1b9 369 for (int i = 0; i < n; i++)
networker 0:7493bf6bb1b9 370 ret = (ret<<8) + (unsigned)p[i];
networker 0:7493bf6bb1b9 371 return ret;
networker 0:7493bf6bb1b9 372 }
networker 0:7493bf6bb1b9 373
networker 3:e8d2ebb7392e 374 //unsigned SDPHandler::length(const unsigned char *el, unsigned &p) {
networker 3:e8d2ebb7392e 375 unsigned length(const unsigned char *el, unsigned &p) {
networker 0:7493bf6bb1b9 376 unsigned len = 0;
networker 0:7493bf6bb1b9 377 switch (el[p++] & 7) {//length
networker 0:7493bf6bb1b9 378 case 0:
networker 0:7493bf6bb1b9 379 len = 1;
networker 0:7493bf6bb1b9 380 break;
networker 0:7493bf6bb1b9 381 case 1:
networker 0:7493bf6bb1b9 382 len = 2;
networker 0:7493bf6bb1b9 383 break;
networker 0:7493bf6bb1b9 384 case 2:
networker 0:7493bf6bb1b9 385 len = 4;
networker 0:7493bf6bb1b9 386 break;
networker 0:7493bf6bb1b9 387 case 3:
networker 0:7493bf6bb1b9 388 len = 8;
networker 0:7493bf6bb1b9 389 break;
networker 0:7493bf6bb1b9 390 case 4:
networker 0:7493bf6bb1b9 391 len = 16;
networker 0:7493bf6bb1b9 392 break;
networker 0:7493bf6bb1b9 393 case 7://4bytes
networker 0:7493bf6bb1b9 394 len= el[p++]<<24;
networker 0:7493bf6bb1b9 395 len += el[p++]<<16;
networker 0:7493bf6bb1b9 396 case 6://2bytes
networker 0:7493bf6bb1b9 397 len += el[p++]<<8;
networker 0:7493bf6bb1b9 398 case 5://1byte
networker 0:7493bf6bb1b9 399 len += el[p++];
networker 0:7493bf6bb1b9 400 break;
networker 0:7493bf6bb1b9 401 }
networker 0:7493bf6bb1b9 402 return len;
networker 0:7493bf6bb1b9 403 }
networker 0:7493bf6bb1b9 404
networker 1:70ee392bcfd4 405 extern "C" void HardFault_Handler() {
networker 1:70ee392bcfd4 406 printf("Hard Fault! %d bytes left\n", AvailableMemory(1));
networker 1:70ee392bcfd4 407 while (1);
networker 1:70ee392bcfd4 408 }
networker 0:7493bf6bb1b9 409
networker 3:e8d2ebb7392e 410 unsigned SDPHandler::parseLight (const unsigned char *el, unsigned count, sdp_data* &result, serv_rec* &record) {
networker 1:70ee392bcfd4 411 unsigned p = 0;
networker 1:70ee392bcfd4 412 unsigned len = length(el, p);
networker 1:70ee392bcfd4 413 int end = p+len;//end is the index of the item just after the sequence
networker 1:70ee392bcfd4 414 sdp_data *item = 0;
networker 1:70ee392bcfd4 415 switch (el[0]>>3) {//type
networker 1:70ee392bcfd4 416 case sdp_data::NULL_:
networker 1:70ee392bcfd4 417 printf("NULL ");
networker 1:70ee392bcfd4 418 break;
networker 1:70ee392bcfd4 419 case sdp_data::UNSIGNED:
networker 1:70ee392bcfd4 420 printf("UINT%d=%u ", len, (unsigned)getval(el+p, len));
networker 1:70ee392bcfd4 421 break;
networker 1:70ee392bcfd4 422 case sdp_data::SIGNED:
networker 1:70ee392bcfd4 423 printf("INT%d=%d ", len, (unsigned)getval(el+p, len));
networker 1:70ee392bcfd4 424 break;
networker 1:70ee392bcfd4 425 case sdp_data::UUID:
networker 1:70ee392bcfd4 426 if (len==16) {
networker 1:70ee392bcfd4 427 printf("UUID16= ");
networker 1:70ee392bcfd4 428 for (int i = 0; i < 16; i++)
networker 1:70ee392bcfd4 429 printf("%02x ", el[p+i]);
networker 1:70ee392bcfd4 430 } else
networker 1:70ee392bcfd4 431 printf("UUID%d=%u ", len, (unsigned)getval(el+p, len));
networker 1:70ee392bcfd4 432 break;
networker 1:70ee392bcfd4 433 case sdp_data::STRING:
networker 1:70ee392bcfd4 434 printf("STR%d='%s' ", len, (char*)el+p);
networker 1:70ee392bcfd4 435 break;
networker 1:70ee392bcfd4 436 case sdp_data::BOOL:
networker 1:70ee392bcfd4 437 printf("BOOL%d=%d ", len, (unsigned)getval(el+p, len));
networker 1:70ee392bcfd4 438 break;
networker 1:70ee392bcfd4 439 case sdp_data::SEQUENCE:
networker 1:70ee392bcfd4 440 goto skip;
networker 1:70ee392bcfd4 441 case sdp_data::ALTERNATIVE:
networker 1:70ee392bcfd4 442 skip: {//p points just after the length indicator, hence at the first item IN the sequence
networker 3:e8d2ebb7392e 443 printf("SEQ%d{%p ", len, item);
networker 1:70ee392bcfd4 444 int n = 0;
networker 1:70ee392bcfd4 445 unsigned short key;
networker 1:70ee392bcfd4 446 serv_rec *dummy = 0;
networker 1:70ee392bcfd4 447 while (p < end) {
networker 1:70ee392bcfd4 448 sdp_data *elem = 0;
networker 1:70ee392bcfd4 449 p += parseLight(el + p, len-p, elem, dummy);//parse each element in the sequence, the second arg is as yet unused
networker 1:70ee392bcfd4 450 if (record) {
networker 1:70ee392bcfd4 451 if (n & 1) { //value
networker 1:70ee392bcfd4 452 record->insert(pair<unsigned short, sdp_data*>(key, elem));
networker 1:70ee392bcfd4 453 } else //key
networker 1:70ee392bcfd4 454 key = n;
networker 1:70ee392bcfd4 455 n++;
networker 1:70ee392bcfd4 456 }
networker 1:70ee392bcfd4 457 }
networker 1:70ee392bcfd4 458 }
networker 1:70ee392bcfd4 459 printf("}\n");
networker 1:70ee392bcfd4 460 break;
networker 1:70ee392bcfd4 461 case 8:
networker 1:70ee392bcfd4 462 printf("URL%d='%s' ", len, (char*)el+p);
networker 1:70ee392bcfd4 463 break;
networker 1:70ee392bcfd4 464 default:
networker 1:70ee392bcfd4 465 printf("Parse: Unknown type %d, len=%d (code=%#02X)\n", el[0]>>3, len, el[0]);
networker 1:70ee392bcfd4 466 }
networker 1:70ee392bcfd4 467 result = item;
networker 1:70ee392bcfd4 468 return end;
networker 1:70ee392bcfd4 469 }
networker 0:7493bf6bb1b9 470
networker 3:e8d2ebb7392e 471 unsigned SDPHandler::parse (const unsigned char *el, unsigned count, sdp_data* &result, serv_rec* &record) {
networker 0:7493bf6bb1b9 472 unsigned p = 0;
networker 0:7493bf6bb1b9 473 unsigned len = length(el, p);
networker 0:7493bf6bb1b9 474 int end = p+len;//end is the index of the item just after the sequence
networker 0:7493bf6bb1b9 475 sdp_data *item = 0;
networker 0:7493bf6bb1b9 476 switch (el[0]>>3) {//type
networker 0:7493bf6bb1b9 477 case sdp_data::NULL_:
networker 0:7493bf6bb1b9 478 item = new sdp_data();
networker 0:7493bf6bb1b9 479 break;
networker 0:7493bf6bb1b9 480 case sdp_data::UNSIGNED:
networker 0:7493bf6bb1b9 481 item = new sdp_data((unsigned)getval(el+p, len), len);
networker 0:7493bf6bb1b9 482 break;
networker 0:7493bf6bb1b9 483 case sdp_data::SIGNED:
networker 0:7493bf6bb1b9 484 item = new sdp_data((int)getval(el+p, len), len);
networker 0:7493bf6bb1b9 485 break;
networker 0:7493bf6bb1b9 486 case sdp_data::UUID:
networker 0:7493bf6bb1b9 487 if (len==16) {
networker 0:7493bf6bb1b9 488 char rev[16];
networker 0:7493bf6bb1b9 489 for (int i = 0; i < 16; i++)
networker 0:7493bf6bb1b9 490 rev[i] = el[p+15-i];
networker 0:7493bf6bb1b9 491 item = new sdp_data(sdp_data::UUID, rev, len);
networker 0:7493bf6bb1b9 492 } else
networker 0:7493bf6bb1b9 493 item = new sdp_data(sdp_data::UUID, getval(el+p, len), len);
networker 0:7493bf6bb1b9 494 break;
networker 0:7493bf6bb1b9 495 case sdp_data::STRING:
networker 0:7493bf6bb1b9 496 item = new sdp_data((char*)el+p, len);
networker 0:7493bf6bb1b9 497 break;
networker 0:7493bf6bb1b9 498 case sdp_data::BOOL:
networker 0:7493bf6bb1b9 499 item = new sdp_data((bool)getval(el+p, len), len);
networker 0:7493bf6bb1b9 500 break;
networker 0:7493bf6bb1b9 501 case sdp_data::SEQUENCE:
networker 0:7493bf6bb1b9 502 item = new sdp_data(sdp_data::SEQUENCE);
networker 0:7493bf6bb1b9 503 goto skip;
networker 0:7493bf6bb1b9 504 case sdp_data::ALTERNATIVE:
networker 0:7493bf6bb1b9 505 item = new sdp_data(sdp_data::ALTERNATIVE);
networker 0:7493bf6bb1b9 506 skip: {//p points just after the length indicator, hence at the first item IN the sequence
networker 2:d5a27b2d2e08 507 //printf("SEQ%d{%p ", len, item);
networker 0:7493bf6bb1b9 508 int n = 0;
networker 0:7493bf6bb1b9 509 unsigned short key;
networker 2:d5a27b2d2e08 510 serv_rec *dummy = 0;//means: there is no service record to fill in for deeper levels
networker 0:7493bf6bb1b9 511 while (p < end) {
networker 2:d5a27b2d2e08 512 sdp_data *elem = 0; //this becomes the tree with attribute values
networker 0:7493bf6bb1b9 513 p += parse(el + p, len-p, elem, dummy);//parse each element in the sequence, the second arg is as yet unused
networker 2:d5a27b2d2e08 514 if (record) { //if at the level of attribute list, add elem to record as key/value pair
networker 0:7493bf6bb1b9 515 if (n & 1) { //value
networker 0:7493bf6bb1b9 516 record->insert(pair<unsigned short, sdp_data*>(key, elem));
networker 0:7493bf6bb1b9 517 } else //key
networker 0:7493bf6bb1b9 518 key = elem->asUnsigned();
networker 0:7493bf6bb1b9 519 n++;
networker 2:d5a27b2d2e08 520 } else //just add the elements to the value tree
networker 2:d5a27b2d2e08 521 item->add_element(elem);
networker 0:7493bf6bb1b9 522 }
networker 0:7493bf6bb1b9 523 }
networker 1:70ee392bcfd4 524 //printf("}\n");
networker 0:7493bf6bb1b9 525 break;
networker 0:7493bf6bb1b9 526 case 8:
networker 0:7493bf6bb1b9 527 item = new sdp_data(sdp_data::URL, (char*)el+p, len);
networker 0:7493bf6bb1b9 528 break;
networker 0:7493bf6bb1b9 529 default:
networker 0:7493bf6bb1b9 530 printf("Parse: Unknown type %d, len=%d (code=%#02X)\n", el[0]>>3, len, el[0]);
networker 0:7493bf6bb1b9 531 }
networker 0:7493bf6bb1b9 532 result = item;
networker 0:7493bf6bb1b9 533 return end;
networker 0:7493bf6bb1b9 534 }
networker 0:7493bf6bb1b9 535
networker 3:e8d2ebb7392e 536 void SDPHandler::append(const unsigned char *payload, int len) {
networker 1:70ee392bcfd4 537 unsigned char *tmp = new unsigned char[byteCount + len];//append the payload to the previous continuation buffer
networker 1:70ee392bcfd4 538 if (contBuf && byteCount) {
networker 3:e8d2ebb7392e 539 memcpy(tmp, contBuf, byteCount); //copy the existing part
networker 3:e8d2ebb7392e 540 delete[] contBuf;//delete the old buffer
networker 1:70ee392bcfd4 541 }
networker 1:70ee392bcfd4 542 memcpy(tmp+byteCount, payload, len); //append the new part
networker 1:70ee392bcfd4 543 contBuf = tmp;
networker 1:70ee392bcfd4 544 byteCount += len;
networker 1:70ee392bcfd4 545 }
networker 1:70ee392bcfd4 546
networker 3:e8d2ebb7392e 547 void SDPHandler::freeBuf() {
networker 1:70ee392bcfd4 548 if (contBuf) {
networker 3:e8d2ebb7392e 549 delete[] contBuf;
networker 3:e8d2ebb7392e 550 contBuf = 0;
networker 1:70ee392bcfd4 551 }
networker 1:70ee392bcfd4 552 byteCount = 0;
networker 1:70ee392bcfd4 553 }
networker 1:70ee392bcfd4 554
networker 2:d5a27b2d2e08 555
networker 2:d5a27b2d2e08 556 //TODO: test case 7, add server support (cases 2, 4, 6)
networker 2:d5a27b2d2e08 557 //3 cases: cont==0 && contBuf==0 -> use rsp; cont!=0 -> append; cont==0 && contBuf!=0 -> append and use contBuf
networker 3:e8d2ebb7392e 558 int SDPHandler::parseRsp(const unsigned char*rsp, int len) {
networker 3:e8d2ebb7392e 559 //unsigned tid = rsp[2] + ((unsigned)rsp[1]<<8);
networker 0:7493bf6bb1b9 560 unsigned parlen = rsp[4] + ((unsigned)rsp[3]<<8);
networker 2:d5a27b2d2e08 561 //printf("ParseRsp: tid=%04X, parlen=%d ", tid, parlen);
networker 0:7493bf6bb1b9 562 unsigned cont = 0;
networker 0:7493bf6bb1b9 563 switch (rsp[0]) {
networker 0:7493bf6bb1b9 564 case 1: {//errorRsp
networker 0:7493bf6bb1b9 565 unsigned errorcode = rsp[6] + ((unsigned)rsp[5]<<8);
networker 0:7493bf6bb1b9 566 if (parlen > 2) {
networker 0:7493bf6bb1b9 567 printf("ErrorInfo (%d bytes) for error %d is available\n", parlen-2, errorcode);
networker 0:7493bf6bb1b9 568 }
networker 0:7493bf6bb1b9 569 if (ErrorResponse)
networker 0:7493bf6bb1b9 570 ErrorResponse(errorcode);
networker 0:7493bf6bb1b9 571 return errorcode;
networker 0:7493bf6bb1b9 572 }
networker 0:7493bf6bb1b9 573 //break;
networker 0:7493bf6bb1b9 574 case 3: { //servicesearchRsp
networker 1:70ee392bcfd4 575 unsigned total = rsp[6] + ((unsigned)rsp[5]<<8);
networker 0:7493bf6bb1b9 576 unsigned current = rsp[8] + ((unsigned)rsp[7]<<8);
networker 0:7493bf6bb1b9 577 cont = rsp[9+4*current];
networker 1:70ee392bcfd4 578 memcpy(contState, &rsp[9+4*current], cont+1);//copy the continuation state
networker 3:e8d2ebb7392e 579 //printf("total=%d, current=%d, cont=%d\n", total, current, cont);
networker 1:70ee392bcfd4 580 if (cont) {
networker 1:70ee392bcfd4 581 //no special handling here, just append the servicerecordhandles
networker 1:70ee392bcfd4 582 }
networker 0:7493bf6bb1b9 583 //linear list of 32bit service-handles
networker 0:7493bf6bb1b9 584 for (int i = 0; i < current; i++) {
networker 0:7493bf6bb1b9 585 unsigned result = 0;
networker 0:7493bf6bb1b9 586 for (int j = 0; j< 4; j++)
networker 0:7493bf6bb1b9 587 result = (result<<8) + rsp[9 + 4*i + j];
networker 1:70ee392bcfd4 588 printf("SDP Search handle %08X\n", result);
networker 0:7493bf6bb1b9 589 services.insert(pair<unsigned, serv_rec*>(result, 0));
networker 0:7493bf6bb1b9 590 }
networker 0:7493bf6bb1b9 591 if (ServiceSearchResponse)
networker 0:7493bf6bb1b9 592 ServiceSearchResponse();
networker 0:7493bf6bb1b9 593 }
networker 0:7493bf6bb1b9 594 break;
networker 0:7493bf6bb1b9 595 case 5: { //serviceattributeRsp
networker 1:70ee392bcfd4 596 unsigned count = rsp[6] + ((unsigned)rsp[5]<<8);//bytes in this part of the attribute list
networker 2:d5a27b2d2e08 597 // append(rsp+7, count);
networker 0:7493bf6bb1b9 598 cont = rsp[7+count];
networker 1:70ee392bcfd4 599 memcpy(contState, &rsp[7+count], cont+1);//copy the continuation state
networker 2:d5a27b2d2e08 600 if (cont) {
networker 3:e8d2ebb7392e 601 append(rsp+7, count);
networker 3:e8d2ebb7392e 602 break;
networker 2:d5a27b2d2e08 603 }
networker 2:d5a27b2d2e08 604 //printf("count=%d parsing...\n", byteCount);
networker 0:7493bf6bb1b9 605 serv_rec *serv = new serv_rec;
networker 3:e8d2ebb7392e 606 if (contBuf) {
networker 3:e8d2ebb7392e 607 append(rsp+7, count);
networker 3:e8d2ebb7392e 608 parse(contBuf, byteCount, tree, serv);
networker 2:d5a27b2d2e08 609 } else
networker 3:e8d2ebb7392e 610 parse(rsp+7, count, tree, serv);
networker 2:d5a27b2d2e08 611 //printf("...parsing done, ");
networker 2:d5a27b2d2e08 612 //get the AttributeID, make sure attribId 0 is always included in the request
networker 2:d5a27b2d2e08 613 unsigned key = (*serv)[0]->asUnsigned();//AttributeID '0' always refers to the serviceID
networker 2:d5a27b2d2e08 614 //printf("Key=%#X\n", key); //key will be 0 when not requested
networker 2:d5a27b2d2e08 615 services[key] = serv; //Add the attribute list to the services
networker 1:70ee392bcfd4 616 freeBuf();
networker 0:7493bf6bb1b9 617 if (ServiceAttributeResponse)
networker 0:7493bf6bb1b9 618 ServiceAttributeResponse(serv);
networker 0:7493bf6bb1b9 619 }
networker 0:7493bf6bb1b9 620 break;
networker 1:70ee392bcfd4 621 //below is UNTESTED
networker 0:7493bf6bb1b9 622 case 7: { //servicesearchattributeRsp
networker 0:7493bf6bb1b9 623 unsigned count = rsp[6] + ((unsigned)rsp[5]<<8);
networker 1:70ee392bcfd4 624 append(rsp+7, count);
networker 0:7493bf6bb1b9 625 cont = rsp[7+count];
networker 1:70ee392bcfd4 626 memcpy(contState, &rsp[7+count], cont+1);
networker 0:7493bf6bb1b9 627 if (cont)
networker 0:7493bf6bb1b9 628 break;
networker 1:70ee392bcfd4 629 unsigned pos = 0;
networker 1:70ee392bcfd4 630 if (contBuf[pos]>>3 != sdp_data::SEQUENCE) {
networker 1:70ee392bcfd4 631 printf("Expected a sequence of attribute lists\n");
networker 1:70ee392bcfd4 632 break;
networker 1:70ee392bcfd4 633 }
networker 1:70ee392bcfd4 634 unsigned len = length(contBuf, pos);//get the length of the list of lists and advance pos to the first list
networker 1:70ee392bcfd4 635 while (pos<len) {
networker 0:7493bf6bb1b9 636 printf("pos=%d, count=%d, parsing...\n", pos, len);
networker 0:7493bf6bb1b9 637 serv_rec *serv = new serv_rec;
networker 1:70ee392bcfd4 638 pos = parse(contBuf+pos, len, tree, serv);
networker 0:7493bf6bb1b9 639 unsigned key = (*serv)[0]->asUnsigned();
networker 0:7493bf6bb1b9 640 services[key] = serv;
networker 0:7493bf6bb1b9 641 }
networker 1:70ee392bcfd4 642 freeBuf();
networker 0:7493bf6bb1b9 643 printf("...parsing done, pos=%d\n", pos);
networker 0:7493bf6bb1b9 644 if (ServiceSearchAttributeResponse)
networker 0:7493bf6bb1b9 645 ServiceSearchAttributeResponse();
networker 0:7493bf6bb1b9 646 }
networker 0:7493bf6bb1b9 647 break;
networker 0:7493bf6bb1b9 648 default:
networker 0:7493bf6bb1b9 649 printf("Unknown SDP response type %02X\n", rsp[0]);
networker 3:e8d2ebb7392e 650 break;
networker 0:7493bf6bb1b9 651 }
networker 0:7493bf6bb1b9 652 return 0;
networker 0:7493bf6bb1b9 653 }
networker 3:e8d2ebb7392e 654
networker 3:e8d2ebb7392e 655 //************************ SERVER related *******************************************//
networker 3:e8d2ebb7392e 656
networker 3:e8d2ebb7392e 657 //unsigned SDPHandler::parseUUID(const u8* data, int len, unsigned &p) {
networker 3:e8d2ebb7392e 658 unsigned parseUUID(const u8* data, int len, unsigned &p) {
networker 3:e8d2ebb7392e 659 unsigned u = 0;
networker 3:e8d2ebb7392e 660 if ((data[p]>>3) != sdp_data::UUID) {
networker 3:e8d2ebb7392e 661 printf(" UUID expected, got %d ", data[p]>>3);
networker 3:e8d2ebb7392e 662 return (unsigned)-1;
networker 3:e8d2ebb7392e 663 }
networker 3:e8d2ebb7392e 664 switch (data[p++] & 7) {
networker 3:e8d2ebb7392e 665 case 1:
networker 3:e8d2ebb7392e 666 u = getval(data+p, 2);
networker 3:e8d2ebb7392e 667 p +=2;
networker 3:e8d2ebb7392e 668 break;
networker 3:e8d2ebb7392e 669 case 2:
networker 3:e8d2ebb7392e 670 u = getval(data+p, 4);
networker 3:e8d2ebb7392e 671 p += 4;
networker 3:e8d2ebb7392e 672 break;
networker 3:e8d2ebb7392e 673 case 4:
networker 3:e8d2ebb7392e 674 u = getval(data+p, 4);
networker 3:e8d2ebb7392e 675 p += 16;
networker 3:e8d2ebb7392e 676 break;
networker 3:e8d2ebb7392e 677 default:
networker 3:e8d2ebb7392e 678 printf(" UUID must be 2, 4 or 16 bytes, got type %d\n", data[p-1]);
networker 3:e8d2ebb7392e 679 }
networker 3:e8d2ebb7392e 680 return u;
networker 3:e8d2ebb7392e 681 }
networker 3:e8d2ebb7392e 682
networker 3:e8d2ebb7392e 683 #define SVC_HANDLE 0x0001001DU //serial service
networker 3:e8d2ebb7392e 684 void SDPManager::buildServer() {
networker 3:e8d2ebb7392e 685 static sdp_data rfcomm(sdp_data::SEQUENCE);
networker 3:e8d2ebb7392e 686 static sdp_data l2cap(sdp_data::SEQUENCE);
networker 3:e8d2ebb7392e 687 static sdp_data protocol(sdp_data::SEQUENCE);
networker 3:e8d2ebb7392e 688 static sdp_data serviceclass(sdp_data::SEQUENCE);
networker 3:e8d2ebb7392e 689 static sdp_data browsegroup(sdp_data::SEQUENCE);
networker 3:e8d2ebb7392e 690 static sdp_data root(sdp_data::UUID, BROWSEROOT);
networker 3:e8d2ebb7392e 691 static sdp_data l2capuuid(sdp_data::UUID, 0x0100);
networker 3:e8d2ebb7392e 692 static sdp_data rfcommuuid(sdp_data::UUID, 0x003);
networker 3:e8d2ebb7392e 693 static sdp_data serial(sdp_data::UUID, 0x1101);
networker 3:e8d2ebb7392e 694 static sdp_data chan(1U,1);
networker 3:e8d2ebb7392e 695 static sdp_data handle(SVC_HANDLE,4);
networker 3:e8d2ebb7392e 696 static sdp_data serviceID(0U, 2);
networker 4:d5c3e499603d 697 // static sdp_data name("MBED BlueUSB RFCOMM Serial");
networker 4:d5c3e499603d 698 static sdp_data name("Serial Port");
networker 3:e8d2ebb7392e 699 rfcomm.add_element(&rfcommuuid);
networker 3:e8d2ebb7392e 700 rfcomm.add_element(&chan);
networker 3:e8d2ebb7392e 701 l2cap.add_element(&l2capuuid);
networker 3:e8d2ebb7392e 702 protocol.add_element(&l2cap);
networker 3:e8d2ebb7392e 703 protocol.add_element(&rfcomm);
networker 3:e8d2ebb7392e 704 serviceclass.add_element(&serial);
networker 3:e8d2ebb7392e 705 browsegroup.add_element(&root);
networker 3:e8d2ebb7392e 706 static serv_rec attr_list;
networker 3:e8d2ebb7392e 707 attr_list[0] = &handle;
networker 3:e8d2ebb7392e 708 attr_list[1] = &serviceclass;
networker 3:e8d2ebb7392e 709 attr_list[4] = &protocol;
networker 3:e8d2ebb7392e 710 attr_list[5] = &browsegroup;
networker 3:e8d2ebb7392e 711 attr_list[0x100] = &name;
networker 3:e8d2ebb7392e 712 server[SVC_HANDLE] = &attr_list;//server is static and this statement crashes the program when invoked from the constructor which is also invoked statically
networker 3:e8d2ebb7392e 713 }
networker 3:e8d2ebb7392e 714
networker 3:e8d2ebb7392e 715 int SDPManager::findUUID(unsigned h, unsigned uuid) {
networker 3:e8d2ebb7392e 716 serv_rec *rec = server[h];
networker 3:e8d2ebb7392e 717 for ( serv_rec::iterator it = rec->begin(); it != rec->end(); it++) {
networker 3:e8d2ebb7392e 718 if (it->second->findUUID(uuid))
networker 3:e8d2ebb7392e 719 return it->first;
networker 3:e8d2ebb7392e 720 }
networker 3:e8d2ebb7392e 721 printf("rejected %08X because of %04Xx\n", h, uuid);
networker 3:e8d2ebb7392e 722 return -1;
networker 3:e8d2ebb7392e 723 }
networker 3:e8d2ebb7392e 724
networker 3:e8d2ebb7392e 725 void SDPManager::match(bool elig[], unsigned uuid) {
networker 3:e8d2ebb7392e 726 map<unsigned, serv_rec*>::iterator idx;
networker 3:e8d2ebb7392e 727 int i = 0;
networker 3:e8d2ebb7392e 728 for (idx = server.begin(); idx != server.end(); idx++, i++)
networker 3:e8d2ebb7392e 729 if (findUUID(idx->first, uuid) < 0)
networker 3:e8d2ebb7392e 730 elig[i] = false;
networker 3:e8d2ebb7392e 731 }
networker 3:e8d2ebb7392e 732
networker 3:e8d2ebb7392e 733 bool SDPManager::isInList(unsigned short id, const unsigned char* list, int end) {
networker 3:e8d2ebb7392e 734 int len;
networker 3:e8d2ebb7392e 735 for (unsigned pos = 0; pos < end; pos += len) {
networker 3:e8d2ebb7392e 736 len = length(list, pos);
networker 3:e8d2ebb7392e 737 switch (len) {
networker 3:e8d2ebb7392e 738 case 2: //single value
networker 3:e8d2ebb7392e 739 if (getval(list+pos, 2) == id)
networker 3:e8d2ebb7392e 740 return true;
networker 3:e8d2ebb7392e 741 break;
networker 3:e8d2ebb7392e 742 case 4: //range
networker 3:e8d2ebb7392e 743 if (getval(list+pos, 2) > id) break;
networker 3:e8d2ebb7392e 744 if (getval(list+pos+2, 2) < id) break;
networker 3:e8d2ebb7392e 745 return true;
networker 3:e8d2ebb7392e 746 default:
networker 3:e8d2ebb7392e 747 printf("Unexpected length %d\n", len);
networker 3:e8d2ebb7392e 748 }
networker 3:e8d2ebb7392e 749 }
networker 3:e8d2ebb7392e 750 return false;
networker 3:e8d2ebb7392e 751 }
networker 3:e8d2ebb7392e 752
networker 3:e8d2ebb7392e 753 void SDPManager::addToReply(sdp_data *svc, serv_rec *list, const unsigned char* att, int end) {
networker 3:e8d2ebb7392e 754 unsigned short len, low, high;
networker 3:e8d2ebb7392e 755 serv_rec::iterator from, to, idx;
networker 4:d5c3e499603d 756 if (list==0) {
networker 4:d5c3e499603d 757 printf("Invalid attribute list (NULL)\n");
networker 4:d5c3e499603d 758 return;
networker 4:d5c3e499603d 759 }
networker 3:e8d2ebb7392e 760 for (unsigned pos = 0; pos < end; pos += len) {
networker 3:e8d2ebb7392e 761 len = length(att, pos);
networker 3:e8d2ebb7392e 762 switch (len) {
networker 3:e8d2ebb7392e 763 case 2: //single value
networker 3:e8d2ebb7392e 764 low = getval(att+pos, 2);
networker 3:e8d2ebb7392e 765 svc->add_element(new sdp_data(low, 2));
networker 3:e8d2ebb7392e 766 svc->add_element((*list)[low]);
networker 3:e8d2ebb7392e 767 printf("Found attrib %d\n", low);
networker 3:e8d2ebb7392e 768 break;
networker 3:e8d2ebb7392e 769 case 4: //range
networker 3:e8d2ebb7392e 770 low = getval(att+pos, 2);
networker 3:e8d2ebb7392e 771 high = getval(att+pos+2, 2);
networker 3:e8d2ebb7392e 772 from = list->lower_bound(low);
networker 3:e8d2ebb7392e 773 to = list->upper_bound(high);
networker 3:e8d2ebb7392e 774 for (idx = from; idx != to; idx++) {
networker 4:d5c3e499603d 775 svc->add_element(new sdp_data(idx->first, 2));
networker 4:d5c3e499603d 776 svc->add_element(idx->second);
networker 4:d5c3e499603d 777 printf("Found attrib %d\n", idx->first);
networker 3:e8d2ebb7392e 778 }
networker 3:e8d2ebb7392e 779 break;
networker 3:e8d2ebb7392e 780 default:
networker 3:e8d2ebb7392e 781 printf("Unexpected length %d\n", len);
networker 3:e8d2ebb7392e 782 }
networker 3:e8d2ebb7392e 783 }
networker 3:e8d2ebb7392e 784 }
networker 3:e8d2ebb7392e 785
networker 3:e8d2ebb7392e 786 //for continuations, just generate the entire list, truncate to desired length and append position of the remainder as continuation
networker 3:e8d2ebb7392e 787 //on the next iteration, generate the list again, use continuation to find remainder and reiterate
networker 3:e8d2ebb7392e 788 void SDPManager::SDPServer(int socket, SocketState state, const u8* data, int len, void* userData) {
networker 3:e8d2ebb7392e 789 unsigned tid = data[2] + ((unsigned)data[1]<<8);
networker 3:e8d2ebb7392e 790 unsigned parlen = data[4] + ((unsigned)data[3]<<8);
networker 3:e8d2ebb7392e 791 //printf("ParseReq: PDU_ID=%d, tid=%04X, parlen=%d ", data[0], tid, parlen);
networker 3:e8d2ebb7392e 792 unsigned pos = 5;
networker 3:e8d2ebb7392e 793 switch (data[0]) {
networker 3:e8d2ebb7392e 794 case 1: {//errorRsp
networker 3:e8d2ebb7392e 795 unsigned errorcode = data[6] + ((unsigned)data[5]<<8);
networker 3:e8d2ebb7392e 796 if (parlen > 2) {
networker 3:e8d2ebb7392e 797 printf("ErrorInfo (%d bytes) for error %d is available\n", parlen-2, errorcode);
networker 3:e8d2ebb7392e 798 }
networker 3:e8d2ebb7392e 799 errorhandler(errorcode);
networker 3:e8d2ebb7392e 800 }
networker 3:e8d2ebb7392e 801 break;
networker 3:e8d2ebb7392e 802 case 2: { //servicesearchReq
networker 4:d5c3e499603d 803 printf("servicesearchReq almost implemented\n");
networker 4:d5c3e499603d 804 unsigned pat[12];//the received search pattern
networker 4:d5c3e499603d 805 int pn;//number of uuids in the pattern
networker 4:d5c3e499603d 806 if (data[pos]>>3 != sdp_data::SEQUENCE) {//the uuids are wrapped in a sequence
networker 4:d5c3e499603d 807 printf("Expected a sequence of UUIDs\n");
networker 4:d5c3e499603d 808 break;
networker 4:d5c3e499603d 809 }
networker 4:d5c3e499603d 810 unsigned end = pos + length(data, pos);//get the length of the list of lists and advance pos to the first list
networker 4:d5c3e499603d 811 bool *eligible = new bool[server.size()];//marks for the services identified by the search pattern
networker 4:d5c3e499603d 812 for (int i = 0; i < server.size(); i++) eligible[i] = true;
networker 4:d5c3e499603d 813 for (pn = 0; pn < 12 && pos < end; pn++) {
networker 4:d5c3e499603d 814 pat[pn] = parseUUID(data,end, pos);//store uuid from the sequence in the pattern
networker 4:d5c3e499603d 815 match(eligible, pat[pn]);//unmark a service when it does not contain the uuid
networker 4:d5c3e499603d 816 //printf("pos=%d, count=%d, uuid=%#X\n", pos, len, pat[pn]);
networker 4:d5c3e499603d 817 }
networker 4:d5c3e499603d 818
networker 4:d5c3e499603d 819 unsigned count = getval(data+pos, 2); //maximum length of attribute list to return
networker 4:d5c3e499603d 820 pos += 2;
networker 4:d5c3e499603d 821 unsigned tail = data[pos];
networker 4:d5c3e499603d 822 if (tail) {
networker 4:d5c3e499603d 823 tail = getval(data+pos+1, tail);
networker 4:d5c3e499603d 824 printf("requested continuation tailpos=%u\n", tail);
networker 4:d5c3e499603d 825 } else {
networker 4:d5c3e499603d 826 //printf("No continuation requested\n");
networker 4:d5c3e499603d 827 }
networker 4:d5c3e499603d 828 unsigned *handles = new unsigned[server.size()];
networker 4:d5c3e499603d 829 int total = 0, current = 0;
networker 4:d5c3e499603d 830 map<unsigned, serv_rec*>::iterator idx;
networker 4:d5c3e499603d 831 int i = 0;
networker 4:d5c3e499603d 832 for (idx = server.begin(); idx != server.end() && total < count; idx++, i++)
networker 4:d5c3e499603d 833 if (eligible[i])
networker 4:d5c3e499603d 834 handles[total++] = idx->first;
networker 4:d5c3e499603d 835 ServiceSearchReply(tid, handles, total, tail);
networker 4:d5c3e499603d 836 delete[] handles;
networker 4:d5c3e499603d 837 delete[] eligible;
networker 3:e8d2ebb7392e 838 }
networker 3:e8d2ebb7392e 839 break;
networker 3:e8d2ebb7392e 840 case 4: { //serviceattributeReq
networker 4:d5c3e499603d 841 printf("serviceattributeReq almost implemented\n");
networker 4:d5c3e499603d 842 sdp_data reply(sdp_data::SEQUENCE);//the attributelist of the reply
networker 4:d5c3e499603d 843 unsigned svcid = getval(data+pos, 4);
networker 4:d5c3e499603d 844 pos += 4;
networker 4:d5c3e499603d 845 unsigned count = getval(data+pos, 2); //maximum length of attribute list to return
networker 4:d5c3e499603d 846 pos += 2;
networker 4:d5c3e499603d 847 int len = length(data, pos); //get the length of the attributeID list
networker 4:d5c3e499603d 848 int cont = pos + len;
networker 4:d5c3e499603d 849 printf("svcid=%08X, count=%u, len=%u, pos=%u\n", svcid, count, len, pos);
networker 4:d5c3e499603d 850 addToReply(&reply, server[svcid], data+pos, len);
networker 4:d5c3e499603d 851 unsigned tail = data[cont];
networker 4:d5c3e499603d 852 printf("tail=%u, reply size=%d\n", tail, reply.Size());
networker 4:d5c3e499603d 853 if (tail) {
networker 4:d5c3e499603d 854 tail = getval(data+cont+1, tail);
networker 4:d5c3e499603d 855 printf("requested continuation tailpos=%u, size=%u\n", tail, reply.Size());
networker 4:d5c3e499603d 856 } else {
networker 4:d5c3e499603d 857 //printf("No continuation requested\n");
networker 4:d5c3e499603d 858 }
networker 4:d5c3e499603d 859
networker 4:d5c3e499603d 860 ServiceAttributeReply(tid, &reply, count, tail);
networker 4:d5c3e499603d 861 for (int k = 0; k < reply.items(); k++) {
networker 4:d5c3e499603d 862 if ((k & 1) == 0) //even hence ID
networker 4:d5c3e499603d 863 delete reply.item(k); //destroy the ID
networker 4:d5c3e499603d 864 reply.remove(k); //set all items to nil to prevent destruction of the DB
networker 4:d5c3e499603d 865 }
networker 3:e8d2ebb7392e 866 }
networker 3:e8d2ebb7392e 867 break;
networker 3:e8d2ebb7392e 868 case 6: { //servicesearchattributeReq
networker 3:e8d2ebb7392e 869 sdp_data reply(sdp_data::SEQUENCE);//the attributelist of the reply
networker 3:e8d2ebb7392e 870
networker 3:e8d2ebb7392e 871 unsigned pat[12];//the received search pattern
networker 3:e8d2ebb7392e 872 int pn;//number of uuids in the pattern
networker 3:e8d2ebb7392e 873 if (data[pos]>>3 != sdp_data::SEQUENCE) {//the uuids are wrapped in a sequence
networker 3:e8d2ebb7392e 874 printf("Expected a sequence of UUIDs\n");
networker 3:e8d2ebb7392e 875 break;
networker 3:e8d2ebb7392e 876 }
networker 3:e8d2ebb7392e 877 unsigned end = pos + length(data, pos);//get the length of the list of lists and advance pos to the first list
networker 3:e8d2ebb7392e 878 bool *eligible = new bool[server.size()];//marks for the services identified by the search pattern
networker 3:e8d2ebb7392e 879 for (int i = 0; i < server.size(); i++) eligible[i] = true;
networker 3:e8d2ebb7392e 880 for (pn = 0; pn < 12 && pos < end; pn++) {
networker 3:e8d2ebb7392e 881 pat[pn] = parseUUID(data,end, pos);//store uuid from the sequence in the pattern
networker 3:e8d2ebb7392e 882 match(eligible, pat[pn]);//unmark a service when it does not contain the uuid
networker 3:e8d2ebb7392e 883 //printf("pos=%d, count=%d, uuid=%#X\n", pos, len, pat[pn]);
networker 3:e8d2ebb7392e 884 }
networker 3:e8d2ebb7392e 885
networker 3:e8d2ebb7392e 886 unsigned count = getval(data+pos, 2); //maximum length of attribute list to return
networker 3:e8d2ebb7392e 887 pos += 2;
networker 3:e8d2ebb7392e 888
networker 3:e8d2ebb7392e 889 int len = length(data, pos); //get the length of the attributeID list
networker 3:e8d2ebb7392e 890 int cont = pos + len;
networker 3:e8d2ebb7392e 891 //printf("Count = %d pos=%d, data[pos]=%02x, len=%d, cont=%d\n", count, pos, data[pos], len, cont);
networker 3:e8d2ebb7392e 892 int i = 0;
networker 3:e8d2ebb7392e 893 for (map<unsigned, serv_rec*>::iterator idx = server.begin(); idx != server.end(); idx++, i++) {//foreach service
networker 3:e8d2ebb7392e 894 //printf("testing service handle %08X\n", idx->first);
networker 3:e8d2ebb7392e 895 if (!eligible[i]) continue; //skip services that don't match the pattern
networker 3:e8d2ebb7392e 896 sdp_data *svc = new sdp_data(sdp_data::SEQUENCE); //create a sequence for the attributes of the present service
networker 3:e8d2ebb7392e 897 #if 0
networker 3:e8d2ebb7392e 898 for (serv_rec::iterator attr = idx->second->begin(); attr != idx->second->end(); attr++) {//foreach attrib in the service
networker 3:e8d2ebb7392e 899 //printf("testing attribID %u\n", attr->first);
networker 3:e8d2ebb7392e 900 if (isInList(attr->first, data+pos, len)) {//check if it is requested
networker 3:e8d2ebb7392e 901 printf("Found attribID %d\n", attr->first);
networker 3:e8d2ebb7392e 902 sdp_data *p = attr->second; //the attribute
networker 3:e8d2ebb7392e 903 svc->add_element(new sdp_data(attr->first, 2)); //add the attribute ID as an unsigned short
networker 3:e8d2ebb7392e 904 svc->add_element(p); //add the attribute
networker 3:e8d2ebb7392e 905 //printf("appending %d bytes\n", p->Size());
networker 3:e8d2ebb7392e 906 }
networker 3:e8d2ebb7392e 907 }
networker 3:e8d2ebb7392e 908 #else
networker 3:e8d2ebb7392e 909 //alternatively use map::lower/upper_bound and equal_range, needs only one pass over the range list for each service
networker 3:e8d2ebb7392e 910 addToReply(svc, idx->second, data+pos, len);
networker 3:e8d2ebb7392e 911 #endif
networker 3:e8d2ebb7392e 912 reply.add_element(svc); //append the new attribute list to the reply list
networker 3:e8d2ebb7392e 913 }
networker 4:d5c3e499603d 914
networker 3:e8d2ebb7392e 915 unsigned tail = data[cont];
networker 3:e8d2ebb7392e 916 if (tail) {
networker 3:e8d2ebb7392e 917 tail = getval(data+cont+1, tail);
networker 3:e8d2ebb7392e 918 printf("requested continuation tailpos=%u, size=%u\n", tail, reply.Size());
networker 4:d5c3e499603d 919 } else {
networker 3:e8d2ebb7392e 920 //printf("No continuation requested\n");
networker 3:e8d2ebb7392e 921 }
networker 3:e8d2ebb7392e 922 ServiceSearchAttributeReply(tid, &reply, count, tail);
networker 4:d5c3e499603d 923
networker 3:e8d2ebb7392e 924 for (int j = 0; j < reply.items(); j++) {
networker 3:e8d2ebb7392e 925 sdp_data *al = reply.item(j);
networker 3:e8d2ebb7392e 926 for (int k = 0; k < al->items(); k++) {
networker 3:e8d2ebb7392e 927 if ((k & 1) == 0) //even hence ID
networker 3:e8d2ebb7392e 928 delete al->item(k); //destroy the ID
networker 3:e8d2ebb7392e 929 al->remove(k); //set all items to nil to prevent destruction of the DB
networker 3:e8d2ebb7392e 930 }
networker 3:e8d2ebb7392e 931 delete al; //destroy the list;
networker 3:e8d2ebb7392e 932 reply.remove(j);
networker 3:e8d2ebb7392e 933 }
networker 3:e8d2ebb7392e 934 delete[] eligible;
networker 3:e8d2ebb7392e 935 }
networker 3:e8d2ebb7392e 936 break;
networker 3:e8d2ebb7392e 937 default:
networker 3:e8d2ebb7392e 938 printf("Unknown SDP request type %02X\n", data[0]);
networker 3:e8d2ebb7392e 939 break;
networker 3:e8d2ebb7392e 940 }
networker 3:e8d2ebb7392e 941 }