+
+ // reuse the address, so we can run if a former server was killed off
+ if (inSettings->mThreadMode == kMode_Listener) {
+ val = 1;
+ rc = setsockopt(inSettings->mSock, SOL_SOCKET, SO_REUSEADDR, &val, len);
+ WARN_errno( rc == SOCKET_ERROR, "setsockopt SO_REUSEADDR" );
+ }
+}
+
+void MakeSocket(thread_Settings *inSettings)
+{
+ struct addrinfo *local = NULL, *src,
+ *remote = NULL, *dst, hints;
+ char port[6];
+ int rc, socktype = sockType(inSettings->mProtocol);
+
+ assert(inSettings->mLocalhost || inSettings->mHost);
+
+ memset(&inSettings->local, 0, sizeof(inSettings->local));
+ memset(&inSettings->peer, 0, sizeof(inSettings->peer));
+ sprintf(port, "%u", inSettings->mPort);
+
+ /*
+ * Set up address hint structure
+ */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = inSettings->mSockAF;
+ hints.ai_socktype = socktype;
+ /*
+ * CHEAT: getaddrinfo does not support SOCK_DCCP and using a zero
+ * ai_socktype will return IPv4 addresses first (which is bad on
+ * a dual-stack host). Pretend here to be UDP - this usually works.
+ */
+ if (inSettings->mProtocol == IPPROTO_DCCP)
+ hints.ai_socktype = SOCK_DGRAM;
+
+ /* only use addresses available on the host */
+ hints.ai_flags = AI_ADDRCONFIG;
+ if (inSettings->mSockAF == AF_INET6)
+ /* use v4-mapped-v6 if no v6 addresses found */
+ hints.ai_flags |= AI_V4MAPPED | AI_ALL;
+
+ /*
+ * Obtain local/remote address information
+ */
+ if (inSettings->mLocalhost || inSettings->mThreadMode == kMode_Listener) {
+ if (inSettings->mLocalhost == NULL)
+ hints.ai_flags |= AI_PASSIVE;
+ if ((rc = getaddrinfo(inSettings->mLocalhost, port, &hints, &local)))
+ die("Can not resolve local address %s#%s: %s",
+ inSettings->mLocalhost ? : "(local)", port, gai_strerror(rc));
+ }
+
+ if (inSettings->mHost && inSettings->mThreadMode != kMode_Listener) {
+ if ((rc = getaddrinfo(inSettings->mHost, port, &hints, &remote)))
+ die("Can not resolve peer address %s#%s: %s",
+ inSettings->mHost, port, gai_strerror(rc));
+ }
+
+ /*
+ * Iterate over all src/dst combination, exhausting dst first
+ */
+ for (src = local, dst = remote; src != NULL || dst != NULL; /* no op */ ) {
+ if (src && src->ai_family == AF_INET &&
+ dst && dst->ai_family == AF_INET6)
+ goto get_next_dst; /* v4 -> v6 is not possible */
+
+ inSettings->mSockAF = src ? src->ai_family : dst->ai_family;
+ inSettings->mSock = socket(inSettings->mSockAF, socktype,
+ inSettings->mProtocol);
+ if (inSettings->mSock < 0)
+ goto get_next_dst;
+
+ SetSocketOptions(inSettings);
+
+ if (src) {
+ if (bind(inSettings->mSock, src->ai_addr, src->ai_addrlen) < 0) {
+ close(inSettings->mSock);
+ goto get_next_src;
+ }
+ if (!dst)
+ break; /* bind-only completed successfully */
+ }
+
+ if (dst && connect(inSettings->mSock, dst->ai_addr, dst->ai_addrlen) == 0)
+ break; /* connection completed successfully */
+ close(inSettings->mSock);
+get_next_dst:
+ if (dst && (dst = dst->ai_next))
+ continue;
+get_next_src:
+ if (src && (src = src->ai_next))
+ dst = remote; /* restart inner loop */
+ }
+
+ if (src == NULL && dst == NULL)
+ die("Can not create %s socket", protoName(inSettings->mProtocol));
+ if (src) {
+ if (SockAddr_isMulticast(src->ai_addr))
+ setMulticast(inSettings);
+ memcpy(&inSettings->local, src->ai_addr, src->ai_addrlen);
+ }
+ if (dst) {
+ if (SockAddr_isMulticast(dst->ai_addr))
+ setMulticast(inSettings);
+ memcpy(&inSettings->peer, dst->ai_addr, dst->ai_addrlen);
+ }
+
+ if (local)
+ freeaddrinfo(local);
+ if (remote)
+ freeaddrinfo(remote);
+
+ if (isMulticast(inSettings) && !isConnectionLess(inSettings))
+ die("Can not use %s with multicast.", protoName(inSettings->mProtocol));