src/windows/native/java/net/TwoStacksPlainDatagramSocketImpl.c

Print this page




 336     int addrlen = sizeof(rmtaddr);
 337 
 338     /*
 339      * A no-op if this OS doesn't support it.
 340      */
 341     if (!supportPortUnreachable()) {
 342         return JNI_FALSE;
 343     }
 344 
 345     /*
 346      * Peek at the queue to see if there is an ICMP port unreachable. If there
 347      * is then receive it.
 348      */
 349     FD_ZERO(&tbl);
 350     FD_SET(fd, &tbl);
 351     while(1) {
 352         if (select(/*ignored*/fd+1, &tbl, 0, 0, &t) <= 0) {
 353             break;
 354         }
 355         if (recvfrom(fd, buf, 1, MSG_PEEK,
 356                          (struct sockaddr *)&rmtaddr, &addrlen) != JVM_IO_ERR) {
 357             break;
 358         }
 359         if (WSAGetLastError() != WSAECONNRESET) {
 360             /* some other error - we don't care here */
 361             break;
 362         }
 363 
 364         recvfrom(fd, buf, 1, 0,  (struct sockaddr *)&rmtaddr, &addrlen);
 365         got_icmp = JNI_TRUE;
 366     }
 367 
 368     return got_icmp;
 369 }
 370 
 371 
 372 /*
 373  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
 374  * Method:    init
 375  * Signature: ()V
 376  */


 491         } else {
 492             NET_ThrowCurrent (env, "Cannot bind");
 493             return;
 494         }
 495     } else {
 496         if (NET_WinBind(fd, (struct sockaddr *)&lcladdr, lcladdrlen, exclBind) == -1) {
 497             if (WSAGetLastError() == WSAEACCES) {
 498                 WSASetLastError(WSAEADDRINUSE);
 499             }
 500             NET_ThrowCurrent(env, "Cannot bind");
 501             return;
 502         }
 503     }
 504 
 505     if (port == 0) {
 506         if (fd == -1) {
 507             /* must be an IPV6 only socket. */
 508             fd = fd1;
 509         }
 510         if (getsockname(fd, (struct sockaddr *)&lcladdr, &lcladdrlen) == -1) {
 511             NET_ThrowCurrent(env, "JVM_GetSockName");
 512             return;
 513         }
 514         port = ntohs((u_short) GET_PORT (&lcladdr));
 515     }
 516     (*env)->SetIntField(env, this, pdsi_localPortID, port);
 517 }
 518 
 519 
 520 /*
 521  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
 522  * Method:    connect0
 523  * Signature: (Ljava/net/InetAddress;I)V
 524  */
 525 
 526 JNIEXPORT void JNICALL
 527 Java_java_net_TwoStacksPlainDatagramSocketImpl_connect0(JNIEnv *env, jobject this,
 528                                                jobject address, jint port) {
 529     /* The object's field */
 530     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 531     jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);


 683         }
 684         fdObj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
 685     }
 686 
 687     if (IS_NULL(fdObj)) {
 688         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 689                         "Socket closed");
 690         return;
 691     }
 692     fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 693 
 694     packetBufferLen = (*env)->GetIntField(env, packet, dp_lengthID);
 695     /* Note: the buffer needn't be greater than 65,536 (0xFFFF)...
 696      * the maximum size of an IP packet. Anything bigger is truncated anyway.
 697      */
 698     if (packetBufferLen > MAX_PACKET_LEN) {
 699         packetBufferLen = MAX_PACKET_LEN;
 700     }
 701 
 702     if (connected) {
 703         addrp = 0; /* arg to JVM_Sendto () null in this case */
 704         addrlen = 0;
 705     } else {
 706       if (NET_InetAddressToSockaddr(env, iaObj, packetPort, (struct sockaddr *)&rmtaddr, &addrlen, JNI_FALSE) != 0) {
 707         return;
 708       }
 709     }
 710 
 711     if (packetBufferLen > MAX_BUFFER_LEN) {
 712 
 713         /*
 714          * On 95/98 if we try to send a datagram >12k to an application
 715          * on the same machine then this will fail silently. Thus we
 716          * catch this situation here so that we can throw an exception
 717          * when this arises.
 718          * On ME if we try to send a datagram with a size greater than
 719          * that supported by the service provider then no error is
 720          * returned.
 721          */
 722         if (!w2k_or_later) { /* avoid this check on Win 2K or better. Does not work with IPv6.
 723                       * Check is not necessary on these OSes */


 740          * than 2048 bytes into several operations of size 2048.
 741          * This saves a malloc()/memcpy()/free() for big
 742          * buffers.  This is OK for file IO and TCP, but that
 743          * strategy violates the semantics of a datagram protocol.
 744          * (one big send) != (several smaller sends).  So here
 745          * we *must* alloc the buffer.  Note it needn't be bigger
 746          * than 65,536 (0xFFFF) the max size of an IP packet.
 747          * anything bigger is truncated anyway.
 748          */
 749         fullPacket = (char *)malloc(packetBufferLen);
 750         if (!fullPacket) {
 751             JNU_ThrowOutOfMemoryError(env, "Send buf native heap allocation failed");
 752             return;
 753         }
 754     } else {
 755         fullPacket = &(BUF[0]);
 756     }
 757 
 758     (*env)->GetByteArrayRegion(env, packetBuffer, packetBufferOffset, packetBufferLen,
 759                                (jbyte *)fullPacket);
 760     switch (sendto(fd, fullPacket, packetBufferLen, 0,
 761                        (struct sockaddr *)addrp, addrlen)) {
 762         case JVM_IO_ERR:
 763             NET_ThrowCurrent(env, "Datagram send failed");
 764             break;
 765 
 766         case JVM_IO_INTR:
 767             JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
 768                             "operation interrupted");
 769     }
 770 
 771     if (packetBufferLen > MAX_BUFFER_LEN) {
 772         free(fullPacket);
 773     }
 774 }
 775 
 776 /*
 777  * check which socket was last serviced when there was data on both sockets.
 778  * Only call this if sure that there is data on both sockets.
 779  */
 780 static int checkLastFD (JNIEnv *env, jobject this, int fd, int fd1) {
 781     int nextfd, lastfd = (*env)->GetIntField(env, this, pdsi_lastfdID);
 782     if (lastfd == -1) {
 783         /* arbitrary. Choose fd */
 784         (*env)->SetIntField(env, this, pdsi_lastfdID, fd);
 785         return fd;
 786     } else {
 787         if (lastfd == fd) {
 788             nextfd = fd1;


 834         address = getInetAddress_addr(env, addressObj);
 835         /* We only handle IPv4 for now. Will support IPv6 once its in the os */
 836         family = AF_INET;
 837     }
 838 
 839     do {
 840         retry = FALSE;
 841 
 842         /*
 843          * If a timeout has been specified then we select on the socket
 844          * waiting for a read event or a timeout.
 845          */
 846         if (timeout) {
 847             int ret;
 848             prevTime = JVM_CurrentTimeMillis(env, 0);
 849             ret = NET_Timeout (fd, timeout);
 850             if (ret == 0) {
 851                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
 852                                 "Peek timed out");
 853                 return ret;
 854             } else if (ret == JVM_IO_ERR) {
 855                 NET_ThrowCurrent(env, "timeout in datagram socket peek");
 856                 return ret;
 857             } else if (ret == JVM_IO_INTR) {
 858                 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
 859                                 "operation interrupted");
 860                 return ret;
 861             }
 862         }
 863 
 864         /* now try the peek */
 865         n = recvfrom(fd, buf, 1, MSG_PEEK,
 866                          (struct sockaddr *)&remote_addr, &remote_addrsize);
 867 
 868         if (n == JVM_IO_ERR) {
 869             if (WSAGetLastError() == WSAECONNRESET) {
 870                 jboolean connected;
 871 
 872                 /*
 873                  * An icmp port unreachable - we must receive this as Windows
 874                  * does not reset the state of the socket until this has been
 875                  * received.
 876                  */
 877                 purgeOutstandingICMP(env, this, fd);
 878 
 879                 connected =  (*env)->GetBooleanField(env, this, pdsi_connected);
 880                 if (connected) {
 881                     JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
 882                                        "ICMP Port Unreachable");
 883                     return 0;
 884                 }
 885 
 886                 /*
 887                  * If a timeout was specified then we need to adjust it because
 888                  * we may have used up some of the timeout befor the icmp port
 889                  * unreachable arrived.
 890                  */
 891                 if (timeout) {
 892                     jlong newTime = JVM_CurrentTimeMillis(env, 0);
 893                     timeout -= (jint)(newTime - prevTime);
 894                     if (timeout <= 0) {
 895                         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
 896                                 "Receive timed out");
 897                         return 0;
 898                     }
 899                     prevTime = newTime;
 900                 }
 901 
 902                 /* Need to retry the recv */
 903                 retry = TRUE;
 904             }
 905         }
 906     } while (retry);
 907 
 908     if (n == JVM_IO_ERR && WSAGetLastError() != WSAEMSGSIZE) {
 909         NET_ThrowCurrent(env, "Datagram peek failed");
 910         return 0;
 911     }
 912     if (n == JVM_IO_INTR) {
 913         JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", 0);
 914         return 0;
 915     }
 916     setInetAddress_addr(env, addressObj, ntohl(remote_addr.sin_addr.s_addr));
 917     setInetAddress_family(env, addressObj, IPv4);
 918 
 919     /* return port */
 920     return ntohs(remote_addr.sin_port);
 921 }
 922 
 923 JNIEXPORT jint JNICALL
 924 Java_java_net_TwoStacksPlainDatagramSocketImpl_peekData(JNIEnv *env, jobject this,
 925                                            jobject packet) {
 926 
 927      char BUF[MAX_BUFFER_LEN];
 928     char *fullPacket;
 929     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 930     jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
 931     jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID);
 932 
 933     jbyteArray packetBuffer;
 934     jint packetBufferOffset, packetBufferLen;
 935 


