summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan McGee <dpmcgee@gmail.com>2008-09-16 22:20:17 -0500
committerDan McGee <dan@archlinux.org>2008-10-05 19:49:38 -0500
commitcf7ca31c0d2895803a822ecb41fc394c25f05027 (patch)
tree3ff0ff028759974449f7f801857304b9d805decf
parent8b267356438f7b428d150f34f011e7cdb351c30b (diff)
downloadonkyocontrol-cf7ca31c0d2895803a822ecb41fc394c25f05027.tar.gz
onkyocontrol-cf7ca31c0d2895803a822ecb41fc394c25f05027.zip
More fun changes
* Play around with strdup() since it isn't actually part of ISO C. * Get code to compile under c89, c99, and gnu99 * Rework open_listener() to use getaddrinfo() Signed-off-by: Dan McGee <dpmcgee@gmail.com>
-rw-r--r--Makefile9
-rw-r--r--onkyo.c96
-rw-r--r--onkyo.h43
-rw-r--r--receiver.c9
-rw-r--r--util.c66
5 files changed, 150 insertions, 73 deletions
diff --git a/Makefile b/Makefile
index e105314..37874fc 100644
--- a/Makefile
+++ b/Makefile
@@ -1,9 +1,10 @@
# Makefile for Onkyo Receiver communication program
-CFLAGS = -Wall -Wextra -g -O2 -march=i686
-#CFLAGS = -Wall -Wextra -g -pedantic -fstrict-aliasing -Wunreachable-code -fstack-protector -march=native
+#CFLAGS = -Wall -Wextra -ggdb3 -O2 -march=i686
+# -Wunreachable-code -pedantic -march=native -fstack-protector -std=c99
+CFLAGS = -Wall -Wextra -ggdb -O2 -fstrict-aliasing -march=native
program = onkyocontrol
-objects = command.o onkyo.o receiver.o
+objects = command.o onkyo.o receiver.o util.o
.PHONY: all clean
@@ -24,6 +25,8 @@ receiver.o: Makefile receiver.c onkyo.h
onkyo.o: Makefile onkyo.c onkyo.h
+util.o: Makefile util.c onkyo.h
+
doc:
mkdir doc
doxygen
diff --git a/onkyo.c b/onkyo.c
index 3929cac..c254888 100644
--- a/onkyo.c
+++ b/onkyo.c
@@ -20,6 +20,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#define _POSIX_C_SOURCE 1 /* signal handlers, getaddrinfo */
+#define _XOPEN_SOURCE 500 /* SA_RESTART */
+
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
@@ -68,7 +71,7 @@ static void cleanup(int ret) __attribute__ ((noreturn));
static void pipehandler(int signo);
static void realhandler(int signo);
static int open_serial_device(const char *path);
-static int open_listener(const char *host, int port);
+static int open_listener(const char *host, const char *service);
static int open_connection(int fd);
static void end_connection(conn *c);
static int process_input(conn *c);
@@ -238,14 +241,14 @@ static int open_serial_device(const char *path)
* Open a listening socket on the given bind address and port number.
* Also add it to our global list of listeners.
* @param host the hostname to bind to; NULL or "any" for all addresses
- * @param port the port number to listen on
+ * @param service the service name or port number to bind to
* @return the new socket fd
*/
-static int open_listener(const char *host, int port)
+static int open_listener(const char *host, const char *service)
{
- int i, fd;
- struct sockaddr_in sin;
- const int trueval = 1;
+ int i, ret, fd = -1;
+ struct addrinfo hints;
+ struct addrinfo *result, *rp;
/* make sure we have room in our list */
for(i = 0; i < MAX_LISTENERS && listeners[i] > -1; i++)
@@ -255,48 +258,65 @@ static int open_listener(const char *host, int port)
return(-1);
}
- /* open an inet socket with the default protocol */
- fd = socket(AF_INET, SOCK_STREAM, 0);
- if (fd < 0) {
- perror(host);
- return(-1);
- }
- /* set up our connection host, port, etc. */
- memset(&sin, 0, sizeof(struct sockaddr_in));
- sin.sin_family = AF_INET;
- sin.sin_port = htons(port);
- /* determine our resolved host address */
+ /* set up our hints structure with known info */
+ memset(&hints, 0, sizeof(struct addrinfo));
+ /* allow IPv4 or IPv6 */
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ /* passive flag is ignored if a node is specified in getaddrinfo call */
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_protocol = 0;
+
+ /* decide whether to pass a host into our getaddrinfo call. */
if(!host || strcmp(host, "any") == 0) {
- sin.sin_addr.s_addr = INADDR_ANY;
+ ret = getaddrinfo(NULL, service, &hints, &result);
} else {
- struct hostent *he;
- if(!(he = gethostbyname(host))) {
- perror(host);
- return(-1);
- }
- /* assumption- using IPv4, he->h_addrtype = AF_INET */
- memcpy((char *)&sin.sin_addr.s_addr,
- (char *)he->h_addr, he->h_length);
+ ret = getaddrinfo(host, service, &hints, &result);
}
- /* set the ability to reuse local addresses */
- if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&trueval,
- sizeof(int)) < 0) {
- perror("setsockopt()");
+ if(ret != 0) {
+ fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ret));
return(-1);
}
- /* bind to the given address */
- if(bind(fd, (struct sockaddr *)&sin, sizeof(struct sockaddr)) < 0) {
- perror("bind()");
- return(-1);
+
+ /* we get a list of results back, try to bind to each until one works */
+ for(rp = result; rp != NULL; rp = rp->ai_next) {
+ int on = 1;
+ /* attempt to open the socket */
+ fd = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
+ if (fd == -1)
+ continue;
+
+ /* attempt to set the ability to reuse local addresses */
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+
+ /* attempt bind to the given address */
+ if(bind(fd, result->ai_addr, rp->ai_addrlen) == 0)
+ /* we found one that works! */
+ break;
+
+ /* oh noes, didn't work, keep looping */
+ close(fd);
+ }
+
+ /* if we didn't find an available socket/bind, we are out of luck */
+ if(rp == NULL) {
+ fprintf(stderr, "could not bind to any available addresses\n");
+ fd = -1;
}
+
+ /* make sure we free the result of our addr query */
+ freeaddrinfo(result);
+
/* start listening */
- if(listen(fd, 5) < 0) {
+ if(fd != -1 && listen(fd, 5) < 0) {
perror("listen()");
- return(-1);
+ fd = -1;
}
/* place the listener in our array */
- listeners[i] = fd;
+ if(fd != -1) {
+ listeners[i] = fd;
+ }
return(fd);
}
@@ -499,7 +519,7 @@ int main(int argc, char *argv[])
init_commands();
/* open our listener connection */
- open_listener(NULL, 8701);
+ open_listener(LISTENHOST, LISTENPORT);
/* Terminal settings are all done. Now it is time to watch for input
* on our socket and handle it as necessary. We also handle incoming
diff --git a/onkyo.h b/onkyo.h
index f5e1ec9..f1ceab7 100644
--- a/onkyo.h
+++ b/onkyo.h
@@ -7,12 +7,16 @@
#ifndef ONKYO_H
#define ONKYO_H
-#include <unistd.h> /* close, read, write */
-#include <errno.h> /* for errno refs */
+#include <sys/types.h> /* ssize_t, size_t */
/** The serial port device to connect on */
#define SERIALDEVICE "/dev/ttyS0"
+/** The hostname to listen on; "any" will listen on any interface */
+#define LISTENHOST "any"
+/** The port number to listen on (note: it is a string, not a num) */
+#define LISTENPORT "8701"
+
/** Max size for our serial device pool */
#define MAX_SERIALDEVS 1
/** Max size for our listener pool */
@@ -44,33 +48,14 @@ void free_commands(void);
char *process_incoming_message(int serialfd);
int process_command(int serialfd, const char *str);
-/* trivial functions, keep them inlined */
-static inline void xclose(int fd)
-{
- while(close(fd) && errno == EINTR);
-}
-
-static inline ssize_t xread(int fd, void *buf, size_t len)
-{
- ssize_t nr;
- while(1) {
- nr = read(fd, buf, len);
- if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
- continue;
- return nr;
- }
-}
-
-static inline ssize_t xwrite(int fd, const void *buf, size_t len)
-{
- ssize_t nr;
- while(1) {
- nr = write(fd, buf, len);
- if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
- continue;
- return nr;
- }
-}
+/* util.c - trivial utility functions */
+void xclose(int fd);
+ssize_t xread(int fd, void *buf, size_t len);
+ssize_t xwrite(int fd, const void *buf, size_t len);
+/* if using ISO C, strdup() is not actually defined, provide our own */
+#ifndef strdup
+char *strdup(const char *s);
+#endif /* strdup */
#endif /* ONKYO_H */
diff --git a/receiver.c b/receiver.c
index 39013ba..ba07c50 100644
--- a/receiver.c
+++ b/receiver.c
@@ -20,7 +20,6 @@
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
-#include <errno.h>
#include <string.h>
#include "onkyo.h"
@@ -69,8 +68,12 @@ int rcvr_handle_status(int serialfd, char **status)
if(retval > 0) {
buf[retval] = '\0';
/* return the status message if asked for */
- if(status)
- *status = strdup(buf);
+ if(status) {
+ const size_t len = strlen(buf) + 1;
+ *status = malloc(len * sizeof(char));
+ if(*status)
+ memcpy(*status, buf, len);
+ }
return(0);
}
diff --git a/util.c b/util.c
new file mode 100644
index 0000000..b422bde
--- /dev/null
+++ b/util.c
@@ -0,0 +1,66 @@
+/*
+ * util.c - Onkyo receiver utility functions
+ *
+ * Copyright (c) 2008 Dan McGee <dpmcgee@gmail.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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h> /* malloc */
+#include <unistd.h> /* close, read, write */
+#include <errno.h> /* for errno refs */
+#include <string.h> /* memcpy */
+
+void xclose(int fd)
+{
+ while(close(fd) && errno == EINTR);
+}
+
+ssize_t xread(int fd, void *buf, size_t len)
+{
+ ssize_t nr;
+ while(1) {
+ nr = read(fd, buf, len);
+ if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
+ continue;
+ return nr;
+ }
+}
+
+ssize_t xwrite(int fd, const void *buf, size_t len)
+{
+ ssize_t nr;
+ while(1) {
+ nr = write(fd, buf, len);
+ if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
+ continue;
+ return nr;
+ }
+}
+
+/* if using ISO C, strdup() is not actually defined, provide our own */
+#ifndef strdup
+char *strdup(const char *s)
+{
+ char *ret = NULL;
+ if(s) {
+ const size_t len = strlen(s) + 1;
+ ret = malloc(len * sizeof(char));
+ if(ret)
+ memcpy(ret, s, len);
+ }
+ return(ret);
+}
+#endif /* strdup */
+