~brightbox/brightbox/updcast-20110710

1.1.1 by Michael Schutte
Import upstream version 20100130
1
#include "config.h"
2
1 by Tomas Pospisek
Import upstream version 20040531
3
#include <sys/types.h>
4
#include <unistd.h>
5
#include <sys/time.h>
6
#include <string.h>
7
#include <stdlib.h>
8
#include <errno.h>
9
1.1.1 by Michael Schutte
Import upstream version 20100130
10
#include <fcntl.h>
11
12
#ifdef HAVE_ARPA_INET_H
13
# include <arpa/inet.h>
14
#endif
15
16
#ifdef HAVE_NETDB_H
17
# include <netdb.h>
18
#endif
19
20
#ifdef HAVE_NET_IF_H
21
# include <net/if.h>
22
#endif
23
24
#ifdef HAVE_SYS_IOCTL_H
25
# include <sys/ioctl.h>
26
#endif
27
28
#ifdef __MINGW32__
29
30
#include <ws2tcpip.h>
31
#define ioctl ioctlsocket
32
33
#include <iprtrmib.h>
34
#include <iphlpapi.h>
35
36
#endif /* __MINGW32__ */
1 by Tomas Pospisek
Import upstream version 20040531
37
38
#include "log.h"
39
#include "socklib.h"
1.1.1 by Michael Schutte
Import upstream version 20100130
40
#include "util.h"
41
42
#ifndef SOL_IP
43
#define SOL_IP IPPROTO_IP
44
#endif
45
46
#ifdef __linux__
47
48
#include <linux/types.h>
49
50
typedef unsigned long long u64;
51
typedef unsigned int u32;
52
typedef unsigned short u16;
53
typedef unsigned char u8;
54
55
#include <linux/ethtool.h>
56
#include <linux/sockios.h>
57
58
#endif
59
60
// for Darwin
61
#ifdef _SIZEOF_ADDR_IFREQ
62
    #define IFREQ_SIZE(a) _SIZEOF_ADDR_IFREQ(a)
63
#endif
64
65
#ifndef DEBUG
66
# define DEBUG 0
67
#endif
1 by Tomas Pospisek
Import upstream version 20040531
68
69
#ifdef LOSSTEST
70
/**
71
 * Packet loss/swap testing...
72
 */
73
long int write_loss = 0;
74
long int read_loss = 0;
75
long int read_swap = 0;
76
unsigned int seed=0;
77
78
int loseSendPacket(void) {
79
    if(write_loss) {
80
	long r = random();
81
	if(r < write_loss)
82
	    return 1;
83
    }
84
    return 0;
85
}
86
87
#define STASH_SIZE 64
88
89
static int stashed;
90
static struct packetStash {
91
    unsigned char data[4092];
92
    int size;
93
} packetStash[STASH_SIZE];
94
95
/**
96
 * Lose a packet
97
 */
98
void loseRecvPacket(int s) {
99
    if(read_loss) {
100
	while(random() < read_loss) {
101
	    int x;
102
	    flprintf("Losing packet\n");
103
	    recv(s, (void *) &x, sizeof(x),0);
104
	}
105
    }
106
    if(read_swap) {
107
	while(stashed < STASH_SIZE && random() < read_swap) {
108
	    int size;
109
	    flprintf("Stashing packet %d\n", stashed);
1.1.1 by Michael Schutte
Import upstream version 20100130
110
	    size = recv(s, packetStash[stashed].data,
1 by Tomas Pospisek
Import upstream version 20040531
111
			sizeof(packetStash[stashed].data),0);
112
	    packetStash[stashed].size = size;
113
	    stashed++;
114
	}
115
    }
116
}
117
118
/**
119
 * bring stored packet back up...
120
 */
