⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sdpserver.c

📁 Affix - Bluetooth Protocol Stack for Linux has been developed at Nokia Research Center in Helsinki
💻 C
字号:
/*    Affix - Bluetooth Protocol Stack for Linux   Copyright (C) 2001,2002 Nokia Corporation   Author: Dmitry Kasatkin <dmitry.kasatkin@nokia.com>   Original Author: Guruprasad Krishnamurthy <kgprasad@hotmail.com>   This program is free software; you can redistribute it and/or modify it   under the terms of the GNU General Public License as published by the   Free Software Foundation; either version 2 of the License, or (at your   option) any later version.   This program is distributed in the hope that it will be useful, but   WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU   General Public License for more details.   You should have received a copy of the GNU General Public License along   with this program; if not, write to the Free Software Foundation, Inc.,   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.   *//*   $Id: sdpserver.c,v 1.58 2003/04/17 11:30:32 kds Exp $   Contains the implementation of the SDP server itself including   the main() of the server and it's initialization   Fixes:   		Imre Deak <ext-imre.deak@nokia.com>		Dmitry Kasatkin*/#include <affix/config.h>#include <stdio.h>#include <stdint.h>#include <stdlib.h>#include <fcntl.h>#include <errno.h>#include <unistd.h>#include <signal.h>#include <string.h>#include <getopt.h>#include <sys/socket.h>#include <netinet/in.h>#include <sys/select.h>#include <sys/stat.h>#include <sys/time.h>#include <affix/bluetooth.h>#include <affix/sdp.h>#include <affix/sdpclt.h>#include <affix/sdpsrv.h>#include "utils.h"#include "servicedb.h"#include "attr.h"#include "cstate.h"fd_set		activeFdSet;int		serverBTSockFd;int		serverTCPSockFd;int		maxFd;int		argind;static int	got_signal = 0;/* ** Server and client socket addresses */struct sockaddr_affix	serverBTAddr;struct sockaddr_in	serverINAddr;extern void startWorkers(int);uuid_t sdpSrvUUID;slist_t *versionNumberSeq = NULL;sdpsvc_t *sdpSvcRec;sdpsvc_t *publicBrowseGroupRoot;/* ** List of version numbers supported ** by the SDP server. Add to this list ** when newer versions are supported */const int sdpServerVnumEntries = 1;uint16_t sdpVnumArray[1] = { 0x0100 };char *pSvcName = "SDP Server";char *pProvName = "Nokia Research Center";char *pSvcDesc = "Affix Service Discovery server";char *pBrowseGroupName = "Public Browse Group Root";char *pGroupDesc = "Root of public group hierarchy";int _sdp_process_req(sdp_request_t *request);int _sdp_disc_req(int fd);/* ** The service DB state is an attribute of the service record ** of the SDP server itself. This attribute is guaranteed to ** change if any of the contents of the service repository ** changes. This function updates the timestamp of value of ** the svcDBState attribute ** Set the SDP server DB. Simply a timestamp which is the marker ** when the DB was modified. */void sdp_update_time(void){	uint32_t	dbts = sdp_get_time();		sdp_append_attr(sdpSvcRec, SDP_ATTR_SERVICE_DB_STATE, sdp_put_u32(dbts));	sdp_gen_svc_pdu(sdpSvcRec);}int registerPublicBrowseGroupRoot(void){	int		status = 0;	sdpdata_t	*attr;	publicBrowseGroupRoot = sdp_create_svc();	publicBrowseGroupRoot->serviceRecordHandle = (uint32_t)publicBrowseGroupRoot;	sdp_add_svc(publicBrowseGroupRoot);	sdp_append_attr(publicBrowseGroupRoot, SDP_ATTR_SERVICE_RECORD_HANDLE, 					sdp_put_u32(publicBrowseGroupRoot->serviceRecordHandle));	sdp_set_info_attr(publicBrowseGroupRoot, pBrowseGroupName, pProvName, pGroupDesc);	attr = sdp_set_class_attr(publicBrowseGroupRoot);	sdp_add_class(attr, SDP_UUID_BROWSE_GROUP_DESC);	sdp_add_uuid16_to_pattern(publicBrowseGroupRoot, SDP_UUID_BROWSE_GROUP_DESC);		sdp_set_group_attr(publicBrowseGroupRoot, SDP_UUID_PUBLIC_BROWSE_GROUP);	sdp_add_uuid16_to_pattern(publicBrowseGroupRoot, SDP_UUID_PUBLIC_BROWSE_GROUP);	sdp_gen_svc_pdu(publicBrowseGroupRoot);	return status;}/* ** The SDP server must present it's own service record to ** the service repository. This can be accessed by service ** discovery clients. This methods constructs a service record ** and stores it in the reposssitory */int registerSDPServerService(void){	int		status = 0, i;	sdpdata_t	*data;	sdpdata_t	*attr, *param;	sdpSvcRec = sdp_create_svc();	/*	 ** Force the svcRecHandle to be SDP_ATTR_SERVICE_RECORD_HANDLE - 0	 */	sdpSvcRec->serviceRecordHandle = SDP_ATTR_SERVICE_RECORD_HANDLE;	sdp_add_svc(sdpSvcRec);	sdp_append_attr(sdpSvcRec, SDP_ATTR_SERVICE_RECORD_HANDLE, sdp_put_u32(sdpSvcRec->serviceRecordHandle));	/*	 ** Add all attributes to service record. No need to	 ** commit since we are the server and this record is	 ** already in the serviceDB	 */	status = sdp_set_info_attr(sdpSvcRec, pSvcName, pProvName, pSvcDesc);	attr = sdp_set_class_attr(sdpSvcRec);	sdp_add_class(attr, SDP_UUID_SDP_SERVER);	sdp_add_uuid16_to_pattern(sdpSvcRec, SDP_UUID_SDP_SERVER);	/*	 ** Set the version numbers supported, these are passed as arguments	 ** to the server on command line. Now defaults to 1.0	 ** Build the version number sequence first	 */	data = sdp_create_seq();	for (i = 0; i < sdpServerVnumEntries; i++)		sdp_append_u16(data, sdpVnumArray[i]);	sdp_append_attr(sdpSvcRec, SDP_ATTR_VERSION_NUMBER_LIST, data);	sdp_set_service_attr(sdpSvcRec, SDP_UUID_SDP);	sdp_add_uuid16_to_pattern(sdpSvcRec, SDP_UUID_SDP);	attr = sdp_set_proto_attr(sdpSvcRec);	param = sdp_add_proto(attr, SDP_UUID_L2CAP, SDP_PSM, 2, 1);	attr = sdp_set_subgroup_attr(sdpSvcRec);	sdp_add_subgroup(attr, SDP_UUID_PUBLIC_BROWSE_GROUP);	sdp_add_uuid16_to_pattern(sdpSvcRec, SDP_UUID_PUBLIC_BROWSE_GROUP);	sdp_update_time();	return 0;}/* ** SDP server initialization on startup includes creating ** the BT PSM and TCP sockets over which service discovery clients ** and service registration clients respectively access the ** SDP server */int initServer(void){	int status = 0;	status = sdp_init(SDP_SVC_SERVER);	if (status != 0) {		BTERROR("Could not find local BT device address, terminating");		return -1;	}	sdp_init_svcdb();	sdp_init_cscache();	/*	 ** Register the public browse group Root	 */	registerPublicBrowseGroupRoot();	/*	 ** Register the SDP server as a service	 */	registerSDPServerService();	/*	 ** Create our socket on PSM 1 and	 ** set activeFdSet	 */	serverBTSockFd = socket(PF_AFFIX, SOCK_SEQPACKET, BTPROTO_L2CAP);	if (serverBTSockFd < 0) {		BTERROR("BT Socket creation failure:%s", strerror(errno));		return serverBTSockFd;	}	serverBTAddr.family = AF_AFFIX;	serverBTAddr.devnum = HCIDEV_ANY;	serverBTAddr.bda = BDADDR_ANY;	serverBTAddr.port = SDP_PSM;	status = bind(serverBTSockFd, (struct sockaddr *)&serverBTAddr, sizeof(serverBTAddr));	if (status < 0) {		BTERROR("BT bind failure:%s", strerror(errno));		return status;	}	status = listen(serverBTSockFd, 5);	if (status < 0)		return status;	FD_SET(serverBTSockFd, &activeFdSet);	maxFd = serverBTSockFd;	serverTCPSockFd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);	if (serverTCPSockFd < 0) {		BTERROR("TCP socket creation failure:%s", strerror(errno));		return serverTCPSockFd;	}	serverINAddr.sin_family = AF_INET;	serverINAddr.sin_port = SDP_TCP_PORT;	status = bind(serverTCPSockFd, (struct sockaddr *)&serverINAddr, sizeof(serverINAddr));	if (status < 0) {		BTERROR("TCP bind failure:%s", strerror(errno));		return status;	}	status = listen(serverTCPSockFd, 5);	FD_SET(serverTCPSockFd, &activeFdSet);	maxFd = serverTCPSockFd;	return status;}void exitServer(void){	sdp_reset_svcdb();	sdp_cleanup_cscache();	close(serverBTSockFd);	close(serverTCPSockFd);}/* ** This is the SDP server main thread ** After appropriate initialization, uses the select() ** to field inputs from both the BT and TCP sockets. ** ** Calls the _sdp_process_req() if single threaded else ** extracts the request and populates the request queue  ** for servicing by one or more worker threads that are ** active */void sdpServerSignalHandler(int sig){	got_signal = sig;}void usage(void){	fprintf(stderr, "btsdp %s [-d] [-b]\n"			"  -d: start as daemon\n  -b: with debug info\n", affix_version);}int main(int argc, char **argv){	/*	 ** Create our socket for connection	 ** requests. Start worker threads	 */	int	status = 0, lind, c;	int	btdaemon = 0;	int	clientCount = 0;	struct option	opts[] = {		{"help", 0, 0, 'h'},		{"daemon", 0, 0, 'd'},		{"debug", 0, 0, 'b'},		{0, 0, 0, 0}	};	openlog(NULL/*argv[0]*/, 0, LOG_DAEMON);	affix_logmask = BTDEBUG_MODULE;	for (;;) {		c = getopt_long(argc, argv, "+hdbD", opts, &lind);		if (c == -1)			break;		switch (c) {			case 'h':				usage();				return -1;				break;			case 'd':				btdaemon = 1;				break;			case 'D':				btdaemon = 2;	// do not fork				break;			case 'b':				affix_logmask = BTDEBUG_MODULE;				break;			case ':':				printf("Missing parameters for option: %c\n", optopt);				return 1;				break;			case '?':				printf("Unknown option: %c\n", optopt);				return 1;				break;		}	}	argind = optind;	BTINFO("%s %s started.", argv[0], affix_version);	status = initServer();	if (status) {		BTERROR("Terminating, init error");		return -1;	}	if (btdaemon && become_daemon(btdaemon != 2))		return 0;	signal(SIGINT, sdpServerSignalHandler);	signal(SIGTERM, sdpServerSignalHandler);	signal(SIGABRT, sdpServerSignalHandler);	signal(SIGQUIT, sdpServerSignalHandler);	for (;;) {		int		numFds;		int		newFd;		fd_set		checkFds;		struct timeval	tv;		int 		fd;		FD_ZERO(&checkFds);		checkFds = activeFdSet;		if (!clientCount)			tv.tv_sec = 3;		else			tv.tv_sec = 1000;		tv.tv_usec = 0;				/*		 ** Check on active fds		 */		DBPRT("selecting new FD to read, clientCount: %d\n", clientCount);		numFds = select(maxFd+1, &checkFds, NULL, NULL, &tv);		DBPRT("Selected: %d, %s (%d)", numFds, strerror(errno), errno);		if (numFds < 0) {			DBPRT("Select error:%s", strerror(errno));			goto exit;		} else if (numFds == 0) {			/* timeout happend */			if (clientCount == 0) {				DBPRT("No connected clients, quit...\n");				goto exit;			}		}		if (FD_ISSET(serverBTSockFd, &checkFds)) {			/*			 ** A new Bluetooth connection ..			 */			struct sockaddr_affix	clientBTAddr;			socklen_t		sockLength = sizeof(clientBTAddr);			numFds--;			newFd = accept(serverBTSockFd, (struct sockaddr *)&clientBTAddr, &sockLength);			DBPRT("new bt fd : %d", newFd); 			if (newFd != -1) {				if (newFd > maxFd)					maxFd = newFd;				FD_SET(newFd, &activeFdSet);				clientCount++;			} else				BTERROR("Error accepting Bluetooth client connection:%s", strerror(errno));						} else if (FD_ISSET(serverTCPSockFd, &checkFds)) {			/*			 ** A new TCP connection			 */			struct sockaddr_in	clientINAddr;			socklen_t		sockLength = sizeof(clientINAddr);			numFds--;			newFd = accept(serverTCPSockFd, (struct sockaddr *)&clientINAddr, &sockLength);			DBPRT("new tcp fd : %d", newFd);			if (newFd != -1) {				if (newFd > maxFd)					maxFd = newFd;				FD_SET(newFd, &activeFdSet);				clientCount++;			} else				BTERROR("Error accepting TCP client connection:%s", strerror(errno));		} else {			for (fd = 0; fd <= maxFd && numFds; fd++) {				if (fd == serverBTSockFd || fd == serverTCPSockFd)					continue;				if (FD_ISSET(fd, &checkFds)) {					int 		rx_count;					sdp_hdr_t	sdpHeader;					sdp_request_t	sdpReq;					int		pkt_len;					numFds--;					DBPRT("Reading from : %d", fd);					rx_count = recv(fd, &sdpHeader, sizeof(sdp_hdr_t), MSG_PEEK);					DBPRT("Bytes read : %d", rx_count);					if (rx_count >= sizeof(sdp_hdr_t)) {						pkt_len = sizeof(sdp_hdr_t) + ntohs(sdpHeader.paramLength);						DBPRT("PDU size : %d", pkt_len);						sdpReq.data = (char*)malloc(pkt_len);						if (!sdpReq.data)							goto disc;						rx_count = recv(fd, sdpReq.data, pkt_len, 0);						DBPRT("Bytes read : %d", rx_count);						if (rx_count >= sizeof(sdp_hdr_t)) {							sdpReq.fd = fd;							sdpReq.mtu = sdp_getmtu(fd);							sdpReq.len = rx_count;							status = _sdp_process_req(&sdpReq);							free(sdpReq.data);							if (status < 0)								goto disc;						} else {							free(sdpReq.data);							goto disc;						}					} else {				disc:						if (rx_count < 0) {							BTERROR("Read error:%s", strerror(errno));						}						_sdp_disc_req(fd);						sdp_close(fd);						DBPRT("Conn closed: %d, read: %d", fd, rx_count);						clientCount--;						FD_CLR(fd, &activeFdSet);						if (fd == maxFd)							maxFd--;					} 				}			}		}	}exit:	exitServer();	BTINFO("%s terminated.", argv[0]);	return status;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -