doorbell

view doorbelld/src/srv.c @ 5:f21ae31ef0e7

craptacular
author John Tsiombikas <nuclear@member.fsf.org>
date Tue, 15 Mar 2016 08:35:21 +0200
parents 08ea0abdbb8a
children 026156ea8801
line source
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <stddef.h>
5 #include <stdint.h>
6 #include <errno.h>
7 #include <assert.h>
8 #include <unistd.h>
9 #include <fcntl.h>
10 #include <sys/socket.h>
11 #include <arpa/inet.h>
12 #include "srv.h"
13 #include "dynarr.h"
15 /* TODO convert this whole thing to multicast */
17 static int lis_sock = -1, max_socket = -1;
18 static int *csock;
20 int srv_init(int port)
21 {
22 struct sockaddr_in addr;
24 if(lis_sock != -1) {
25 fprintf(stderr, "%s: already running\n", __func__);
26 return -1;
27 }
29 if((lis_sock = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
30 fprintf(stderr, "%s: failed to create listening socket\n", __func__);
31 return -1;
32 }
33 if(!(csock = dynarr_alloc(1, sizeof *csock))) {
34 fprintf(stderr, "%s: failed to allocate client socket array\n", __func__);
35 return -1;
36 }
37 csock[0] = lis_sock;
38 max_socket = lis_sock;
40 fcntl(lis_sock, F_SETFL, fcntl(lis_sock, F_GETFL) | O_NONBLOCK);
42 memset(&addr, 0, sizeof addr);
43 addr.sin_family = AF_INET;
44 addr.sin_port = htons(port);
45 addr.sin_addr.s_addr = INADDR_ANY;
46 if(bind(lis_sock, (struct sockaddr*)&addr, sizeof addr) == -1) {
47 fprintf(stderr, "%s: failed to bind port %d\n", __func__, port);
48 close(lis_sock);
49 lis_sock = -1;
50 return -1;
51 }
52 listen(lis_sock, 8);
54 return 0;
55 }
57 void srv_shutdown(void)
58 {
59 int i, sz = dynarr_size(csock);
60 for(i=0; i<sz; i++) {
61 close(csock[i]);
62 }
63 dynarr_free(csock);
64 csock = 0;
65 lis_sock = -1;
66 max_socket = -1;
67 }
69 int srv_num_sockets(void)
70 {
71 return dynarr_size(csock);
72 }
74 int *srv_sockets(void)
75 {
76 return csock;
77 }
79 int srv_max_socket(void)
80 {
81 return max_socket;
82 }
84 int srv_handle(int s)
85 {
86 static char buf[1024];
87 int sz;
89 if(s == lis_sock) {
90 /* incoming connection */
91 struct sockaddr_in addr;
92 socklen_t addr_size = sizeof addr;
93 if((s = accept(lis_sock, (struct sockaddr*)&addr, &addr_size)) == -1) {
94 fprintf(stderr, "%s: failed to accept incoming connection: %s\n", __func__, strerror(errno));
95 return -1;
96 }
97 printf("%s: incoming connection from %s:%d\n", __func__,
98 inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
99 csock = dynarr_push(csock, &s);
100 assert(csock);
101 if(s > max_socket) {
102 max_socket = s;
103 }
104 fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK);
105 return 0;
106 }
108 /* handle client */
109 while((sz = read(s, buf, sizeof buf - 1)) > 0) {
110 printf("%s: got data: %s\n", __func__, buf);
111 }
112 if(sz <= 0 && errno != EAGAIN) {
113 /* client closed connection probably */
114 int i, num_clients = dynarr_size(csock);
115 printf("%s: removing client\n", __func__);
116 close(s);
117 max_socket = lis_sock;
118 for(i=0; i<num_clients; i++) {
119 if(csock[i] == s) {
120 csock[i] = csock[num_clients - 1];
121 }
122 if(csock[i] > max_socket) {
123 max_socket = csock[i];
124 }
125 }
127 csock = dynarr_pop(csock);
128 --num_clients;
129 }
130 return 0;
131 }
133 struct video_block {
134 unsigned int magic;
135 int frame;
136 int x, y;
137 int width, height;
138 int frame_width, frame_height;
139 char pixels[1];
140 };
141 #define VBLOCK_HEADER_SIZE (offsetof(struct video_block, pixels))
143 void srv_send_frame(unsigned char *frame, int xsz, int ysz)
144 {
145 static int frame_num;
146 static unsigned char *buffer;
147 int i, j, size, num_clients;
148 struct video_block *vblock;
149 uint16_t *dest;
151 printf("sending frame\n");
153 /* for now just send a big block */
154 size = xsz * ysz * 2 + VBLOCK_HEADER_SIZE;
155 if(!buffer && !(buffer = malloc(size))) {
156 fprintf(stderr, "failed to allocate frame send buffer\n");
157 return;
158 }
159 vblock = (struct video_block*)buffer;
161 vblock->magic = 0x12341234;
162 vblock->frame = frame_num++;
163 vblock->x = vblock->y = 0;
164 vblock->width = vblock->frame_width = xsz;
165 vblock->height = vblock->frame_height = ysz;
167 dest = (uint16_t*)vblock->pixels;
169 for(i=0; i<ysz; i++) {
170 for(j=0; j<xsz; j++) {
171 unsigned int r = frame[0];
172 unsigned int g = frame[1];
173 unsigned int b = frame[2];
175 *dest++ = ((r << 8) & 0xf800) | ((g << 3) & 0x7e0) | ((b >> 3) & 0x1f);
176 frame += 4;
177 }
178 }
180 num_clients = dynarr_size(csock);
181 for(i=1; i<num_clients; i++) { /* first socket is the listening socket */
182 write(csock[i], buffer, size);
183 }
184 }