121
int RecvMsg(int s, struct msghdr *msg, int flags) {
122
    if(read_swap && stashed) {
123
	if(random() / stashed < read_swap) {
124
	    int slot = random() % stashed;
125
	    int iovnr;
126
	    char *data = packetStash[slot].data;
127
	    int totalLen = packetStash[slot].size;
128
	    int retBytes=0;
129
	    flprintf("Bringing out %d\n", slot);
130
	    for(iovnr=0; iovnr < msg->msg_iovlen; iovnr++) {
131
		int len = msg->msg_iov[iovnr].iov_len;
132
		if(len > totalLen)
133
		    len = totalLen;
1.1.1 by Michael Schutte
Import upstream version 20100130
134
		memcpy(msg->msg_iov[iovnr].iov_base, data, len);
1 by Tomas Pospisek
Import upstream version 20040531
135
		totalLen -= len;
136
		data += len;
137
		retBytes += len;
138
		if(totalLen == 0)
139
		    break;
140
	    }
141
	    packetStash[slot]=packetStash[stashed];
142
	    stashed--;
143
	    return retBytes;
144
	}
145
    }
146
    return recvmsg(s, msg, flags);
147
}
148
149
void setWriteLoss(char *l) {
150
    write_loss = (long) (atof(l) * RAND_MAX);
151
}
152
153
void setReadLoss(char *l) {
154
    read_loss = (long) (atof(l) * RAND_MAX);
155
}
156
157
void setReadSwap(char *l) {
158
    read_swap = (long) (atof(l) * RAND_MAX);
159
}
160
161
162
void srandomTime(int printSeed) {
163
    struct timeval tv;
164
    long seed;
165
    gettimeofday(&tv, 0);
166
    seed = (tv.tv_usec * 2000) ^ tv.tv_sec;
167
    if(printSeed)
168
	flprintf("seed=%ld\n", seed);
169
    srandom(seed);
170
}
171
#endif
172
173
/* makes a socket address */
1.1.1 by Michael Schutte
Import upstream version 20100130
174
int makeSockAddr(char *hostname, short port, struct sockaddr_in *addr)
1 by Tomas Pospisek
Import upstream version 20040531
175
{
176
    struct hostent *host;
177
1.1.1 by Michael Schutte
Import upstream version 20100130
178
    memset ((char *) addr, 0, sizeof(struct sockaddr_in));
1 by Tomas Pospisek
Import upstream version 20040531
179
    if (hostname && *hostname) {
180
	char *inaddr;
181
	int len;
182
183
	host = gethostbyname(hostname);
184
	if (host == NULL) {
185
	    udpc_fatal(1, "Unknown host %s\n", hostname);
186
	}
1.1.1 by Michael Schutte
Import upstream version 20100130
187
1 by Tomas Pospisek
Import upstream version 20040531
188
	inaddr = host->h_addr_list[0];
189
	len = host->h_length;
1.1.1 by Michael Schutte
Import upstream version 20100130
190
	memcpy((void *)&((struct sockaddr_in *)addr)->sin_addr, inaddr, len);
1 by Tomas Pospisek
Import upstream version 20040531
191
    }
192
193
    ((struct sockaddr_in *)addr)->sin_family = AF_INET;
194
    ((struct sockaddr_in *)addr)->sin_port = htons(port);
195
    return 0;
196
}
197
1.1.1 by Michael Schutte
Import upstream version 20100130
198
#ifdef HAVE_PTON
199
# define INET_ATON(a,i) inet_pton(AF_INET,a,i)
200
#else
201
# ifdef HAVE_ATON
202
#  define INET_ATON(a,i) inet_aton(a,i)
203
# else
204
205
#ifndef INADDR_NONE
206
#define INADDR_NONE ((in_addr_t)-1)
207
#endif
208
209
static inline int INET_ATON(const char *a, struct in_addr *i) {
210
	i->s_addr=inet_addr(a);
211
	if(i->s_addr == INADDR_NONE && strcmp(a, "255.255.255.255"))
212
		return 0; /* Address invalid */
213
	return 1; /* Address valid */
214
}
215
# endif
216
#endif
217
218
219
static int initSockAddress(addr_type_t addr_type,
220
			   net_if_t *net_if,
221
			   in_addr_t ip,
222
			   unsigned short port,
223
			   struct sockaddr_in *addr) {
224
    memset ((char *) addr, 0, sizeof(struct sockaddr_in));
225
    addr->sin_family = AF_INET;
226
    addr->sin_port = htons(port);
227
228
    if(!net_if && addr_type != ADDR_TYPE_MCAST)
229
	udpc_fatal(1, "initSockAddr without ifname\n");
230
231
    switch(addr_type) {
232
    case ADDR_TYPE_UCAST:
233
	addr->sin_addr = net_if->addr;
234
	break;
235
    case ADDR_TYPE_BCAST:
236
	addr->sin_addr = net_if->bcast;
237
	break;
238
    case ADDR_TYPE_MCAST:
239
	addr->sin_addr.s_addr = ip;
240
	break;
1 by Tomas Pospisek
Import upstream version 20040531
241
    }
242
    return 0;
243
}
244
1.1.1 by Michael Schutte
Import upstream version 20100130
245
int getMyAddress(net_if_t *net_if, struct sockaddr_in *addr) {
246
    return initSockAddress(ADDR_TYPE_UCAST, net_if, INADDR_ANY, 0, addr);
247
}
248
249
250
int getBroadCastAddress(net_if_t *net_if, struct sockaddr_in *addr,
1 by Tomas Pospisek
Import upstream version 20040531
251
			short port){
1.1.1 by Michael Schutte
Import upstream version 20100130
252
    int r= initSockAddress(ADDR_TYPE_BCAST, net_if, INADDR_ANY, port, addr);
253
    if(addr->sin_addr.s_addr == 0) {
254
      /* Quick hack to make it work for loopback */
255
      struct sockaddr_in ucast;
256
      initSockAddress(ADDR_TYPE_UCAST, net_if, INADDR_ANY, port, &ucast);
1 by Tomas Pospisek
Import upstream version 20040531
257
1.1.1 by Michael Schutte
Import upstream version 20100130
258
      if((ntohl(ucast.sin_addr.s_addr) & 0xff000000) == 0x7f000000)
259
	addr->sin_addr.s_addr = ucast.sin_addr.s_addr;
1 by Tomas Pospisek
Import upstream version 20040531
260
    }
1.1.1 by Michael Schutte
Import upstream version 20100130
261
    return r;
262
}
263
264
static int mcastListen(int sock, net_if_t *net_if, struct sockaddr_in *addr);
265
266
static int safe_inet_aton(const char *address, struct in_addr *ip) {
267
    if(!INET_ATON(address, ip))
268
	udpc_fatal(-1, "Bad address %s", address);
1 by Tomas Pospisek
Import upstream version 20040531
269
    return 0;
270
}
271
1.1.1 by Michael Schutte
Import upstream version 20100130
272
273
int getMcastAllAddress(struct sockaddr_in *addr, const char *address,
274
		       short port){
275
    struct in_addr ip;
276
    int ret;
277
1 by Tomas Pospisek
Import upstream version 20040531
278
    if(address == NULL || address[0] == '\0')
1.1.1 by Michael Schutte
Import upstream version 20100130
279
	safe_inet_aton("224.0.0.1", &ip);
1 by Tomas Pospisek
Import upstream version 20040531
280
    else {
1.1.1 by Michael Schutte
Import upstream version 20100130
281
	if((ret=safe_inet_aton(address, &ip))<0)
282
	   return ret;
283
    }
284
    return initSockAddress(ADDR_TYPE_MCAST, NULL, ip.s_addr, port, addr);
1 by Tomas Pospisek
Import upstream version 20040531
285
}
286
287
1.1.1 by Michael Schutte
Import upstream version 20100130
288
int doSend(int s, void *message, size_t len, struct sockaddr_in *to) {
1 by Tomas Pospisek
Import upstream version 20040531
289
/*    flprintf("sent: %08x %d\n", *(int*) message, len);*/
290
#ifdef LOSSTEST
291
    loseSendPacket();
292
#endif
1.1.1 by Michael Schutte
Import upstream version 20100130
293
    return sendto(s, message, len, 0, (struct sockaddr*) to, sizeof(*to));
1 by Tomas Pospisek
Import upstream version 20040531
294
}
295
1.1.1 by Michael Schutte
Import upstream version 20100130
296
int doReceive(int s, void *message, size_t len,
297
	      struct sockaddr_in *from, int portBase) {
1 by Tomas Pospisek
Import upstream version 20040531
298
    socklen_t slen;
299
    int r;
1.1.1 by Michael Schutte
Import upstream version 20100130
300
    unsigned short port;
1 by Tomas Pospisek
Import upstream version 20040531
301
    char ipBuffer[16];
302
303
    slen = sizeof(*from);
304
#ifdef LOSSTEST
305
    loseRecvPacket(s);
306
#endif
1.1.1 by Michael Schutte
Import upstream version 20100130
307
    r = recvfrom(s, message, len, 0, (struct sockaddr *)from, &slen);
1 by Tomas Pospisek
Import upstream version 20040531
308
    if (r < 0)
309
	return r;
1.1.1 by Michael Schutte
Import upstream version 20100130
310
    port = ntohs(from->sin_port);
1 by Tomas Pospisek
Import upstream version 20040531
311
    if(port != RECEIVER_PORT(portBase) && port != SENDER_PORT(portBase)) {
1.1.1 by Michael Schutte
Import upstream version 20100130
312
	udpc_flprintf("Bad message from port %s.%d\n",
1 by Tomas Pospisek
Import upstream version 20040531
313
		      getIpString(from, ipBuffer),
314
		      ntohs(((struct sockaddr_in *)from)->sin_port));
315
	return -1;
316
    }
317
/*    flprintf("recv: %08x %d\n", *(int*) message, r);*/
318
    return r;
319
}
320
321
int getSendBuf(int sock) {
322
    int bufsize;
1.1.1 by Michael Schutte
Import upstream version 20100130
323
    socklen_t len=sizeof(int);
324
    if(getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char*)&bufsize, &len) < 0)
