Skip to contentSkip to conversation

rfcomm utility patch to loop and startup executable when connection received

Bluez-devel Frédéric DALLEAU 2 participants 4 messages Aug 9, 2006 – Aug 10, 2006 Bluetooth drivers

lore
Share & tools
lore
#0 lore raw

Hi,

I came accross the need to startup an executable when rfcomm receives a connection. I also added an option called watch that allows rfcomm not to exit when the rfcomm connection is closed. It simply loops and calls listen.

listen   <dev> [channel [cmd]]          Listen
watch    <dev> [channel [cmd]]          Watch

rfcomm --raw watch 0 1 "cat {}"
rfcomm --raw listen 0 1 "cat {}"

Not specifying the cmd parameter will simply wait for [control-c] as before.

the {} will be replaced by the address of the rfcomm device created. In the example the command run will be 'cat /dev/rfcomm0'.

Attached is the patch.
Frédéric.

? Makefile
? Makefile.in
? aclocal.m4
? autom4te.cache
? config.guess
? config.h
? config.h.in
? config.log
? config.status
? config.sub
? configure
? depcomp
? install-sh
? libtool
? ltmain.sh
? missing
? mkinstalldirs
? stamp-h.in
? stamp-h1
? alsa/.deps
? alsa/Makefile
? alsa/Makefile.in
? common/.deps
? common/Makefile
? common/Makefile.in
? cups/.deps
? cups/Makefile
? cups/Makefile.in
? daemon/.deps
? daemon/Makefile
? daemon/Makefile.in
? dund/.deps
? dund/Makefile
? dund/Makefile.in
? extra/.deps
? extra/Makefile
? extra/Makefile.in
? fuse/.deps
? fuse/Makefile
? fuse/Makefile.in
? hcid/.deps
? hcid/Makefile
? hcid/Makefile.in
? hidd/.deps
? hidd/Makefile
? hidd/Makefile.in
? pand/.deps
? pand/Makefile
? pand/Makefile.in
? rfcomm/.deps
? rfcomm/.libs
? rfcomm/Makefile
? rfcomm/Makefile.in
? rfcomm/lexer.c
? rfcomm/main.c.modified
? rfcomm/main.patch
? rfcomm/parser.c
? rfcomm/parser.h
? rfcomm/rfcomm
? scripts/Makefile
? scripts/Makefile.in
? sdpd/.deps
? sdpd/Makefile
? sdpd/Makefile.in
? test/.deps
? test/Makefile
? test/Makefile.in
? tools/.deps
? tools/Makefile
? tools/Makefile.in
Index: rfcomm/main.c
===================================================================
RCS file: /cvsroot/bluez/utils/rfcomm/main.c,v
retrieving revision 1.19

main.c +89 -5
diff -u -r1.19 main.c
@@ -39,6 +39,7 @@
 #include <sys/param.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
+#include <sys/wait.h>
 
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/hci.h>
@@ -252,6 +253,67 @@
 	return 0;
 }
 