1018     }
1019 
1020     do {
1021         int ret;
1022         retry = FALSE;
1023 
1024         /*
1025          * If a timeout has been specified then we select on the socket
1026          * waiting for a read event or a timeout.
1027          */
1028         if (checkBoth) {
1029             int t = timeout == 0 ? -1: timeout;
1030             prevTime = JVM_CurrentTimeMillis(env, 0);
1031             ret = NET_Timeout2 (fd, fd1, t, &fduse);
1032             /* all subsequent calls to recv() or select() will use the same fd
1033              * for this call to peek() */
1034             if (ret <= 0) {
1035                 if (ret == 0) {
1036                     JNU_ThrowByName(env,JNU_JAVANETPKG "SocketTimeoutException",
1037                                         "Peek timed out");
1038                 } else if (ret == JVM_IO_ERR) {
1039                     NET_ThrowCurrent(env, "timeout in datagram socket peek");
1040                 } else if (ret == JVM_IO_INTR) {
1041                     JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
1042                                     "operation interrupted");
1043                 }
1044                 if (packetBufferLen > MAX_BUFFER_LEN) {
1045                     free(fullPacket);
1046                 }
1047                 return -1;
1048             }
1049             if (ret == 2) {
1050                 fduse = checkLastFD (env, this, fd, fd1);
1051             }
1052             checkBoth = FALSE;
1053         } else if (timeout) {
1054             if (prevTime == 0) {
1055                 prevTime = JVM_CurrentTimeMillis(env, 0);
1056             }
1057             ret = NET_Timeout (fduse, timeout);
1058             if (ret <= 0) {
1059                 if (ret == 0) {
1060                     JNU_ThrowByName(env,JNU_JAVANETPKG "SocketTimeoutException",
1061                                     "Receive timed out");
1062                 } else if (ret == JVM_IO_ERR) {
1063                     JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1064                                     "Socket closed");
1065                 } else if (ret == JVM_IO_INTR) {
1066                     JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
1067                                     "operation interrupted");
1068                 }
1069                 if (packetBufferLen > MAX_BUFFER_LEN) {
1070                     free(fullPacket);
1071                 }
1072                 return -1;
1073             }
1074         }
1075 
1076         /* receive the packet */
1077         n = recvfrom(fduse, fullPacket, packetBufferLen, MSG_PEEK,
1078                          (struct sockaddr *)&remote_addr, &remote_addrsize);
1079         port = (int) ntohs ((u_short) GET_PORT((SOCKETADDRESS *)&remote_addr));
1080         if (n == JVM_IO_ERR) {
1081             if (WSAGetLastError() == WSAECONNRESET) {
1082                 jboolean connected;
1083 
1084                 /*
1085                  * An icmp port unreachable - we must receive this as Windows
1086                  * does not reset the state of the socket until this has been
1087                  * received.
1088                  */
1089                 purgeOutstandingICMP(env, this, fduse);
1090 
1091                 connected = (*env)->GetBooleanField(env, this, pdsi_connected);
1092                 if (connected) {
1093                     JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
1094                                        "ICMP Port Unreachable");
1095 
1096                     if (packetBufferLen > MAX_BUFFER_LEN) {
1097                         free(fullPacket);
1098                     }
1099                     return -1;
1100                 }


1227         nsockets ++;
1228     }
1229     if (!IS_NULL(fd1Obj)) {
1230         fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
1231         nsockets ++;
1232     }
1233 
1234     if (nsockets == 2) { /* need to choose one of them */
1235         /* was fduse set in peek? */
1236         fduse = (*env)->GetIntField(env, this, pdsi_fduseID);
1237         if (fduse == -1) {
1238             /* not set in peek(), must select on both sockets */
1239             int ret, t = (timeout == 0) ? -1: timeout;
1240             ret = NET_Timeout2 (fd, fd1, t, &fduse);
1241             if (ret == 2) {
1242                 fduse = checkLastFD (env, this, fd, fd1);
1243             } else if (ret <= 0) {
1244                 if (ret == 0) {
1245                     JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
1246                                     "Receive timed out");
1247                 } else if (ret == JVM_IO_ERR) {
1248                     JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1249                                     "Socket closed");
1250                 } else if (ret == JVM_IO_INTR) {
1251                     JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
1252                                     "operation interrupted");
1253                 }
1254                 return;
1255             }
1256         }
1257     } else if (!ipv6_supported) {
1258         fduse = fd;
1259     } else if (IS_NULL(fdObj)) {
1260         /* ipv6 supported: and this socket bound to an IPV6 only address */
1261         fduse = fd1;
1262     } else {
1263         /* ipv6 supported: and this socket bound to an IPV4 only address */
1264         fduse = fd;
1265     }
1266 
1267     if (IS_NULL(packet)) {
1268         JNU_ThrowNullPointerException(env, "packet");
1269         return;
1270     }
1271 
1272     packetBuffer = (*env)->GetObjectField(env, packet, dp_bufID);