1 by Tomas Pospisek
Import upstream version 20040531
325
	return -1;
326
    return bufsize;
327
}
328
329
void setSendBuf(int sock, unsigned int bufsize) {
1.1.1 by Michael Schutte
Import upstream version 20100130
330
    if(setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char*)&bufsize, sizeof(bufsize))< 0)
1 by Tomas Pospisek
Import upstream version 20040531
331
	perror("Set send buffer");
332
}
333
334
unsigned int getRcvBuf(int sock) {
335
    unsigned int bufsize;
1.1.1 by Michael Schutte
Import upstream version 20100130
336
    socklen_t len=sizeof(int);
337
    if(getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&bufsize, &len) < 0)
1 by Tomas Pospisek
Import upstream version 20040531
338
	return -1;
339
    return bufsize;
340
}
341
342
void setRcvBuf(int sock, unsigned int bufsize) {
1.1.1 by Michael Schutte
Import upstream version 20100130
343
    if(setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
344
		  (char*) &bufsize, sizeof(bufsize))< 0)
1 by Tomas Pospisek
Import upstream version 20040531
345
	perror("Set receiver buffer");
346
}
347
348
int setSocketToBroadcast(int sock) {
349
    /* set the socket to broadcast */
350
    int p = 1;
1.1.1 by Michael Schutte
Import upstream version 20100130
351
    return setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&p, sizeof(int));
1 by Tomas Pospisek
Import upstream version 20040531
352
}
353
354
int setTtl(int sock, int ttl) {
355
    /* set the socket to broadcast */
1.1.1 by Michael Schutte
Import upstream version 20100130
356
    return setsockopt(sock, SOL_IP, IP_MULTICAST_TTL, (char*)&ttl, sizeof(int));
1 by Tomas Pospisek
Import upstream version 20040531
357
}
358
1.1.1 by Michael Schutte
Import upstream version 20100130
359
#ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
1 by Tomas Pospisek
Import upstream version 20040531
360
# define IP_MREQN ip_mreqn
361
#else
362
# define IP_MREQN ip_mreq
363
#endif
364
365
#define getSinAddr(addr) (((struct sockaddr_in *) addr)->sin_addr)
366
1.1.1 by Michael Schutte
Import upstream version 20100130
367
1 by Tomas Pospisek
Import upstream version 20040531
368
/**
369
 * Fill in the mreq structure with the given interface and address
370
 */
1.1.1 by Michael Schutte
Import upstream version 20100130
371
static int fillMreq(net_if_t *net_if, struct in_addr addr,
1 by Tomas Pospisek
Import upstream version 20040531
372
		    struct IP_MREQN *mreq) {
1.1.1 by Michael Schutte
Import upstream version 20100130
373
#ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
374
    mreq->imr_ifindex = net_if->index;
1 by Tomas Pospisek
Import upstream version 20040531
375
    mreq->imr_address.s_addr = 0;
376
#else
1.1.1 by Michael Schutte
Import upstream version 20100130
377
    mreq->imr_interface = net_if->addr;
1 by Tomas Pospisek
Import upstream version 20040531
378
#endif
379
    mreq->imr_multiaddr = addr;
380
381
    return 0;
382
}
383
384
/**
385
 * Perform a multicast operation
386
 */
1.1.1 by Michael Schutte
Import upstream version 20100130
387
static int mcastOp(int sock, net_if_t *net_if, struct in_addr addr,
388
		   int code, const char *message) {
1 by Tomas Pospisek
Import upstream version 20040531
389
    struct IP_MREQN mreq;
390
    int r;
1.1.1 by Michael Schutte
Import upstream version 20100130
391
392
    fillMreq(net_if, addr, &mreq);
393
    r = setsockopt(sock, SOL_IP, code, (char*)&mreq, sizeof(mreq));
1 by Tomas Pospisek
Import upstream version 20040531
394
    if(r < 0) {
395
	perror(message);
396
	exit(1);
397
    }
398
    return 0;
399
}
400
401
402
/*
1.1.1 by Michael Schutte
Import upstream version 20100130
403
struct in_addr getSinAddr(struct sockaddr_in *addr) {
1 by Tomas Pospisek
Import upstream version 20040531
404
    return ((struct sockaddr_in *) addr)->sin_addr;
405
}
406
*/
407
408
/**
409
 * Set socket to listen on given multicast address Not 100% clean, it
410
 * would be preferable to make a new socket, and not only subscribe it
411
 * to the multicast address but also _bind_ to it. Indeed, subscribing
412
 * alone is not enough, as we may get traffic destined to multicast
413
 * address subscribed to by other apps on the machine. However, for
414
 * the moment, we skip this concern, as udpcast's main usage is
415
 * software installation, and in that case it runs on an otherwise
416
 * quiet system.
417
 */
