int main(int argc, char *argv[]) { int sockfd; int pkt_size = 3000; int opt; int addr_family = AF_INET6; /* Default address family */ uint16_t dest_port = PORT; char *dest_ip; int len_send, len_recv; char buf_send[65535], buf_recv[65535]; /* Adding support for both IPv4 and IPv6 */ struct sockaddr_storage dest_addr; /* Can contain both sockaddr_in and sockaddr_in6 */ memset(&dest_addr, 0, sizeof(dest_addr)); while ((opt = getopt(argc, argv, "s:64v:p:")) != -1) { if (opt == 's') pkt_size = atoi(optarg); if (opt == '4') addr_family = AF_INET; if (opt == '6') addr_family = AF_INET6; if (opt == 'v') verbose = atoi(optarg); if (opt == 'p') dest_port = atoi(optarg); } if (optind >= argc) { fprintf(stderr, "Expected dest IP-address (IPv6 or IPv4) argument after options\n"); exit(2); } dest_ip = argv[optind]; if (verbose > 0) printf("Destination IP:%s port:%d\n", dest_ip, dest_port); sockfd = socket(addr_family, SOCK_DGRAM, 0); /* Socket options, see man-pages ip(7) and ipv6(7) */ //int set_pmtu_disc = IP_PMTUDISC_DO; /* do PMTU = Don't Fragment */ int set_pmtu_disc = IP_PMTUDISC_DONT; /* Allow fragments, dont do PMTU */ Setsockopt(sockfd, IPPROTO_IP, IP_MTU_DISCOVER, &set_pmtu_disc, sizeof(int)); Setsockopt(sockfd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &set_pmtu_disc, sizeof(int)); /* Setup dest_addr depending on IPv4 or IPv6 address */ setup_sockaddr(addr_family, &dest_addr, dest_ip, dest_port); /* Connect to recv ICMP error messages */ connect(sockfd, (struct sockaddr *)&dest_addr, sockaddr_len(&dest_addr)); len_send = send_packet(sockfd, &dest_addr, buf_send, pkt_size); len_recv = recv_packet(sockfd, &dest_addr, buf_recv, len_send); validate_packet(len_send, len_recv, buf_send, buf_recv); }
struct tr_peer_socket tr_netOpenPeerUTPSocket(tr_session* session, tr_address const* addr, tr_port port, bool clientIsSeed UNUSED) { struct tr_peer_socket ret = TR_PEER_SOCKET_INIT; if (tr_address_is_valid_for_peers(addr, port)) { struct sockaddr_storage ss; socklen_t const sslen = setup_sockaddr(addr, port, &ss); struct UTPSocket* const socket = UTP_Create(tr_utpSendTo, session, (struct sockaddr*)&ss, sslen); if (socket != NULL) { ret = tr_peer_socket_utp_create(socket); } } return ret; }
static tr_socket_t tr_netBindTCPImpl(tr_address const* addr, tr_port port, bool suppressMsgs, int* errOut) { TR_ASSERT(tr_address_is_valid(addr)); static int const domains[NUM_TR_AF_INET_TYPES] = { AF_INET, AF_INET6 }; struct sockaddr_storage sock; tr_socket_t fd; int addrlen; int optval; fd = socket(domains[addr->type], SOCK_STREAM, 0); if (fd == TR_BAD_SOCKET) { *errOut = sockerrno; return TR_BAD_SOCKET; } if (evutil_make_socket_nonblocking(fd) == -1) { *errOut = sockerrno; tr_netCloseSocket(fd); return TR_BAD_SOCKET; } optval = 1; setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void const*)&optval, sizeof(optval)); setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void const*)&optval, sizeof(optval)); #ifdef IPV6_V6ONLY if (addr->type == TR_AF_INET6) { if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (void const*)&optval, sizeof(optval)) == -1) { if (sockerrno != ENOPROTOOPT) /* if the kernel doesn't support it, ignore it */ { *errOut = sockerrno; tr_netCloseSocket(fd); return TR_BAD_SOCKET; } } } #endif addrlen = setup_sockaddr(addr, htons(port), &sock); if (bind(fd, (struct sockaddr*)&sock, addrlen) == -1) { int const err = sockerrno; if (!suppressMsgs) { char const* fmt; char const* hint; char err_buf[512]; if (err == EADDRINUSE) { hint = _("Is another copy of Transmission already running?"); } else { hint = NULL; } if (hint == NULL) { fmt = _("Couldn't bind port %d on %s: %s"); } else { fmt = _("Couldn't bind port %d on %s: %s (%s)"); } tr_logAddError(fmt, port, tr_address_to_string(addr), tr_net_strerror(err_buf, sizeof(err_buf), err), hint); } tr_netCloseSocket(fd); *errOut = err; return TR_BAD_SOCKET; } if (!suppressMsgs) { tr_logAddDebug("Bound socket %" PRIdMAX " to port %d on %s", (intmax_t)fd, port, tr_address_to_string(addr)); } #ifdef TCP_FASTOPEN #ifndef SOL_TCP #define SOL_TCP IPPROTO_TCP #endif optval = 5; setsockopt(fd, SOL_TCP, TCP_FASTOPEN, (void const*)&optval, sizeof(optval)); #endif if (listen(fd, 128) == -1) { *errOut = sockerrno; tr_netCloseSocket(fd); return TR_BAD_SOCKET; } return fd; }
struct tr_peer_socket tr_netOpenPeerSocket(tr_session* session, tr_address const* addr, tr_port port, bool clientIsSeed) { TR_ASSERT(tr_address_is_valid(addr)); struct tr_peer_socket ret = TR_PEER_SOCKET_INIT; static int const domains[NUM_TR_AF_INET_TYPES] = { AF_INET, AF_INET6 }; tr_socket_t s; struct sockaddr_storage sock; socklen_t addrlen; tr_address const* source_addr; socklen_t sourcelen; struct sockaddr_storage source_sock; char err_buf[512]; if (!tr_address_is_valid_for_peers(addr, port)) { return ret; } s = tr_fdSocketCreate(session, domains[addr->type], SOCK_STREAM); if (s == TR_BAD_SOCKET) { return ret; } /* seeds don't need much of a read buffer... */ if (clientIsSeed) { int n = 8192; if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, (void const*)&n, sizeof(n)) == -1) { tr_logAddInfo("Unable to set SO_RCVBUF on socket %" PRIdMAX ": %s", (intmax_t)s, tr_net_strerror(err_buf, sizeof(err_buf), sockerrno)); } } if (evutil_make_socket_nonblocking(s) == -1) { tr_netClose(session, s); return ret; } addrlen = setup_sockaddr(addr, port, &sock); /* set source address */ source_addr = tr_sessionGetPublicAddress(session, addr->type, NULL); TR_ASSERT(source_addr != NULL); sourcelen = setup_sockaddr(source_addr, 0, &source_sock); if (bind(s, (struct sockaddr*)&source_sock, sourcelen) == -1) { tr_logAddError(_("Couldn't set source address %s on %" PRIdMAX ": %s"), tr_address_to_string(source_addr), (intmax_t)s, tr_net_strerror(err_buf, sizeof(err_buf), sockerrno)); tr_netClose(session, s); return ret; } if (connect(s, (struct sockaddr*)&sock, addrlen) == -1 && #ifdef _WIN32 sockerrno != WSAEWOULDBLOCK && #endif sockerrno != EINPROGRESS) { int const tmperrno = sockerrno; if ((tmperrno != ENETUNREACH && tmperrno != EHOSTUNREACH) || addr->type == TR_AF_INET) { tr_logAddError(_("Couldn't connect socket %" PRIdMAX " to %s, port %d (errno %d - %s)"), (intmax_t)s, tr_address_to_string(addr), (int)ntohs(port), tmperrno, tr_net_strerror(err_buf, sizeof(err_buf), tmperrno)); } tr_netClose(session, s); } else { ret = tr_peer_socket_tcp_create(s); } tr_logAddDeep(__FILE__, __LINE__, NULL, "New OUTGOING connection %" PRIdMAX " (%s)", (intmax_t)s, tr_peerIoAddrStr(addr, port)); return ret; }
static void parse_opts(int argc, char **argv) { int max_len, hdrlen; int c; while ((c = getopt(argc, argv, "46cC:D:l:mM:p:s:S:tuz")) != -1) { switch (c) { case '4': if (cfg_family != PF_UNSPEC) error(1, 0, "Pass one of -4 or -6"); cfg_family = PF_INET; cfg_alen = sizeof(struct sockaddr_in); break; case '6': if (cfg_family != PF_UNSPEC) error(1, 0, "Pass one of -4 or -6"); cfg_family = PF_INET6; cfg_alen = sizeof(struct sockaddr_in6); break; case 'c': cfg_cache_trash = true; break; case 'C': cfg_cpu = strtol(optarg, NULL, 0); break; case 'D': setup_sockaddr(cfg_family, optarg, &cfg_dst_addr); break; case 'l': cfg_runtime_ms = strtoul(optarg, NULL, 10) * 1000; break; case 'm': cfg_sendmmsg = true; break; case 'M': cfg_msg_nr = strtoul(optarg, NULL, 10); break; case 'p': cfg_port = strtoul(optarg, NULL, 0); break; case 's': cfg_payload_len = strtoul(optarg, NULL, 0); break; case 'S': cfg_gso_size = strtoul(optarg, NULL, 0); cfg_segment = true; break; case 't': cfg_tcp = true; break; case 'u': cfg_connected = false; break; case 'z': cfg_zerocopy = true; break; } } if (optind != argc) usage(argv[0]); if (cfg_family == PF_UNSPEC) error(1, 0, "must pass one of -4 or -6"); if (cfg_tcp && !cfg_connected) error(1, 0, "connectionless tcp makes no sense"); if (cfg_segment && cfg_sendmmsg) error(1, 0, "cannot combine segment offload and sendmmsg"); if (cfg_family == PF_INET) hdrlen = sizeof(struct iphdr) + sizeof(struct udphdr); else hdrlen = sizeof(struct ip6_hdr) + sizeof(struct udphdr); cfg_mss = ETH_DATA_LEN - hdrlen; max_len = ETH_MAX_MTU - hdrlen; if (!cfg_gso_size) cfg_gso_size = cfg_mss; if (cfg_payload_len > max_len) error(1, 0, "payload length %u exceeds max %u", cfg_payload_len, max_len); }