1307      * If this Windows edition supports ICMP port unreachable and if we
1308      * are not connected then we need to know if a timeout has been specified
1309      * and if so we need to pick up the current time. These are required in
1310      * order to implement the semantics of timeout, viz :-
1311      * timeout set to t1 but ICMP port unreachable arrives in t2 where
1312      * t2 < t1. In this case we must discard the ICMP packets and then
1313      * wait for the next packet up to a maximum of t1 minus t2.
1314      */
1315     connected = (*env)->GetBooleanField(env, this, pdsi_connected);
1316     if (supportPortUnreachable() && !connected && timeout &&!ipv6_supported) {
1317         prevTime = JVM_CurrentTimeMillis(env, 0);
1318     }
1319 
1320     if (timeout && nsockets == 1) {
1321         int ret;
1322         ret = NET_Timeout(fduse, timeout);
1323         if (ret <= 0) {
1324             if (ret == 0) {
1325                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
1326                                 "Receive timed out");
1327             } else if (ret == JVM_IO_ERR) {
1328                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1329                                 "Socket closed");
1330             } else if (ret == JVM_IO_INTR) {
1331                 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
1332                                 "operation interrupted");
1333             }
1334             if (packetBufferLen > MAX_BUFFER_LEN) {
1335                 free(fullPacket);
1336             }
1337             return;
1338         }
1339     }
1340 
1341     /*
1342      * Loop only if we discarding ICMP port unreachable packets
1343      */
1344     do {
1345         retry = FALSE;
1346 
1347         /* receive the packet */
1348         n = recvfrom(fduse, fullPacket, packetBufferLen, 0,
1349                          (struct sockaddr *)&remote_addr, &remote_addrsize);
1350 
1351         if (n == JVM_IO_ERR) {
1352             if (WSAGetLastError() == WSAECONNRESET) {
1353                 /*
1354                  * An icmp port unreachable has been received - consume any other
1355                  * outstanding packets.
1356                  */
1357                 purgeOutstandingICMP(env, this, fduse);
1358 
1359                 /*
1360                  * If connected throw a PortUnreachableException
1361                  */
1362 
1363                 if (connected) {
1364                     JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
1365                                        "ICMP Port Unreachable");
1366 
1367                     if (packetBufferLen > MAX_BUFFER_LEN) {
1368                         free(fullPacket);
1369                     }
1370 
1371                     return;


1375                  * If a timeout was specified then we need to adjust it because
1376                  * we may have used up some of the timeout before the icmp port
1377                  * unreachable arrived.
1378                  */
1379                 if (timeout) {
1380                     int ret;
1381                     jlong newTime = JVM_CurrentTimeMillis(env, 0);
1382                     timeout -= (jint)(newTime - prevTime);
1383                     prevTime = newTime;
1384 
1385                     if (timeout <= 0) {
1386                         ret = 0;
1387                     } else {
1388                         ret = NET_Timeout(fduse, timeout);
1389                     }
1390 
1391                     if (ret <= 0) {
1392                         if (ret == 0) {
1393                             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
1394                                             "Receive timed out");
1395                         } else if (ret == JVM_IO_ERR) {
1396                             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1397                                             "Socket closed");
1398                         } else if (ret == JVM_IO_INTR) {
1399                             JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
1400                                             "operation interrupted");
1401                         }
1402                         if (packetBufferLen > MAX_BUFFER_LEN) {
1403                             free(fullPacket);
1404                         }
1405                         return;
1406                     }
1407                 }
1408 
1409                 /*
1410                  * An ICMP port unreachable was received but we are
1411                  * not connected so ignore it.
1412                  */
1413                 retry = TRUE;
1414             }
1415         }
1416     } while (retry);
1417 
1418     /* truncate the data if the packet's length is too small */
1419     if (n > packetBufferLen) {
1420         n = packetBufferLen;


1483  */
1484 JNIEXPORT void JNICALL
1485 Java_java_net_TwoStacksPlainDatagramSocketImpl_datagramSocketCreate(JNIEnv *env,
1486                                                            jobject this) {
1487     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
1488     jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
1489 
1490     int fd, fd1;
1491     int t = TRUE;
1492     DWORD x1, x2; /* ignored result codes */
1493     int ipv6_supported = ipv6_available();
1494 
1495     int arg = -1;
1496 
1497     if (IS_NULL(fdObj) || (ipv6_supported && IS_NULL(fd1Obj))) {
1498         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
1499         return;
1500     } else {
1501         fd =  (int) socket (AF_INET, SOCK_DGRAM, 0);
1502     }
1503     if (fd == JVM_IO_ERR) {
1504         NET_ThrowCurrent(env, "Socket creation failed");
1505         return;
1506     }
1507     SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE);
1508     (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd);
1509     NET_SetSockOpt(fd, SOL_SOCKET, SO_BROADCAST, (char*)&t, sizeof(BOOL));
1510 
1511     if (ipv6_supported) {
1512         /* SIO_UDP_CONNRESET fixes a bug introduced in Windows 2000, which
1513          * returns connection reset errors un connected UDP sockets (as well
1514          * as connected sockets. The solution is to only enable this feature
1515          * when the socket is connected
1516          */
1517         t = FALSE;
1518         WSAIoctl(fd,SIO_UDP_CONNRESET,&t,sizeof(t),&x1,sizeof(x1),&x2,0,0);
1519         t = TRUE;
1520         fd1 = socket (AF_INET6, SOCK_DGRAM, 0);
1521         if (fd1 == JVM_IO_ERR) {
1522             NET_ThrowCurrent(env, "Socket creation failed");
1523             return;
1524         }
1525         NET_SetSockOpt(fd1, SOL_SOCKET, SO_BROADCAST, (char*)&t, sizeof(BOOL));
1526         t = FALSE;
1527         WSAIoctl(fd1,SIO_UDP_CONNRESET,&t,sizeof(t),&x1,sizeof(x1),&x2,0,0);
1528         (*env)->SetIntField(env, fd1Obj, IO_fd_fdID, fd1);
1529         SetHandleInformation((HANDLE)(UINT_PTR)fd1, HANDLE_FLAG_INHERIT, FALSE);
1530     } else {
1531         /* drop the second fd */
1532         (*env)->SetObjectField(env, this, pdsi_fd1ID, NULL);
1533     }
1534 }
1535 
1536 /*
1537  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
1538  * Method:    datagramSocketClose
1539  * Signature: ()V
1540  */
1541 JNIEXPORT void JNICALL




 336     int addrlen = sizeof(rmtaddr);
 337 
 338     /*
 339      * A no-op if this OS doesn't support it.
 340      */
 341     if (!supportPortUnreachable()) {
 342         return JNI_FALSE;
 343     }
 344 
 345     /*
 346      * Peek at the queue to see if there is an ICMP port unreachable. If there
 347      * is then receive it.
 348      */
 349     FD_ZERO(&tbl);
 350     FD_SET(fd, &tbl);
 351     while(1) {
 352         if (select(/*ignored*/fd+1, &tbl, 0, 0, &t) <= 0) {
 353             break;
 354         }
 355         if (recvfrom(fd, buf, 1, MSG_PEEK,
 356                          (struct sockaddr *)&rmtaddr, &addrlen) != SOCKET_ERROR) {
 357             break;
 358         }
 359         if (WSAGetLastError() != WSAECONNRESET) {
 360             /* some other error - we don't care here */
 361             break;
 362         }
 363 
 364         recvfrom(fd, buf, 1, 0,  (struct sockaddr *)&rmtaddr, &addrlen);
 365         got_icmp = JNI_TRUE;
 366     }
 367 
 368     return got_icmp;
 369 }
 370 
 371 
 372 /*
 373  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
 374  * Method:    init
 375  * Signature: ()V
 376  */


 491         } else {
 492             NET_ThrowCurrent (env, "Cannot bind");
 493             return;
 494         }
 495     } else {
 496         if (NET_WinBind(fd, (struct sockaddr *)&lcladdr, lcladdrlen, exclBind) == -1) {
 497             if (WSAGetLastError() == WSAEACCES) {
 498                 WSASetLastError(WSAEADDRINUSE);
 499             }
 500             NET_ThrowCurrent(env, "Cannot bind");
 501             return;
 502         }
 503     }
 504 
 505     if (port == 0) {
 506         if (fd == -1) {
 507             /* must be an IPV6 only socket. */
 508             fd = fd1;
 509         }
 510         if (getsockname(fd, (struct sockaddr *)&lcladdr, &lcladdrlen) == -1) {
 511             NET_ThrowCurrent(env, "getsockname");
 512             return;
 513         }
 514         port = ntohs((u_short) GET_PORT (&lcladdr));
 515     }
 516     (*env)->SetIntField(env, this, pdsi_localPortID, port);
 517 }
 518 
 519 
 520 /*
 521  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
 522  * Method:    connect0
 523  * Signature: (Ljava/net/InetAddress;I)V
 524  */
 525 
 526 JNIEXPORT void JNICALL
 527 Java_java_net_TwoStacksPlainDatagramSocketImpl_connect0(JNIEnv *env, jobject this,
 528                                                jobject address, jint port) {
 529     /* The object's field */
 530     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 531     jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);


 683         }
 684         fdObj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
 685     }
 686 
 687     if (IS_NULL(fdObj)) {
 688         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
 689                         "Socket closed");
 690         return;
 691     }
 692     fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 693 
 694     packetBufferLen = (*env)->GetIntField(env, packet, dp_lengthID);
 695     /* Note: the buffer needn't be greater than 65,536 (0xFFFF)...
 696      * the maximum size of an IP packet. Anything bigger is truncated anyway.
 697      */
 698     if (packetBufferLen > MAX_PACKET_LEN) {
 699         packetBufferLen = MAX_PACKET_LEN;
 700     }
 701 
 702     if (connected) {
 703         addrp = 0; /* arg to sendto () null in this case */
 704         addrlen = 0;
 705     } else {
 706       if (NET_InetAddressToSockaddr(env, iaObj, packetPort, (struct sockaddr *)&rmtaddr, &addrlen, JNI_FALSE) != 0) {
 707         return;
 708       }
 709     }
 710 
 711     if (packetBufferLen > MAX_BUFFER_LEN) {
 712 
 713         /*
 714          * On 95/98 if we try to send a datagram >12k to an application
 715          * on the same machine then this will fail silently. Thus we
 716          * catch this situation here so that we can throw an exception
 717          * when this arises.
 718          * On ME if we try to send a datagram with a size greater than
 719          * that supported by the service provider then no error is
 720          * returned.
 721          */
 722         if (!w2k_or_later) { /* avoid this check on Win 2K or better. Does not work with IPv6.
 723                       * Check is not necessary on these OSes */


 740          * than 2048 bytes into several operations of size 2048.
 741          * This saves a malloc()/memcpy()/free() for big
 742          * buffers.  This is OK for file IO and TCP, but that
 743          * strategy violates the semantics of a datagram protocol.
 744          * (one big send) != (several smaller sends).  So here
 745          * we *must* alloc the buffer.  Note it needn't be bigger
 746          * than 65,536 (0xFFFF) the max size of an IP packet.
 747          * anything bigger is truncated anyway.
 748          */
 749         fullPacket = (char *)malloc(packetBufferLen);
 750         if (!fullPacket) {
 751             JNU_ThrowOutOfMemoryError(env, "Send buf native heap allocation failed");
 752             return;
 753         }
 754     } else {
 755         fullPacket = &(BUF[0]);
 756     }
 757 
 758     (*env)->GetByteArrayRegion(env, packetBuffer, packetBufferOffset, packetBufferLen,
 759                                (jbyte *)fullPacket);
 760     if (sendto(fd, fullPacket, packetBufferLen, 0,
 761                (struct sockaddr *)addrp, addrlen) == SOCKET_ERROR) {

 762          NET_ThrowCurrent(env, "Datagram send failed");





 763     }
 764 
 765     if (packetBufferLen > MAX_BUFFER_LEN) {
 766         free(fullPacket);
 767     }
 768 }
 769 
 770 /*
 771  * check which socket was last serviced when there was data on both sockets.
 772  * Only call this if sure that there is data on both sockets.
 773  */
 774 static int checkLastFD (JNIEnv *env, jobject this, int fd, int fd1) {
 775     int nextfd, lastfd = (*env)->GetIntField(env, this, pdsi_lastfdID);
 776     if (lastfd == -1) {
 777         /* arbitrary. Choose fd */
 778         (*env)->SetIntField(env, this, pdsi_lastfdID, fd);
 779         return fd;
 780     } else {
 781         if (lastfd == fd) {
 782             nextfd = fd1;


 828         address = getInetAddress_addr(env, addressObj);
 829         /* We only handle IPv4 for now. Will support IPv6 once its in the os */
 830         family = AF_INET;
 831     }
 832 
 833     do {
 834         retry = FALSE;
 835 
 836         /*
 837          * If a timeout has been specified then we select on the socket
 838          * waiting for a read event or a timeout.
 839          */
 840         if (timeout) {
 841             int ret;
 842             prevTime = JVM_CurrentTimeMillis(env, 0);
 843             ret = NET_Timeout (fd, timeout);
 844             if (ret == 0) {
 845                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
 846                                 "Peek timed out");
 847                 return ret;
 848             } else if (ret == -1) {
 849                 NET_ThrowCurrent(env, "timeout in datagram socket peek");
 850                 return ret;




 851             }
 852         }
 853 
 854         /* now try the peek */
 855         n = recvfrom(fd, buf, 1, MSG_PEEK,
 856                          (struct sockaddr *)&remote_addr, &remote_addrsize);
 857 
 858         if (n == SOCKET_ERROR) {
 859             if (WSAGetLastError() == WSAECONNRESET) {
 860                 jboolean connected;
 861 
 862                 /*
 863                  * An icmp port unreachable - we must receive this as Windows
 864                  * does not reset the state of the socket until this has been
 865                  * received.
 866                  */
 867                 purgeOutstandingICMP(env, this, fd);
 868 
 869                 connected =  (*env)->GetBooleanField(env, this, pdsi_connected);
 870                 if (connected) {
 871                     JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
 872                                        "ICMP Port Unreachable");
 873                     return 0;
 874                 }
 875 
 876                 /*
 877                  * If a timeout was specified then we need to adjust it because
 878                  * we may have used up some of the timeout befor the icmp port
 879                  * unreachable arrived.
 880                  */
 881                 if (timeout) {
 882                     jlong newTime = JVM_CurrentTimeMillis(env, 0);
 883                     timeout -= (jint)(newTime - prevTime);
 884                     if (timeout <= 0) {
 885                         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
 886                                 "Receive timed out");
 887                         return 0;
 888                     }
 889                     prevTime = newTime;
 890                 }
 891 
 892                 /* Need to retry the recv */
 893                 retry = TRUE;
 894             }
 895         }
 896     } while (retry);
 897 
 898     if (n == SOCKET_ERROR && WSAGetLastError() != WSAEMSGSIZE) {
 899         NET_ThrowCurrent(env, "Datagram peek failed");
 900         return 0;
 901     }




 902     setInetAddress_addr(env, addressObj, ntohl(remote_addr.sin_addr.s_addr));
 903     setInetAddress_family(env, addressObj, IPv4);
 904 
 905     /* return port */
 906     return ntohs(remote_addr.sin_port);
 907 }
 908 
 909 JNIEXPORT jint JNICALL
 910 Java_java_net_TwoStacksPlainDatagramSocketImpl_peekData(JNIEnv *env, jobject this,
 911                                            jobject packet) {
 912 
 913      char BUF[MAX_BUFFER_LEN];
 914     char *fullPacket;
 915     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
 916     jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
 917     jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID);
 918 
 919     jbyteArray packetBuffer;
 920     jint packetBufferOffset, packetBufferLen;
 921 