1.1.1 by Michael Schutte
Import upstream version 20100130
418
static int mcastListen(int sock, net_if_t *net_if, struct sockaddr_in *addr) {
419
    return mcastOp(sock, net_if, getSinAddr(addr), IP_ADD_MEMBERSHIP,
1 by Tomas Pospisek
Import upstream version 20040531
420
		   "Subscribe to multicast group");
421
}
422
423
1.1.1 by Michael Schutte
Import upstream version 20100130
424
int setMcastDestination(int sock, net_if_t *net_if, struct sockaddr_in *addr) {
425
#ifdef WINDOWS
1 by Tomas Pospisek
Import upstream version 20040531
426
    int r;
1.1.1 by Michael Schutte
Import upstream version 20100130
427
    struct sockaddr_in interface_addr;
1 by Tomas Pospisek
Import upstream version 20040531
428
    struct in_addr if_addr;
1.1.1 by Michael Schutte
Import upstream version 20100130
429
    getMyAddress(net_if, &interface_addr);
1 by Tomas Pospisek
Import upstream version 20040531
430
    if_addr = getSinAddr(&interface_addr);
1.1.1 by Michael Schutte
Import upstream version 20100130
431
    r = setsockopt (sock, IPPROTO_IP, IP_MULTICAST_IF,
432
		    (char *) &if_addr, sizeof(if_addr));
1 by Tomas Pospisek
Import upstream version 20040531
433
    if(r < 0)
434
	fatal(1, "Set multicast send interface");
435
    return 0;
436
#else
437
    /* IP_MULTICAST_IF not correctly supported on Cygwin */
1.1.1 by Michael Schutte
Import upstream version 20100130
438
    return mcastOp(sock, net_if, getSinAddr(addr), IP_MULTICAST_IF,
1 by Tomas Pospisek
Import upstream version 20040531
439
		   "Set multicast send interface");
440
#endif
441
}
442
1.1.1 by Michael Schutte
Import upstream version 20100130
443
444
#ifdef __MINGW32__
445
static MIB_IFROW *getIfRow(MIB_IFTABLE *iftab, DWORD dwIndex) {
446
    int j;
447
448
    /* Find the corresponding interface row (for name and
449
     * MAC address) */
450
    for(j=0; j<iftab->dwNumEntries; j++) {
451
	MIB_IFROW *ifrow = &iftab->table[j];
452
	/* eth0, eth1, ... */
453
	if(ifrow->dwIndex == dwIndex)
454
	    return ifrow;
455
    }
456
    return NULL;
457
}
458
459
static char *fmtName(MIB_IFROW *ifrow) {
460
    char *out;
461
    int l = ifrow->dwDescrLen+1;
462
    if(ifrow->dwPhysAddrLen)
463
	l+=2+3*ifrow->dwPhysAddrLen;
464
    out = malloc(ifrow->dwDescrLen+l+1);
465
    if(!out)
466
	return NULL;
467
    memcpy(out, ifrow->bDescr, ifrow->dwDescrLen);
468
    out[ifrow->dwDescrLen]='\0';
469
470
    if(ifrow->dwPhysAddrLen) {
471
	int k;
472
	char *ptr=out+strlen(out);
473
	strcpy(ptr, " (");
474
	ptr+=2;
475
	for(k=0; k<ifrow->dwPhysAddrLen; k++) {
476
	    if(k)
477
		*ptr++='-';
478
	    sprintf(ptr, "%02x", 255 & ifrow->bPhysAddr[k]);
479
	    ptr += 2;
480
	}
481
	strcpy(ptr, ")");
482
    }
483
    return out;
484
}
485
#endif /* __MINGW32__ */
486
487
#ifndef __MINGW32__
488
/**
489
 * Tests whether the given card has link
490
 * 0 no
491
 * 1 yes
492
 * -1 unknown
493
 */
494
static int hasLink(int s, const char *ifname) {
495
496
#ifdef ETHTOOL_GLINK
497
  struct ifreq ifr;
498
  struct ethtool_value edata;
499
500
  edata.cmd = ETHTOOL_GLINK;
501
502
  strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)-1);
503
  ifr.ifr_data = (char *) &edata;
504
505
  if(ioctl(s, SIOCETHTOOL, &ifr) == -1) {
506
    /* Operation not supported */
507
    return -1;
508
  } else {
509
    return edata.data;
510
  }
511
#else
512
  return -1;
513
#endif
514
}
515
#endif
516
517
/**
518
 * Tests whether the given card operates in full duplex mode
519
 * 0 no
520
 * 1 yes
521
 * -1 unknown
522
 */
523
int isFullDuplex(int s, const char *ifname) {
524
525
#ifdef ETHTOOL_GLINK
526
  struct ifreq ifr;
527
  struct ethtool_cmd ecmd;
528
529
  ecmd.cmd = ETHTOOL_GSET;
530
531
  strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)-1);
532
  ifr.ifr_data = (char *) &ecmd;
533
534
  if(ioctl(s, SIOCETHTOOL, &ifr) == -1) {
535
    /* Operation not supported */
536
    return -1;
537
  } else {
538
    return ecmd.duplex;
539
  }
540
#else
541
  return -1;
542
#endif
543
}
544
545
1 by Tomas Pospisek
Import upstream version 20040531
546
/**
547
 * Canonize interface name. If attempt is not NULL, pick the interface
548
 * which has that address.
1.1.1 by Michael Schutte
Import upstream version 20100130
549
 * If attempt is NULL, pick interfaces in the following order of preference
1 by Tomas Pospisek
Import upstream version 20040531
550
 * 1. eth0
551
 * 2. Anything starting with eth0:
552
 * 3. Anything starting with eth
553
 * 4. Anything else
554
 * 5. localhost
555
 * 6. zero address
556
 */
