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