/* Service Discovery Protocol (SDP) Copyright (C) 2002 Maxim Krasnyansky , Stephen Crane Based on original SDP implementation by Nokia Corporation. Copyright (C) 2001,2002 Nokia Corporation. Original author Guruprasad Krishnamurthy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS SOFTWARE IS DISCLAIMED. */ /* Service registration requests. Fixes: Guruprasad Krishnamurthy */ /* * $Id$ */ #include #include #include #include "sdpd.h" extern void update_db_timestamp(void); // FIXME: refactor for server-side static sdp_record_t *extract_pdu_server(char *p, uint32_t handleExpected, int *scanned) { int extractStatus = -1, localExtractedLength = 0; uint8_t dtd; int seqlen = 0; sdp_record_t *rec = NULL; uint16_t attrId, lookAheadAttrId; sdp_data_t *pAttr = NULL; uint32_t handle = 0xffffffff; *scanned = sdp_extract_seqtype(p, &dtd, &seqlen); p += *scanned; lookAheadAttrId = ntohs(sdp_get_unaligned((uint16_t *)(p + sizeof(uint8_t)))); SDPDBG("Look ahead attr id : %d\n", lookAheadAttrId); if (lookAheadAttrId == SDP_ATTR_RECORD_HANDLE) { handle = ntohl(sdp_get_unaligned((uint32_t *)(p + sizeof(uint8_t) + sizeof(uint16_t) + sizeof(uint8_t)))); SDPDBG("SvcRecHandle : 0x%x\n", handle); rec = sdp_record_find(handle); } else if (handleExpected != 0xffffffff) rec = sdp_record_find(handleExpected); if (rec == NULL) { rec = sdp_record_alloc(); rec->attrlist = NULL; if (lookAheadAttrId == SDP_ATTR_RECORD_HANDLE) { rec->handle = handle; sdp_record_add(rec); } else if (handleExpected != 0xffffffff) { rec->handle = handleExpected; sdp_record_add(rec); } } while (localExtractedLength < seqlen) { int attrSize = sizeof(uint8_t); int attrValueLength = 0; SDPDBG("Extract PDU, sequenceLength: %d localExtractedLength: %d", seqlen, localExtractedLength); dtd = *(uint8_t *)p; attrId = ntohs(sdp_get_unaligned((uint16_t *)(p + attrSize))); attrSize += sizeof(uint16_t); SDPDBG("DTD of attrId : %d Attr id : 0x%x \n", dtd, attrId); pAttr = sdp_extract_attr(p + attrSize, &attrValueLength, rec); SDPDBG("Attr id : 0x%x attrValueLength : %d\n", attrId, attrValueLength); attrSize += attrValueLength; if (pAttr == NULL) { SDPDBG("Terminating extraction of attributes"); break; } localExtractedLength += attrSize; p += attrSize; sdp_attr_replace(rec, attrId, pAttr); extractStatus = 0; SDPDBG("Extract PDU, seqLength: %d localExtractedLength: %d", seqlen, localExtractedLength); } if (extractStatus == 0) { SDPDBG("Successful extracting of Svc Rec attributes\n"); #ifdef SDP_DEBUG sdp_print_service_attr(rec->attrlist); #endif *scanned += seqlen; } return rec; } /* * Add the newly created service record to the service repository */ int service_register_req(sdp_req_t *req, sdp_buf_t *rsp) { int scanned = 0; sdp_data_t *handle; char *p = req->buf + sizeof(sdp_pdu_hdr_t); sdp_record_t *rec; req->flags = *p++; // save image of PDU: we need it when clients request this attribute rec = extract_pdu_server(p, 0xffffffff, &scanned); if (rec == NULL) { sdp_put_unaligned(htons(SDP_INVALID_SYNTAX), (uint16_t *)rsp->data); rsp->data_size = sizeof(uint16_t); return -1; } rec->handle = (uint32_t)rec; sdp_record_add(rec); if (!(req->flags & SDP_RECORD_PERSIST)) sdp_svcdb_set_collectable(rec, req->sock); handle = sdp_data_alloc(SDP_UINT32, &rec->handle); sdp_attr_replace(rec, SDP_ATTR_RECORD_HANDLE, handle); /* * if the browse group descriptor is NULL, * ensure that the record belongs to the ROOT group */ if (sdp_data_get(rec, SDP_ATTR_BROWSE_GRP_LIST) == NULL) { uuid_t uuid; sdp_uuid16_create(&uuid, PUBLIC_BROWSE_GROUP); sdp_pattern_add_uuid(rec, &uuid); } update_db_timestamp(); /* Build a rsp buffer */ sdp_put_unaligned(htonl(rec->handle), (uint32_t *)rsp->data); rsp->data_size = sizeof(uint32_t); return 0; } /* * Update a service record */ int service_update_req(sdp_req_t *req, sdp_buf_t *rsp) { sdp_record_t *orec; int status = 0, scanned = 0; char *p = req->buf + sizeof(sdp_pdu_hdr_t); uint32_t handle = ntohl(sdp_get_unaligned((uint32_t *)p)); SDPDBG(""); SDPDBG("Svc Rec Handle: 0x%x\n", handle); p += sizeof(uint32_t); orec = sdp_record_find(handle); SDPDBG("SvcRecOld: 0x%x\n", (uint32_t)orec); if (orec) { sdp_record_t *nrec = extract_pdu_server(p, handle, &scanned); if (nrec && handle == nrec->handle) update_db_timestamp(); else { SDPDBG("SvcRecHandle : 0x%x\n", handle); SDPDBG("SvcRecHandleNew : 0x%x\n", nrec->handle); SDPDBG("SvcRecNew : 0x%x\n", (uint32_t) nrec); SDPDBG("SvcRecOld : 0x%x\n", (uint32_t) orec); SDPDBG("Failure to update, restore old value\n"); if (nrec) sdp_record_free(nrec); status = SDP_INVALID_SYNTAX; } } else status = SDP_INVALID_RECORD_HANDLE; p = rsp->data; sdp_put_unaligned(htons(status), (uint16_t *)p); rsp->data_size = sizeof(uint16_t); return status; } /* * Remove a registered service record */ int service_remove_req(sdp_req_t *req, sdp_buf_t *rsp) { char *p = req->buf + sizeof(sdp_pdu_hdr_t); uint32_t handle = ntohl(sdp_get_unaligned((uint32_t *)p)); sdp_record_t *rec; int status = 0; SDPDBG(""); /* extract service record handle */ p += sizeof(uint32_t); rec = sdp_record_find(handle); if (rec) { sdp_svcdb_collect(rec); status = sdp_record_remove(handle); sdp_record_free(rec); if (status == 0) update_db_timestamp(); } else { status = SDP_INVALID_RECORD_HANDLE; SDPDBG("Could not find record : 0x%x\n", handle); } p = rsp->data; sdp_put_unaligned(htons(status), (uint16_t *)p); rsp->data_size = sizeof(uint16_t); return status; }