1.1.1 by Michael Schutte
Import upstream version 20100130
557
net_if_t *getNetIf(const char *wanted) {
558
#ifndef __MINGW32__
1 by Tomas Pospisek
Import upstream version 20040531
559
	struct ifreq *ifrp, *ifend, *chosen;
560
	struct ifconf ifc;
1.1.1 by Michael Schutte
Import upstream version 20100130
561
	int s;
562
#else /* __MINGW32__ */
563
	int i;
564
565
	int etherNo=-1;
566
	int wantedEtherNo=-2; /* Wanted ethernet interface */
567
568
	MIB_IPADDRTABLE *iptab=NULL;
569
	MIB_IFTABLE *iftab=NULL;
570
571
	MIB_IPADDRROW *iprow, *chosen=NULL;
572
	MIB_IFROW *chosenIf=NULL;
573
	WORD wVersionRequested; /* Version of Winsock to load */
574
	WSADATA wsaData; /* Winsock implementation details */
575
	ULONG a;
576
577
	int r;
578
#endif /* __MINGW32__ */
579
580
	int lastGoodness=0;
1 by Tomas Pospisek
Import upstream version 20040531
581
	struct in_addr wantedAddress;
1.1.1 by Michael Schutte
Import upstream version 20100130
582
	int isAddress=0;
583
	int wantedLen=0;
584
	net_if_t *net_if;
585
586
	if(wanted == NULL) {
587
	    wanted = getenv("IFNAME");
588
	}
589
590
	if(wanted && INET_ATON(wanted, &wantedAddress))
591
	    isAddress=1;
592
	else
593
	    wantedAddress.s_addr=0;
594
595
	if(wanted)
596
	    wantedLen=strlen(wanted);
597
598
	net_if = MALLOC(net_if_t);
599
	if(net_if == NULL)
600
	    udpc_fatal(1, "Out of memory error");
601
602
#ifndef __MINGW32__
603
604
	s = socket(PF_INET, SOCK_DGRAM, 0);
605
	if (s < 0) {
606
	    perror("make socket");
607
	    exit(1);
608
	}
609
610
	ifc.ifc_len = sizeof(struct ifreq) * 10;
611
	while(1) {
1.1.2 by Neil Wilson
Import upstream version 20110710
612
	    int len = ifc.ifc_len;
1.1.1 by Michael Schutte
Import upstream version 20100130
613
	    ifc.ifc_buf = (caddr_t) malloc(ifc.ifc_len);
614
	    if(ifc.ifc_buf == NULL) {
615
		udpc_fatal(1, "Out of memory error");
616
	    }
617
618
	    if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0 ||
619
		ifc.ifc_len < (signed int)sizeof(struct ifreq)) {
620
		perror("udpcast: SIOCGIFCONF: ");
621
		exit(1);
622
	    }
623
624
	    if(len == ifc.ifc_len) {
625
		ifc.ifc_len += sizeof(struct ifreq) * 10;
626
		free(ifc.ifc_buf);
627
	    } else
628
		break;
629
	}
630
631
	ifend = (struct ifreq *)((char *)ifc.ifc_buf + ifc.ifc_len);
632
	chosen=NULL;
633
634
	for (ifrp = (struct ifreq *) ifc.ifc_buf ; ifrp < ifend;
635
#ifdef IFREQ_SIZE
636
	     ifrp = IFREQ_SIZE(*ifrp) + (char *)ifrp
637
#else
638
	     ifrp++
639
#endif
640
	     ) {
1 by Tomas Pospisek
Import upstream version 20040531
641
	    unsigned long iaddr = getSinAddr(&ifrp->ifr_addr).s_addr;
1.1.1 by Michael Schutte
Import upstream version 20100130
642
	    int goodness;
643
644
	    if(ifrp->ifr_addr.sa_family != PF_INET)
645
		continue;
646
647
	    if(wanted) {
648
		if(isAddress && iaddr == wantedAddress.s_addr) {
649
		    goodness=8;
650
		} else if(strcmp(wanted, ifrp->ifr_name) ==0) {
651
		    /* perfect match on interface name */
652
		    goodness=12;
653
		} else if(wanted != NULL &&
654
			  strncmp(wanted, ifrp->ifr_name, wantedLen) ==0) {
655
		    /* prefix match on interface name */
656
		    goodness=7;
657
		} else {
658
		    /* no match, try next */
659
		    continue;
1 by Tomas Pospisek
Import upstream version 20040531
660
		}
661
	    } else {
662
		if(iaddr == 0) {
663
		    /* disregard interfaces whose address is zero */
664
		    goodness = 1;
665
		} else if(iaddr == htonl(0x7f000001)) {
666
		    /* disregard localhost type devices */
667
		    goodness = 2;
1.1.1 by Michael Schutte
Import upstream version 20100130
668
		} else if(strcmp("eth0", ifrp->ifr_name) == 0 ||
669
			  strcmp("en0",  ifrp->ifr_name) == 0) {
670
		    /* prefer first ethernet interface */
1 by Tomas Pospisek
Import upstream version 20040531
671
		    goodness = 6;
672
		} else if(strncmp("eth0:", ifrp->ifr_name, 5) == 0) {
1.1.1 by Michael Schutte
Import upstream version 20100130
673
		    /* second choice: any secondary addresses of first ethernet */
1 by Tomas Pospisek
Import upstream version 20040531
674
		    goodness = 5;
1.1.1 by Michael Schutte
Import upstream version 20100130
675
		} else if(strncmp("eth", ifrp->ifr_name, 3) == 0 ||
676
			  strncmp("en",  ifrp->ifr_name, 2) == 0) {
1 by Tomas Pospisek
Import upstream version 20040531
677
		    /* and, if not available, any other ethernet device */
678
		    goodness = 4;
679
		} else {
680
		    goodness = 3;
681
		}
1.1.1 by Michael Schutte
Import upstream version 20100130
682
	    }
683
684
	    if(hasLink(s, ifrp->ifr_name))
685
	      /* Good or unknown link status privileged over known
686
	       * disconnected */
687
	      goodness += 3;
688
689
	    /* If all else is the same, prefer interfaces that
690
	     * have broadcast */
691
	    goodness = goodness * 2;
692
	    if(goodness >= lastGoodness) {
693
		/* Privilege broadcast-enabled interfaces */
694
		if(ioctl(s,  SIOCGIFBRDADDR, ifrp) < 0)
695
		    udpc_fatal(-1, "Error getting broadcast address for %s: %s",
696
			       ifrp->ifr_name, strerror(errno));
697
		if(getSinAddr(&ifrp->ifr_ifru.ifru_broadaddr).s_addr)
698
		    goodness++;
699
	    }
700
701
	    if(goodness > lastGoodness) {
702
		chosen = ifrp;
703
		lastGoodness = goodness;
704
		net_if->addr.s_addr = iaddr;
1 by Tomas Pospisek
Import upstream version 20040531
705
	    }
706
	}
707
708
709
	if(!chosen) {
710
	    fprintf(stderr, "No suitable network interface found\n");
711
	    fprintf(stderr, "The following interfaces are available:\n");
712
1.1.1 by Michael Schutte
Import upstream version 20100130
713
	    for (ifrp = (struct ifreq *) ifc.ifc_buf ; ifrp < ifend;
714
#ifdef IFREQ_SIZE
715
		 ifrp = IFREQ_SIZE(*ifrp) + (char *)ifrp
716
#else
717
		 ifrp++
718
#endif
719
		 ) {
1 by Tomas Pospisek
Import upstream version 20040531
720
		char buffer[16];
1.1.1 by Michael Schutte
Import upstream version 20100130
721
722
		if(ifrp->ifr_addr.sa_family != PF_INET)
723
		    continue;
724
1 by Tomas Pospisek
Import upstream version 20040531
725
		fprintf(stderr, "\t%s\t%s\n",
1.1.1 by Michael Schutte
Import upstream version 20100130
726
			ifrp->ifr_name,
727
			udpc_getIpString((struct sockaddr_in *)&ifrp->ifr_addr, buffer));
728
	    }
729
	    exit(1);
730
	}
