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>
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 nonblock(int fd) {
157 r= fcntl(fd,F_GETFL); if (r<0) sysfail("nonblock fcntl F_GETFL");
159 r= fcntl(fd,F_SETFL,r); if (r<0) sysfail("nonblock fcntl F_GETFL");
162 static void blocksignals(int how) {
167 sigaddset(&set,SIGCHLD);
168 r= sigprocmask(how,&set,0);
169 if (r) sysfail("sigprocmask");
172 static int mksocket(int type, int proto,
173 const struct sockaddr_in *sa, const char *what) {
176 fd= socket(PF_INET, type, proto);
177 if (fd<0) sysfail("socket %s",what);
179 r= bind(fd, (struct sockaddr*)&mcast_sa, sizeof(*sa));
180 if (r) sysfail("bind %s",what);
185 static void mkmcastrecv(const struct sockaddr_in *sa, const char *what) {
189 mcast_fd= mksocket(SOCK_DGRAM, IPPROTO_UDP, sa, what);
191 mreq.imr_multiaddr= sa->sin_addr;
192 mreq.imr_interface.s_addr= INADDR_ANY;
193 r= setsockopt(mcast_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
194 if (r) sysfail("add mcast membership %s", what);
197 /*---------- player ----------*/
199 static void recvd_play(void) {
203 r= unmar_CTRL_PLAY(&pkt);
204 if (r) { fprintf(stderr,"bad PLAY packet\n"); return; }
208 static void recvd_stop(void) {
212 r= unmar_CTRL_STOP(&pkt);
213 if (r) { fprintf(stderr,"bad STOP packet\n"); return; }
216 static void player(void) {
217 struct sockaddr_in peer_sa, old_peer_sa;
218 socklen_t peer_salen;
221 mkmcastrecv(&ctrl_sa, "ctrl");
223 memset(&old_peer_sa, 0, sizeof(old_peer_sa));
226 peer_salen= sizeof(peer_sa);
227 memset(&peer_sa, 0, sizeof(peer_sa));
229 blocksignals(SIG_UNBLOCK);
230 packet_len= recvfrom(mcast_fd, packet, sizeof(packet),
231 MSG_TRUNC, (struct sockaddr*)&peer_sa, &peer_salen);
232 blocksignals(SIG_BLOCK);
235 if (errno==EINTR) continue;
236 perror("mcast_fd recvfrom");
239 if (peer_salen != sizeof(peer_sa)) {
240 fprintf(stderr,"mcast_fd recvfrom salen %ld not %ld\n",
241 (unsigned long)peer_salen, (unsigned long)sizeof(peer_sa));
244 if (packet_len > sizeof(packet)) {
245 fprintf(stderr,"mcast_fd recvfrom packet len %ld longer than max %ld\n",
246 (unsigned long)packet_len, (unsigned long)sizeof(packet));
249 if (memcmp(&old_peer_sa, &peer_sa, sizeof(old_peer_sa))) {
250 char *p= inet_ntoa(peer_sa.sin_addr);
251 fprintf(stderr,"receiving from %s:%d\n",p,ntohs(peer_sa.sin_port));
252 memcpy(&old_peer_sa, &peer_sa, sizeof(old_peer_sa));
255 fprintf(stderr,"empty packet!\n");
266 fprintf(stderr,"unknown opcode %d\n",packet[0]);
271 /*---------- server ----------*/
274 requ_fd= mksocket(SOCK_STREAM, IPPROTO_TCP, &requ_sa, "requ");
277 /*---------- main ----------*/
279 static void argaddr(struct sin_addr *sa, const char *addr_name, int port) {
280 memset(sa,0,sizeof(*sa));
281 sa->sin_family= AF_INET;
283 r= inet_aton(ov_mcast, &mcast_sa.sin_addr);
284 if (!r) badusage("invalid addr `%s'", addr_name);
286 if (port<0 || port>65536) badusage("invalid port %d",port);
288 sa->sin_port= htons(port);
291 int main(int argc, const char **argv) {
294 if (ov_port_data < 0) ov_port_data= ov_port_ctrl+1;
295 myopt(&argv, cmdinfos);
297 argaddr(&requ_sa, ov_requ, ov_requ_port);
298 argaddr(&ctrl_sa, ov_mcast, ov_ctrl_port);
299 argaddr(&data_sa, ov_data, ov_data_port);
301 if (argv[1] && ov_mode != 'p')
302 badusage("mode takes no non-option arguments");
312 if (!argv[1] || argv[2])
313 badusage("play-requester takes one non-option argument");