2 * http://www.ibiblio.org/pub/Linux/docs/HOWTO/Multicast-HOWTO
13 #include <sys/types.h>
15 #include <sys/socket.h>
16 #include <netinet/in.h>
17 #include <arpa/inet.h>
19 typedef unsigned char Byte;
21 static const char *ov_mcast= "239.193.27.221";
22 static int ov_port_ctrl= 4101;
23 static int ov_port_data= -1;
26 static struct sockaddr_in mcast_sa;
28 static void sysfail(const char *m) { perror(m); exit(16); }
30 static Byte packet[1024];
31 static int packet_len;
33 static uint64_t htonll(uint64_t v) {
35 return (v >> 32) | (v << 32);
42 #define OP_CTRL_PLAY 1
43 #define OP_CTRL_STOP 2
44 #define OP_CTRL_DATA 3
46 #define MAR_CTRL_PLAY \
57 #define MAR_CTRL_STOP \
70 #define FI8(f) F(f, uint8_t, v)
71 #define FI32(f) F(f, uint32_t, htonl(v))
72 #define FI64(f) F(f, uint64_t, htonll(v))
80 #define FR(f,t,l) t f[(l)]; int f##_l;
82 #define MAR(m) typedef struct Mar_##m { MAR_##m } Mar_##m;
89 #define F(f,t,c) { t v= d->f; *(t*)p= c; p += sizeof(t); };
90 #define FR(f,t,l) assert(d->f##_l<=l); memcpy(p,d->f,d->f##_l); p+=d->f##_l;
93 static void mar_##m(const Mar_##m *d) { \
96 packet_len= p - packet; \
97 assert(packet_len < sizeof(packet)); \
107 if (lr < sizeof(t)) return -1; \
109 p += sizeof(t); lr -= sizeof(t); \
112 #define FR(f,t,l) { \
113 if (lr > l) return -1; \
114 memcpy(d->f, p, lr); \
120 static int unmar_##m(Mar_##m *d) { \
121 const Byte *p= packet; \
122 int lr= packet_len; \
132 static void nonblock(int fd) {
134 r= fcntl(fd,F_GETFL); if (r<0) sysfail("nonblock fcntl F_GETFL");
136 r= fcntl(fd,F_SETFL,r); if (r<0) sysfail("nonblock fcntl F_GETFL");
139 static void blocksignals(int how) {
144 sigaddset(&set,SIGCHLD);
145 r= sigprocmask(how,&set,0);
146 if (r) sysfail("sigprocmask");
149 static void recvd_play(void) {
153 r= unmar_CTRL_PLAY(&pkt);
154 if (r) { fprintf(stderr,"bad PLAY packet\n"); return; }
157 static void recvd_stop(void) {
161 r= unmar_CTRL_STOP(&pkt);
162 if (r) { fprintf(stderr,"bad STOP packet\n"); return; }
165 static void player(void) {
166 struct sockaddr_in peer_sa, old_peer_sa;
167 socklen_t peer_salen;
171 memset(&old_peer_sa, 0, sizeof(old_peer_sa));
173 mcast_fd= socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
174 if (mcast_fd<0) sysfail("mcast_fd socket");
176 r= bind(mcast_fd, (struct sockaddr*)&mcast_sa, sizeof(mcast_sa));
177 if (r) sysfail("mcast_fd bind");
179 mcast_sa.sin_port= htons(ov_port_ctrl);
181 mreq.imr_multiaddr= mcast_sa.sin_addr;
182 mreq.imr_interface.s_addr= INADDR_ANY;
183 r= setsockopt(mcast_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
184 if (r) sysfail("mcast_fd add memb");
187 peer_salen= sizeof(peer_sa);
188 memset(&peer_sa, 0, sizeof(peer_sa));
190 blocksignals(SIG_UNBLOCK);
191 packet_len= recvfrom(mcast_fd, packet, sizeof(packet),
192 MSG_TRUNC, (struct sockaddr*)&peer_sa, &peer_salen);
193 blocksignals(SIG_BLOCK);
196 if (errno==EINTR) continue;
197 perror("mcast_fd recvfrom");
200 if (peer_salen != sizeof(peer_sa)) {
201 fprintf(stderr,"mcast_fd recvfrom salen %ld not %ld\n",
202 (unsigned long)peer_salen, (unsigned long)sizeof(peer_sa));
205 if (packet_len > sizeof(packet)) {
206 fprintf(stderr,"mcast_fd recvfrom packet len %ld longer than max %ld\n",
207 (unsigned long)packet_len, (unsigned long)sizeof(packet));
210 if (memcmp(&old_peer_sa, &peer_sa, sizeof(old_peer_sa))) {
211 char *p= inet_ntoa(peer_sa.sin_addr);
212 fprintf(stderr,"receiving from %s:%d\n",p,ntohs(peer_sa.sin_port));
213 memcpy(&old_peer_sa, &peer_sa, sizeof(old_peer_sa));
216 fprintf(stderr,"empty packet!\n");
227 fprintf(stderr,"unknown opcode %d\n",packet[0]);
232 int main(int argc, const char *const *argv) {
235 if (ov_port_data < 0) ov_port_data= ov_port_ctrl+1;
237 memset(&mcast_sa,0,sizeof(mcast_sa));
238 mcast_sa.sin_family= AF_INET;
239 r= inet_aton(ov_mcast, &mcast_sa.sin_addr); assert(r);