1004     }
1005 
1006     do {
1007         int ret;
1008         retry = FALSE;
1009 
1010         /*
1011          * If a timeout has been specified then we select on the socket
1012          * waiting for a read event or a timeout.
1013          */
1014         if (checkBoth) {
1015             int t = timeout == 0 ? -1: timeout;
1016             prevTime = JVM_CurrentTimeMillis(env, 0);
1017             ret = NET_Timeout2 (fd, fd1, t, &fduse);
1018             /* all subsequent calls to recv() or select() will use the same fd
1019              * for this call to peek() */
1020             if (ret <= 0) {
1021                 if (ret == 0) {
1022                     JNU_ThrowByName(env,JNU_JAVANETPKG "SocketTimeoutException",
1023                                         "Peek timed out");
1024                 } else if (ret == -1) {
1025                     NET_ThrowCurrent(env, "timeout in datagram socket peek");



1026                 }
1027                 if (packetBufferLen > MAX_BUFFER_LEN) {
1028                     free(fullPacket);
1029                 }
1030                 return -1;
1031             }
1032             if (ret == 2) {
1033                 fduse = checkLastFD (env, this, fd, fd1);
1034             }
1035             checkBoth = FALSE;
1036         } else if (timeout) {
1037             if (prevTime == 0) {
1038                 prevTime = JVM_CurrentTimeMillis(env, 0);
1039             }
1040             ret = NET_Timeout (fduse, timeout);
1041             if (ret <= 0) {
1042                 if (ret == 0) {
1043                     JNU_ThrowByName(env,JNU_JAVANETPKG "SocketTimeoutException",
1044                                     "Receive timed out");
1045                 } else if (ret == -1) {
1046                     JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1047                                     "Socket closed");



1048                 }
1049                 if (packetBufferLen > MAX_BUFFER_LEN) {
1050                     free(fullPacket);
1051                 }
1052                 return -1;
1053             }
1054         }
1055 
1056         /* receive the packet */
1057         n = recvfrom(fduse, fullPacket, packetBufferLen, MSG_PEEK,
1058                          (struct sockaddr *)&remote_addr, &remote_addrsize);
1059         port = (int) ntohs ((u_short) GET_PORT((SOCKETADDRESS *)&remote_addr));
1060         if (n == SOCKET_ERROR) {
1061             if (WSAGetLastError() == WSAECONNRESET) {
1062                 jboolean connected;
1063 
1064                 /*
1065                  * An icmp port unreachable - we must receive this as Windows
1066                  * does not reset the state of the socket until this has been
1067                  * received.
1068                  */
1069                 purgeOutstandingICMP(env, this, fduse);
1070 
1071                 connected = (*env)->GetBooleanField(env, this, pdsi_connected);
1072                 if (connected) {
1073                     JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
1074                                        "ICMP Port Unreachable");
1075 
1076                     if (packetBufferLen > MAX_BUFFER_LEN) {
1077                         free(fullPacket);
1078                     }
1079                     return -1;
1080                 }


1207         nsockets ++;
1208     }
1209     if (!IS_NULL(fd1Obj)) {
1210         fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
1211         nsockets ++;
1212     }
1213 
1214     if (nsockets == 2) { /* need to choose one of them */
1215         /* was fduse set in peek? */
1216         fduse = (*env)->GetIntField(env, this, pdsi_fduseID);
1217         if (fduse == -1) {
1218             /* not set in peek(), must select on both sockets */
1219             int ret, t = (timeout == 0) ? -1: timeout;
1220             ret = NET_Timeout2 (fd, fd1, t, &fduse);
1221             if (ret == 2) {
1222                 fduse = checkLastFD (env, this, fd, fd1);
1223             } else if (ret <= 0) {
1224                 if (ret == 0) {
1225                     JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
1226                                     "Receive timed out");
1227                 } else if (ret == -1) {
1228                     JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1229                                     "Socket closed");



1230                 }
1231                 return;
1232             }
1233         }
1234     } else if (!ipv6_supported) {
1235         fduse = fd;
1236     } else if (IS_NULL(fdObj)) {
1237         /* ipv6 supported: and this socket bound to an IPV6 only address */
1238         fduse = fd1;
1239     } else {
1240         /* ipv6 supported: and this socket bound to an IPV4 only address */
1241         fduse = fd;
1242     }
1243 
1244     if (IS_NULL(packet)) {
1245         JNU_ThrowNullPointerException(env, "packet");
1246         return;
1247     }
1248 
1249     packetBuffer = (*env)->GetObjectField(env, packet, dp_bufID);


