Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 315 lines (265 sloc) 8.081 kb
9f36689 @dsp Redo
authored
1 #define _GNU_SOURCE
2
dc38e72 @dsp Intial commit
authored
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <stdint.h>
6 #include <string.h>
7 #include <unistd.h>
8
9 #include <sys/types.h>
10 #include <sys/socket.h>
11 #include <netinet/in.h>
9f36689 @dsp Redo
authored
12 #include <poll.h>
dc38e72 @dsp Intial commit
authored
13
14 #include <avahi-client/client.h>
15 #include <avahi-client/publish.h>
16 #include <avahi-common/simple-watch.h>
17 #include <avahi-common/malloc.h>
18 #include <avahi-common/error.h>
19
20 #define NAME "moodlamp"
21 #define SERVICE "_moodlamp._udp"
9f36689 @dsp Redo
authored
22 #define UDP_PORT 2323
23 #define TCP_PORT 2324
dc38e72 @dsp Intial commit
authored
24
25 AvahiEntryGroup *group = NULL;
26 AvahiSimplePoll *sp = NULL;
27 char *name;
28
29 static int serv();
30
31 static
32 void entry_group_callback(AvahiEntryGroup * g, AvahiEntryGroupState state,
33 AVAHI_GCC_UNUSED void *userdata)
34 {
35 group = g;
36
37 /* Called whenever the entry group state changes */
38 switch (state) {
39 case AVAHI_ENTRY_GROUP_ESTABLISHED:
40 /* The entry group has been established successfully */
41 fprintf(stderr, "Service '%s' successfully established.\n", name);
42 serv();
43 break;
44
45 case AVAHI_ENTRY_GROUP_COLLISION:{
46 fprintf(stderr,
47 "Service name collision, renaming service to '%s'\n",
48 name);
49 avahi_simple_poll_quit(sp);
50 break;
51 }
52
53 case AVAHI_ENTRY_GROUP_FAILURE:
54 fprintf(stderr, "Entry group failure: %s\n",
55 avahi_strerror(avahi_client_errno
56 (avahi_entry_group_get_client(g))));
57 /* Some kind of failure happened while we were registering our services */
58 avahi_simple_poll_quit(sp);
59 break;
60
61 case AVAHI_ENTRY_GROUP_UNCOMMITED:
62 case AVAHI_ENTRY_GROUP_REGISTERING:
63 ;
64 }
65 }
66
67 static
9f36689 @dsp Redo
authored
68 void create_service(AvahiClient * c, const char * service, int port)
dc38e72 @dsp Intial commit
authored
69 {
70 int ret;
71
72 if (!group) {
73 group = avahi_entry_group_new(c, entry_group_callback, NULL);
74 if (!group) {
75 fprintf(stderr, "Cannot create new entry group");
76 avahi_simple_poll_quit(sp);
77 return;
78 }
79 }
80
81 if (avahi_entry_group_is_empty(group)) {
82 /* Add the service for IPP */
83 if ((ret = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC,
9f36689 @dsp Redo
authored
84 AVAHI_PROTO_UNSPEC, 0,
85 name, service,
86 NULL, NULL, port,
dc38e72 @dsp Intial commit
authored
87 NULL)) < 0) {
88
89 if (ret == AVAHI_ERR_COLLISION) {
90 fprintf(stderr, "Service name collision");
91 avahi_simple_poll_quit(sp);
92 return;
93 }
94
95 fprintf(stderr, "Failed to add _moodlamp._udp service: %s\n",
96 avahi_strerror(ret));
97 avahi_simple_poll_quit(sp);
98 return;
99 }
100
101 /* Tell the server to register the service */
102 if ((ret = avahi_entry_group_commit(group)) < 0) {
103 fprintf(stderr, "Failed to commit entry group: %s\n",
104 avahi_strerror(ret));
105 avahi_simple_poll_quit(sp);
106 return;
107 }
108 }
109 }
110
111 static
112 void client_callback(AvahiClient * c, AvahiClientState s, void *userdata)
113 {
114 switch (s) {
115 case AVAHI_CLIENT_S_RUNNING:
9f36689 @dsp Redo
authored
116 create_service(c, "_moodlamp._udp", UDP_PORT);
117 create_service(c, "_moodlamp._tcp", TCP_PORT);
dc38e72 @dsp Intial commit
authored
118 break;
119 case AVAHI_CLIENT_FAILURE:
120 avahi_simple_poll_quit(sp);
121 break;
122 case AVAHI_CLIENT_S_COLLISION:
123 case AVAHI_CLIENT_S_REGISTERING:
124 if (group) {
125 avahi_entry_group_reset(group);
126 }
127 case AVAHI_CLIENT_CONNECTING:
128 break;
129 }
130 }
131
071ca47 @dsp Proper handling of incoming bytes
authored
132 static void set(int b1, int b2, int b3)
dc38e72 @dsp Intial commit
authored
133 {
071ca47 @dsp Proper handling of incoming bytes
authored
134 fprintf(stderr, "set to %02x %02x %02x\n", b1, b2, b3);
dc38e72 @dsp Intial commit
authored
135 }
136
071ca47 @dsp Proper handling of incoming bytes
authored
137 static void fade(int b1, int b2, int b3, unsigned long ms)
dc38e72 @dsp Intial commit
authored
138 {
071ca47 @dsp Proper handling of incoming bytes
authored
139 fprintf(stderr, "fade to %02x %02x %02x in %ldms\n", b1, b2, b3, ms);
dc38e72 @dsp Intial commit
authored
140 }
141
9f36689 @dsp Redo
authored
142 static void exec_command(char *command, ssize_t len, void *retbuf,
143 ssize_t *retlen)
144 {
145 unsigned short *numbs;
146
147 numbs = alloca(sizeof(unsigned short) * len);
148 memset(numbs, 0, len);
149 for (int i = 0; i < len && command[i] != '0'; i++) {
150 numbs[i] = command[i] & 0xFF;
151 }
152
153
154 if (numbs[0] == 'B') {
155 for (int i = 0; i < len-2; i++) {
156 numbs[i] = numbs[i+2];
157 }
158 }
159
160 switch (numbs[0]) {
161 case 'C':
162 set(numbs[1], numbs[2], numbs[3]);
163 break;
164 case 'F':
165 case 'M':
166 case 'T':
167 if (len >= 6) {
168 unsigned int time = 0;
169 time = numbs[4] << 8;
170 time += numbs[5] && 0xFF;
171 fade(numbs[1], numbs[2], numbs[3], time);
172 } else {
173 fprintf(stderr, "not a ASCII moodlamp command");
174 }
175 break;
176 case 'V':
177 break;
178 default:
179 fprintf(stderr, "not a ASCII moodlamp command\n");
180 }
181 }
182
183 static void handle_tcp(int sock) {
184 char command[6];
185 void * retbuf = NULL;
186 ssize_t retlen, s;
187 struct sockaddr_in6 caddr;
188 socklen_t caddrlen;
189
190 int fd = accept(sock, &caddr, &caddrlen);
191 if ((s = read(fd, command, 6)) < 0) {
192 fprintf(stderr, "not a ASCII moodlamp command\n");
193 return;
194 }
195
196 exec_command(command, strlen(command), retbuf, &retlen);
197 write(fd, command, retlen);
198 close(fd);
199 }
200
201 static void handle_udp(int sock)
dc38e72 @dsp Intial commit
authored
202 {
9f36689 @dsp Redo
authored
203 size_t s;
204 char command[6];
dc38e72 @dsp Intial commit
authored
205 struct sockaddr_in6 caddr;
206 socklen_t caddrlen;
207
9f36689 @dsp Redo
authored
208 if ((s = recvfrom
209 (sock, command, 6, 0, (struct sockaddr *) &caddr,
210 &caddrlen)) < 4) {
211 fprintf(stderr, "not a ASCII moodlamp command");
212 return;
213 }
214 exec_command(command, s, NULL, NULL);
215 }
216
217 static int serv(void)
218 {
219 struct pollfd fds[2];
220 int udp_sock, tcp_sock;
221 struct sockaddr_in6 tcp_addr;
222 struct sockaddr_in6 udp_addr;
223
224 udp_sock = socket(AF_INET6, SOCK_DGRAM, 0);
225 tcp_sock = socket(AF_INET6, SOCK_STREAM, 0);
226
227 if (udp_sock < 0) {
228 fprintf(stderr, "cannot create udp socket");
229 return -1;
230 }
231
232 if (tcp_sock < 0) {
233 fprintf(stderr, "cannot create udp socket");
dc38e72 @dsp Intial commit
authored
234 return -1;
235 }
236
9f36689 @dsp Redo
authored
237 memset(&udp_addr, 0, sizeof(udp_addr));
238 udp_addr.sin6_port = htons(UDP_PORT);
239 udp_addr.sin6_addr = in6addr_any;
240
241 memset(&tcp_addr, 0, sizeof(tcp_addr));
242 tcp_addr.sin6_port = htons(TCP_PORT);
243 tcp_addr.sin6_addr = in6addr_any;
dc38e72 @dsp Intial commit
authored
244
9f36689 @dsp Redo
authored
245 if (bind(udp_sock, (struct sockaddr *) &udp_addr, sizeof(udp_addr))) {
246 fprintf(stderr, "cannot bind udp socket");
dc38e72 @dsp Intial commit
authored
247 return -1;
248 }
071ca47 @dsp Proper handling of incoming bytes
authored
249
9f36689 @dsp Redo
authored
250 if (bind(tcp_sock, (struct sockaddr *) &tcp_addr, sizeof(tcp_addr))) {
251 fprintf(stderr, "cannot bind tcp socket");
252 return -1;
253 }
071ca47 @dsp Proper handling of incoming bytes
authored
254
9f36689 @dsp Redo
authored
255 fds[0].fd = udp_sock;
256 fds[1].fd = tcp_sock;
257 fds[0].events = POLLIN | POLLPRI;
258 fds[1].events = POLLIN | POLLPRI;
259 fds[0].revents = 0;
260 fds[1].revents = 0;
dc38e72 @dsp Intial commit
authored
261
9f36689 @dsp Redo
authored
262 listen(tcp_sock, 10);
263 while (1) {
264 if (poll(fds, 2, 1000) <= 0) {
dc38e72 @dsp Intial commit
authored
265 continue;
266 }
071ca47 @dsp Proper handling of incoming bytes
authored
267
9f36689 @dsp Redo
authored
268 fprintf(stderr, "socket ready\n");
269 for (int sockn = 0; sockn < 2; sockn++) {
270 if (fds[sockn].revents && fds[sockn].fd == tcp_sock) {
271 handle_tcp(tcp_sock);
272 } else if (fds[sockn].revents && fds[sockn].fd == udp_sock) {
273 handle_udp(udp_sock);
071ca47 @dsp Proper handling of incoming bytes
authored
274 }
dc38e72 @dsp Intial commit
authored
275 }
276 }
277 }
278
279 int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char *argv[])
280 {
281 AvahiClient *client = NULL;
282 int error, ret = 0;
283
284 name = avahi_strdup(NAME);
285 sp = avahi_simple_poll_new();
286 if (!sp) {
287 fprintf(stderr, "Cannot instantiate simple poll");
288 goto cleanup;
289 }
290
291 client =
292 avahi_client_new(avahi_simple_poll_get(sp), 0, client_callback,
293 NULL, &error);
294 if (!client) {
295 fprintf(stderr, "Cannot instanitate client");
296 goto cleanup;
297 }
298
299 avahi_simple_poll_loop(sp);
300
301 ret = 1;
302
303 cleanup:
304 if (client) {
305 avahi_client_free(client);
306 }
307
308 if (sp) {
309 avahi_simple_poll_free(sp);
310 }
311 avahi_free(name);
312
313 return ret;
314 }
Something went wrong with that request. Please try again.