2 * http://www.ibiblio.org/pub/Linux/docs/HOWTO/Multicast-HOWTO
13 #include <sys/types.h>
14 #include <sys/socket.h>
15 #include <netinet/in.h>
16 #include <arpa/inet.h>
21 typedef unsigned char Byte;
23 static int ov_mode= 'r';
24 static const char *ov_requ= "127.0.0.1";
25 static const char *ov_mcast= "239.193.27.221";
27 static int ov_port_requ= 4101;
28 static int ov_port_ctrl= 4101;
29 static int ov_port_data= -1;
31 static const struct cmdinfo cmdinfos[]= {
32 { "server", 0, &ov_mode,0,0, 's' },
33 { "player", 0, &ov_mode,0,0, 'p' },
34 { "request", 0, &ov_mode,0,0, 'r' },
35 { "mcast-addr", 1, 0,&ov_mcast },
36 { "requ-addr", 1, 0,&ov_requ },
37 { "requ-port", 1, &ov_port_requ },
38 { "ctrl-port", 1, &ov_port_ctrl },
39 { "data-port", 1, &ov_port_data },
44 static int mcast_fd, requ_fd;
45 static struct sockaddr_in requ_sa, ctrl_sa, data_sa;
47 static void sysfail(const char *m) { perror(m); exit(16); }
49 static Byte packet[1024];
50 static int packet_len;
52 /*---------- marshalling ----------*/
54 static uint64_t htonll(uint64_t v) {
56 return (v >> 32) | (v << 32);
63 #define OP_CTRL_PLAY 1
64 #define OP_CTRL_STOP 2
65 #define OP_CTRL_DATA 3
67 #define MAR_CTRL_PLAY \
78 #define MAR_CTRL_STOP \
91 #define FI8(f) F(f, uint8_t, v)
92 #define FI32(f) F(f, uint32_t, htonl(v))
93 #define FI64(f) F(f, uint64_t, htonll(v))
100 #define F(f,t,c) t f;
101 #define FR(f,t,l) t f[(l)]; int f##_l;
103 #define MAR(m) typedef struct Mar_##m { MAR_##m } Mar_##m;
110 #define F(f,t,c) { t v= d->f; *(t*)p= c; p += sizeof(t); };
111 #define FR(f,t,l) assert(d->f##_l<=l); memcpy(p,d->f,d->f##_l); p+=d->f##_l;
114 static void mar_##m(const Mar_##m *d) { \
117 packet_len= p - packet; \
118 assert(packet_len < sizeof(packet)); \
128 if (lr < sizeof(t)) return -1; \
130 p += sizeof(t); lr -= sizeof(t); \
133 #define FR(f,t,l) { \
134 if (lr > l) return -1; \
135 memcpy(d->f, p, lr); \
141 static int unmar_##m(Mar_##m *d) { \
142 const Byte *p= packet; \
143 int lr= packet_len; \
153 /*---------- general stuff ----------*/
155 static void blocksignals(int how) {
160 sigaddset(&set,SIGCHLD);
161 r= sigprocmask(how,&set,0);
162 if (r) sysfail("sigprocmask");
165 static int mksocket(int type, int proto,
166 const struct sockaddr_in *sa, const char *what) {
169 fd= socket(PF_INET, type, proto);
170 if (fd<0) sysfail("socket %s",what);
172 r= bind(fd, (struct sockaddr*)&mcast_sa, sizeof(*sa));
173 if (r) sysfail("bind %s",what);
178 static void mkmcastrecv(const struct sockaddr_in *sa, const char *what) {
182 mcast_fd= mksocket(SOCK_DGRAM, IPPROTO_UDP, sa, what);
184 mreq.imr_multiaddr= sa->sin_addr;
185 mreq.imr_interface.s_addr= INADDR_ANY;
186 r= setsockopt(mcast_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
187 if (r) sysfail("add mcast membership %s", what);
190 /*---------- player ----------*/
192 static void recvd_play(void) {
196 r= unmar_CTRL_PLAY(&pkt);
197 if (r) { fprintf(stderr,"bad PLAY packet\n"); return; }
201 static void recvd_stop(void) {
205 r= unmar_CTRL_STOP(&pkt);
206 if (r) { fprintf(stderr,"bad STOP packet\n"); return; }
209 static void player(void) {
210 struct sockaddr_in peer_sa, old_peer_sa;
211 socklen_t peer_salen;
214 mkmcastrecv(&ctrl_sa, "ctrl");
216 memset(&old_peer_sa, 0, sizeof(old_peer_sa));
219 peer_salen= sizeof(peer_sa);
220 memset(&peer_sa, 0, sizeof(peer_sa));
222 blocksignals(SIG_UNBLOCK);
223 packet_len= recvfrom(mcast_fd, packet, sizeof(packet),
224 MSG_TRUNC, (struct sockaddr*)&peer_sa, &peer_salen);
225 blocksignals(SIG_BLOCK);
228 if (errno==EINTR) continue;
229 perror("mcast_fd recvfrom");
232 if (peer_salen != sizeof(peer_sa)) {
233 fprintf(stderr,"mcast_fd recvfrom salen %ld not %ld\n",
234 (unsigned long)peer_salen, (unsigned long)sizeof(peer_sa));
237 if (packet_len > sizeof(packet)) {
238 fprintf(stderr,"mcast_fd recvfrom packet len %ld longer than max %ld\n",
239 (unsigned long)packet_len, (unsigned long)sizeof(packet));
242 if (memcmp(&old_peer_sa, &peer_sa, sizeof(old_peer_sa))) {
243 char *p= inet_ntoa(peer_sa.sin_addr);
244 fprintf(stderr,"receiving from %s:%d\n",p,ntohs(peer_sa.sin_port));
245 memcpy(&old_peer_sa, &peer_sa, sizeof(old_peer_sa));
248 fprintf(stderr,"empty packet!\n");
259 fprintf(stderr,"unknown opcode %d\n",packet[0]);
264 /*---------- server ----------*/
267 requ_fd= mksocket(SOCK_STREAM, IPPROTO_TCP, &requ_sa, "requ");
270 /*---------- main ----------*/
272 static void argaddr(struct sin_addr *sa, const char *addr_name, int port) {
273 memset(sa,0,sizeof(*sa));
274 sa->sin_family= AF_INET;
276 r= inet_aton(ov_mcast, &mcast_sa.sin_addr);
277 if (!r) badusage("invalid addr `%s'", addr_name);
279 if (port<0 || port>65536) badusage("invalid port %d",port);
281 sa->sin_port= htons(port);
284 int main(int argc, const char **argv) {
287 if (ov_port_data < 0) ov_port_data= ov_port_ctrl+1;
288 myopt(&argv, cmdinfos);
290 argaddr(&requ_sa, ov_requ, ov_requ_port);
291 argaddr(&ctrl_sa, ov_mcast, ov_ctrl_port);
292 argaddr(&data_sa, ov_data, ov_data_port);
294 if (argv[1] && ov_mode != 'p')
295 badusage("mode takes no non-option arguments");
305 if (!argv[1] || argv[2])
306 badusage("play-requester takes one non-option argument");