731
732
	net_if->name = strdup(chosen->ifr_name);
733
734
#ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
735
	/* Index for multicast subscriptions */
736
	if(ioctl(s,  SIOCGIFINDEX, chosen) < 0)
737
	    udpc_fatal(-1, "Error getting index for %s: %s", net_if->name,
738
		       strerror(errno));
739
	net_if->index = chosen->ifr_ifindex;
740
#endif
741
742
	/* Broadcast */
743
	if(ioctl(s,  SIOCGIFBRDADDR, chosen) < 0)
744
	    udpc_fatal(-1, "Error getting broadcast address for %s: %s",
745
		       net_if->name, strerror(errno));
746
	net_if->bcast = getSinAddr(&chosen->ifr_ifru.ifru_broadaddr);
747
748
	close(s);
749
	free(ifc.ifc_buf);
750
751
#else /* __MINGW32__ */
752
753
	/* WINSOCK initialization */
754
	wVersionRequested = MAKEWORD(2, 0); /* Request Winsock v2.0 */
755
	if (WSAStartup(wVersionRequested, &wsaData) != 0) /* Load Winsock DLL */ {
756
	    fprintf(stderr,"WSAStartup() failed");
757
	    exit(1);
758
	}
759
	/* End WINSOCK initialization */
760
761
762
	a=0;
763
	r=GetIpAddrTable(iptab, &a, TRUE);
764
	iptab=malloc(a);
765
	r=GetIpAddrTable(iptab, &a, TRUE);
766
767
	a=0;
768
	r=GetIfTable(iftab, &a, TRUE);
769
	iftab=malloc(a);
770
	r=GetIfTable(iftab, &a, TRUE);
771
772
	if(wanted && !strncmp(wanted, "eth", 3) && wanted[3]) {
773
	    char *ptr;
774
	    int n = strtoul(wanted+3, &ptr, 10);
775
	    if(!*ptr)
776
		wantedEtherNo=n;
777
	}
778
779
	for(i=0; i<iptab->dwNumEntries; i++) {
780
	    int goodness=-1;
781
	    unsigned long iaddr;
782
	    int isEther=0;
783
	    MIB_IFROW *ifrow;
784
785
	    iprow = &iptab->table[i];
786
	    iaddr = iprow->dwAddr;
787
788
	    ifrow = getIfRow(iftab, iprow->dwIndex);
789
790
	    if(ifrow && ifrow->dwPhysAddrLen == 6 && iprow->dwBCastAddr) {
791
		isEther=1;
792
		etherNo++;
793
	    }
794
795
	    if(wanted) {
796
		if(isAddress && iaddr == wantedAddress.s_addr) {
797
		    goodness=8;
798
		} else if(isEther && wantedEtherNo == etherNo) {
799
			goodness=9;
800
		} else if(ifrow->dwPhysAddrLen) {
801
		    int j;
802
		    const char *ptr=wanted;
803
		    for(j=0; *ptr && j<ifrow->dwPhysAddrLen; j++) {
804
			int digit = strtoul(ptr, (char**)&ptr, 16);
805
			if(digit != ifrow->bPhysAddr[j])
806
			    break; /* Digit mismatch */
807
			if(*ptr == '-' || *ptr == ':') {
808
			    ptr++;
809
			}
810
		    }
811
		    if(!*ptr && j == ifrow->dwPhysAddrLen) {
812
			goodness=9;
813
		    }
814
		}
815
	    } else {
816
		if(iaddr == 0) {
817
		    /* disregard interfaces whose address is zero */
818
		    goodness = 1;
819
		} else if(iaddr == htonl(0x7f000001)) {
820
		    /* disregard localhost type devices */
821
		    goodness = 2;
822
		} else if(isEther) {
823
		    /* prefer ethernet */
824
		    goodness = 6;
825
		} else if(ifrow->dwPhysAddrLen) {
826
		    /* then prefer interfaces which have a physical address */
827
		    goodness = 4;
828
		} else {
829
		    goodness = 3;
830
		}
831
	    }
832
833
	    goodness = goodness * 2;
834
	    /* If all else is the same, prefer interfaces that
835
	     * have broadcast */
836
	    if(goodness >= lastGoodness) {
837
		/* Privilege broadcast-enabled interfaces */
838
		if(iprow->dwBCastAddr)
839
		    goodness++;
840
	    }
841
842
	    if(goodness > lastGoodness) {
843
		chosen = iprow;
844
		chosenIf = ifrow;
845
		lastGoodness = goodness;
846
	    }
847
	}
848
849
	if(!chosen) {
850
	    fprintf(stderr, "No suitable network interface found%s%s\n",
851
		    wanted ? " for " : "", wanted ? wanted : "");
852
	    fprintf(stderr, "The following interfaces are available:\n");
853
854
	    for(i=0; i<iptab->dwNumEntries; i++) {
855
		char buffer[16];
856
		struct sockaddr_in addr;
857
		MIB_IFROW *ifrow;
858
		char *name=NULL;
859
		iprow = &iptab->table[i];
860
		addr.sin_addr.s_addr = iprow->dwAddr;
861
		ifrow = getIfRow(iftab, iprow->dwIndex);
862
		name = fmtName(ifrow);
863
		fprintf(stderr, " %15s  %s\n",
864
			udpc_getIpString(&addr, buffer),
865
			name ? name : "");
866
		if(name)
867
		    free(name);
868
	    }
869
	    exit(1);
870
	}
871
872
	net_if->bcast.s_addr = net_if->addr.s_addr = chosen->dwAddr;
873
	if(chosen->dwBCastAddr)
874
	    net_if->bcast.s_addr |= ~chosen->dwMask;
875
	if(chosenIf) {
876
	    net_if->name = fmtName(chosenIf);
877
	} else {
878
	    net_if->name = "*";
879
	}
880
	free(iftab);
881
	free(iptab);
882
#endif /* __MINGW32__ */
883
884
	return net_if;
