src/solaris/native/java/net/net_util_md.c

Print this page




  23  * questions.
  24  */
  25 
  26 #include <errno.h>
  27 #include <string.h>
  28 #include <sys/types.h>
  29 #include <sys/socket.h>
  30 #include <netinet/tcp.h>        /* Defines TCP_NODELAY, needed for 2.6 */
  31 #include <netinet/in.h>
  32 #include <net/if.h>
  33 #include <netdb.h>
  34 #include <stdlib.h>
  35 #include <dlfcn.h>
  36 
  37 #ifndef _ALLBSD_SOURCE
  38 #include <values.h>
  39 #else
  40 #include <limits.h>
  41 #include <sys/param.h>
  42 #include <sys/sysctl.h>

  43 #ifndef MAXINT
  44 #define MAXINT INT_MAX
  45 #endif
  46 #endif
  47 
  48 #ifdef __solaris__

  49 #include <sys/sockio.h>
  50 #include <stropts.h>
  51 #include <inet/nd.h>
  52 #endif
  53 
  54 #ifdef __linux__

  55 #include <arpa/inet.h>
  56 #include <net/route.h>
  57 #include <sys/utsname.h>
  58 
  59 #ifndef IPV6_FLOWINFO_SEND
  60 #define IPV6_FLOWINFO_SEND      33
  61 #endif
  62 
  63 #endif
  64 
  65 #include "jni_util.h"
  66 #include "jvm.h"
  67 #include "net_util.h"
  68 
  69 #include "java_net_SocketOptions.h"
  70 
  71 /* needed from libsocket on Solaris 8 */
  72 
  73 getaddrinfo_f getaddrinfo_ptr = NULL;
  74 freeaddrinfo_f freeaddrinfo_ptr = NULL;


  93     if (ni_class == NULL) {
  94         jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
  95         CHECK_NULL(c);
  96         c = (*env)->NewGlobalRef(env, c);
  97         CHECK_NULL(c);
  98         ni_defaultIndexID = (*env)->GetStaticFieldID(
  99             env, c, "defaultIndex", "I");
 100         ni_class = c;
 101     }
 102     int defaultIndex;
 103     struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)him;
 104     if (sin6->sin6_family == AF_INET6 && (sin6->sin6_scope_id == 0)) {
 105         defaultIndex = (*env)->GetStaticIntField(env, ni_class,
 106                                                  ni_defaultIndexID);
 107         sin6->sin6_scope_id = defaultIndex;
 108     }
 109 #endif
 110 }
 111 
 112 int getDefaultScopeID(JNIEnv *env) {

 113     static jclass ni_class = NULL;
 114     static jfieldID ni_defaultIndexID;
 115     if (ni_class == NULL) {
 116         jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
 117         CHECK_NULL_RETURN(c, 0);
 118         c = (*env)->NewGlobalRef(env, c);
 119         CHECK_NULL_RETURN(c, 0);
 120         ni_defaultIndexID = (*env)->GetStaticFieldID(env, c,
 121                                                      "defaultIndex", "I");
 122         ni_class = c;
 123     }
 124     int defaultIndex = 0;
 125     defaultIndex = (*env)->GetStaticIntField(env, ni_class,
 126                                              ni_defaultIndexID);
 127     return defaultIndex;
 128 }
 129 














 130 #ifdef __solaris__
 131 static int init_tcp_max_buf, init_udp_max_buf;
 132 static int tcp_max_buf;
 133 static int udp_max_buf;
 134 static int useExclBind = 0;
 135 
 136 /*
 137  * Get the specified parameter from the specified driver. The value
 138  * of the parameter is assumed to be an 'int'. If the parameter
 139  * cannot be obtained return -1
 140  */
 141 int net_getParam(char *driver, char *param)
 142 {
 143     struct strioctl stri;
 144     char buf [64];
 145     int s;
 146     int value;
 147 
 148     s = open (driver, O_RDWR);
 149     if (s < 0) {


 305 #if defined(DONT_ENABLE_IPV6)
 306 jint  IPv6_supported()
 307 {
 308     return JNI_FALSE;
 309 }
 310 
 311 #else /* !DONT_ENABLE_IPV6 */
 312 
 313 jint  IPv6_supported()
 314 {
 315 #ifndef AF_INET6
 316     return JNI_FALSE;
 317 #endif
 318 
 319 #ifdef AF_INET6
 320     int fd;
 321     void *ipv6_fn;
 322     SOCKADDR sa;
 323     socklen_t sa_len = sizeof(sa);
 324 
 325     fd = JVM_Socket(AF_INET6, SOCK_STREAM, 0) ;
 326     if (fd < 0) {
 327         /*
 328          *  TODO: We really cant tell since it may be an unrelated error
 329          *  for now we will assume that AF_INET6 is not available
 330          */
 331         return JNI_FALSE;
 332     }
 333 
 334     /*
 335      * If fd 0 is a socket it means we've been launched from inetd or
 336      * xinetd. If it's a socket then check the family - if it's an
 337      * IPv4 socket then we need to disable IPv6.
 338      */
 339     if (getsockname(0, (struct sockaddr *)&sa, &sa_len) == 0) {
 340         struct sockaddr *saP = (struct sockaddr *)&sa;
 341         if (saP->sa_family != AF_INET6) {
 342             return JNI_FALSE;
 343         }
 344     }
 345 


1190     return 0;
1191 }
1192 #endif
1193 
1194 
1195 /*
1196  * Wrapper for getsockopt system routine - does any necessary
1197  * pre/post processing to deal with OS specific oddities :-
1198  *
1199  * IP_TOS is a no-op with IPv6 sockets as it's setup when
1200  * the connection is established.
1201  *
1202  * On Linux the SO_SNDBUF/SO_RCVBUF values must be post-processed
1203  * to compensate for an incorrect value returned by the kernel.
1204  */
1205 int
1206 NET_GetSockOpt(int fd, int level, int opt, void *result,
1207                int *len)
1208 {
1209     int rv;

1210 
1211 #ifdef AF_INET6
1212     if ((level == IPPROTO_IP) && (opt == IP_TOS)) {
1213         if (ipv6_available()) {
1214 
1215             /*
1216              * For IPv6 socket option implemented at Java-level
1217              * so return -1.
1218              */
1219             int *tc = (int *)result;
1220             *tc = -1;
1221             return 0;
1222         }
1223     }
1224 #endif
1225 
1226 #ifdef __solaris__
1227     rv = getsockopt(fd, level, opt, result, len);
1228 #else
1229     {
1230         socklen_t socklen = *len;
1231         rv = getsockopt(fd, level, opt, result, &socklen);
1232         *len = socklen;
1233     }
1234 #endif
1235 
1236     if (rv < 0) {
1237         return rv;
1238     }
1239 
1240 #ifdef __linux__
1241     /*
1242      * On Linux SO_SNDBUF/SO_RCVBUF aren't symmetric. This
1243      * stems from additional socket structures in the send
1244      * and receive buffers.
1245      */
1246     if ((level == SOL_SOCKET) && ((opt == SO_SNDBUF)
1247                                   || (opt == SO_RCVBUF))) {
1248         int n = *((int *)result);
1249         n /= 2;
1250         *((int *)result) = n;
1251     }
1252 #endif
1253 
1254 /* Workaround for Mac OS treating linger value as


1325 
1326 #if defined(AF_INET6) && defined(__linux__)
1327         if (ipv6_available()) {
1328             int optval = 1;
1329             return setsockopt(fd, IPPROTO_IPV6, IPV6_FLOWINFO_SEND,
1330                               (void *)&optval, sizeof(optval));
1331         }
1332 #endif
1333 
1334         iptos = (int *)arg;
1335         *iptos &= (IPTOS_TOS_MASK | IPTOS_PREC_MASK);
1336     }
1337 
1338     /*
1339      * SOL_SOCKET/{SO_SNDBUF,SO_RCVBUF} - On Solaris we may need to clamp
1340      * the value when it exceeds the system limit.
1341      */
1342 #ifdef __solaris__
1343     if (level == SOL_SOCKET) {
1344         if (opt == SO_SNDBUF || opt == SO_RCVBUF) {
1345             int sotype=0, arglen;

1346             int *bufsize, maxbuf;
1347             int ret;
1348 
1349             /* Attempt with the original size */
1350             ret = setsockopt(fd, level, opt, arg, len);
1351             if ((ret == 0) || (ret == -1 && errno != ENOBUFS))
1352                 return ret;
1353 
1354             /* Exceeded system limit so clamp and retry */
1355 
1356             arglen = sizeof(sotype);
1357             if (getsockopt(fd, SOL_SOCKET, SO_TYPE, (void *)&sotype,
1358                            &arglen) < 0) {
1359                 return -1;
1360             }
1361 
1362             /*
1363              * We try to get tcp_maxbuf (and udp_max_buf) using
1364              * an ioctl() that isn't available on all versions of Solaris.
1365              * If that fails, we use the search algorithm in findMaxBuf()


1529     if (him->sa_family == AF_INET) {
1530         struct sockaddr_in *sa = (struct sockaddr_in *)him;
1531         if ((ntohl(sa->sin_addr.s_addr) & 0x7f0000ff) == 0x7f0000ff) {
1532             errno = EADDRNOTAVAIL;
1533             return -1;
1534         }
1535     }
1536 #endif
1537 
1538 #if defined(__solaris__) && defined(AF_INET6)
1539     /*
1540      * Solaris has separate IPv4 and IPv6 port spaces so we
1541      * use an exclusive bind when SO_REUSEADDR is not used to
1542      * give the illusion of a unified port space.
1543      * This also avoids problems with IPv6 sockets connecting
1544      * to IPv4 mapped addresses whereby the socket conversion
1545      * results in a late bind that fails because the
1546      * corresponding IPv4 port is in use.
1547      */
1548     if (ipv6_available()) {
1549         int arg, len;

1550 
1551         len = sizeof(arg);
1552         if (useExclBind || getsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
1553                        (char *)&arg, &len) == 0) {
1554             if (useExclBind || arg == 0) {
1555                 /*
1556                  * SO_REUSEADDR is disabled or sun.net.useExclusiveBind
1557                  * property is true so enable TCP_EXCLBIND or
1558                  * UDP_EXCLBIND
1559                  */
1560                 len = sizeof(arg);
1561                 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&arg,
1562                                &len) == 0) {
1563                     if (arg == SOCK_STREAM) {
1564                         level = IPPROTO_TCP;
1565                         exclbind = TCP_EXCLBIND;
1566                     } else {
1567                         level = IPPROTO_UDP;
1568                         exclbind = UDP_EXCLBIND;
1569                     }




  23  * questions.
  24  */
  25 
  26 #include <errno.h>
  27 #include <string.h>
  28 #include <sys/types.h>
  29 #include <sys/socket.h>
  30 #include <netinet/tcp.h>        /* Defines TCP_NODELAY, needed for 2.6 */
  31 #include <netinet/in.h>
  32 #include <net/if.h>
  33 #include <netdb.h>
  34 #include <stdlib.h>
  35 #include <dlfcn.h>
  36 
  37 #ifndef _ALLBSD_SOURCE
  38 #include <values.h>
  39 #else
  40 #include <limits.h>
  41 #include <sys/param.h>
  42 #include <sys/sysctl.h>
  43 #include <sys/ioctl.h>
  44 #ifndef MAXINT
  45 #define MAXINT INT_MAX
  46 #endif
  47 #endif
  48 
  49 #ifdef __solaris__
  50 #include <sys/filio.h>
  51 #include <sys/sockio.h>
  52 #include <stropts.h>
  53 #include <inet/nd.h>
  54 #endif
  55 
  56 #ifdef __linux__
  57 #include <sys/ioctl.h>
  58 #include <arpa/inet.h>
  59 #include <net/route.h>
  60 #include <sys/utsname.h>
  61 
  62 #ifndef IPV6_FLOWINFO_SEND
  63 #define IPV6_FLOWINFO_SEND      33
  64 #endif
  65 
  66 #endif
  67 
  68 #include "jni_util.h"
  69 #include "jvm.h"
  70 #include "net_util.h"
  71 
  72 #include "java_net_SocketOptions.h"
  73 
  74 /* needed from libsocket on Solaris 8 */
  75 
  76 getaddrinfo_f getaddrinfo_ptr = NULL;
  77 freeaddrinfo_f freeaddrinfo_ptr = NULL;


  96     if (ni_class == NULL) {
  97         jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
  98         CHECK_NULL(c);
  99         c = (*env)->NewGlobalRef(env, c);
 100         CHECK_NULL(c);
 101         ni_defaultIndexID = (*env)->GetStaticFieldID(
 102             env, c, "defaultIndex", "I");
 103         ni_class = c;
 104     }
 105     int defaultIndex;
 106     struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)him;
 107     if (sin6->sin6_family == AF_INET6 && (sin6->sin6_scope_id == 0)) {
 108         defaultIndex = (*env)->GetStaticIntField(env, ni_class,
 109                                                  ni_defaultIndexID);
 110         sin6->sin6_scope_id = defaultIndex;
 111     }
 112 #endif
 113 }
 114 
 115 int getDefaultScopeID(JNIEnv *env) {
 116     int defaultIndex = 0;
 117     static jclass ni_class = NULL;
 118     static jfieldID ni_defaultIndexID;
 119     if (ni_class == NULL) {
 120         jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
 121         CHECK_NULL_RETURN(c, 0);
 122         c = (*env)->NewGlobalRef(env, c);
 123         CHECK_NULL_RETURN(c, 0);
 124         ni_defaultIndexID = (*env)->GetStaticFieldID(env, c,
 125                                                      "defaultIndex", "I");
 126         ni_class = c;
 127     }    

 128     defaultIndex = (*env)->GetStaticIntField(env, ni_class,
 129                                              ni_defaultIndexID);
 130     return defaultIndex;
 131 }
 132 
 133 #define RESTARTABLE(_cmd, _result) do { \
 134     do { \
 135         _result = _cmd; \
 136     } while((_result == -1) && (errno == EINTR)); \
 137 } while(0)
 138 
 139 int NET_SocketAvailable(int s, jint *pbytes) {
 140     int result;
 141     RESTARTABLE(ioctl(s, FIONREAD, pbytes), result);
 142     // note: ioctl can return 0 when successful, NET_SocketAvailable
 143     // is expected to return 0 on failure and 1 on success.
 144     return (result == -1) ? 0 : 1;
 145 }
 146 
 147 #ifdef __solaris__
 148 static int init_tcp_max_buf, init_udp_max_buf;
 149 static int tcp_max_buf;
 150 static int udp_max_buf;
 151 static int useExclBind = 0;
 152 
 153 /*
 154  * Get the specified parameter from the specified driver. The value
 155  * of the parameter is assumed to be an 'int'. If the parameter
 156  * cannot be obtained return -1
 157  */
 158 int net_getParam(char *driver, char *param)
 159 {
 160     struct strioctl stri;
 161     char buf [64];
 162     int s;
 163     int value;
 164 
 165     s = open (driver, O_RDWR);
 166     if (s < 0) {


 322 #if defined(DONT_ENABLE_IPV6)
 323 jint  IPv6_supported()
 324 {
 325     return JNI_FALSE;
 326 }
 327 
 328 #else /* !DONT_ENABLE_IPV6 */
 329 
 330 jint  IPv6_supported()
 331 {
 332 #ifndef AF_INET6
 333     return JNI_FALSE;
 334 #endif
 335 
 336 #ifdef AF_INET6
 337     int fd;
 338     void *ipv6_fn;
 339     SOCKADDR sa;
 340     socklen_t sa_len = sizeof(sa);
 341 
 342     fd = socket(AF_INET6, SOCK_STREAM, 0) ;
 343     if (fd < 0) {
 344         /*
 345          *  TODO: We really cant tell since it may be an unrelated error
 346          *  for now we will assume that AF_INET6 is not available
 347          */
 348         return JNI_FALSE;
 349     }
 350 
 351     /*
 352      * If fd 0 is a socket it means we've been launched from inetd or
 353      * xinetd. If it's a socket then check the family - if it's an
 354      * IPv4 socket then we need to disable IPv6.
 355      */
 356     if (getsockname(0, (struct sockaddr *)&sa, &sa_len) == 0) {
 357         struct sockaddr *saP = (struct sockaddr *)&sa;
 358         if (saP->sa_family != AF_INET6) {
 359             return JNI_FALSE;
 360         }
 361     }
 362 


1207     return 0;
1208 }
1209 #endif
1210 
1211 
1212 /*
1213  * Wrapper for getsockopt system routine - does any necessary
1214  * pre/post processing to deal with OS specific oddities :-
1215  *
1216  * IP_TOS is a no-op with IPv6 sockets as it's setup when
1217  * the connection is established.
1218  *
1219  * On Linux the SO_SNDBUF/SO_RCVBUF values must be post-processed
1220  * to compensate for an incorrect value returned by the kernel.
1221  */
1222 int
1223 NET_GetSockOpt(int fd, int level, int opt, void *result,
1224                int *len)
1225 {
1226     int rv;
1227     socklen_t socklen = *len;
1228 
1229 #ifdef AF_INET6
1230     if ((level == IPPROTO_IP) && (opt == IP_TOS)) {
1231         if (ipv6_available()) {
1232 
1233             /*
1234              * For IPv6 socket option implemented at Java-level
1235              * so return -1.
1236              */
1237             int *tc = (int *)result;
1238             *tc = -1;
1239             return 0;
1240         }
1241     }
1242 #endif
1243 





1244     rv = getsockopt(fd, level, opt, result, &socklen);
1245     *len = socklen;


1246 
1247     if (rv < 0) {
1248         return rv;
1249     }
1250 
1251 #ifdef __linux__
1252     /*
1253      * On Linux SO_SNDBUF/SO_RCVBUF aren't symmetric. This
1254      * stems from additional socket structures in the send
1255      * and receive buffers.
1256      */
1257     if ((level == SOL_SOCKET) && ((opt == SO_SNDBUF)
1258                                   || (opt == SO_RCVBUF))) {
1259         int n = *((int *)result);
1260         n /= 2;
1261         *((int *)result) = n;
1262     }
1263 #endif
1264 
1265 /* Workaround for Mac OS treating linger value as


1336 
1337 #if defined(AF_INET6) && defined(__linux__)
1338         if (ipv6_available()) {
1339             int optval = 1;
1340             return setsockopt(fd, IPPROTO_IPV6, IPV6_FLOWINFO_SEND,
1341                               (void *)&optval, sizeof(optval));
1342         }
1343 #endif
1344 
1345         iptos = (int *)arg;
1346         *iptos &= (IPTOS_TOS_MASK | IPTOS_PREC_MASK);
1347     }
1348 
1349     /*
1350      * SOL_SOCKET/{SO_SNDBUF,SO_RCVBUF} - On Solaris we may need to clamp
1351      * the value when it exceeds the system limit.
1352      */
1353 #ifdef __solaris__
1354     if (level == SOL_SOCKET) {
1355         if (opt == SO_SNDBUF || opt == SO_RCVBUF) {
1356             int sotype=0;
1357             socklen_t arglen;
1358             int *bufsize, maxbuf;
1359             int ret;
1360 
1361             /* Attempt with the original size */
1362             ret = setsockopt(fd, level, opt, arg, len);
1363             if ((ret == 0) || (ret == -1 && errno != ENOBUFS))
1364                 return ret;
1365 
1366             /* Exceeded system limit so clamp and retry */
1367 
1368             arglen = sizeof(sotype);
1369             if (getsockopt(fd, SOL_SOCKET, SO_TYPE, (void *)&sotype,
1370                            &arglen) < 0) {
1371                 return -1;
1372             }
1373 
1374             /*
1375              * We try to get tcp_maxbuf (and udp_max_buf) using
1376              * an ioctl() that isn't available on all versions of Solaris.
1377              * If that fails, we use the search algorithm in findMaxBuf()


1541     if (him->sa_family == AF_INET) {
1542         struct sockaddr_in *sa = (struct sockaddr_in *)him;
1543         if ((ntohl(sa->sin_addr.s_addr) & 0x7f0000ff) == 0x7f0000ff) {
1544             errno = EADDRNOTAVAIL;
1545             return -1;
1546         }
1547     }
1548 #endif
1549 
1550 #if defined(__solaris__) && defined(AF_INET6)
1551     /*
1552      * Solaris has separate IPv4 and IPv6 port spaces so we
1553      * use an exclusive bind when SO_REUSEADDR is not used to
1554      * give the illusion of a unified port space.
1555      * This also avoids problems with IPv6 sockets connecting
1556      * to IPv4 mapped addresses whereby the socket conversion
1557      * results in a late bind that fails because the
1558      * corresponding IPv4 port is in use.
1559      */
1560     if (ipv6_available()) {
1561         int arg;
1562         socklen_t len;
1563 
1564         len = sizeof(arg);
1565         if (useExclBind || getsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
1566                        (char *)&arg, &len) == 0) {
1567             if (useExclBind || arg == 0) {
1568                 /*
1569                  * SO_REUSEADDR is disabled or sun.net.useExclusiveBind
1570                  * property is true so enable TCP_EXCLBIND or
1571                  * UDP_EXCLBIND
1572                  */
1573                 len = sizeof(arg);
1574                 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&arg,
1575                                &len) == 0) {
1576                     if (arg == SOCK_STREAM) {
1577                         level = IPPROTO_TCP;
1578                         exclbind = TCP_EXCLBIND;
1579                     } else {
1580                         level = IPPROTO_UDP;
1581                         exclbind = UDP_EXCLBIND;
1582                     }