+static void run_command_line(struct pollfd* p, char* command_line, char* device_name)
+{
+	int i=0;
+	pid_t pid, child;
+	char command[256] = "";
+#define NBARGVS 8
+	char * argv_table[NBARGVS+1];
+	char* cur_arg=NULL;
+	char* next_arg=NULL;
+	int status = 0;
+
+	memset(argv_table, 0, sizeof(argv_table));
+	strncpy(command, command_line, sizeof(command));
+	command[sizeof(command)-1]=0;
+	cur_arg = command;
+			
+	// Create params table, end with NULL hence +1 in declaration
+	i=0;
+	while(i<NBARGVS) {
+		argv_table[i] = cur_arg;
+		next_arg = strchr(cur_arg, ' ');
+		if(next_arg) { *next_arg=0; cur_arg = next_arg+1; }
+		else break;
+		i++;
+	}
+	for(i=0; i<NBARGVS && argv_table[i]; i++) {
+		if(strcmp(argv_table[i], "{}")==0) {
+			argv_table[i] = device_name;
+		}
+	}
+
+	pid = fork();
+
+	switch(pid) {
+		case 0:
+			// Replace children with new process
+			i = execv(command, argv_table);
+			fprintf(stderr, "execv failed %s=%d (errno=%d:%s)\n", command, i, errno, strerror(errno));
+			break;
+		case -1:
+			// failed
+			fprintf(stderr, "fork %s failed\n", command);
+			break;
+		default:
+			// Parent, Wait for children and also watch fd for errors
+			while (1) {
+				child = waitpid(-1, &status, WNOHANG);
+				if (child == pid || (child < 0 && errno != EAGAIN))
+					break;
+
+				p->revents = 0;
+				if (poll(p, 1, 200) || __io_canceled) {
+					kill(pid, SIGTERM);
+					waitpid(pid, &status, 0);
+					break;
+				}
+			}
+			break;
+	}
+}
+
 static void cmd_connect(int ctl, int dev, bdaddr_t *bdaddr, int argc, char **argv)
 {
 	struct sockaddr_rc laddr, raddr;
@@ -402,6 +464,7 @@
 	socklen_t alen;
 	char dst[18], devname[MAXPATHLEN];
 	int sk, nsk, fd, try = 30;
+	char* command_line = (argc < 3) ? NULL : argv[2];
 
 	laddr.rc_family = AF_BLUETOOTH;
 	bacpy(&laddr.rc_bdaddr, bdaddr);
@@ -499,10 +562,14 @@
 	p.fd = fd;
 	p.events = POLLERR | POLLHUP;
 
-	while (!__io_canceled) {
-		p.revents = 0;
-		if (poll(&p, 1, 100))
-			break;
+	if(!command_line) {
+		while (!__io_canceled) {
+			p.revents = 0;
+			if (poll(&p, 1, 100))
+				break;
+		}
+	} else {
+		run_command_line(&p, command_line, devname);
 	}
 
 	printf("Disconnected\n");
@@ -510,6 +577,22 @@
 	close(fd);
 }
 
+static void cmd_watch(int ctl, int dev, bdaddr_t *bdaddr, int argc, char **argv)
+{
+	struct sigaction sa;
+
+	sa.sa_handler = sig_term;
+	sigaction(SIGTERM, &sa, NULL);
+	sigaction(SIGINT,  &sa, NULL);
+
+        // While process not killed
+        while(!__io_canceled)
+        {
+                cmd_listen(ctl, dev, bdaddr, argc, argv);
+                usleep(100*1000);
+        }
+}
+
 static void cmd_create(int ctl, int dev, bdaddr_t *bdaddr, int argc, char **argv)
 {
 	if (strcmp(argv[0], "all") == 0)
@@ -552,7 +635,8 @@
 	{ "release", "unbind", cmd_release, "<dev>",                    "Release device" },
 	{ "show",    "info",   cmd_show,    "<dev>",                    "Show device"    },
 	{ "connect", "conn",   cmd_connect, "<dev> <bdaddr> [channel]", "Connect device" },
-	{ "listen",  "server", cmd_listen,  "<dev> [channel]",          "Listen"         },
+	{ "listen",  "server", cmd_listen,  "<dev> [channel [cmd]]",    "Listen"         },
+	{ "watch",   "watch",  cmd_watch,   "<dev> [channel [cmd]]",    "Watch"          },
 	{ NULL, NULL, NULL, 0, 0 }
 };
 

-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security? Get stuff done quickly with pre-integrated technology to make your job easier Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642

_______________________________________________
Bluez-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/bluez-devel

maintainer
#1 lore raw

Hi Frederic,

Quoted 8 lines

I came accross the need to startup an executable when rfcomm receives a connection. I also added an option called watch that allows rfcomm not to exit when the rfcomm connection is closed. It simply loops and calls listen.

listen   <dev> [channel [cmd]]          Listen
watch    <dev> [channel [cmd]]          Watch
Quoted 7 lines

rfcomm --raw watch 0 1 "cat {}"
rfcomm --raw listen 0 1 "cat {}"

Not specifying the cmd parameter will simply wait for [control-c] as before.

the {} will be replaced by the address of the rfcomm device created. In the example the command run will be 'cat /dev/rfcomm0'.

the feature looks useful, but the patch is not acceptable. You need to fix the coding style. What is the difference between listen and watch?

Regards

Marcel

-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security? Get stuff done quickly with pre-integrated technology to make your job easier Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
Bluez-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/bluez-devel

#2 lore raw

Hi Marcel,

Quoted 5 lines
Quoted 5 lines

I came accross the need to startup an executable when rfcomm receives a connection. I also added an option called watch that allows rfcomm not to exit when the rfcomm connection is closed. It simply loops and calls listen.

listen   <dev> [channel [cmd]]          Listen
watch    <dev> [channel [cmd]]          Watch
Quoted 8 lines
Quoted 8 lines

rfcomm --raw watch 0 1 "cat {}"
rfcomm --raw listen 0 1 "cat {}"

Not specifying the cmd parameter will simply wait for [control-c] as before.

the {} will be replaced by the address of the rfcomm device created. In the example the command run will be 'cat /dev/rfcomm0'.

The syntax changed a little :

rfcomm --raw watch 0 1 cat {}
rfcomm --raw listen 0 1 cat {}

Note that "" must no longer be added arround the command line. The channel must be present as it is the number of arguments that is used to determine the start of the cmdline.

Quoted 4 lines

the feature looks useful, but the patch is not acceptable. You need to fix the coding style.

Attached patch has been modified around what I've found to be coding style. It's ways cleaner than the previous one. However, if it does not suit you, please let me know with the maximum details.

Quoted 3 lines

What is the difference between listen and watch?

Watch will not quit when client disconnect. Instead, it will start listening again.

Thanks
Frédéric

Index: main.c
===================================================================
RCS file: /cvsroot/bluez/utils/rfcomm/main.c,v
retrieving revision 1.19

main.c +71 -5
diff -u -r1.19 main.c
@@ -39,6 +39,7 @@
 #include <sys/param.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
+#include <sys/wait.h>
 
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/hci.h>
@@ -252,6 +253,52 @@
 	return 0;
 }
 