1 by Tomas Pospisek
Import upstream version 20040531
885
}
886
1.1.1 by Michael Schutte
Import upstream version 20100130
887
/**
888
 * @param addr_type
889
 *   UCAST - my unicast address attached to this device
890
 *   BCAST - my broadcast addres attached to this device
891
 *   MCAST - multicast address
892
 * @param ifname
893
 *   Interface name
894
 * @param mcast
895
 *   Multicast address (only used if type MCAST)
896
 * @param port
897
 *   Port to bind address to
898
 */
899
int makeSocket(addr_type_t addr_type,
900
	       net_if_t *net_if,
901
	       struct sockaddr_in *tmpl,
902
	       int port) {
1 by Tomas Pospisek
Import upstream version 20040531
903
    int ret, s;
1.1.1 by Michael Schutte
Import upstream version 20100130
904
    struct sockaddr_in myaddr;
905
    in_addr_t ip=0;
906
907
#ifdef WINDOWS
908
    static int lastSocket=-1;
909
    /* Very ugly hack, but hey!, this is for Windows */
910
911
    if(addr_type == ADDR_TYPE_MCAST) {
912
	mcastListen(lastSocket, net_if, tmpl);
913
	return -1;
914
    } else if(addr_type != ADDR_TYPE_UCAST)
915
	return -1;
916
#endif
1 by Tomas Pospisek
Import upstream version 20040531
917
918
    s = socket(PF_INET, SOCK_DGRAM, 0);
919
    if (s < 0) {
920
	perror("make socket");
921
	exit(1);
922
    }
923
1.1.1 by Michael Schutte
Import upstream version 20100130
924
    if(addr_type == ADDR_TYPE_MCAST && tmpl != NULL) {
925
	ip = tmpl->sin_addr.s_addr;
926
    }
927
928
    ret = initSockAddress(addr_type, net_if, ip, port, &myaddr);
929
    if(ret < 0)
930
	udpc_fatal(1, "Could not get socket address fot %d/%s",
931
		   addr_type, net_if->name);
932
    if(addr_type == ADDR_TYPE_BCAST && myaddr.sin_addr.s_addr == 0) {
933
      /* Attempting to bind to broadcast address on not-broadcast media ... */
934
      closesocket(s);
935
      return -1;
936
    }
1 by Tomas Pospisek
Import upstream version 20040531
937
    ret = bind(s, (struct sockaddr *) &myaddr, sizeof(myaddr));
938
    if (ret < 0) {
939
	char buffer[16];
940
	udpc_fatal(1, "bind socket to %s:%d (%s)\n",
1.1.1 by Michael Schutte
Import upstream version 20100130
941
		   udpc_getIpString(&myaddr, buffer),
1 by Tomas Pospisek
Import upstream version 20040531
942
		   udpc_getPort(&myaddr),
943
		   strerror(errno));
944
    }
945
1.1.1 by Michael Schutte
Import upstream version 20100130
946
    if(addr_type == ADDR_TYPE_MCAST)
947
	mcastListen(s, net_if, &myaddr);
948
#ifdef WINDOWS
949
    lastSocket=s;
950
#endif
1 by Tomas Pospisek
Import upstream version 20040531
951
    return s;
952
}
953
1.1.1 by Michael Schutte
Import upstream version 20100130
954
void printMyIp(net_if_t *net_if)
1 by Tomas Pospisek
Import upstream version 20040531
955
{
956
    char buffer[16];
1.1.1 by Michael Schutte
Import upstream version 20100130
957
    struct sockaddr_in myaddr;
1 by Tomas Pospisek
Import upstream version 20040531
958
1.1.1 by Michael Schutte
Import upstream version 20100130
959
    getMyAddress(net_if, &myaddr);
960
    udpc_flprintf("%s", udpc_getIpString(&myaddr,buffer));
1 by Tomas Pospisek
Import upstream version 20040531
961
}
962
1.1.1 by Michael Schutte
Import upstream version 20100130
963
char *udpc_getIpString(struct sockaddr_in *addr, char *buffer) {
964
    long iaddr = htonl(getSinAddr(addr).s_addr);
965
    sprintf(buffer,"%ld.%ld.%ld.%ld",
966
	    (iaddr >> 24) & 0xff,
967
	    (iaddr >> 16) & 0xff,
1 by Tomas Pospisek
Import upstream version 20040531
968
	    (iaddr >>  8) & 0xff,
1.1.1 by Michael Schutte
Import upstream version 20100130
969
	    iaddr & 0xff);
1 by Tomas Pospisek
Import upstream version 20040531
970
    return buffer;
971
}
972
1.1.1 by Michael Schutte
Import upstream version 20100130
973
int ipIsEqual(struct sockaddr_in *left, struct sockaddr_in *right) {
1 by Tomas Pospisek
Import upstream version 20040531
974
    return getSinAddr(left).s_addr == getSinAddr(right).s_addr;
975
}
976
1.1.1 by Michael Schutte
Import upstream version 20100130
977
int ipIsZero(struct sockaddr_in *ip) {
1 by Tomas Pospisek
Import upstream version 20040531
978
    return getSinAddr(ip).s_addr == 0;
979
}
980
1.1.1 by Michael Schutte
Import upstream version 20100130
981
unsigned short udpc_getPort(struct sockaddr_in *addr) {
1 by Tomas Pospisek
Import upstream version 20040531
982
    return ntohs(((struct sockaddr_in *) addr)->sin_port);
983
}
984
1.1.1 by Michael Schutte
Import upstream version 20100130
985
void setPort(struct sockaddr_in *addr, unsigned short port) {
1 by Tomas Pospisek
Import upstream version 20040531
986
    ((struct sockaddr_in *) addr)->sin_port = htons(port);
987
}
988
989
1.1.1 by Michael Schutte
Import upstream version 20100130
990
void clearIp(struct sockaddr_in *addr) {
991
    addr->sin_addr.s_addr = 0;
992
    addr->sin_family = AF_INET;
993
}
994
995
void setIpFromString(struct sockaddr_in *addr, char *ip) {
996
    safe_inet_aton(ip, &addr->sin_addr);
997
    addr->sin_family = AF_INET;
998
}
999
1000
void copyIpFrom(struct sockaddr_in *dst, struct sockaddr_in *src) {
1001
    dst->sin_addr = src->sin_addr;
1002
    dst->sin_family = src->sin_family;
1003
}
1004
1005
void getDefaultMcastAddress(net_if_t *net_if, struct sockaddr_in *mcast) {
1006
    getMyAddress(net_if, mcast);
1007
    mcast->sin_addr.s_addr &= htonl(0x07ffffff);
1008
    mcast->sin_addr.s_addr |= htonl(0xe8000000);
1009
}
1010
1011
1012
void copyToMessage(unsigned char *dst, struct sockaddr_in *src) {
1 by Tomas Pospisek
Import upstream version 20040531
1013
    memcpy(dst, (char *) &((struct sockaddr_in *)src)->sin_addr,
1014
	   sizeof(struct in_addr));
1015
}
1016
1017
1.1.1 by Michael Schutte
Import upstream version 20100130
1018
void copyFromMessage(struct sockaddr_in *dst, unsigned char *src) {
1019
    memcpy((char *) &dst->sin_addr, src, sizeof(struct in_addr));
1 by Tomas Pospisek
Import upstream version 20040531
1020
}
1021
1.1.1 by Michael Schutte
Import upstream version 20100130
1022
int isAddressEqual(struct sockaddr_in *a, struct sockaddr_in *b) {
1 by Tomas Pospisek
Import upstream version 20040531
1023
    return !memcmp((char *) a, (char *)b, 8);
1024
}
1025
1026
unsigned long parseSize(char *sizeString) {
1027
    char *eptr;
1028
    unsigned long size = strtoul(sizeString, &eptr, 10);
1029
    if(eptr && *eptr) {
1030
	switch(*eptr) {
1031
	    case 'm':
1032
	    case 'M':
1033
		size *= 1024 * 1024;
1034
		break;
1035
	    case 'k':
1036
	    case 'K':
1037
		size *= 1024;
1038
		break;
1039
	    case '\0':
1040
		break;
1041
	    default:
1042
		udpc_fatal(1, "Unit %c unsupported\n", *eptr);
1043
	}
1044
    }
1045
    return size;
1046
}
1047
1.1.1 by Michael Schutte
Import upstream version 20100130
1048
void zeroSockArray(int *socks, int nr) {
1049
    int i;
1050
1051
    for(i=0; i<nr; i++)
1052
	socks[i] = -1;
1053
}
1054
1055
int selectSock(int *socks, int nr, int startTimeout) {
1056
    fd_set read_set;
1057
    int r;
1058
    int maxFd;
1059
    struct timeval tv, *tvp;
1060
    if(startTimeout) {
1061
	tv.tv_sec = startTimeout;
1062
	tv.tv_usec = 0;
1063
	tvp = &tv;
1064
    } else {
1065
	tvp = NULL;
1066
    }
1067
    maxFd = prepareForSelect(socks, nr, &read_set);
1068
    r = select(maxFd+1, &read_set, NULL, NULL, tvp);
1069
    if(r < 0)
1070
	return r;
1071
    return getSelectedSock(socks, nr, &read_set);
1072
}
1073
1074
int prepareForSelect(int *socks, int nr, fd_set *read_set) {
1075
    int i;
1076
    int maxFd;
1077
    FD_ZERO(read_set);
1078
    maxFd=-1;
1079
    for(i=0; i<nr; i++) {
1080
	if(socks[i] == -1)
1081
	    continue;
1082
	FD_SET(socks[i], read_set);
1083
	if(socks[i] > maxFd)
1084
	    maxFd = socks[i];
1085
    }
1086
    return maxFd;
1087
}
1088
1089
int getSelectedSock(int *socks, int nr, fd_set *read_set) {
1090
    int i;
1091
    for(i=0; i<nr; i++) {
1092
	if(socks[i] == -1)
1093
	    continue;
1094
	if(FD_ISSET(socks[i], read_set))
1095
	    return socks[i];
1096
    }
1097
    return -1;
1098
}
1099
1100
void closeSock(int *socks, int nr, int target) {
1101
    int i;
1102
    int sock = socks[target];
1103
1104
    socks[target]=-1;
1105
    for(i=0; i<nr; i++)
1106
	if(socks[i] == sock)
1107
	    return;
1108
    closesocket(sock);
1109
}
1110
1111
int isMcastAddress(struct sockaddr_in *addr) {
1112
    int ip = ntohl(addr->sin_addr.s_addr) >> 24;
1113
    return ip >= 0xe0 && ip < 0xf0;
1114
}
1115
1116
1117
#ifdef __MINGW32__
1118
1119
static ssize_t getLength(const struct msghdr *msg) {
1120
    ssize_t size=0;
1121
    int i;
1122
1123
    for(i=0; i<msg->msg_iovlen; i++) {
1124
	size += msg->msg_iov[i].iov_len;
1125
    }
1126
    return size;
1127
}
1128
1129
static void doCopy(const struct msghdr *msg, char *ptr, int n, int dir) {
1130
    int i;
1131
    for(i=0; n >=0 && i<msg->msg_iovlen; i++) {
1132
	int l = msg->msg_iov[i].iov_len;
1133
	if(l > n)
1134
	    l = n;
1135
	if(dir) {
1136
	    memcpy(msg->msg_iov[i].iov_base, ptr, l);
1137
	} else {
1138
	    memcpy(ptr, msg->msg_iov[i].iov_base, l);
1 by Tomas Pospisek
Import upstream version 20040531
1139
	}
1.1.1 by Michael Schutte
Import upstream version 20100130
1140
	n   -= l;
1141
	ptr += l;
1142
    }
1143
}
1144
1145
ssize_t recvmsg(int s, struct msghdr *msg, int flags) {
1146
    ssize_t size=getLength(msg);
1147
    char *buffer = malloc(size);
1148
    int n; /* bytes left to copy */
1149
1150
    if(buffer == NULL) {
1151
	/* Out of memory */
1152
	errno = ENOMEM;
1153
	return -1;
1154
    }
1155
    n = recvfrom(s, buffer, size, flags,
1156
		 msg->msg_name, &msg->msg_namelen);
1157
    doCopy(msg, buffer, n, 1);
1158
    free(buffer);
1159
    return n;
1160
}
1161
1162
ssize_t sendmsg (int fd, const struct msghdr *msg, int flags) {
1163
    ssize_t size=getLength(msg);
1164
    char *buffer = malloc(size);
1165
    int n;
1166
1167
    if(buffer == NULL) {
1168
	/* Out of memory */
1169
	errno = ENOMEM;
1170
	return -1;
1171
    }
1172
    doCopy(msg, buffer, size, 0);
1173
    n = sendto(fd, buffer, size, flags,
1174
	       msg->msg_name, msg->msg_namelen);
1175
    free(buffer);
1176
    return n;
1177
}
1178
1179
1180
#endif /* __MINGW32__ */