doorbell
changeset 2:d3f2a2b19504
doorbell server under construction
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sun, 13 Mar 2016 07:56:03 +0200 |
parents | a5755687dd75 |
children | 73b16c2ae6bf |
files | .hgignore doorbelld/Makefile doorbelld/src/dynarr.c doorbelld/src/dynarr.h doorbelld/src/main.c doorbelld/src/srv.c doorbelld/src/srv.h |
diffstat | 7 files changed, 460 insertions(+), 0 deletions(-) [+] |
line diff
1.1 --- a/.hgignore Tue Mar 08 03:26:01 2016 +0200 1.2 +++ b/.hgignore Sun Mar 13 07:56:03 2016 +0200 1.3 @@ -2,3 +2,5 @@ 1.4 \.d$ 1.5 \.swp$ 1.6 spycam$ 1.7 +doorbelld$ 1.8 +\.ppm$
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/doorbelld/Makefile Sun Mar 13 07:56:03 2016 +0200 2.3 @@ -0,0 +1,13 @@ 2.4 +src = $(wildcard src/*.c) 2.5 +obj = $(src:.c=.o) 2.6 +bin = doorbelld 2.7 + 2.8 +CFLAGS = -pedantic -Wall -g 2.9 +LDFLAGS = -lwcam -lpthread 2.10 + 2.11 +$(bin): $(obj) 2.12 + $(CC) -o $@ $(obj) $(LDFLAGS) 2.13 + 2.14 +.PHONY: clean 2.15 +clean: 2.16 + rm -f $(obj) $(bin)
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/doorbelld/src/dynarr.c Sun Mar 13 07:56:03 2016 +0200 3.3 @@ -0,0 +1,128 @@ 3.4 +/* dynarr - dynamic resizable C array data structure 3.5 + * author: John Tsiombikas <nuclear@member.fsf.org> 3.6 + * license: public domain 3.7 + */ 3.8 +#include <stdio.h> 3.9 +#include <stdlib.h> 3.10 +#include <string.h> 3.11 +#include "dynarr.h" 3.12 + 3.13 +/* The array descriptor keeps auxilliary information needed to manipulate 3.14 + * the dynamic array. It's allocated adjacent to the array buffer. 3.15 + */ 3.16 +struct arrdesc { 3.17 + int nelem, szelem; 3.18 + int max_elem; 3.19 + int bufsz; /* not including the descriptor */ 3.20 +}; 3.21 + 3.22 +#define DESC(x) ((struct arrdesc*)((char*)(x) - sizeof(struct arrdesc))) 3.23 + 3.24 +void *dynarr_alloc(int elem, int szelem) 3.25 +{ 3.26 + struct arrdesc *desc; 3.27 + 3.28 + if(!(desc = malloc(elem * szelem + sizeof *desc))) { 3.29 + return 0; 3.30 + } 3.31 + desc->nelem = desc->max_elem = elem; 3.32 + desc->szelem = szelem; 3.33 + desc->bufsz = elem * szelem; 3.34 + return (char*)desc + sizeof *desc; 3.35 +} 3.36 + 3.37 +void dynarr_free(void *da) 3.38 +{ 3.39 + if(da) { 3.40 + free(DESC(da)); 3.41 + } 3.42 +} 3.43 + 3.44 +void *dynarr_resize(void *da, int elem) 3.45 +{ 3.46 + int newsz; 3.47 + void *tmp; 3.48 + struct arrdesc *desc; 3.49 + 3.50 + if(!da) return 0; 3.51 + desc = DESC(da); 3.52 + 3.53 + newsz = desc->szelem * elem; 3.54 + 3.55 + if(!(tmp = realloc(desc, newsz + sizeof *desc))) { 3.56 + return 0; 3.57 + } 3.58 + desc = tmp; 3.59 + 3.60 + desc->nelem = desc->max_elem = elem; 3.61 + desc->bufsz = newsz; 3.62 + return (char*)desc + sizeof *desc; 3.63 +} 3.64 + 3.65 +int dynarr_empty(void *da) 3.66 +{ 3.67 + return DESC(da)->nelem ? 0 : 1; 3.68 +} 3.69 + 3.70 +int dynarr_size(void *da) 3.71 +{ 3.72 + return DESC(da)->nelem; 3.73 +} 3.74 + 3.75 + 3.76 +/* stack semantics */ 3.77 +void *dynarr_push(void *da, void *item) 3.78 +{ 3.79 + struct arrdesc *desc; 3.80 + int nelem; 3.81 + 3.82 + desc = DESC(da); 3.83 + nelem = desc->nelem; 3.84 + 3.85 + if(nelem >= desc->max_elem) { 3.86 + /* need to resize */ 3.87 + struct arrdesc *tmp; 3.88 + int newsz = desc->max_elem ? desc->max_elem * 2 : 1; 3.89 + 3.90 + if(!(tmp = dynarr_resize(da, newsz))) { 3.91 + fprintf(stderr, "failed to resize\n"); 3.92 + return da; 3.93 + } 3.94 + da = tmp; 3.95 + desc = DESC(da); 3.96 + desc->nelem = nelem; 3.97 + } 3.98 + 3.99 + if(item) { 3.100 + memcpy((char*)da + desc->nelem++ * desc->szelem, item, desc->szelem); 3.101 + } 3.102 + return da; 3.103 +} 3.104 + 3.105 +void *dynarr_pop(void *da) 3.106 +{ 3.107 + struct arrdesc *desc; 3.108 + int nelem; 3.109 + 3.110 + desc = DESC(da); 3.111 + nelem = desc->nelem; 3.112 + 3.113 + if(!nelem) return da; 3.114 + 3.115 + if(nelem <= desc->max_elem / 3) { 3.116 + /* reclaim space */ 3.117 + struct arrdesc *tmp; 3.118 + int newsz = desc->max_elem / 2; 3.119 + 3.120 + if(!(tmp = dynarr_resize(da, newsz))) { 3.121 + fprintf(stderr, "failed to resize\n"); 3.122 + return da; 3.123 + } 3.124 + da = tmp; 3.125 + desc = DESC(da); 3.126 + desc->nelem = nelem; 3.127 + } 3.128 + desc->nelem--; 3.129 + 3.130 + return da; 3.131 +}
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/doorbelld/src/dynarr.h Sun Mar 13 07:56:03 2016 +0200 4.3 @@ -0,0 +1,38 @@ 4.4 +/* dynarr - dynamic resizable C array data structure 4.5 + * author: John Tsiombikas <nuclear@member.fsf.org> 4.6 + * license: public domain 4.7 + */ 4.8 +#ifndef DYNARR_H_ 4.9 +#define DYNARR_H_ 4.10 + 4.11 +void *dynarr_alloc(int elem, int szelem); 4.12 +void dynarr_free(void *da); 4.13 +void *dynarr_resize(void *da, int elem); 4.14 + 4.15 +int dynarr_empty(void *da); 4.16 +int dynarr_size(void *da); 4.17 + 4.18 +/* stack semantics */ 4.19 +void *dynarr_push(void *da, void *item); 4.20 +void *dynarr_pop(void *da); 4.21 + 4.22 + 4.23 +/* usage example: 4.24 + * ------------- 4.25 + * int *arr = dynarr_alloc(0, sizeof *arr); 4.26 + * 4.27 + * int x = 10; 4.28 + * arr = dynarr_push(arr, &x); 4.29 + * x = 5; 4.30 + * arr = dynarr_push(arr, &x); 4.31 + * x = 42; 4.32 + * arr = dynarr_push(arr, &x); 4.33 + * 4.34 + * for(i=0; i<dynarr_size(arr); i++) { 4.35 + * printf("%d\n", arr[i]); 4.36 + * } 4.37 + * dynarr_free(arr); 4.38 + */ 4.39 + 4.40 + 4.41 +#endif /* DYNARR_H_ */
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/doorbelld/src/main.c Sun Mar 13 07:56:03 2016 +0200 5.3 @@ -0,0 +1,141 @@ 5.4 +#include <stdio.h> 5.5 +#include <stdlib.h> 5.6 +#include <string.h> 5.7 +#include <errno.h> 5.8 +#include <signal.h> 5.9 +#include <pthread.h> 5.10 +#include <wcam.h> 5.11 +#include "srv.h" 5.12 + 5.13 +void *frame_proc(void *arg); 5.14 +int save_image(const char *fname, unsigned char *pixels, int xsz, int ysz); 5.15 +void sighandler(int s); 5.16 + 5.17 +int fd; 5.18 +int width = 640; 5.19 +int height = 480; 5.20 +int framerate = 30; 5.21 +unsigned char *frame; 5.22 +int done; 5.23 +int frame_available; 5.24 +pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 5.25 +pthread_cond_t condvar = PTHREAD_COND_INITIALIZER; 5.26 + 5.27 +int main(int argc, char **argv) 5.28 +{ 5.29 + char *devfile = "/dev/video0"; 5.30 + pthread_t thread; 5.31 + 5.32 + if(argv[1]) { 5.33 + devfile = argv[1]; 5.34 + } 5.35 + 5.36 + signal(SIGINT, sighandler); 5.37 + signal(SIGQUIT, sighandler); 5.38 + signal(SIGSEGV, sighandler); 5.39 + 5.40 + if(srv_init(2828) == -1) { 5.41 + return 1; 5.42 + } 5.43 + 5.44 + if(!(frame = malloc(width * height * 4))) { 5.45 + perror("failed to allocate frame"); 5.46 + return 1; 5.47 + } 5.48 + 5.49 + if((fd = wcam_open(devfile, width, height, framerate)) == -1) { 5.50 + fprintf(stderr, "failed to open video device: %s\n", devfile); 5.51 + return 1; 5.52 + } 5.53 + wcam_start(fd); 5.54 + 5.55 + if(pthread_create(&thread, 0, frame_proc, 0) == -1) { 5.56 + fprintf(stderr, "failed to create frame processing thread\n"); 5.57 + return 1; 5.58 + } 5.59 + 5.60 + while(!done) { 5.61 + int i, res; 5.62 + int *sock = srv_sockets(); 5.63 + int num_sockets = srv_num_sockets(); 5.64 + int maxfd = srv_max_socket(); 5.65 + fd_set rdset; 5.66 + 5.67 + if(fd > maxfd) maxfd = fd; 5.68 + 5.69 + FD_ZERO(&rdset); 5.70 + FD_SET(fd, &rdset); 5.71 + 5.72 + for(i=0; i<num_sockets; i++) { 5.73 + FD_SET(sock[i], &rdset); 5.74 + } 5.75 + 5.76 + while((res = select(maxfd + 1, &rdset, 0, 0, 0)) == -1 && errno == EINTR); 5.77 + if(res == -1) { 5.78 + fprintf(stderr, "unexpected failure while waiting for I/O\n"); 5.79 + break; 5.80 + } 5.81 + 5.82 + if(FD_ISSET(fd, &rdset)) { 5.83 + wcam_wait(fd); 5.84 + pthread_mutex_lock(&mutex); 5.85 + frame_available = 1; 5.86 + pthread_mutex_unlock(&mutex); 5.87 + pthread_cond_signal(&condvar); 5.88 + } 5.89 + 5.90 + for(i=0; i<num_sockets; i++) { 5.91 + if(FD_ISSET(sock[i], &rdset)) { 5.92 + srv_handle(sock[i]); 5.93 + } 5.94 + } 5.95 + } 5.96 + 5.97 + frame_available = 1; 5.98 + pthread_cond_signal(&condvar); 5.99 + pthread_join(thread, 0); 5.100 + free(frame); 5.101 + wcam_stop(fd); 5.102 + wcam_close(fd); 5.103 + return 0; 5.104 +} 5.105 + 5.106 +void *frame_proc(void *arg) 5.107 +{ 5.108 + for(;;) { 5.109 + pthread_mutex_lock(&mutex); 5.110 + while(!frame_available) { 5.111 + pthread_cond_wait(&condvar, &mutex); 5.112 + } 5.113 + frame_available = 0; 5.114 + pthread_mutex_unlock(&mutex); 5.115 + 5.116 + if(done) break; 5.117 + 5.118 + wcam_read_frame_rgb(fd, frame); 5.119 + save_image("output.ppm", frame, width, height); 5.120 + } 5.121 + return 0; 5.122 +} 5.123 + 5.124 +int save_image(const char *fname, unsigned char *pixels, int xsz, int ysz) 5.125 +{ 5.126 + int i, num_pixels = xsz * ysz; 5.127 + FILE *fp = fopen(fname, "wb"); 5.128 + if(!fp) return -1; 5.129 + 5.130 + fprintf(fp, "P6\n%d %d\n255\n", xsz, ysz); 5.131 + for(i=0; i<num_pixels; i++) { 5.132 + fputc(*pixels++, fp); 5.133 + fputc(*pixels++, fp); 5.134 + fputc(*pixels++, fp); 5.135 + ++pixels; 5.136 + } 5.137 + fclose(fp); 5.138 + return 0; 5.139 +} 5.140 + 5.141 +void sighandler(int s) 5.142 +{ 5.143 + done = 1; 5.144 +}
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/doorbelld/src/srv.c Sun Mar 13 07:56:03 2016 +0200 6.3 @@ -0,0 +1,123 @@ 6.4 +#include <stdio.h> 6.5 +#include <stdlib.h> 6.6 +#include <string.h> 6.7 +#include <errno.h> 6.8 +#include <assert.h> 6.9 +#include <unistd.h> 6.10 +#include <fcntl.h> 6.11 +#include <sys/socket.h> 6.12 +#include <arpa/inet.h> 6.13 +#include "srv.h" 6.14 +#include "dynarr.h" 6.15 + 6.16 +static int lis_sock = -1, max_socket = -1; 6.17 +static int *csock; 6.18 + 6.19 +int srv_init(int port) 6.20 +{ 6.21 + struct sockaddr_in addr; 6.22 + 6.23 + if(lis_sock != -1) { 6.24 + fprintf(stderr, "%s: already running\n", __func__); 6.25 + return -1; 6.26 + } 6.27 + 6.28 + if((lis_sock = socket(PF_INET, SOCK_STREAM, 0)) == -1) { 6.29 + fprintf(stderr, "%s: failed to create listening socket\n", __func__); 6.30 + return -1; 6.31 + } 6.32 + if(!(csock = dynarr_alloc(1, sizeof *csock))) { 6.33 + fprintf(stderr, "%s: failed to allocate client socket array\n", __func__); 6.34 + return -1; 6.35 + } 6.36 + csock[0] = lis_sock; 6.37 + max_socket = lis_sock; 6.38 + 6.39 + fcntl(lis_sock, F_SETFD, fcntl(lis_sock, F_GETFD) | O_NONBLOCK); 6.40 + 6.41 + memset(&addr, 0, sizeof addr); 6.42 + addr.sin_family = AF_INET; 6.43 + addr.sin_port = htons(port); 6.44 + addr.sin_addr.s_addr = INADDR_ANY; 6.45 + if(bind(lis_sock, (struct sockaddr*)&addr, sizeof addr) == -1) { 6.46 + fprintf(stderr, "%s: failed to bind port %d\n", __func__, port); 6.47 + close(lis_sock); 6.48 + lis_sock = -1; 6.49 + return -1; 6.50 + } 6.51 + 6.52 + return 0; 6.53 +} 6.54 + 6.55 +void srv_shutdown(void) 6.56 +{ 6.57 + int i, sz = dynarr_size(csock); 6.58 + for(i=0; i<sz; i++) { 6.59 + close(csock[i]); 6.60 + } 6.61 + dynarr_free(csock); 6.62 + csock = 0; 6.63 + lis_sock = -1; 6.64 + max_socket = -1; 6.65 +} 6.66 + 6.67 +int srv_num_sockets(void) 6.68 +{ 6.69 + return dynarr_size(csock); 6.70 +} 6.71 + 6.72 +int *srv_sockets(void) 6.73 +{ 6.74 + return csock; 6.75 +} 6.76 + 6.77 +int srv_max_socket(void) 6.78 +{ 6.79 + return max_socket; 6.80 +} 6.81 + 6.82 +int srv_handle(int s) 6.83 +{ 6.84 + static char buf[1024]; 6.85 + int sz; 6.86 + 6.87 + if(s == lis_sock) { 6.88 + /* incoming connection */ 6.89 + struct sockaddr_in addr; 6.90 + int addr_size; 6.91 + 6.92 + if((s = accept(lis_sock, (struct sockaddr*)&addr, (int*)&addr_size)) == -1) { 6.93 + fprintf(stderr, "%s: failed to accept incoming connection\n", __func__); 6.94 + return -1; 6.95 + } 6.96 + printf("%s: incoming connection from %s:%d\n", __func__, 6.97 + inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); 6.98 + csock = dynarr_push(csock, &s); 6.99 + assert(csock); 6.100 + return 0; 6.101 + } 6.102 + 6.103 + /* handle client */ 6.104 + while((sz = read(s, buf, sizeof buf - 1)) > 0) { 6.105 + printf("%s: got data: %s\n", __func__, buf); 6.106 + } 6.107 + if(sz < 0 && errno != EAGAIN) { 6.108 + /* client closed connection probably */ 6.109 + int i, num_clients = dynarr_size(csock); 6.110 + printf("%s: removing client\n", __func__); 6.111 + close(s); 6.112 + for(i=0; i<num_clients; i++) { 6.113 + if(csock[i] == s) { 6.114 + csock[i] = csock[num_clients - 1]; 6.115 + csock = dynarr_pop(csock); 6.116 + break; 6.117 + } 6.118 + } 6.119 + assert(i < num_clients); 6.120 + } 6.121 + return 0; 6.122 +} 6.123 + 6.124 +void srv_send_frame(unsigned char *frame, int xsz, int ysz) 6.125 +{ 6.126 +}
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/doorbelld/src/srv.h Sun Mar 13 07:56:03 2016 +0200 7.3 @@ -0,0 +1,15 @@ 7.4 +#ifndef SRV_H_ 7.5 +#define SRV_H_ 7.6 + 7.7 +int srv_init(int port); 7.8 +void srv_shutdown(void); 7.9 + 7.10 +int srv_num_sockets(void); 7.11 +int *srv_sockets(void); 7.12 +int srv_max_socket(void); 7.13 + 7.14 +int srv_handle(int s); 7.15 + 7.16 +void srv_send_frame(unsigned char *frame, int xsz, int ysz); 7.17 + 7.18 +#endif /* SRV_H_ */