+static void run_cmdline(struct pollfd *p, char *devname, int argc, char ** argv)
+{
+	int i = 0;
+	pid_t pid, child;
+	int status = 0;
+	char** cmdargv = malloc((argc+1)*sizeof(char*));
+
+	if(!cmdargv)
+		return;
+
+	for(i=0; i<argc; i++) {
+		cmdargv[i] = (strcmp(argv[i], "{}")==0)?devname:argv[i];
+	}
+	cmdargv[i] = NULL;
+
+	pid = fork();
+
+	switch(pid) {
+	case 0:
+		i = execvp(cmdargv[0], cmdargv);
+		fprintf(stderr, "Couldn't execute command %s (errno=%d:%s)\n", cmdargv[0], errno, strerror(errno));
+		break;
+	case -1:
+		fprintf(stderr, "Couldn't fork to execute command %s\n", cmdargv[0]);
+		break;
+	default:
+		while (1) {
+			child = waitpid(-1, &status, WNOHANG);
+			if (child == pid || (child < 0 && errno != EAGAIN))
+				break;
+
+			p->revents = 0;
+			if (poll(p, 1, 200) || __io_canceled) {
+				kill(pid, SIGTERM);
+				waitpid(pid, &status, 0);
+				break;
+			}
+
+			usleep(10*1000);
+		}
+		break;
+	}
+
+	free(cmdargv);
+}
+
 static void cmd_connect(int ctl, int dev, bdaddr_t *bdaddr, int argc, char **argv)
 {
 	struct sockaddr_rc laddr, raddr;
@@ -499,10 +546,14 @@
 	p.fd = fd;
 	p.events = POLLERR | POLLHUP;
 
-	while (!__io_canceled) {
-		p.revents = 0;
-		if (poll(&p, 1, 100))
-			break;
+	if(argc <= 2) {
+		while (!__io_canceled) {
+			p.revents = 0;
+			if (poll(&p, 1, 100))
+				break;
+		}
+	} else {
+		run_cmdline(&p, devname, argc-2, argv+2);
 	}
 
 	printf("Disconnected\n");
@@ -510,6 +561,20 @@
 	close(fd);
 }
 
+static void cmd_watch(int ctl, int dev, bdaddr_t *bdaddr, int argc, char **argv)
+{
+	struct sigaction sa;
+
+	sa.sa_handler = sig_term;
+	sigaction(SIGTERM, &sa, NULL);
+	sigaction(SIGINT,  &sa, NULL);
+
+	while(!__io_canceled) {
+		cmd_listen(ctl, dev, bdaddr, argc, argv);
+		usleep(10*1000);
+	}
+}
+
 static void cmd_create(int ctl, int dev, bdaddr_t *bdaddr, int argc, char **argv)
 {
 	if (strcmp(argv[0], "all") == 0)
@@ -552,7 +617,8 @@
 	{ "release", "unbind", cmd_release, "<dev>",                    "Release device" },
 	{ "show",    "info",   cmd_show,    "<dev>",                    "Show device"    },
 	{ "connect", "conn",   cmd_connect, "<dev> <bdaddr> [channel]", "Connect device" },
-	{ "listen",  "server", cmd_listen,  "<dev> [channel]",          "Listen"         },
+	{ "listen",  "server", cmd_listen,  "<dev> [channel [cmd]]",    "Listen"         },
+	{ "watch",   "watch",  cmd_watch,   "<dev> [channel [cmd]]",    "Watch"          },
 	{ NULL, NULL, NULL, 0, 0 }
 };
 

-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security? Get stuff done quickly with pre-integrated technology to make your job easier Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642

_______________________________________________
Bluez-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/bluez-devel

#3 lore raw

Re: [Bluez-devel] rfcomm utility patch to loop and startup executable when connection received [REPOST]

Marcel,
Please ignore previous patch,
Frédéric

Quoted 28 lines · Frédéric DALLEAU

Hi Marcel,

Quoted 5 lines
Quoted 5 lines

I came accross the need to startup an executable when rfcomm receives a connection. I also added an option called watch that allows rfcomm not to exit when the rfcomm connection is closed. It simply loops and calls listen.

listen   <dev> [channel [cmd]]          Listen
watch    <dev> [channel [cmd]]          Watch
Quoted 8 lines
Quoted 7 lines

rfcomm --raw watch 0 1 "cat {}"
rfcomm --raw listen 0 1 "cat {}"

Not specifying the cmd parameter will simply wait for [control-c] as before.

the {} will be replaced by the address of the rfcomm device created. In the example the command run will be 'cat /dev/rfcomm0'.

The syntax changed a little :

rfcomm --raw watch 0 1 cat {}
rfcomm --raw listen 0 1 cat {}

Note that "" must no longer be added arround the command line. The channel must be present as it is the number of arguments that is used to determine the start of the cmdline.

Quoted 4 lines

the feature looks useful, but the patch is not acceptable. You need to fix the coding style.

Attached patch has been modified around what I've found to be coding style. It's ways cleaner than the previous one. However, if it does not suit you, please let me know with the maximum details.

Quoted 7 lines
Quoted 3 lines

What is the difference between listen and watch?

Watch will not quit when client disconnect. Instead, it will start listening again.

Thanks
Frédéric

? Makefile
? Makefile.in
? aclocal.m4
? autom4te.cache
? config.guess
? config.h
? config.h.in
? config.log
? config.status
? config.sub
? configure
? depcomp
? install-sh
? libtool
? ltmain.sh
? missing
? mkinstalldirs
? stamp-h.in
? stamp-h1
? alsa/.deps
? alsa/Makefile
? alsa/Makefile.in
? common/.deps
? common/Makefile
? common/Makefile.in
? cups/.deps
? cups/Makefile
? cups/Makefile.in
? daemon/.deps
? daemon/Makefile
? daemon/Makefile.in
? dund/.deps
? dund/Makefile
? dund/Makefile.in
? extra/.deps
? extra/Makefile
? extra/Makefile.in
? fuse/.deps
? fuse/Makefile
? fuse/Makefile.in
? hcid/.deps
? hcid/Makefile
? hcid/Makefile.in
? hidd/.deps
? hidd/Makefile
? hidd/Makefile.in
? pand/.deps
? pand/Makefile
? pand/Makefile.in
? rfcomm/.deps
? rfcomm/.libs
? rfcomm/Makefile
? rfcomm/Makefile.in
? rfcomm/cvs
? rfcomm/lexer.c
? rfcomm/main.c.modified
? rfcomm/main.patch
? rfcomm/parser.c
? rfcomm/parser.h
? rfcomm/rfcomm
? scripts/Makefile
? scripts/Makefile.in
? sdpd/.deps
? sdpd/Makefile
? sdpd/Makefile.in
? test/.deps
? test/Makefile
? test/Makefile.in
? tools/.deps
? tools/Makefile
? tools/Makefile.in
Index: rfcomm/main.c
===================================================================
RCS file: /cvsroot/bluez/utils/rfcomm/main.c,v
retrieving revision 1.21

main.c +71 -5
diff -u -r1.21 main.c
@@ -39,6 +39,7 @@
 #include <sys/param.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
+#include <sys/wait.h>
 
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/hci.h>
@@ -252,6 +253,52 @@
 	return 0;
 }
 