1284      * If this Windows edition supports ICMP port unreachable and if we
1285      * are not connected then we need to know if a timeout has been specified
1286      * and if so we need to pick up the current time. These are required in
1287      * order to implement the semantics of timeout, viz :-
1288      * timeout set to t1 but ICMP port unreachable arrives in t2 where
1289      * t2 < t1. In this case we must discard the ICMP packets and then
1290      * wait for the next packet up to a maximum of t1 minus t2.
1291      */
1292     connected = (*env)->GetBooleanField(env, this, pdsi_connected);
1293     if (supportPortUnreachable() && !connected && timeout &&!ipv6_supported) {
1294         prevTime = JVM_CurrentTimeMillis(env, 0);
1295     }
1296 
1297     if (timeout && nsockets == 1) {
1298         int ret;
1299         ret = NET_Timeout(fduse, timeout);
1300         if (ret <= 0) {
1301             if (ret == 0) {
1302                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
1303                                 "Receive timed out");
1304             } else if (ret == -1) {
1305                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1306                                 "Socket closed");



1307             }
1308             if (packetBufferLen > MAX_BUFFER_LEN) {
1309                 free(fullPacket);
1310             }
1311             return;
1312         }
1313     }
1314 
1315     /*
1316      * Loop only if we discarding ICMP port unreachable packets
1317      */
1318     do {
1319         retry = FALSE;
1320 
1321         /* receive the packet */
1322         n = recvfrom(fduse, fullPacket, packetBufferLen, 0,
1323                          (struct sockaddr *)&remote_addr, &remote_addrsize);
1324 
1325         if (n == SOCKET_ERROR) {
1326             if (WSAGetLastError() == WSAECONNRESET) {
1327                 /*
1328                  * An icmp port unreachable has been received - consume any other
1329                  * outstanding packets.
1330                  */
1331                 purgeOutstandingICMP(env, this, fduse);
1332 
1333                 /*
1334                  * If connected throw a PortUnreachableException
1335                  */
1336 
1337                 if (connected) {
1338                     JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",
1339                                        "ICMP Port Unreachable");
1340 
1341                     if (packetBufferLen > MAX_BUFFER_LEN) {
1342                         free(fullPacket);
1343                     }
1344 
1345                     return;


1349                  * If a timeout was specified then we need to adjust it because
1350                  * we may have used up some of the timeout before the icmp port
1351                  * unreachable arrived.
1352                  */
1353                 if (timeout) {
1354                     int ret;
1355                     jlong newTime = JVM_CurrentTimeMillis(env, 0);
1356                     timeout -= (jint)(newTime - prevTime);
1357                     prevTime = newTime;
1358 
1359                     if (timeout <= 0) {
1360                         ret = 0;
1361                     } else {
1362                         ret = NET_Timeout(fduse, timeout);
1363                     }
1364 
1365                     if (ret <= 0) {
1366                         if (ret == 0) {
1367                             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
1368                                             "Receive timed out");
1369                         } else if (ret == -1) {
1370                             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1371                                             "Socket closed");



1372                         }
1373                         if (packetBufferLen > MAX_BUFFER_LEN) {
1374                             free(fullPacket);
1375                         }
1376                         return;
1377                     }
1378                 }
1379 
1380                 /*
1381                  * An ICMP port unreachable was received but we are
1382                  * not connected so ignore it.
1383                  */
1384                 retry = TRUE;
1385             }
1386         }
1387     } while (retry);
1388 
1389     /* truncate the data if the packet's length is too small */
1390     if (n > packetBufferLen) {
1391         n = packetBufferLen;


1454  */
1455 JNIEXPORT void JNICALL
1456 Java_java_net_TwoStacksPlainDatagramSocketImpl_datagramSocketCreate(JNIEnv *env,
1457                                                            jobject this) {
1458     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
1459     jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
1460 
1461     int fd, fd1;
1462     int t = TRUE;
1463     DWORD x1, x2; /* ignored result codes */
1464     int ipv6_supported = ipv6_available();
1465 
1466     int arg = -1;
1467 
1468     if (IS_NULL(fdObj) || (ipv6_supported && IS_NULL(fd1Obj))) {
1469         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
1470         return;
1471     } else {
1472         fd =  (int) socket (AF_INET, SOCK_DGRAM, 0);
1473     }
1474     if (fd == SOCKET_ERROR) {
1475         NET_ThrowCurrent(env, "Socket creation failed");
1476         return;
1477     }
1478     SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE);
1479     (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd);
1480     NET_SetSockOpt(fd, SOL_SOCKET, SO_BROADCAST, (char*)&t, sizeof(BOOL));
1481 
1482     if (ipv6_supported) {
1483         /* SIO_UDP_CONNRESET fixes a bug introduced in Windows 2000, which
1484          * returns connection reset errors un connected UDP sockets (as well
1485          * as connected sockets. The solution is to only enable this feature
1486          * when the socket is connected
1487          */
1488         t = FALSE;
1489         WSAIoctl(fd,SIO_UDP_CONNRESET,&t,sizeof(t),&x1,sizeof(x1),&x2,0,0);
1490         t = TRUE;
1491         fd1 = socket (AF_INET6, SOCK_DGRAM, 0);
1492         if (fd1 == SOCKET_ERROR) {
1493             NET_ThrowCurrent(env, "Socket creation failed");
1494             return;
1495         }
1496         NET_SetSockOpt(fd1, SOL_SOCKET, SO_BROADCAST, (char*)&t, sizeof(BOOL));
1497         t = FALSE;
1498         WSAIoctl(fd1,SIO_UDP_CONNRESET,&t,sizeof(t),&x1,sizeof(x1),&x2,0,0);
1499         (*env)->SetIntField(env, fd1Obj, IO_fd_fdID, fd1);
1500         SetHandleInformation((HANDLE)(UINT_PTR)fd1, HANDLE_FLAG_INHERIT, FALSE);
1501     } else {
1502         /* drop the second fd */
1503         (*env)->SetObjectField(env, this, pdsi_fd1ID, NULL);
1504     }
1505 }
1506 
1507 /*
1508  * Class:     java_net_TwoStacksPlainDatagramSocketImpl
1509  * Method:    datagramSocketClose
1510  * Signature: ()V
1511  */
1512 JNIEXPORT void JNICALL