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

📄 states.c

📁 linux蓝牙剖面实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * *  Headset Profile support for Linux * *  Copyright (C) 2006  Fabien Chevalier * *  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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA * */#include <bluetooth/bluetooth.h>#include <bluetooth/rfcomm.h>#include <bluetooth/sdp.h>#include <bluetooth/sdp_lib.h>#include <bluetooth/sco.h>#include <sys/socket.h>#include <sys/poll.h>#include <sys/un.h>#include <fcntl.h>#include <unistd.h>#include <stdlib.h>#include <errno.h>#include <syslog.h>#include <stdint.h>#include <config.h>#include "states.h"#include "sdp.h"#include "volctl.h"#include "dbus.h"/* Local defines */  /* Size for sco packets we send/receive */#define SCO_PACKET_LEN        48#define CTL_LRU_ARRAY_SIZE    5  /* PCM Appl IPC packet types */#define PKT_TYPE_CFG_BDADDR        0#define PKT_TYPE_CFG_PAGINGTIMEOUT 1#define PKT_TYPE_CFG_ACK           2#define PKT_TYPE_CFG_NACK          3#define PKT_TYPE_ERROR_IND         4#define PKT_TYPE_STREAMING_IND     5/* Local structures definition */typedef struct ipc_packet {	unsigned char type;	union {		bdaddr_t     bdaddr;	               /* PKT_TYPE_CFG_BDADDR        */		int32_t      timeout;                  /* PKT_TYPE_CFG_PAGINGTIMEOUT */		int32_t	     errorcode;		       /* PKT_TYPE_ERROR_IND         */	};} ipc_packet_t;/* Local variables */  /* Stores SDP session used to scan for Headset Profile */static sdp_session_t *hs_sdp_session;  /* Stores the bd address for the device we are connected to */static bdaddr_t       hs_bdaddr;static long           hs_pagingtimeout;  /* Stores if we are in/or just came out from a state where we     are connected to the headset */static int            hs_connected;/* Functions shared by all states */static void appl_send_error_pkt(int error, int applfd){	ipc_packet_t pkt = {.type = PKT_TYPE_ERROR_IND};	int bckp = errno; /* backing up errno */	pkt.errorcode = error;	send(applfd, &pkt, sizeof(pkt), MSG_NOSIGNAL);	errno = bckp;}   /* This one is shared by all states, as it is not supposed to alter / depend on the state in which we are */static void process_at_command(const char* data, unsigned int datalen);void connectedReadCtlAppl(struct State *s, short revents){	volctl_ReadCtlApplSocket(s, revents, volctl_write_fromappl);}void unconnectedReadCtlAppl(struct State *s, short revents){	volctl_ReadCtlApplSocket(s, revents, volctl_write_fromappl_unconnected);}static struct State * genericGetNextState(struct State *this){	return this->_next_state;}static void genericReadRfcomm(struct State *this, short revents){	if((revents & (POLLHUP | POLLERR)) == 0) {		char buffer[32];		int size;		if((size = recv(hspd_sockets[IDX_RFCOMM_SOCK], buffer, sizeof(buffer) - 1, 0)) > 0) {			buffer[size] = 0;			process_at_command(buffer, size);		}		this->_next_state = this;	}	else {		syslog(LOG_NOTICE, "Headset disconnected as RFCOMM socket died");		/* back to Idle */		this->_next_state = &HeadsetIdleState;	}}static void genericReadSco(struct State *this, short revents){	if((revents & (POLLHUP | POLLERR)) == 0) {		this->_next_state = this;	}	else {		syslog(LOG_NOTICE, "Headset disconnected as SCO socket died");		/* back to Idle */		this->_next_state = &HeadsetIdleState;	}}static int rfcommConnectAsync(const bdaddr_t * dst, uint8_t channel){	struct sockaddr_rc addr;	int s;	if ((s = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)) < 0) {		return -1;	}	/* Set socket as non blocking */	if(fcntl(s, F_SETFL, O_NONBLOCK) < 0) {		close(s);		return -1;		}	memset(&addr, 0, sizeof(addr));	addr.rc_family = AF_BLUETOOTH;	bacpy(&addr.rc_bdaddr, dst);	addr.rc_channel = channel;	if ((connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) 			&& (errno != EAGAIN) && (errno != EINPROGRESS)) {		close(s);		return -1;	}	return s;}static int scoConnectAsync(const bdaddr_t * dst){	struct sockaddr_sco addr;	int s;	if ((s = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO)) < 0) {		return -1;	}	/* Set socket as non blocking */	if(fcntl(s, F_SETFL, O_NONBLOCK) < 0) {		close(s);		return -1;		}	memset(&addr, 0, sizeof(addr));	addr.sco_family = AF_BLUETOOTH;	bacpy(&addr.sco_bdaddr, dst);	if ((connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0)			&& (errno != EAGAIN) && (errno != EINPROGRESS)) {		close(s);		return -1;	}	return s;}static int recv_cfg(int applsockfd, bdaddr_t* bdaddr, long *timeout){	int ret;	int expected_configs = 2;	const int CFG_TIMEOUT = 1000;	struct pollfd pfd = {.fd = applsockfd, .events = POLLIN};		while(expected_configs > 0) {		ret = poll(&pfd, 1, CFG_TIMEOUT);		if(ret == 1 && (!(pfd.revents & (POLLHUP | POLLERR))) ) {			expected_configs--;			ipc_packet_t pkt;			recv(applsockfd, &pkt, sizeof(ipc_packet_t), 0);			switch(pkt.type) {			case PKT_TYPE_CFG_BDADDR:				if(bdaddr != 0) {					bacpy(bdaddr, &pkt.bdaddr);					pkt.type = PKT_TYPE_CFG_ACK;				}				else {					pkt.type = PKT_TYPE_CFG_NACK;				}				send(applsockfd, &pkt, sizeof(ipc_packet_t), MSG_NOSIGNAL); 				break;			case PKT_TYPE_CFG_PAGINGTIMEOUT:				if(timeout != 0) {					if(pkt.timeout <= 0) {						*timeout = -1;						}					else {						*timeout = pkt.timeout;					}					pkt.type = PKT_TYPE_CFG_ACK;				}				else {					pkt.type = PKT_TYPE_CFG_NACK;				}				send(applsockfd, &pkt, sizeof(ipc_packet_t), MSG_NOSIGNAL); 				break;			default:				syslog(LOG_WARNING, "ignoring packet from local appli: type = %d", pkt.type);			}		}		else if (ret == 0) {			syslog(LOG_ERR, "Timeout retrieving configuration from local appli.");			return -1;		}		else {			syslog(LOG_ERR, "unable to retrieve configuration from local appli: %s", strerror(errno));			return -1;		}		}	return 0;}/* Idle State */static void headsetIdleEnter(struct State *this){	if(hs_connected) {		signalHeadsetDisconnected(&hs_bdaddr);	}	hs_connected = 0;	/* killing client sockets */	if(hspd_sockets[IDX_PCM_APPL_SOCK] != 0) {		close(hspd_sockets[IDX_PCM_APPL_SOCK]);		hspd_sockets[IDX_PCM_APPL_SOCK] = 0;	}	if(hspd_sockets[IDX_SCO_SOCK] != 0) {		close(hspd_sockets[IDX_SCO_SOCK]);		hspd_sockets[IDX_SCO_SOCK] = 0;	}	if(hspd_sockets[IDX_RFCOMM_SOCK] != 0) {		close(hspd_sockets[IDX_RFCOMM_SOCK]);		hspd_sockets[IDX_RFCOMM_SOCK] = 0;	}	if(hspd_sockets[IDX_SDP_SOCK] != 0) {		close(hspd_sockets[IDX_SDP_SOCK]);		hspd_sockets[IDX_SDP_SOCK] = 0;	}	memset(&hs_bdaddr, 0, sizeof(bdaddr_t));	/* This is not a transitional state */	this->_next_state = this;	}static void headsetIdleHandleApplConnReq(struct State *this){	struct sockaddr_un client_addr;	unsigned int client_addr_len = sizeof(client_addr);	/* Per default stay in same state */	this->_next_state = this;		/* Connect Appli to us */	int _appl_sock = accept(hspd_sockets[IDX_PCM_APPL_SRV_SOCK], (struct sockaddr *)&client_addr, &client_addr_len);	if(_appl_sock != -1) {		/* Retrieve configuration parameters */		fcntl(_appl_sock, F_SETFL, O_NONBLOCK);		if(recv_cfg(_appl_sock, &hs_bdaddr, &hs_pagingtimeout) >= 0) {			char remoteaddr[32];			ba2str(&hs_bdaddr, remoteaddr);			syslog(LOG_INFO, "Configuration phase ended: target bdaddr is %s, timeout is %ld ms", remoteaddr, hs_pagingtimeout);			/* Launch SDP on bluetooth headset */			hs_sdp_session = sdp_connect(BDADDR_ANY, &hs_bdaddr, SDP_NON_BLOCKING);				if(hs_sdp_session != 0) {				hspd_sockets[IDX_PCM_APPL_SOCK] = _appl_sock;				hspd_sockets[IDX_SDP_SOCK] = sdp_get_socket(hs_sdp_session);				this->_next_state = &HeadsetPagingState;			}			else {				appl_send_error_pkt(errno, _appl_sock);				syslog(LOG_ERR, "unable to create bluetooth L2CAP socket: %s", strerror(errno));				close(_appl_sock);			}		}		else {			close(_appl_sock);			return;		}	}}static void headsetIdleHandleRfcommConnReq(struct State *this){	struct sockaddr_rc client_addr;	unsigned int client_addr_len = sizeof(client_addr);	/* Per default stay in same state */	this->_next_state = this;		/* Connect Appli to us */	int _rfcomm_sock = accept(hspd_sockets[IDX_RFCOMM_SRV_SOCK], (struct sockaddr *)&client_addr, &client_addr_len);	if(_rfcomm_sock != -1) {		char remoteaddr[32];		ba2str(&client_addr.rc_bdaddr, remoteaddr);		syslog(LOG_INFO, "Incoming RFCOMM hs connection from %s accepted",				remoteaddr);		hspd_sockets[IDX_RFCOMM_SOCK] = _rfcomm_sock;		bacpy(&hs_bdaddr, &client_addr.rc_bdaddr);		hs_connected = 1;		signalHeadsetConnected(&hs_bdaddr);		this->_next_state = &HeadsetConnectedState;	}	else {		appl_send_error_pkt(errno, hspd_sockets[IDX_PCM_APPL_SOCK]);		syslog(LOG_ERR, "unable to accept bluetooth RFCOMM socket : %s", strerror(errno));		close(_rfcomm_sock);	}}struct State HeadsetIdleState = {	.name = "Idle",	.pollEvents = {		[IDX_PCM_APPL_SRV_SOCK]   = POLLIN,		[IDX_CTL_APPL_SRV_SOCK]   = POLLIN,		[IDX_RFCOMM_SRV_SOCK] = POLLIN	 },	.enter               = headsetIdleEnter,	.handleApplConnReq   = headsetIdleHandleApplConnReq,	.handleRfcommConnReq = headsetIdleHandleRfcommConnReq,	.readCtlAppl         = unconnectedReadCtlAppl,	.getNextState        = genericGetNextState,};/* Paging State */static void headsetPagingReadSdp(struct State *this, short revents){	/* Fetching result code */	int errcode = -1;	unsigned int opt_size = sizeof(int);	/* Per default stay in same state */	this->_next_state = &HeadsetIdleState;		if(getsockopt(hspd_sockets[IDX_SDP_SOCK], SOL_SOCKET, SO_ERROR, &errcode, &opt_size) == 0) {		if(errcode == 0) {			/* Retrieving sdp info */			uint32_t range = 0x0000ffff;			sdp_list_t *attrid, *search, *seq, *next;			uuid_t group;			int searchresult;			uint8_t channel = 1;						sdp_uuid16_create(&group, HEADSET_PROFILE_ID);						attrid = sdp_list_append(0, &range);			search = sdp_list_append(0, &group);			searchresult =			sdp_service_search_attr_req(hs_sdp_session, search, SDP_ATTR_REQ_RANGE,							attrid, &seq);			sdp_list_free(attrid, 0);			sdp_list_free(search, 0);					if (searchresult == 0) {				for (; seq; seq = next) {					sdp_record_t *rec = (sdp_record_t *) seq->data;					sdp_list_t *list = 0;					if (sdp_get_access_protos(rec, &list) == 0) {						channel = sdp_get_proto_port(list, RFCOMM_UUID);					}					next = seq->next;					free(seq);					sdp_record_free(rec);				}			}			else {				syslog(LOG_WARNING, "Service search failed: %s", strerror(errno));			}			sdp_close(hs_sdp_session);			/* Socket is already closed by sdp_close, so we only zero it */			hspd_sockets[IDX_SDP_SOCK] = 0;			/* Try connecting to bluetooth headset */			int _rfcomm_sock = rfcommConnectAsync(&hs_bdaddr, channel);						if(_rfcomm_sock >= 0) {				hspd_sockets[IDX_RFCOMM_SOCK] = _rfcomm_sock;				this->_next_state = &HeadsetConnectingState;			}			else {				appl_send_error_pkt(errno, hspd_sockets[IDX_PCM_APPL_SOCK]);				syslog(LOG_ERR, "unable to create bluetooth RFCOMM socket: %s", strerror(errno));			}		}		else {			appl_send_error_pkt(errcode, hspd_sockets[IDX_PCM_APPL_SOCK]);			syslog(LOG_NOTICE, "unable to connect L2CAP socket to headset: %s", strerror(errcode));			/* go to default state : idle */		}	}	else {		sdp_close(hs_sdp_session);		hspd_sockets[IDX_SDP_SOCK] = 0;	}}void headsetPagingTimedout(struct State *this){	appl_send_error_pkt(EHOSTUNREACH, hspd_sockets[IDX_PCM_APPL_SOCK]);	syslog(LOG_NOTICE, "Timeout connecting L2CAP socket to headset, aborting.");	this->_next_state = &HeadsetIdleState;}int headsetPagingGetTimeout(struct State *this){	return hs_pagingtimeout;}struct State HeadsetPagingState = {	.name = "Paging",	.pollEvents = {		[IDX_CTL_APPL_SRV_SOCK]   = POLLIN,		[IDX_SDP_SOCK] = POLLOUT,	 },	.readSdp       = headsetPagingReadSdp,	.timedout      = headsetPagingTimedout,	.getTimeout    = headsetPagingGetTimeout,	.readCtlAppl   = unconnectedReadCtlAppl,	.getNextState  = genericGetNextState,};/* Connecting State */static void headsetConnectingReadRfcomm(struct State *this, short revents){	/* Fectching result code */	int errcode;	unsigned int opt_size = sizeof(int);	/* default next state is back to home : idle */	this->_next_state = &HeadsetIdleState;	if(getsockopt(hspd_sockets[IDX_RFCOMM_SOCK], SOL_SOCKET, SO_ERROR, &errcode, &opt_size) == 0) {		if(errcode == 0) {			hs_connected = 1;			signalHeadsetConnected(&hs_bdaddr);			/* Go to HeadsetReady state */			this->_next_state = &HeadsetReadyState;		}		else {			appl_send_error_pkt(errcode, hspd_sockets[IDX_PCM_APPL_SOCK]);

⌨️ 快捷键说明

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