+static void run_cmdline(struct pollfd *p, char *devname, int argc, char ** argv)
+{
+	int i = 0;
+	pid_t pid, child;
+	int status = 0;
+	char** cmdargv = malloc((argc+1)*sizeof(char*));
+
+	if(!cmdargv)
+		return;
+
+	for(i=0; i<argc; i++) {
+		cmdargv[i] = (strcmp(argv[i], "{}")==0)?devname:argv[i];
+	}
+	cmdargv[i] = NULL;
+
+	pid = fork();
+
+	switch(pid) {
+	case 0:
+		i = execvp(cmdargv[0], cmdargv);
+		fprintf(stderr, "Couldn't execute command %s (errno=%d:%s)\n", cmdargv[0], errno, strerror(errno));
+		break;
+	case -1:
+		fprintf(stderr, "Couldn't fork to execute command %s\n", cmdargv[0]);
+		break;
+	default:
+		while (1) {
+			child = waitpid(-1, &status, WNOHANG);
+			if (child == pid || (child < 0 && errno != EAGAIN))
+				break;
+
+			p->revents = 0;
+			if (poll(p, 1, 200) || __io_canceled) {
+				kill(pid, SIGTERM);
+				waitpid(pid, &status, 0);
+				break;
+			}
+
+			usleep(10*1000);
+		}
+		break;
+	}
+
+	free(cmdargv);
+}
+
 static void cmd_connect(int ctl, int dev, bdaddr_t *bdaddr, int argc, char **argv)
 {
 	struct sockaddr_rc laddr, raddr;
@@ -499,10 +546,14 @@
 	p.fd = fd;
 	p.events = POLLERR | POLLHUP;
 
-	while (!__io_canceled) {
-		p.revents = 0;
-		if (poll(&p, 1, 500))
-			break;
+	if(argc <= 2) {
+		while (!__io_canceled) {
+			p.revents = 0;
+			if (poll(&p, 1, 500))
+				break;
+		}
+	} else {
+		run_cmdline(&p, devname, argc-2, argv+2);
 	}
 
 	printf("Disconnected\n");
@@ -510,6 +561,20 @@
 	close(fd);
 }
 
+static void cmd_watch(int ctl, int dev, bdaddr_t *bdaddr, int argc, char **argv)
+{
+	struct sigaction sa;
+
+	sa.sa_handler = sig_term;
+	sigaction(SIGTERM, &sa, NULL);
+	sigaction(SIGINT,  &sa, NULL);
+
+	while(!__io_canceled) {
+		cmd_listen(ctl, dev, bdaddr, argc, argv);
+		usleep(10*1000);
+	}
+}
+
 static void cmd_create(int ctl, int dev, bdaddr_t *bdaddr, int argc, char **argv)
 {
 	if (strcmp(argv[0], "all") == 0)
@@ -552,7 +617,8 @@
 	{ "release", "unbind", cmd_release, "<dev>",                    "Release device" },
 	{ "show",    "info",   cmd_show,    "<dev>",                    "Show device"    },
 	{ "connect", "conn",   cmd_connect, "<dev> <bdaddr> [channel]", "Connect device" },
-	{ "listen",  "server", cmd_listen,  "<dev> [channel]",          "Listen"         },
+	{ "listen",  "server", cmd_listen,  "<dev> [channel [cmd]]",    "Listen"         },
+	{ "watch",   "watch",  cmd_watch,   "<dev> [channel [cmd]]",    "Watch"          },
 	{ NULL, NULL, NULL, 0, 0 }
 };
 

-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security? Get stuff done quickly with pre-integrated technology to make your job easier Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642

_______________________________________________
Bluez-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/bluez-devel