📄 listattr.c
字号:
/* * Here should go the usual boiler plate. * The stuff I've added if Copyright Jean Tourrilhes 2002. * As most of it is cut'n'paste from part of the SDP library, this code * is of course GPL... * Jean II *//************************** DOCUMENTATION **************************//* * This code use a "brute force" approach to parsing SDP records. * Instead of a top down approach in sdptool, which pick only know * attributes/members, we use a bottom up approach, printing every * single bit of the record and trying to associate its defintion * to it. * The advantage is that, of course, every attribute is displayed, * even unknow one. Also, the display is lower level, so much closer * to the raw data, so more useful for SDP debugging. * On the other hand, the display is much less user friendly... * * Why is this code here, and not in the libs, especially that we include * sdp_internal.h ? Well, I don't want to bother every single sdp app * (including sdpd) with lists of attribute. That seems unnecessary * overhead for a feature that is used only for debugging. * * Jean II *//***************************** INCLUDES *****************************/#include <stdio.h>#include "sdp.h"#include "sdp_lib.h"/* We need to access the low level structure of the attributes */#include "sdp_internal.h"/****************************** TYPES ******************************//* Definition of attribute members */struct member_def { char *name;};/* Definition of an attribute */struct attrib_def { int num; /* Numeric ID - 16 bits */ char * name; /* User readable name */ struct member_def * members; /* Definition of attribute args */ int member_max; /* Max of attribute arg definitions */};/* Definition of a service or protocol */struct uuid_def { int num; /* Numeric ID - 16 bits */ char * name; /* User readable name */ struct attrib_def * attribs; /* Specific attribute definitions */ int attrib_max; /* Max of attribute definitions */};/* Context information about current attribute */struct attrib_context { struct uuid_def * service; /* Service UUID, if known */ struct attrib_def * attrib; /* Description of the attribute */ int member_index; /* Index of current attribute member */};/* Context information about the whole service */struct service_context { struct uuid_def * service; /* Service UUID, if known */};/**************************** CONSTANTS ****************************//* Allow us to do nice formatting of the lists */static char *indent_spaces = " ";/* ID of the service attribute. * Most attributes after 0x200 are defined based on the service, so * we need to find what is the service (which is messy) - Jean II */#define SERVICE_ATTR 0x1/* Defintion of the optional arguments in protocol list */static struct member_def protocol_members[] = { { "Protocol" }, { "Channel/Port" }, { "Version" },};/* Defintion of the optional arguments in profile list */static struct member_def profile_members[] = { { "Profile" }, { "Version" },};/* Name of the various attributes. See BT assigned numbers */static struct attrib_def attrib_names[] = { { 0x0, "ServiceRecordHandle", NULL, 0 }, { 0x1, "ServiceClassIDList", NULL, 0 }, { 0x2, "ServiceRecordState", NULL, 0 }, { 0x3, "ServiceID", NULL, 0 }, { 0x4, "ProtocolDescriptorList", protocol_members, sizeof(protocol_members)/sizeof(struct member_def) }, { 0x5, "BrowseGroupList", NULL, 0 }, { 0x6, "LanguageBaseAttributeIDList", NULL, 0 }, { 0x7, "ServiceInfoTimeToLive", NULL, 0 }, { 0x8, "ServiceAvailability", NULL, 0 }, { 0x9, "BluetoothProfileDescriptorList", profile_members, sizeof(profile_members)/sizeof(struct member_def) }, { 0xA, "DocumentationURL", NULL, 0 }, { 0xB, "ClientExecutableURL", NULL, 0 }, { 0xC, "IconURL", NULL, 0 }, { 0xD, "AdditionalProtocolDescriptorLists", NULL, 0 }, /* Definitions after that are tricky (per profile or offset) */};const int attrib_max = sizeof(attrib_names)/sizeof(struct attrib_def);/* Name of the various SPD attributes. See BT assigned numbers */static struct attrib_def sdp_attrib_names[] = { { 0x200, "VersionNumberList", NULL, 0 }, { 0x201, "ServiceDatabaseState", NULL, 0 },};/* Name of the various SPD attributes. See BT assigned numbers */static struct attrib_def browse_attrib_names[] = { { 0x200, "GroupID", NULL, 0 },};/* Same for the UUIDs. See BT assigned numbers */static struct uuid_def uuid16_names[] = { /* -- Protocols -- */ { 0x1, "SDP (Service Discovery Protocol)", NULL, 0 }, { 0x2, "UDP", NULL, 0 }, { 0x3, "RFCOMM", NULL, 0 }, { 0x4, "TCP", NULL, 0 }, { 0x5, "TCS-BIN", NULL, 0 }, { 0x6, "TCS-AT", NULL, 0 }, { 0x8, "OBEX", NULL, 0 }, { 0x9, "IP", NULL, 0 }, { 0xA, "FTP", NULL, 0 }, { 0xC, "HTTP", NULL, 0 }, { 0xE, "WSP", NULL, 0 }, { 0xF, "BNEP (PAN/BNEP)", NULL, 0 }, { 0x10, "UPnP/ESDP", NULL, 0 }, { 0x11, "HIDP", NULL, 0 }, { 0x12, "HardcopyControlChannel", NULL, 0 }, { 0x14, "HardcopyDataChannel", NULL, 0 }, { 0x16, "HardcopyNotification", NULL, 0 }, { 0x17, "AVCTP", NULL, 0 }, { 0x19, "AVDTP", NULL, 0 }, { 0x1B, "CMTP", NULL, 0 }, { 0x1D, "UDI_C-Plane", NULL, 0 }, { 0x100, "L2CAP", NULL, 0 }, /* -- Services -- */ { 0x1000, "ServiceDiscoveryServerServiceClassID (SDP)", sdp_attrib_names, sizeof(sdp_attrib_names)/sizeof(struct attrib_def) }, { 0x1001, "BrowseGroupDescriptorServiceClassID (SDP)", browse_attrib_names, sizeof(browse_attrib_names)/sizeof(struct attrib_def) }, { 0x1002, "PublicBrowseGroup (SDP)", NULL, 0 }, { 0x1101, "SerialPort", NULL, 0 }, { 0x1102, "LANAccessUsingPPP", NULL, 0 }, { 0x1103, "DialupNetworking (DUN)", NULL, 0 }, { 0x1104, "IrMCSync", NULL, 0 }, { 0x1105, "OBEXObjectPush", NULL, 0 }, { 0x1106, "OBEXFileTransfer", NULL, 0 }, { 0x1107, "IrMCSyncCommand", NULL, 0 }, /* ... */ { 0x1115, "PANU (PAN/BNEP)", NULL, 0 }, { 0x1116, "NAP (PAN/BNEP)", NULL, 0 }, { 0x1117, "GN (PAN/BNEP)", NULL, 0 }, /* ... */ { 0x1128, "Common ISDN Access (CIP)", NULL, 0 },};const int uuid16_max = sizeof(uuid16_names)/sizeof(struct uuid_def);/**************************** PROTOTYPES ****************************/void sdp_data_printf(sdp_data_t *, struct attrib_context *, int);/******************************* CODE *******************************//* ------------------------------------------------------------------- *//* * Parse a UUID. * The BT assigned numbers only list UUID16, so I'm not sure the * other types will ever get used... */void sdp_uuid_printf(uuid_t *uuid, struct attrib_context *context, int indent){ if (uuid) { if (uuid->type == SDP_UUID16) { uint16_t uuidNum = uuid->value.uuid16; struct uuid_def *uuidDef = NULL; int i; for(i = 0; i < uuid16_max; i++) if(uuid16_names[i].num == uuidNum) { uuidDef = &uuid16_names[i]; break; } /* Check if it's the service attribute */ if (context->attrib && context->attrib->num == SERVICE_ATTR) { /* We got the service ID !!! */ context->service = uuidDef; } if(uuidDef) printf("%.*sUUID16 : 0x%.4x - %s\n", indent, indent_spaces, uuidNum, uuidDef->name); else printf("%.*sUUID16 : 0x%.4x\n", indent, indent_spaces, uuidNum); } else if (uuid->type == SDP_UUID32) { printf("%.*sUUID32 : 0x%.8x\n", indent, indent_spaces, uuid->value.uuid32); } else if (uuid->type == SDP_UUID128) { unsigned int data0; unsigned short data1; unsigned short data2; unsigned short data3; unsigned int data4; unsigned short data5; memcpy(&data0, &uuid->value.uuid128.data[0], 4); memcpy(&data1, &uuid->value.uuid128.data[4], 2); memcpy(&data2, &uuid->value.uuid128.data[6], 2); memcpy(&data3, &uuid->value.uuid128.data[8], 2); memcpy(&data4, &uuid->value.uuid128.data[10], 4); memcpy(&data5, &uuid->value.uuid128.data[14], 2); printf("%.*sUUID128 : 0x%.8x-%.4x-%.4x-%.4x-%.8x-%.4x\n", indent, indent_spaces, ntohl(data0), ntohs(data1), ntohs(data2), ntohs(data3), ntohl(data4), ntohs(data5)); } else printf("%.*sEnum type of UUID not set\n", indent, indent_spaces); } else printf("%.*sNull passed to print UUID\n", indent, indent_spaces);}/* ------------------------------------------------------------------- *//* * Parse a sequence of data elements (i.e. a list) */static void printf_dataseq(sdp_data_t * pData, struct attrib_context *context, int indent){ sdp_data_t *sdpdata = NULL; sdpdata = pData; if (sdpdata) { context->member_index = 0; do { sdp_data_printf(sdpdata, context, indent + 2); sdpdata = sdpdata->next; context->member_index++; } while (sdpdata); } else { printf("%.*sBroken dataseq link\n", indent, indent_spaces); }}/* ------------------------------------------------------------------- *//* * Parse a single data element (either in the attribute or in a data * sequence). */void sdp_data_printf(sdp_data_t *sdpdata, struct attrib_context *context, int indent){ char *member_name = NULL; /* Find member name. Almost black magic ;-) */ if (context->attrib && context->attrib->members && context->member_index < context->attrib->member_max) { member_name = context->attrib->members[context->member_index].name; } switch (sdpdata->dtd) { case SDP_DATA_NIL: printf("%.*sNil\n", indent, indent_spaces); break; case SDP_BOOL: case SDP_UINT8: case SDP_UINT16: case SDP_UINT32: case SDP_UINT64: case SDP_UINT128: case SDP_INT8: case SDP_INT16: case SDP_INT32: case SDP_INT64: case SDP_INT128: if (member_name) { printf("%.*s%s (Integer) : 0x%x\n", indent, indent_spaces, member_name, sdpdata->val.uint32); } else { printf("%.*sInteger : 0x%x\n", indent, indent_spaces, sdpdata->val.uint32); } break; case SDP_UUID16: case SDP_UUID32: case SDP_UUID128: //printf("%.*sUUID\n", indent, indent_spaces); sdp_uuid_printf(&sdpdata->val.uuid, context, indent); break; case SDP_TEXT_STR8: case SDP_TEXT_STR16: case SDP_TEXT_STR32: printf("%.*sText : \"%s\"\n", indent, indent_spaces, sdpdata->val.str); break; case SDP_URL_STR8: case SDP_URL_STR16: case SDP_URL_STR32: printf("%.*sURL : %s\n", indent, indent_spaces, sdpdata->val.str); break; case SDP_SEQ8: case SDP_SEQ16: case SDP_SEQ32: printf("%.*sData Sequence\n", indent, indent_spaces); printf_dataseq(sdpdata->val.dataseq, context, indent); break; case SDP_ALT8: case SDP_ALT16: case SDP_ALT32: printf("%.*sData Sequence Alternates\n", indent, indent_spaces); /* Not tested, and I believe it's bogus - Jean II */ printf_dataseq(sdpdata->val.dataseq, context, indent); break; }}/* ------------------------------------------------------------------- *//* * Parse a single attribute. */void sdp_attr_printf_func(void *value, void *userData){ sdp_data_t *sdpdata = NULL; uint16_t attrId; struct service_context *service = (struct service_context *) userData; struct attrib_context context; struct attrib_def *attrDef = NULL; int i; sdpdata = (sdp_data_t *)value; attrId = sdpdata->attrId; /* Search amongst the generic attributes */ for (i = 0; i < attrib_max; i++) if (attrib_names[i].num == attrId) { attrDef = &attrib_names[i]; break; } /* Search amongst the specific attributes of this service */ if ((attrDef == NULL) && (service->service != NULL) && (service->service->attribs != NULL)) { struct attrib_def *svc_attribs = service->service->attribs; int svc_attrib_max = service->service->attrib_max; for (i = 0; i < svc_attrib_max; i++) if (svc_attribs[i].num == attrId) { attrDef = &svc_attribs[i]; break; } } if (attrDef) printf("Attribute Identifier : 0x%x - %s\n", attrId, attrDef->name); else printf("Attribute Identifier : 0x%x\n", attrId); /* Build context */ context.service = service->service; context.attrib = attrDef; context.member_index = 0; /* Parse attribute members */ if (sdpdata) sdp_data_printf(sdpdata, &context, 2); else printf(" NULL value\n"); /* Update service */ service->service = context.service;}/* ------------------------------------------------------------------- *//* * Main entry point of this library. Parse a SDP record. * We assume the record has already been read, parsed and cached * locally. Jean II */void sdp_printf_service_attr(sdp_record_t *rec){ if (rec && rec->attrlist) { struct service_context service = { NULL }; sdp_list_foreach(rec->attrlist, sdp_attr_printf_func, &service); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -