doorbell
view doorbelld/src/srv.c @ 6:026156ea8801
foo
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Wed, 16 Mar 2016 00:00:06 +0200 |
parents | f21ae31ef0e7 |
children | dc4018af3a40 |
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 bsock = -1;
18 static struct sockaddr_in baddr;
19 static int lis_sock = -1, max_socket = -1;
20 static int *csock;
22 int srv_init(int port)
23 {
24 int val;
25 struct sockaddr_in addr;
27 if(lis_sock != -1) {
28 fprintf(stderr, "%s: already running\n", __func__);
29 return -1;
30 }
32 if((lis_sock = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
33 fprintf(stderr, "%s: failed to create listening socket\n", __func__);
34 return -1;
35 }
36 if(!(csock = dynarr_alloc(1, sizeof *csock))) {
37 fprintf(stderr, "%s: failed to allocate client socket array\n", __func__);
38 return -1;
39 }
40 csock[0] = lis_sock;
41 max_socket = lis_sock;
43 fcntl(lis_sock, F_SETFL, fcntl(lis_sock, F_GETFL) | O_NONBLOCK);
45 memset(&addr, 0, sizeof addr);
46 addr.sin_family = AF_INET;
47 addr.sin_port = htons(port);
48 addr.sin_addr.s_addr = INADDR_ANY;
49 if(bind(lis_sock, (struct sockaddr*)&addr, sizeof addr) == -1) {
50 fprintf(stderr, "%s: failed to bind port %d\n", __func__, port);
51 close(lis_sock);
52 lis_sock = -1;
53 return -1;
54 }
55 listen(lis_sock, 8);
57 /* then create the video broadcast socket */
58 if((bsock = socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
59 fprintf(stderr, "%s: failed to create video broadcast socket\n", __func__);
60 return -1;
61 }
62 val = 1;
63 setsockopt(bsock, SOL_SOCKET, SO_BROADCAST, &val, sizeof val);
65 memset(&baddr, 0, sizeof baddr);
66 baddr.sin_family = AF_INET;
67 baddr.sin_port = htons(port + 1);
68 baddr.sin_addr.s_addr = 0xffffffff;
70 return 0;
71 }
73 void srv_shutdown(void)
74 {
75 int i, sz = dynarr_size(csock);
76 for(i=0; i<sz; i++) {
77 close(csock[i]);
78 }
79 dynarr_free(csock);
80 csock = 0;
81 lis_sock = -1;
82 max_socket = -1;
83 }
85 int srv_num_sockets(void)
86 {
87 return dynarr_size(csock);
88 }
90 int *srv_sockets(void)
91 {
92 return csock;
93 }
95 int srv_max_socket(void)
96 {
97 return max_socket;
98 }
100 static int handle_new_client(void)
101 {
102 int s;
103 /* incoming connection */
104 struct sockaddr_in addr;
105 socklen_t addr_size = sizeof addr;
106 if((s = accept(lis_sock, (struct sockaddr*)&addr, &addr_size)) == -1) {
107 fprintf(stderr, "%s: failed to accept incoming connection: %s\n", __func__, strerror(errno));
108 return -1;
109 }
110 printf("%s: incoming connection from %s:%d\n", __func__,
111 inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
112 csock = dynarr_push(csock, &s);
113 assert(csock);
114 if(s > max_socket) {
115 max_socket = s;
116 }
117 fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK);
118 return 0;
119 }
121 static int handle_client(int s)
122 {
123 static char buf[1024];
124 int sz;
126 /* handle client */
127 while((sz = read(s, buf, sizeof buf - 1)) > 0) {
128 printf("%s: got data: %s\n", __func__, buf);
129 }
130 if(sz <= 0 && errno != EAGAIN) {
131 /* client closed connection probably */
132 int i, num_clients = dynarr_size(csock);
133 printf("%s: removing client\n", __func__);
134 close(s);
135 max_socket = lis_sock;
136 for(i=0; i<num_clients; i++) {
137 if(csock[i] == s) {
138 csock[i] = csock[num_clients - 1];
139 }
140 if(csock[i] > max_socket) {
141 max_socket = csock[i];
142 }
143 }
145 csock = dynarr_pop(csock);
146 --num_clients;
147 }
148 return 0;
149 }
151 int srv_handle(int s)
152 {
153 if(s == lis_sock) {
154 return handle_new_client();
155 }
157 return handle_client(s);
158 }
160 struct video_block {
161 unsigned int magic;
162 int frame;
163 int x, y;
164 int width, height;
165 int frame_width, frame_height;
166 char pixels[1];
167 };
168 #define VBLOCK_HEADER_SIZE (offsetof(struct video_block, pixels))
170 void srv_send_frame(unsigned char *frame, int xsz, int ysz)
171 {
172 static int frame_num;
173 static unsigned char *buffer;
174 int i, j, size, num_clients;
175 struct video_block *vblock;
176 uint16_t *dest;
178 printf("sending frame\n");
180 /* for now just send a big block */
181 size = xsz * ysz * 2 + VBLOCK_HEADER_SIZE;
182 if(!buffer && !(buffer = malloc(size))) {
183 fprintf(stderr, "failed to allocate frame send buffer\n");
184 return;
185 }
186 vblock = (struct video_block*)buffer;
188 vblock->magic = 0x12341234;
189 vblock->frame = frame_num++;
190 vblock->x = vblock->y = 0;
191 vblock->width = vblock->frame_width = xsz;
192 vblock->height = vblock->frame_height = ysz;
194 dest = (uint16_t*)vblock->pixels;
196 for(i=0; i<ysz; i++) {
197 for(j=0; j<xsz; j++) {
198 unsigned int r = frame[0];
199 unsigned int g = frame[1];
200 unsigned int b = frame[2];
202 *dest++ = ((r << 8) & 0xf800) | ((g << 3) & 0x7e0) | ((b >> 3) & 0x1f);
203 frame += 4;
204 }
205 }
207 num_clients = dynarr_size(csock);
208 for(i=1; i<num_clients; i++) { /* first socket is the listening socket */
209 write(csock[i], buffer, size);
210 }
211 }