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
|