/** * @param addr_type * UCAST - my unicast address attached to this device * BCAST - my broadcast addres attached to this device * MCAST - multicast address * @param ifname * Interface name * @param mcast * Multicast address (only used if type MCAST) * @param port * Port to bind address to */ int makeSocket(addr_type_t addr_type, net_if_t *net_if, struct sockaddr_in *tmpl, int port) { int ret, s; struct sockaddr_in myaddr; in_addr_t ip=0; #ifdef WINDOWS static int lastSocket=-1; /* Very ugly hack, but hey!, this is for Windows */ if(addr_type == ADDR_TYPE_MCAST) { mcastListen(lastSocket, net_if, tmpl); return -1; } else if(addr_type != ADDR_TYPE_UCAST) return -1; #endif s = socket(PF_INET, SOCK_DGRAM, 0); if (s < 0) { perror("make socket"); exit(1); } if(addr_type == ADDR_TYPE_MCAST && tmpl != NULL) { ip = tmpl->sin_addr.s_addr; } ret = initSockAddress(addr_type, net_if, ip, port, &myaddr); if(ret < 0) udpc_fatal(1, "Could not get socket address fot %d/%s", addr_type, net_if->name); if(addr_type == ADDR_TYPE_BCAST && myaddr.sin_addr.s_addr == 0) { /* Attempting to bind to broadcast address on not-broadcast media ... */ closesocket(s); return -1; } ret = bind(s, (struct sockaddr *) &myaddr, sizeof(myaddr)); if (ret < 0) { char buffer[16]; udpc_fatal(1, "bind socket to %s:%d (%s)\n", udpc_getIpString(&myaddr, buffer), udpc_getPort(&myaddr), strerror(errno)); } if(addr_type == ADDR_TYPE_MCAST) mcastListen(s, net_if, &myaddr); #ifdef WINDOWS lastSocket=s; #endif return s; }
static int initSockAddress(addr_type_t addr_type, net_if_t *net_if, in_addr_t ip, unsigned short port, struct sockaddr_in *addr) { memset ((char *) addr, 0, sizeof(struct sockaddr_in)); addr->sin_family = AF_INET; addr->sin_port = htons(port); if(!net_if && addr_type != ADDR_TYPE_MCAST) udpc_fatal(1, "initSockAddr without ifname\n"); switch(addr_type) { case ADDR_TYPE_UCAST: addr->sin_addr = net_if->addr; break; case ADDR_TYPE_BCAST: addr->sin_addr = net_if->bcast; break; case ADDR_TYPE_MCAST: addr->sin_addr.s_addr = ip; break; } return 0; }
static int openOutFile(struct disk_config *disk_config) { int outFile=1; if(disk_config->fileName != NULL) { int oflags = O_CREAT | O_WRONLY | O_TRUNC; if((disk_config->flags & FLAG_SYNC)) { oflags |= O_SYNC; } else if( !(disk_config->flags & FLAG_NOSYNC)) { struct stat buf; if(stat(disk_config->fileName, &buf) == 0) { /* If target is device, open it synchronously */ if(S_ISCHR(buf.st_mode) || S_ISBLK(buf.st_mode)) oflags |= O_SYNC; } } outFile = open(disk_config->fileName, oflags | O_BINARY, 0644); if(outFile < 0) { #ifdef NO_BB #ifndef errno extern int errno; #endif #endif udpc_fatal(1, "open outfile %s: %s\n", disk_config->fileName, strerror(errno)); } } else { #ifdef __MINGW32__ _setmode(1, O_BINARY); #endif } return outFile; }
static int sendRawData(int sock, struct net_config *config, char *header, int headerSize, unsigned char *data, int dataSize) { struct iovec iov[2]; struct msghdr hdr; int packetSize; int ret; iov[0].iov_base = header; iov[0].iov_len = headerSize; iov[1].iov_base = data; iov[1].iov_len = dataSize; hdr.msg_name = &config->dataMcastAddr; hdr.msg_namelen = sizeof(struct sockaddr_in); hdr.msg_iov = iov; hdr.msg_iovlen = 2; initMsgHdr(&hdr); packetSize = dataSize + headerSize; rgWaitAll(config, sock, config->dataMcastAddr.sin_addr.s_addr, packetSize); ret = sendmsg(sock, &hdr, 0); if (ret < 0) { char ipBuffer[16]; udpc_fatal(1, "Could not broadcast data packet to %s:%d (%s)\n", getIpString(&config->dataMcastAddr, ipBuffer), getPort(&config->dataMcastAddr), strerror(errno)); } return 0; }
unsigned long parseSize(char *sizeString) { char *eptr; unsigned long size = strtoul(sizeString, &eptr, 10); if(eptr && *eptr) { switch(*eptr) { case 'm': case 'M': size *= 1024 * 1024; break; case 'k': case 'K': size *= 1024; break; case '\0': break; default: udpc_fatal(1, "Unit %c unsupported\n", *eptr); } } return size; }
static int sendRawData(int sock, struct net_config *config, char *header, int headerSize, unsigned char *data, int dataSize) { struct iovec iov[2]; struct msghdr hdr; int packetSize; int ret; iov[0].iov_base = header; iov[0].iov_len = headerSize; iov[1].iov_base = data; iov[1].iov_len = dataSize; hdr.msg_name = &config->dataMcastAddr; hdr.msg_namelen = sizeof(struct sockaddr_in); hdr.msg_iov = iov; hdr.msg_iovlen = 2; initMsgHdr(&hdr); packetSize = dataSize + headerSize; doRateLimit(config->rateLimit, packetSize); #ifdef FLAG_AUTORATE if(config->flags & FLAG_AUTORATE) doAutoRateLimit(sock, config->dir, config->sendbuf, packetSize); #endif ret = sendmsg(sock, &hdr, 0); if (ret < 0) { char ipBuffer[16]; udpc_fatal(1, "Could not broadcast data packet to %s:%d (%s)\n", getIpString(&config->dataMcastAddr, ipBuffer), getPort(&config->dataMcastAddr), strerror(errno)); } return 0; }
/* makes a socket address */ int makeSockAddr(char *hostname, short port, struct sockaddr_in *addr) { struct hostent *host; memset ((char *) addr, 0, sizeof(struct sockaddr_in)); if (hostname && *hostname) { char *inaddr; int len; host = gethostbyname(hostname); if (host == NULL) { udpc_fatal(1, "Unknown host %s\n", hostname); } inaddr = host->h_addr_list[0]; len = host->h_length; memcpy((void *)&((struct sockaddr_in *)addr)->sin_addr, inaddr, len); } ((struct sockaddr_in *)addr)->sin_family = AF_INET; ((struct sockaddr_in *)addr)->sin_port = htons(port); return 0; }
static void intHandler(int nr) { signalNumber=nr; udpc_fatal(1, "Signal %d: Cancelled by user\n", nr); }
/** * Canonize interface name. If attempt is not NULL, pick the interface * which has that address. * If attempt is NULL, pick interfaces in the following order of preference * 1. eth0 * 2. Anything starting with eth0: * 3. Anything starting with eth * 4. Anything else * 5. localhost * 6. zero address */ net_if_t *getNetIf(const char *wanted) { #ifndef __MINGW32__ struct ifreq *ifrp, *ifend, *chosen; struct ifconf ifc; int s; #else /* __MINGW32__ */ int i; int etherNo=-1; int wantedEtherNo=-2; /* Wanted ethernet interface */ MIB_IPADDRTABLE *iptab=NULL; MIB_IFTABLE *iftab=NULL; MIB_IPADDRROW *iprow, *chosen=NULL; MIB_IFROW *chosenIf=NULL; WORD wVersionRequested; /* Version of Winsock to load */ WSADATA wsaData; /* Winsock implementation details */ ULONG a; int r; #endif /* __MINGW32__ */ int lastGoodness=0; struct in_addr wantedAddress; int isAddress=0; int wantedLen=0; net_if_t *net_if; if(wanted == NULL) { wanted = getenv("IFNAME"); } if(wanted && INET_ATON(wanted, &wantedAddress)) isAddress=1; else wantedAddress.s_addr=0; if(wanted) wantedLen=strlen(wanted); net_if = MALLOC(net_if_t); if(net_if == NULL) udpc_fatal(1, "Out of memory error"); #ifndef __MINGW32__ s = socket(PF_INET, SOCK_DGRAM, 0); if (s < 0) { perror("make socket"); exit(1); } ifc.ifc_len = sizeof(struct ifreq) * 10; while(1) { size_t len = ifc.ifc_len; ifc.ifc_buf = (caddr_t) malloc(ifc.ifc_len); if(ifc.ifc_buf == NULL) { udpc_fatal(1, "Out of memory error"); } if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0 || ifc.ifc_len < (signed int)sizeof(struct ifreq)) { perror("udpcast: SIOCGIFCONF: "); exit(1); } if(len == ifc.ifc_len) { ifc.ifc_len += sizeof(struct ifreq) * 10; free(ifc.ifc_buf); } else break; } ifend = (struct ifreq *)((char *)ifc.ifc_buf + ifc.ifc_len); chosen=NULL; for (ifrp = (struct ifreq *) ifc.ifc_buf ; ifrp < ifend; #ifdef IFREQ_SIZE ifrp = IFREQ_SIZE(*ifrp) + (char *)ifrp #else ifrp++ #endif ) { unsigned long iaddr = getSinAddr(&ifrp->ifr_addr).s_addr; int goodness; if(ifrp->ifr_addr.sa_family != PF_INET) continue; if(wanted) { if(isAddress && iaddr == wantedAddress.s_addr) { goodness=8; } else if(strcmp(wanted, ifrp->ifr_name) ==0) { /* perfect match on interface name */ goodness=12; } else if(wanted != NULL && strncmp(wanted, ifrp->ifr_name, wantedLen) ==0) { /* prefix match on interface name */ goodness=7; } else { /* no match, try next */ continue; } } else { if(iaddr == 0) { /* disregard interfaces whose address is zero */ goodness = 1; } else if(iaddr == htonl(0x7f000001)) { /* disregard localhost type devices */ goodness = 2; } else if(strcmp("eth0", ifrp->ifr_name) == 0 || strcmp("en0", ifrp->ifr_name) == 0) { /* prefer first ethernet interface */ goodness = 6; } else if(strncmp("eth0:", ifrp->ifr_name, 5) == 0) { /* second choice: any secondary addresses of first ethernet */ goodness = 5; } else if(strncmp("eth", ifrp->ifr_name, 3) == 0 || strncmp("en", ifrp->ifr_name, 2) == 0) { /* and, if not available, any other ethernet device */ goodness = 4; } else { goodness = 3; } } if(hasLink(s, ifrp->ifr_name)) /* Good or unknown link status privileged over known * disconnected */ goodness += 3; /* If all else is the same, prefer interfaces that * have broadcast */ goodness = goodness * 2; if(goodness >= lastGoodness) { /* Privilege broadcast-enabled interfaces */ if(ioctl(s, SIOCGIFBRDADDR, ifrp) < 0) udpc_fatal(-1, "Error getting broadcast address for %s: %s", ifrp->ifr_name, strerror(errno)); if(getSinAddr(&ifrp->ifr_ifru.ifru_broadaddr).s_addr) goodness++; } if(goodness > lastGoodness) { chosen = ifrp; lastGoodness = goodness; net_if->addr.s_addr = iaddr; } } if(!chosen) { fprintf(stderr, "No suitable network interface found\n"); fprintf(stderr, "The following interfaces are available:\n"); for (ifrp = (struct ifreq *) ifc.ifc_buf ; ifrp < ifend; #ifdef IFREQ_SIZE ifrp = IFREQ_SIZE(*ifrp) + (char *)ifrp #else ifrp++ #endif ) { char buffer[16]; if(ifrp->ifr_addr.sa_family != PF_INET) continue; fprintf(stderr, "\t%s\t%s\n", ifrp->ifr_name, udpc_getIpString((struct sockaddr_in *)&ifrp->ifr_addr, buffer)); } exit(1); } net_if->name = strdup(chosen->ifr_name); #ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX /* Index for multicast subscriptions */ if(ioctl(s, SIOCGIFINDEX, chosen) < 0) udpc_fatal(-1, "Error getting index for %s: %s", net_if->name, strerror(errno)); net_if->index = chosen->ifr_ifindex; #endif /* Broadcast */ if(ioctl(s, SIOCGIFBRDADDR, chosen) < 0) udpc_fatal(-1, "Error getting broadcast address for %s: %s", net_if->name, strerror(errno)); net_if->bcast = getSinAddr(&chosen->ifr_ifru.ifru_broadaddr); close(s); free(ifc.ifc_buf); #else /* __MINGW32__ */ /* WINSOCK initialization */ wVersionRequested = MAKEWORD(2, 0); /* Request Winsock v2.0 */ if (WSAStartup(wVersionRequested, &wsaData) != 0) /* Load Winsock DLL */ { fprintf(stderr,"WSAStartup() failed"); exit(1); } /* End WINSOCK initialization */ a=0; r=GetIpAddrTable(iptab, &a, TRUE); iptab=malloc(a); r=GetIpAddrTable(iptab, &a, TRUE); a=0; r=GetIfTable(iftab, &a, TRUE); iftab=malloc(a); r=GetIfTable(iftab, &a, TRUE); if(wanted && !strncmp(wanted, "eth", 3) && wanted[3]) { char *ptr; int n = strtoul(wanted+3, &ptr, 10); if(!*ptr) wantedEtherNo=n; } for(i=0; i<iptab->dwNumEntries; i++) { int goodness=-1; unsigned long iaddr; int isEther=0; MIB_IFROW *ifrow; iprow = &iptab->table[i]; iaddr = iprow->dwAddr; ifrow = getIfRow(iftab, iprow->dwIndex); if(ifrow && ifrow->dwPhysAddrLen == 6 && iprow->dwBCastAddr) { isEther=1; etherNo++; } if(wanted) { if(isAddress && iaddr == wantedAddress.s_addr) { goodness=8; } else if(isEther && wantedEtherNo == etherNo) { goodness=9; } else if(ifrow->dwPhysAddrLen) { int j; const char *ptr=wanted; for(j=0; *ptr && j<ifrow->dwPhysAddrLen; j++) { int digit = strtoul(ptr, (char**)&ptr, 16); if(digit != ifrow->bPhysAddr[j]) break; /* Digit mismatch */ if(*ptr == '-' || *ptr == ':') { ptr++; } } if(!*ptr && j == ifrow->dwPhysAddrLen) { goodness=9; } } } else { if(iaddr == 0) { /* disregard interfaces whose address is zero */ goodness = 1; } else if(iaddr == htonl(0x7f000001)) { /* disregard localhost type devices */ goodness = 2; } else if(isEther) { /* prefer ethernet */ goodness = 6; } else if(ifrow->dwPhysAddrLen) { /* then prefer interfaces which have a physical address */ goodness = 4; } else { goodness = 3; } } goodness = goodness * 2; /* If all else is the same, prefer interfaces that * have broadcast */ if(goodness >= lastGoodness) { /* Privilege broadcast-enabled interfaces */ if(iprow->dwBCastAddr) goodness++; } if(goodness > lastGoodness) { chosen = iprow; chosenIf = ifrow; lastGoodness = goodness; } } if(!chosen) { fprintf(stderr, "No suitable network interface found%s%s\n", wanted ? " for " : "", wanted ? wanted : ""); fprintf(stderr, "The following interfaces are available:\n"); for(i=0; i<iptab->dwNumEntries; i++) { char buffer[16]; struct sockaddr_in addr; MIB_IFROW *ifrow; char *name=NULL; iprow = &iptab->table[i]; addr.sin_addr.s_addr = iprow->dwAddr; ifrow = getIfRow(iftab, iprow->dwIndex); name = fmtName(ifrow); fprintf(stderr, " %15s %s\n", udpc_getIpString(&addr, buffer), name ? name : ""); if(name) free(name); } exit(1); } net_if->bcast.s_addr = net_if->addr.s_addr = chosen->dwAddr; if(chosen->dwBCastAddr) net_if->bcast.s_addr |= ~chosen->dwMask; if(chosenIf) { net_if->name = fmtName(chosenIf); } else { net_if->name = "*"; } free(iftab); free(iptab); #endif /* __MINGW32__ */ return net_if; }
static int safe_inet_aton(const char *address, struct in_addr *ip) { if(!INET_ATON(address, ip)) udpc_fatal(-1, "Bad address %s", address); return 0; }
int startReceiver(int doWarn, struct disk_config *disk_config, struct net_config *net_config, struct stat_config *stat_config, const char *ifName) { char ipBuffer[16]; union serverControlMsg Msg; int connectReqSent=0; struct client_config client_config; int outFile=1; int pipedOutFile; struct sockaddr_in myIp; int pipePid = 0; int origOutFile; int haveServerAddress; client_config.sender_is_newgen = 0; net_config->net_if = getNetIf(ifName); zeroSockArray(client_config.socks, NR_CLIENT_SOCKS); client_config.S_UCAST = makeSocket(ADDR_TYPE_UCAST, net_config->net_if, 0, RECEIVER_PORT(net_config->portBase)); client_config.S_BCAST = makeSocket(ADDR_TYPE_BCAST, net_config->net_if, 0, RECEIVER_PORT(net_config->portBase)); if(net_config->ttl == 1 && net_config->mcastRdv == NULL) { getBroadCastAddress(net_config->net_if, &net_config->controlMcastAddr, SENDER_PORT(net_config->portBase)); setSocketToBroadcast(client_config.S_UCAST); } else { getMcastAllAddress(&net_config->controlMcastAddr, net_config->mcastRdv, SENDER_PORT(net_config->portBase)); if(isMcastAddress(&net_config->controlMcastAddr)) { setMcastDestination(client_config.S_UCAST, net_config->net_if, &net_config->controlMcastAddr); setTtl(client_config.S_UCAST, net_config->ttl); client_config.S_MCAST_CTRL = makeSocket(ADDR_TYPE_MCAST, net_config->net_if, &net_config->controlMcastAddr, RECEIVER_PORT(net_config->portBase)); // TODO: subscribe address as receiver to! } } clearIp(&net_config->dataMcastAddr); udpc_flprintf("%sUDP receiver for %s at ", disk_config->pipeName == NULL ? "" : "Compressed ", disk_config->fileName == NULL ? "(stdout)":disk_config->fileName); printMyIp(net_config->net_if); udpc_flprintf(" on %s\n", net_config->net_if->name); connectReqSent = 0; haveServerAddress = 0; client_config.clientNumber= 0; /*default number for asynchronous transfer*/ while(1) { // int len; int msglen; int sock; if (!connectReqSent) { if (sendConnectReq(&client_config, net_config, haveServerAddress) < 0) { perror("sendto to locate server"); } connectReqSent = 1; } haveServerAddress=0; sock = udpc_selectSock(client_config.socks, NR_CLIENT_SOCKS, net_config->startTimeout); if(sock < 0) { return -1; } // len = sizeof(server); msglen=RECV(sock, Msg, client_config.serverAddr, net_config->portBase); if (msglen < 0) { perror("recvfrom to locate server"); exit(1); } if(getPort(&client_config.serverAddr) != SENDER_PORT(net_config->portBase)) /* not from the right port */ continue; switch(ntohs(Msg.opCode)) { case CMD_CONNECT_REPLY: client_config.clientNumber = ntohl(Msg.connectReply.clNr); net_config->blockSize = ntohl(Msg.connectReply.blockSize); udpc_flprintf("received message, cap=%08lx\n", (long) ntohl(Msg.connectReply.capabilities)); if(ntohl(Msg.connectReply.capabilities) & CAP_NEW_GEN) { client_config.sender_is_newgen = 1; copyFromMessage(&net_config->dataMcastAddr, Msg.connectReply.mcastAddr); } if (client_config.clientNumber == -1) { udpc_fatal(1, "Too many clients already connected\n"); } goto break_loop; case CMD_HELLO_STREAMING: case CMD_HELLO_NEW: case CMD_HELLO: connectReqSent = 0; if(ntohs(Msg.opCode) == CMD_HELLO_STREAMING) net_config->flags |= FLAG_STREAMING; if(ntohl(Msg.hello.capabilities) & CAP_NEW_GEN) { client_config.sender_is_newgen = 1; copyFromMessage(&net_config->dataMcastAddr, Msg.hello.mcastAddr); net_config->blockSize = ntohs(Msg.hello.blockSize); if(ntohl(Msg.hello.capabilities) & CAP_ASYNC) net_config->flags |= FLAG_PASSIVE; if(net_config->flags & FLAG_PASSIVE) goto break_loop; } haveServerAddress=1; continue; case CMD_CONNECT_REQ: case CMD_DATA: case CMD_FEC: continue; default: break; } udpc_fatal(1, "Bad server reply %04x. Other transfer in progress?\n", (unsigned short) ntohs(Msg.opCode)); } break_loop: udpc_flprintf("Connected as #%d to %s\n", client_config.clientNumber, getIpString(&client_config.serverAddr, ipBuffer)); getMyAddress(net_config->net_if, &myIp); if(!ipIsZero(&net_config->dataMcastAddr) && !ipIsEqual(&net_config->dataMcastAddr, &myIp) && (ipIsZero(&net_config->controlMcastAddr) || !ipIsEqual(&net_config->dataMcastAddr, &net_config->controlMcastAddr) )) { udpc_flprintf("Listening to multicast on %s\n", getIpString(&net_config->dataMcastAddr, ipBuffer)); client_config.S_MCAST_DATA = makeSocket(ADDR_TYPE_MCAST, net_config->net_if, &net_config->dataMcastAddr, RECEIVER_PORT(net_config->portBase)); } if(net_config->requestedBufSize) { int i; for(i=0; i<NR_CLIENT_SOCKS; i++) if(client_config.socks[i] != -1) setRcvBuf(client_config.socks[i],net_config->requestedBufSize); } outFile=openOutFile(disk_config); origOutFile = outFile; pipedOutFile = openPipe(outFile, disk_config, &pipePid); global_client_config= &client_config; atexit(sendDisconnectWrapper); { struct fifo fifo; int printUncompressedPos = udpc_shouldPrintUncompressedPos(stat_config->printUncompressedPos, origOutFile, pipedOutFile); receiver_stats_t stats = allocReadStats(origOutFile, stat_config->statPeriod, printUncompressedPos); udpc_initFifo(&fifo, net_config->blockSize); fifo.data = pc_makeProduconsum(fifo.dataBufSize, "receive"); client_config.isStarted = 0; if((net_config->flags & (FLAG_PASSIVE|FLAG_NOKBD))) { /* No console used */ client_config.console = NULL; } else { if(doWarn) udpc_flprintf("WARNING: This will overwrite the hard disk of this machine\n"); client_config.console = prepareConsole(0); atexit(fixConsole); } spawnNetReceiver(&fifo,&client_config, net_config, stats); writer(&fifo, pipedOutFile); if(pipePid) { close(pipedOutFile); } pthread_join(client_config.thread, NULL); /* if we have a pipe, now wait for that too */ if(pipePid) { udpc_waitForProcess(pipePid, "Pipe"); } #ifndef __MINGW32__ fsync(origOutFile); #endif /* __MINGW32__ */ displayReceiverStats(stats, 1); } fixConsole(); sendDisconnectWrapper(); global_client_config= NULL; return 0; }