* <netinet/in.h>
* <sys/socket.h>
* ------------------------------------------------------------------- */
-
-
#define HEADERS()
#include "headers.h"
* Set socket options before the listen() or connect() calls.
* These are optional performance tuning factors.
* ------------------------------------------------------------------- */
-
-void SetSocketOptions( thread_Settings *inSettings ) {
- // set the TCP window size (socket buffer sizes)
- // also the UDP buffer size
- // must occur before call to accept() for large window sizes
- setsock_tcp_windowsize( inSettings->mSock, inSettings->mTCPWin,
- (inSettings->mThreadMode == kMode_Client ? 1 : 0) );
+void SetSocketOptions( thread_Settings *inSettings )
+{
+ int rc, val;
+ Socklen_t len = sizeof(int);
// check if we're sending multicast, and set TTL
- if ( isMulticast( inSettings ) && ( inSettings->mTTL > 0 ) ) {
- int val = inSettings->mTTL;
-#ifdef HAVE_MULTICAST
- if ( !SockAddr_isIPv6( &inSettings->local ) ) {
- int rc = setsockopt( inSettings->mSock, IPPROTO_IP, IP_MULTICAST_TTL,
- (const void*) &val, (Socklen_t) sizeof(val));
-
- WARN_errno( rc == SOCKET_ERROR, "multicast ttl" );
- }
-#ifdef HAVE_IPV6_MULTICAST
- else {
- int rc = setsockopt( inSettings->mSock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
- (const void*) &val, (Socklen_t) sizeof(val));
- WARN_errno( rc == SOCKET_ERROR, "multicast ttl" );
- }
-#endif
-#endif
- }
+ if (isMulticast(inSettings) && inSettings->mTTL > 0) {
+ val = inSettings->mTTL;
+ if (SockAddr_isIPv6(&inSettings->local))
+ rc = setsockopt(inSettings->mSock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
+ &val, len);
+ else
+ rc = setsockopt(inSettings->mSock, IPPROTO_IP, IP_MULTICAST_TTL,
+ &val, len);
+ WARN_errno( rc == SOCKET_ERROR, "multicast ttl" );
+ }
-#ifdef IP_TOS
// set IP TOS (type-of-service) field
+#ifdef IP_TOS
if ( inSettings->mTOS > 0 ) {
- int tos = inSettings->mTOS;
- Socklen_t len = sizeof(tos);
- int rc = setsockopt( inSettings->mSock, IPPROTO_IP, IP_TOS,
- (char*) &tos, len );
+ val = inSettings->mTOS;
+ rc = setsockopt( inSettings->mSock, IPPROTO_IP, IP_TOS, &val, len );
WARN_errno( rc == SOCKET_ERROR, "setsockopt IP_TOS" );
}
#endif
- if ( !isUDP( inSettings ) ) {
- // set the TCP maximum segment size
+
+ // TCP-specific options
+ if ( inSettings->mProtocol == kProto_TCP ) {
+
+ // set the TCP window size (socket buffer sizes)
+ // must occur before call to accept() for large window sizes
+ setsock_tcp_windowsize(inSettings->mSock, inSettings->mWinSize,
+ inSettings->mThreadMode == kMode_Client);
setsock_tcp_mss( inSettings->mSock, inSettings->mMSS );
#ifdef TCP_NODELAY
-
- // set TCP nodelay option
if ( isNoDelay( inSettings ) ) {
- int nodelay = 1;
- Socklen_t len = sizeof(nodelay);
- int rc = setsockopt( inSettings->mSock, IPPROTO_TCP, TCP_NODELAY,
- (char*) &nodelay, len );
+ val = 1;
+ rc = setsockopt( inSettings->mSock, IPPROTO_TCP, TCP_NODELAY,
+ &val, len );
WARN_errno( rc == SOCKET_ERROR, "setsockopt TCP_NODELAY" );
}
#endif
+ } else {
+ rc = set_buffer_sock_size(inSettings->mSock, inSettings->mWinSize,
+ inSettings->mThreadMode == kMode_Client);
+ WARN_errno( rc < 0 , "setsockopt for buffer size" );
+ }
+ // DCCP-specific options
+ if ( inSettings->mProtocol == kProto_DCCP ) {
+ /*
+ * We use the service code SC:PERF (0x50455246) from
+ * draft-fairhurst-dccp-serv-codes to identify this service.
+ */
+ val = htonl(0x50455246); /* ALWAYS use htonl */
+ rc = setsockopt( inSettings->mSock, SOL_DCCP, DCCP_SOCKOPT_SERVICE,
+ &val, len );
+ WARN_errno( rc == SOCKET_ERROR, "setsockopt DCCP_SOCKOPT_SERVICE" );
}
+
+ // 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));
}
-// end SetSocketOptions