void tr_udpUninit (tr_session *ss) { tr_dhtUninit (ss); if (ss->udp_socket >= 0) { tr_netCloseSocket (ss->udp_socket); ss->udp_socket = -1; } if (ss->udp_event) { event_free (ss->udp_event); ss->udp_event = NULL; } if (ss->udp6_socket >= 0) { tr_netCloseSocket (ss->udp6_socket); ss->udp6_socket = -1; } if (ss->udp6_event) { event_free (ss->udp6_event); ss->udp6_event = NULL; } if (ss->udp6_bound) { free (ss->udp6_bound); ss->udp6_bound = NULL; } }
bool tr_net_hasIPv6(tr_port port) { static bool result = false; static bool alreadyDone = false; if (!alreadyDone) { int err; tr_socket_t fd = tr_netBindTCPImpl(&tr_in6addr_any, port, true, &err); if (fd != TR_BAD_SOCKET || err != EAFNOSUPPORT) /* we support ipv6 */ { result = true; } if (fd != TR_BAD_SOCKET) { tr_netCloseSocket(fd); } alreadyDone = true; } return result; }
void tr_eventClose (tr_session * session) { assert (tr_isSession (session)); session->events->die = true; tr_logAddDeep (__FILE__, __LINE__, NULL, "closing trevent pipe"); tr_netCloseSocket (session->events->fds[1]); }
int tr_fdSocketAccept( tr_session * session, int b, tr_address * addr, tr_port * port ) { int s; unsigned int len; struct tr_fdInfo * gFd; struct sockaddr_storage sock; assert( tr_isSession( session ) ); assert( session->fdInfo != NULL ); assert( addr ); assert( port ); gFd = session->fdInfo; len = sizeof( struct sockaddr_storage ); s = accept( b, (struct sockaddr *) &sock, &len ); if( ( s >= 0 ) && gFd->socketCount > gFd->socketLimit ) { tr_netCloseSocket( s ); s = -1; } if( s >= 0 ) { /* "The ss_family field of the sockaddr_storage structure will always * align with the family field of any protocol-specific structure." */ if( sock.ss_family == AF_INET ) { struct sockaddr_in *si; union { struct sockaddr_storage dummy; struct sockaddr_in si; } s; s.dummy = sock; si = &s.si; addr->type = TR_AF_INET; addr->addr.addr4.s_addr = si->sin_addr.s_addr; *port = si->sin_port; } else { struct sockaddr_in6 *si; union { struct sockaddr_storage dummy; struct sockaddr_in6 si; } s; s.dummy = sock; si = &s.si; addr->type = TR_AF_INET6; addr->addr.addr6 = si->sin6_addr; *port = si->sin6_port; } ++gFd->socketCount; } return s; }
void tr_natpmpClose( tr_natpmp * nat ) { if( nat ) { if( nat->natpmp.s >= 0 ) tr_netCloseSocket( nat->natpmp.s ); tr_free( nat ); } }
static void readFromPipe (evutil_socket_t fd, short eventType, void * veh) { char ch; int ret; tr_event_handle * eh = veh; dbgmsg ("readFromPipe: eventType is %hd", eventType); /* read the command type */ ch = '\0'; do { ret = piperead (fd, &ch, 1); } while (!eh->die && ret < 0 && errno == EAGAIN); dbgmsg ("command is [%c], ret is %d, errno is %d", ch, ret, (int)errno); switch (ch) { case 'r': /* run in libevent thread */ { struct tr_run_data data; const size_t nwant = sizeof (data); const ev_ssize_t ngot = piperead (fd, &data, nwant); if (!eh->die && (ngot == (ev_ssize_t) nwant)) { dbgmsg ("invoking function in libevent thread"); (data.func)(data.user_data); } break; } case '\0': /* eof */ { dbgmsg ("pipe eof reached... removing event listener"); event_free (eh->pipeEvent); tr_netCloseSocket (eh->fds[0]); event_base_loopexit (eh->base, NULL); break; } default: { assert (0 && "unhandled command type!"); break; } } }
void tr_fdSocketClose( tr_session * session, int fd ) { assert( tr_isSession( session ) ); if( session->fdInfo != NULL ) { struct tr_fdInfo * gFd = session->fdInfo; if( fd >= 0 ) { tr_netCloseSocket( fd ); --gFd->socketCount; } assert( gFd->socketCount >= 0 ); } }
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; }
void tr_dhtUninit(tr_session *ss) { if(session != ss) return; tr_ndbg( "DHT", "Uninitializing DHT" ); event_free( dht_event ); dht_event = NULL; if( dht6_event ) { event_free( dht6_event ); dht6_event = NULL; } /* Since we only save known good nodes, avoid erasing older data if we don't know enough nodes. */ if(tr_dhtStatus(ss, AF_INET, NULL) < TR_DHT_FIREWALLED) tr_ninf( "DHT", "Not saving nodes, DHT not ready" ); else { tr_benc benc; struct sockaddr_in sins[300]; struct sockaddr_in6 sins6[300]; char compact[300 * 6], compact6[300 * 18]; char *dat_file; int i, j, num = 300, num6 = 300; int n = dht_get_nodes(sins, &num, sins6, &num6); tr_ninf( "DHT", "Saving %d (%d + %d) nodes", n, num, num6 ); j = 0; for( i=0; i<num; ++i ) { memcpy( compact + j, &sins[i].sin_addr, 4 ); memcpy( compact + j + 4, &sins[i].sin_port, 2 ); j += 6; } j = 0; for( i=0; i<num6; ++i ) { memcpy( compact6 + j, &sins6[i].sin6_addr, 16 ); memcpy( compact6 + j + 16, &sins6[i].sin6_port, 2 ); j += 18; } tr_bencInitDict( &benc, 3 ); tr_bencDictAddRaw( &benc, "id", myid, 20 ); if(num > 0) tr_bencDictAddRaw( &benc, "nodes", compact, num * 6 ); if(num6 > 0) tr_bencDictAddRaw( &benc, "nodes6", compact6, num6 * 18 ); dat_file = tr_buildPath( ss->configDir, "dht.dat", NULL ); tr_bencToFile( &benc, TR_FMT_BENC, dat_file ); tr_bencFree( &benc ); tr_free( dat_file ); } dht_uninit( 1 ); tr_netCloseSocket( dht_socket ); dht_socket = -1; if(dht6_socket > 0) { tr_netCloseSocket( dht6_socket ); dht6_socket = -1; } tr_ndbg("DHT", "Done uninitializing DHT"); session = NULL; }