diff options
| author | Marcel Holtmann <marcel@holtmann.org> | 2005-01-27 18:16:11 +0000 | 
|---|---|---|
| committer | Marcel Holtmann <marcel@holtmann.org> | 2005-01-27 18:16:11 +0000 | 
| commit | 7715ad4f56e82c9eb4cf75020b1f3039d06ce115 (patch) | |
| tree | 83e9968d324b1ef15d6df166822f28d80bdfc09b /test/l2test.c | |
| parent | 0dab40dad416805e31cb5312956880609dc21443 (diff) | |
Cleanup the socket handling
Diffstat (limited to 'test/l2test.c')
| -rw-r--r-- | test/l2test.c | 295 | 
1 files changed, 177 insertions, 118 deletions
| diff --git a/test/l2test.c b/test/l2test.c index 272f40f6..ac831d97 100644 --- a/test/l2test.c +++ b/test/l2test.c @@ -76,8 +76,8 @@ static long data_size = 0;  static bdaddr_t bdaddr;  static unsigned short psm = 10; -/* Default number of frames to send */ -static int num_frames = -1; // Infinite +/* Default number of frames to send (-1 = infinite) */ +static int num_frames = -1;  static int master = 0;  static int auth = 0; @@ -166,46 +166,58 @@ static void hexdump(char *s, unsigned long l)  static int do_connect(char *svr)  { -	struct sockaddr_l2 rem_addr, loc_addr; +	struct sockaddr_l2 addr;  	struct l2cap_options opts;  	struct l2cap_conninfo conn; -	int s, opt; +	socklen_t optlen; +	int sk, opt; -	if ((s = socket(PF_BLUETOOTH, socktype, BTPROTO_L2CAP)) < 0) { -		syslog(LOG_ERR, "Can't create socket: %s (%d)", strerror(errno), errno); +	/* Create socket */ +	sk = socket(PF_BLUETOOTH, socktype, BTPROTO_L2CAP); +	if (sk < 0) { +		syslog(LOG_ERR, "Can't create socket: %s (%d)", +							strerror(errno), errno);  		return -1;  	} -	memset(&loc_addr, 0, sizeof(loc_addr)); -	loc_addr.l2_family = AF_BLUETOOTH; -	bacpy(&loc_addr.l2_bdaddr, &bdaddr); -	if (bind(s, (struct sockaddr *) &loc_addr, sizeof(loc_addr)) < 0) { -		syslog(LOG_ERR, "Can't bind socket: %s (%d)", strerror(errno), errno); -		exit(1); +	/* Bind to local address */ +	memset(&addr, 0, sizeof(addr)); +	addr.l2_family = AF_BLUETOOTH; +	bacpy(&addr.l2_bdaddr, &bdaddr); + +	if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { +		syslog(LOG_ERR, "Can't bind socket: %s (%d)", +							strerror(errno), errno); +		goto error;  	}  	/* Get default options */  	memset(&opts, 0, sizeof(opts)); -	opt = sizeof(opts); -	if (getsockopt(s, SOL_L2CAP, L2CAP_OPTIONS, &opts, &opt) < 0) { -		syslog(LOG_ERR, "Can't get default L2CAP options: %s (%d)", strerror(errno), errno); -		return -1;	 +	optlen = sizeof(opts); + +	if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, &optlen) < 0) { +		syslog(LOG_ERR, "Can't get default L2CAP options: %s (%d)", +							strerror(errno), errno); +		goto error;  	}  	/* Set new options */  	opts.omtu = omtu;  	opts.imtu = imtu; -	if (setsockopt(s, SOL_L2CAP, L2CAP_OPTIONS, &opts, opt) < 0) { -		syslog(LOG_ERR, "Can't set L2CAP options: %s (%d)", strerror(errno), errno); -		return -1; + +	if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)) < 0) { +		syslog(LOG_ERR, "Can't set L2CAP options: %s (%d)", +							strerror(errno), errno); +		goto error;  	}  	/* Enable SO_LINGER */  	if (linger) {  		struct linger l = { .l_onoff = 1, .l_linger = linger }; -		if (setsockopt(s, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0) { + +		if (setsockopt(sk, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0) {  			syslog(LOG_ERR, "Can't enable SO_LINGER: %s (%d)", -				strerror(errno), errno); +							strerror(errno), errno);  			return -1;  		}  	} @@ -215,63 +227,82 @@ static int do_connect(char *svr)  	if (reliable)  		opt |= L2CAP_LM_RELIABLE; -	if (setsockopt(s, SOL_L2CAP, L2CAP_LM, &opt, sizeof(opt)) < 0) { -		syslog(LOG_ERR, "Can't set L2CAP link mode: %s (%d)", strerror(errno), errno); -		exit(1); +	if (setsockopt(sk, SOL_L2CAP, L2CAP_LM, &opt, sizeof(opt)) < 0) { +		syslog(LOG_ERR, "Can't set L2CAP link mode: %s (%d)", +							strerror(errno), errno); +		goto error;  	} -	memset(&rem_addr, 0, sizeof(rem_addr)); -	rem_addr.l2_family = AF_BLUETOOTH; -	str2ba(svr, &rem_addr.l2_bdaddr); -	rem_addr.l2_psm = htobs(psm); -	if (connect(s, (struct sockaddr *) &rem_addr, sizeof(rem_addr)) < 0 ) { -		syslog(LOG_ERR, "Can't connect: %s (%d)", strerror(errno), errno); -		close(s); -		return -1; +	/* Connect to remote device */ +	memset(&addr, 0, sizeof(addr)); +	addr.l2_family = AF_BLUETOOTH; +	str2ba(svr, &addr.l2_bdaddr); +	addr.l2_psm = htobs(psm); + +	if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0 ) { +		syslog(LOG_ERR, "Can't connect: %s (%d)", +							strerror(errno), errno); +		goto error;  	} +	/* Get current options */  	memset(&opts, 0, sizeof(opts)); -	opt = sizeof(opts); -	if (getsockopt(s, SOL_L2CAP, L2CAP_OPTIONS, &opts, &opt) < 0) { -		syslog(LOG_ERR, "Can't get L2CAP options: %s (%d)", strerror(errno), errno); -		close(s); -		return -1; +	optlen = sizeof(opts); + +	if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, &optlen) < 0) { +		syslog(LOG_ERR, "Can't get L2CAP options: %s (%d)", +							strerror(errno), errno); +		goto error;  	} +	/* Get connection information */  	memset(&conn, 0, sizeof(conn)); -	opt = sizeof(conn); -	if (getsockopt(s, SOL_L2CAP, L2CAP_CONNINFO, &conn, &opt) < 0) { -		syslog(LOG_ERR, "Can't get L2CAP connection information: %s (%d)", strerror(errno), errno); -		close(s); -		return -1; +	optlen = sizeof(conn); + +	if (getsockopt(sk, SOL_L2CAP, L2CAP_CONNINFO, &conn, &optlen) < 0) { +		syslog(LOG_ERR, "Can't get L2CAP connection information: %s (%d)", +							strerror(errno), errno); +		goto error;  	} -	syslog(LOG_INFO, "Connected [imtu %d, omtu %d, flush_to %d, mode %d, handle %d, class 0x%02x%02x%02x]", +	syslog(LOG_INFO, "Connected [imtu %d, omtu %d, flush_to %d, " +				"mode %d, handle %d, class 0x%02x%02x%02x]",  		opts.imtu, opts.omtu, opts.flush_to, opts.mode, conn.hci_handle,  		conn.dev_class[2], conn.dev_class[1], conn.dev_class[0]); -	return s; +	return sk; + +error: +	close(sk); +	return -1;  }  static void do_listen(void (*handler)(int sk))  { -	struct sockaddr_l2 loc_addr, rem_addr; +	struct sockaddr_l2 addr;  	struct l2cap_options opts;  	struct l2cap_conninfo conn; -	int s, s1, opt; +	socklen_t optlen; +	int sk, nsk, opt;  	char ba[18]; -	if ((s = socket(PF_BLUETOOTH, socktype, BTPROTO_L2CAP)) < 0) { -		syslog(LOG_ERR, "Can't create socket: %s (%d)", strerror(errno), errno); +	/* Create socket */ +	sk = socket(PF_BLUETOOTH, socktype, BTPROTO_L2CAP); +	if (sk < 0) { +		syslog(LOG_ERR, "Can't create socket: %s (%d)", +							strerror(errno), errno);  		exit(1);  	} -	loc_addr.l2_family = AF_BLUETOOTH; -	bacpy(&loc_addr.l2_bdaddr, &bdaddr); -	loc_addr.l2_psm = htobs(psm); -	if (bind(s, (struct sockaddr *) &loc_addr, sizeof(loc_addr)) < 0) { -		syslog(LOG_ERR, "Can't bind socket: %s (%d)", strerror(errno), errno); -		exit(1); +	/* Bind to local address */ +	addr.l2_family = AF_BLUETOOTH; +	bacpy(&addr.l2_bdaddr, &bdaddr); +	addr.l2_psm = htobs(psm); + +	if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { +		syslog(LOG_ERR, "Can't bind socket: %s (%d)", +							strerror(errno), errno); +		goto error;  	}  	/* Set link mode */ @@ -287,138 +318,166 @@ static void do_listen(void (*handler)(int sk))  	if (secure)  		opt |= L2CAP_LM_SECURE; -	if (opt && setsockopt(s, SOL_L2CAP, L2CAP_LM, &opt, sizeof(opt)) < 0) { -		syslog(LOG_ERR, "Can't set L2CAP link mode: %s (%d)", strerror(errno), errno); -		exit(1); +	if (opt && setsockopt(sk, SOL_L2CAP, L2CAP_LM, &opt, sizeof(opt)) < 0) { +		syslog(LOG_ERR, "Can't set L2CAP link mode: %s (%d)", +							strerror(errno), errno); +		goto error;  	}  	/* Get default options */ -	opt = sizeof(opts); -	if (getsockopt(s, SOL_L2CAP, L2CAP_OPTIONS, &opts, &opt) < 0) { -		syslog(LOG_ERR, "Can't get default L2CAP options: %s (%d)", strerror(errno), errno); -		exit(1); +	memset(&opts, 0, sizeof(opts)); +	optlen = sizeof(opts); + +	if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, &optlen) < 0) { +		syslog(LOG_ERR, "Can't get default L2CAP options: %s (%d)", +							strerror(errno), errno); +		goto error;  	}  	/* Set new options */  	opts.imtu = imtu; -	if (setsockopt(s, SOL_L2CAP, L2CAP_OPTIONS, &opts, opt) < 0) { -		syslog(LOG_ERR, "Can't set L2CAP options: %s (%d)", strerror(errno), errno); -		exit(1); + +	if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)) < 0) { +		syslog(LOG_ERR, "Can't set L2CAP options: %s (%d)", +							strerror(errno), errno); +		goto error;  	}  	if (socktype == SOCK_DGRAM) { -		handler(s); +		handler(sk);  		return;  	} -	if (listen(s, 10)) { -		syslog(LOG_ERR,"Can not listen on the socket: %s (%d)", strerror(errno), errno); -		exit(1); +	/* Listen for connections */ +	if (listen(sk, 10)) { +		syslog(LOG_ERR, "Can not listen on the socket: %s (%d)", +							strerror(errno), errno); +		goto error;  	} -	syslog(LOG_INFO,"Waiting for connection on psm %d ...", psm); +	syslog(LOG_INFO, "Waiting for connection on psm %d ...", psm);  	while(1) { -		opt = sizeof(rem_addr); -		if ((s1 = accept(s, (struct sockaddr *) &rem_addr, &opt)) < 0) { -			syslog(LOG_ERR,"Accept failed: %s (%d)", strerror(errno), errno); -			exit(1); +		memset(&addr, 0, sizeof(addr)); +		optlen = sizeof(addr); + +		nsk = accept(sk, (struct sockaddr *) &addr, &optlen); +		if (nsk < 0) { +			syslog(LOG_ERR, "Accept failed: %s (%d)", +							strerror(errno), errno); +			goto error;  		}  		if (fork()) {  			/* Parent */ -			close(s1); +			close(nsk);  			continue;  		}  		/* Child */ +		close(sk); -		close(s); - +		/* Get current options */  		memset(&opts, 0, sizeof(opts)); -		opt = sizeof(opts); -		if (getsockopt(s1, SOL_L2CAP, L2CAP_OPTIONS, &opts, &opt) < 0) { -			syslog(LOG_ERR, "Can't get L2CAP options: %s (%d)", strerror(errno), errno); -			close(s1); -			exit(1); +		optlen = sizeof(opts); + +		if (getsockopt(nsk, SOL_L2CAP, L2CAP_OPTIONS, &opts, &optlen) < 0) { +			syslog(LOG_ERR, "Can't get L2CAP options: %s (%d)", +							strerror(errno), errno); +			close(nsk); +			goto error;  		} +		/* Get connection information */  		memset(&conn, 0, sizeof(conn)); -		opt = sizeof(conn); -		if (getsockopt(s1, SOL_L2CAP, L2CAP_CONNINFO, &conn, &opt) < 0) { -			syslog(LOG_ERR, "Can't get L2CAP connection information: %s (%d)", strerror(errno), errno); -			close(s1); -			exit(1); +		optlen = sizeof(conn); + +		if (getsockopt(nsk, SOL_L2CAP, L2CAP_CONNINFO, &conn, &optlen) < 0) { +			syslog(LOG_ERR, "Can't get L2CAP connection information: %s (%d)", +							strerror(errno), errno); +			close(nsk); +			goto error;  		} -		ba2str(&rem_addr.l2_bdaddr, ba); -		syslog(LOG_INFO, "Connect from %s [imtu %d, omtu %d, flush_to %d, mode %d, handle %d, class 0x%02x%02x%02x]\n", +		ba2str(&addr.l2_bdaddr, ba); +		syslog(LOG_INFO, "Connect from %s [imtu %d, omtu %d, flush_to %d, " +				"	mode %d, handle %d, class 0x%02x%02x%02x]",  			ba, opts.imtu, opts.omtu, opts.flush_to, opts.mode, conn.hci_handle,  			conn.dev_class[2], conn.dev_class[1], conn.dev_class[0]);  		/* Enable SO_LINGER */  		if (linger) {  			struct linger l = { .l_onoff = 1, .l_linger = linger }; -			if (setsockopt(s, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0) { + +			if (setsockopt(nsk, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0) {  				syslog(LOG_ERR, "Can't enable SO_LINGER: %s (%d)", -					strerror(errno), errno); -				exit(1); +							strerror(errno), errno); +				close(nsk); +				goto error;  			}  		} -		handler(s1); +		handler(nsk);  		syslog(LOG_INFO, "Disconnect: %m");  		exit(0);  	} + +	return; + +error: +	close(sk); +	exit(1);  } -static void dump_mode(int s) +static void dump_mode(int sk)  { -	int len; -	int opt, optl; +	socklen_t optlen; +	int opt, len;  	syslog(LOG_INFO, "Receiving ...");  	while (1) {  		fd_set rset;  		FD_ZERO(&rset); -		FD_SET(s, &rset); +		FD_SET(sk, &rset); -		if (select(s + 1, &rset, NULL, NULL, NULL) < 0) +		if (select(sk + 1, &rset, NULL, NULL, NULL) < 0)  			return; -		if (!FD_ISSET(s, &rset)) +		if (!FD_ISSET(sk, &rset))  			continue; -		len = read(s, buf, data_size); +		len = read(sk, buf, data_size);  		if (len <= 0) {  			if (len < 0) {  				if (reliable && (errno == ECOMM)) { -					syslog(LOG_INFO, "L2CAP Error ECOMM - clearing error and continuing.\n"); -					optl = sizeof(opt); -					if (getsockopt(s, SOL_SOCKET, SO_ERROR, &opt, &optl ) < 0) { // Clear error -						syslog(LOG_ERR, "Couldn't getsockopt(SO_ERROR): %s (%d)\n", +					syslog(LOG_INFO, "L2CAP Error ECOMM - clearing error and continuing."); +					optlen = sizeof(opt); +					if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &opt, &optlen) < 0) { +						syslog(LOG_ERR, "Couldn't getsockopt(SO_ERROR): %s (%d)",  							strerror(errno), errno);  						return;  					}  					continue;  				} else { -					syslog(LOG_ERR, "Read error: %s(%d)\n", strerror(errno), errno); +					syslog(LOG_ERR, "Read error: %s(%d)", +							strerror(errno), errno);  				}  			}  			return;  		} -		syslog(LOG_INFO, "Recevied %d bytes\n", len); +		syslog(LOG_INFO, "Recevied %d bytes", len);  		hexdump(buf,len);  	}  } -static void recv_mode(int s) +static void recv_mode(int sk)  {  	struct timeval tv_beg,tv_end,tv_diff;  	long total;  	uint32_t seq; -	int opt, optl; +	socklen_t optlen; +	int opt;  	syslog(LOG_INFO,"Receiving ..."); @@ -431,19 +490,19 @@ static void recv_mode(int s)  			uint16_t l;  			int i, r; -			if ((r = recv(s, buf, data_size, 0)) <= 0) { +			if ((r = recv(sk, buf, data_size, 0)) <= 0) {  				if (r < 0) {  					if (reliable && (errno == ECOMM)) {  						syslog(LOG_INFO, "L2CAP Error ECOMM - clearing error and continuing.\n"); -						optl = sizeof(opt); -						if (getsockopt(s, SOL_SOCKET, SO_ERROR, &opt, &optl ) < 0) { // Clear error -							syslog(LOG_ERR, "Couldn't getsockopt(SO_ERROR): %s (%d)\n", +						optlen = sizeof(opt); +						if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &opt, &optlen) < 0) { +							syslog(LOG_ERR, "Couldn't getsockopt(SO_ERROR): %s (%d)",  								strerror(errno), errno);  							return;  						}  						continue;  					} else { -						syslog(LOG_ERR, "Read failed. %s(%d)", +						syslog(LOG_ERR, "Read failed: %s (%d)",  							strerror(errno), errno);  					}  				} @@ -482,7 +541,7 @@ static void recv_mode(int s)  	}  } -static void send_mode(int s) +static void send_mode(int sk)  {  	uint32_t seq;  	int i; @@ -498,20 +557,20 @@ static void send_mode(int s)  		*(uint16_t *) (buf + 4) = htobs(data_size);  		seq++; -		if (send(s, buf, data_size, 0) <= 0) { +		if (send(sk, buf, data_size, 0) <= 0) {  			syslog(LOG_ERR, "Send failed: %s (%d)", strerror(errno), errno);  			exit(1);  		}  	}  	syslog(LOG_INFO, "Closing channel ..."); -	if (shutdown(s, SHUT_RDWR) < 0) +	if (shutdown(sk, SHUT_RDWR) < 0)  		syslog(LOG_INFO, "Close failed: %m");  	else  		syslog(LOG_INFO, "Done");  } -static void senddump_mode(int s) +static void senddump_mode(int sk)  {  	uint32_t seq;  	int i; @@ -527,13 +586,13 @@ static void senddump_mode(int s)  		*(uint16_t *) (buf + 4) = htobs(data_size);  		seq++; -		if (send(s, buf, data_size, 0) <= 0) { +		if (send(sk, buf, data_size, 0) <= 0) {  			syslog(LOG_ERR, "Send failed: %s (%d)", strerror(errno), errno);  			exit(1);  		}  	} -	dump_mode(s); +	dump_mode(sk);  }  static void reconnect_mode(char *svr) | 
