3232import java .io .OutputStream ;
3333import java .io .FileDescriptor ;
3434
35+ /* J2ObjC removed
36+ import dalvik.annotation.optimization.ReachabilitySensitive;
37+ */
3538import dalvik .system .BlockGuard ;
3639import dalvik .system .CloseGuard ;
3740import dalvik .system .SocketTagger ;
@@ -50,8 +53,8 @@ abstract class AbstractPlainSocketImpl extends SocketImpl
5053{
5154 /* instance variable for SO_TIMEOUT */
5255 int timeout ; // timeout in millisec
53- // traffic class
54- int trafficClass ;
56+ // Android-removed: traffic class is set through socket.
57+ // private int trafficClass;
5558
5659 private boolean shut_rd = false ;
5760 private boolean shut_wr = false ;
@@ -237,121 +240,139 @@ public void setOption(int opt, Object val) throws SocketException {
237240 if (isClosedOrPending ()) {
238241 throw new SocketException ("Socket Closed" );
239242 }
243+ // BEGIN Android-removed: Logic dealing with value type moved to socketSetOption.
244+ /*
240245 boolean on = true;
241246 switch (opt) {
242247 /* check type safety b4 going native. These should never
243248 * fail, since only java.Socket* has access to
244249 * PlainSocketImpl.setOption().
245- */
246- case SO_LINGER :
247- if (val == null || (!(val instanceof Integer ) && !(val instanceof Boolean )))
248- throw new SocketException ("Bad parameter for option" );
249- if (val instanceof Boolean ) {
250- /* true only if disabling - enabling should be Integer */
251- on = false ;
252- }
253- break ;
254- case SO_TIMEOUT :
255- if (val == null || (!(val instanceof Integer )))
256- throw new SocketException ("Bad parameter for SO_TIMEOUT" );
257- int tmp = ((Integer ) val ).intValue ();
258- if (tmp < 0 )
259- throw new IllegalArgumentException ("timeout < 0" );
260- timeout = tmp ;
261- break ;
262- case IP_TOS :
263- if (val == null || !(val instanceof Integer )) {
264- throw new SocketException ("bad argument for IP_TOS" );
265- }
266- trafficClass = ((Integer )val ).intValue ();
267- break ;
268- case SO_BINDADDR :
269- throw new SocketException ("Cannot re-bind socket" );
270- case TCP_NODELAY :
271- if (val == null || !(val instanceof Boolean ))
272- throw new SocketException ("bad parameter for TCP_NODELAY" );
273- on = ((Boolean )val ).booleanValue ();
274- break ;
275- case SO_SNDBUF :
276- case SO_RCVBUF :
277- if (val == null || !(val instanceof Integer ) ||
278- !(((Integer )val ).intValue () > 0 )) {
279- throw new SocketException ("bad parameter for SO_SNDBUF " +
280- "or SO_RCVBUF" );
281- }
282- break ;
283- case SO_KEEPALIVE :
284- if (val == null || !(val instanceof Boolean ))
285- throw new SocketException ("bad parameter for SO_KEEPALIVE" );
286- on = ((Boolean )val ).booleanValue ();
287- break ;
288- case SO_OOBINLINE :
289- if (val == null || !(val instanceof Boolean ))
290- throw new SocketException ("bad parameter for SO_OOBINLINE" );
291- on = ((Boolean )val ).booleanValue ();
292- break ;
293- case SO_REUSEADDR :
294- if (val == null || !(val instanceof Boolean ))
295- throw new SocketException ("bad parameter for SO_REUSEADDR" );
296- on = ((Boolean )val ).booleanValue ();
297- break ;
298- default :
299- throw new SocketException ("unrecognized TCP option: " + opt );
250+ *
251+ case SO_LINGER:
252+ if (val == null || (!(val instanceof Integer) && !(val instanceof Boolean)))
253+ throw new SocketException("Bad parameter for option");
254+ if (val instanceof Boolean) {
255+ /* true only if disabling - enabling should be Integer *
256+ on = false;
257+ }
258+ break;
259+ case SO_TIMEOUT:
260+ if (val == null || (!(val instanceof Integer)))
261+ throw new SocketException("Bad parameter for SO_TIMEOUT");
262+ int tmp = ((Integer) val).intValue();
263+ if (tmp < 0)
264+ throw new IllegalArgumentException("timeout < 0");
265+ timeout = tmp;
266+ break;
267+ case IP_TOS:
268+ if (val == null || !(val instanceof Integer)) {
269+ throw new SocketException("bad argument for IP_TOS");
270+ }
271+ trafficClass = ((Integer)val).intValue();
272+ break;
273+ case SO_BINDADDR:
274+ throw new SocketException("Cannot re-bind socket");
275+ case TCP_NODELAY:
276+ if (val == null || !(val instanceof Boolean))
277+ throw new SocketException("bad parameter for TCP_NODELAY");
278+ on = ((Boolean)val).booleanValue();
279+ break;
280+ case SO_SNDBUF:
281+ case SO_RCVBUF:
282+ if (val == null || !(val instanceof Integer) ||
283+ !(((Integer)val).intValue() > 0)) {
284+ throw new SocketException("bad parameter for SO_SNDBUF " +
285+ "or SO_RCVBUF");
286+ }
287+ break;
288+ case SO_KEEPALIVE:
289+ if (val == null || !(val instanceof Boolean))
290+ throw new SocketException("bad parameter for SO_KEEPALIVE");
291+ on = ((Boolean)val).booleanValue();
292+ break;
293+ case SO_OOBINLINE:
294+ if (val == null || !(val instanceof Boolean))
295+ throw new SocketException("bad parameter for SO_OOBINLINE");
296+ on = ((Boolean)val).booleanValue();
297+ break;
298+ case SO_REUSEADDR:
299+ if (val == null || !(val instanceof Boolean))
300+ throw new SocketException("bad parameter for SO_REUSEADDR");
301+ on = ((Boolean)val).booleanValue();
302+ break;
303+ default:
304+ throw new SocketException("unrecognized TCP option: " + opt);
300305 }
301306 socketSetOption(opt, on, val);
307+ */
308+ // END Android-removed: Logic dealing with value type moved to socketSetOption.
309+ // Android-added: Keep track of timeout value not handled by socketSetOption.
310+ if (opt == SO_TIMEOUT ) {
311+ timeout = (Integer ) val ;
312+ }
313+ socketSetOption (opt , val );
302314 }
303-
304315 public Object getOption (int opt ) throws SocketException {
305316 if (isClosedOrPending ()) {
306317 throw new SocketException ("Socket Closed" );
307318 }
308319 if (opt == SO_TIMEOUT ) {
309320 return new Integer (timeout );
310321 }
322+ // BEGIN Android-changed: Logic dealing with value type moved to socketGetOption.
323+ /*
311324 int ret = 0;
312325 /*
313326 * The native socketGetOption() knows about 3 options.
314327 * The 32 bit value it returns will be interpreted according
315328 * to what we're asking. A return of -1 means it understands
316329 * the option but its turned off. It will raise a SocketException
317330 * if "opt" isn't one it understands.
318- */
331+ *
319332
320333 switch (opt) {
321- case TCP_NODELAY :
322- ret = socketGetOption (opt , null );
323- return Boolean .valueOf (ret != -1 );
324- case SO_OOBINLINE :
325- ret = socketGetOption (opt , null );
326- return Boolean .valueOf (ret != -1 );
327- case SO_LINGER :
328- ret = socketGetOption (opt , null );
329- return (ret == -1 ) ? Boolean .FALSE : (Object )(new Integer (ret ));
330- case SO_REUSEADDR :
331- ret = socketGetOption (opt , null );
332- return Boolean .valueOf (ret != -1 );
333- case SO_BINDADDR :
334- InetAddressContainer in = new InetAddressContainer ();
335- ret = socketGetOption (opt , in );
336- return in .addr ;
337- case SO_SNDBUF :
338- case SO_RCVBUF :
339- ret = socketGetOption (opt , null );
340- return new Integer (ret );
341- case IP_TOS :
334+ case TCP_NODELAY:
335+ ret = socketGetOption(opt, null);
336+ return Boolean.valueOf(ret != -1);
337+ case SO_OOBINLINE:
338+ ret = socketGetOption(opt, null);
339+ return Boolean.valueOf(ret != -1);
340+ case SO_LINGER:
341+ ret = socketGetOption(opt, null);
342+ return (ret == -1) ? Boolean.FALSE: (Object)(new Integer(ret));
343+ case SO_REUSEADDR:
344+ ret = socketGetOption(opt, null);
345+ return Boolean.valueOf(ret != -1);
346+ case SO_BINDADDR:
347+ InetAddressContainer in = new InetAddressContainer();
348+ ret = socketGetOption(opt, in);
349+ return in.addr;
350+ case SO_SNDBUF:
351+ case SO_RCVBUF:
352+ ret = socketGetOption(opt, null);
353+ return new Integer(ret);
354+ case IP_TOS:
355+ try {
342356 ret = socketGetOption(opt, null);
343357 if (ret == -1) { // ipv6 tos
344- return new Integer ( trafficClass ) ;
358+ return trafficClass;
345359 } else {
346- return new Integer ( ret ) ;
360+ return ret;
347361 }
348- case SO_KEEPALIVE :
349- ret = socketGetOption (opt , null );
350- return Boolean .valueOf (ret != -1 );
351- // should never get here
352- default :
353- return null ;
362+ } catch (SocketException se) {
363+ // TODO - should make better effort to read TOS or TCLASS
364+ return trafficClass; // ipv6 tos
365+ }
366+ case SO_KEEPALIVE:
367+ ret = socketGetOption(opt, null);
368+ return Boolean.valueOf(ret != -1);
369+ // should never get here
370+ default:
371+ return null;
354372 }
373+ */
374+ return socketGetOption (opt );
375+ // END Android-changed: Logic dealing with value type moved to socketGetOption.
355376 }
356377
357378 /**
@@ -542,12 +563,44 @@ protected void close() throws IOException {
542563 if (!stream ) {
543564 ResourceManager .afterUdpClose ();
544565 }
545- if (closePending ) {
546- return ;
566+ // Android-changed: Socket should be untagged before the preclose.
567+ // After preclose, socket will dup2-ed to marker_fd, therefore, it won't describe
568+ // the same file. If closingPending is true, then the socket has been preclosed.
569+ //
570+ // Also, close the CloseGuard when the #close is called.
571+ if (!closePending ) {
572+ closePending = true ;
573+ guard .close ();
574+
575+ if (fdUseCount == 0 ) {
576+ /*
577+ * We close the FileDescriptor in two-steps - first the
578+ * "pre-close" which closes the socket but doesn't
579+ * release the underlying file descriptor. This operation
580+ * may be lengthy due to untransmitted data and a long
581+ * linger interval. Once the pre-close is done we do the
582+ * actual socket to release the fd.
583+ */
584+ try {
585+ socketPreClose ();
586+ } finally {
587+ socketClose ();
588+ }
589+ // Android-changed: Closed sockets use an invalid fd, not null. b/26470377
590+ // socketClose invalidates the fd by closing the fd.
591+ // fd = null;
592+ return ;
593+ } else {
594+ /*
595+ * If a thread has acquired the fd and a close
596+ * isn't pending then use a deferred close.
597+ * Also decrement fdUseCount to signal the last
598+ * thread that releases the fd to close it.
599+ */
600+ fdUseCount --;
601+ socketPreClose ();
602+ }
547603 }
548- closePending = true ;
549- socketClose ();
550- return ;
551604 }
552605 }
553606 }
@@ -701,40 +754,45 @@ public int getTimeout() {
701754 return timeout ;
702755 }
703756
757+ /*
758+ * "Pre-close" a socket by dup'ing the file descriptor - this enables
759+ * the socket to be closed without releasing the file descriptor.
760+ */
761+ private void socketPreClose () throws IOException {
762+ socketClose0 (true );
763+ }
764+
704765 /*
705766 * Close the socket (and release the file descriptor).
706767 */
707768 protected void socketClose () throws IOException {
708- guard .close ();
709-
710- socketClose0 ();
769+ socketClose0 (false );
711770 }
712771
713772 abstract void socketCreate (boolean isServer ) throws IOException ;
714773 abstract void socketConnect (InetAddress address , int port , int timeout )
715- throws IOException ;
774+ throws IOException ;
716775 abstract void socketBind (InetAddress address , int port )
717- throws IOException ;
776+ throws IOException ;
718777 abstract void socketListen (int count )
719- throws IOException ;
778+ throws IOException ;
720779 abstract void socketAccept (SocketImpl s )
721- throws IOException ;
780+ throws IOException ;
722781 abstract int socketAvailable ()
723- throws IOException ;
724- abstract void socketClose0 ()
725- throws IOException ;
782+ throws IOException ;
783+ abstract void socketClose0 (boolean useDeferredClose )
784+ throws IOException ;
726785 abstract void socketShutdown (int howto )
727- throws IOException ;
728- abstract void socketSetOption (int cmd , boolean on , Object value )
729- throws SocketException ;
730- abstract int socketGetOption (int opt , Object iaContainerObj ) throws SocketException ;
786+ throws IOException ;
787+
788+ // Android-changed: Method signature changes.
789+ // socket{Get,Set}Option work directly with Object values.
790+ abstract void socketSetOption (int cmd , Object value ) throws SocketException ;
791+ abstract Object socketGetOption (int opt ) throws SocketException ;
792+
731793 abstract void socketSendUrgentData (int data )
732- throws IOException ;
794+ throws IOException ;
733795
734796 public final static int SHUT_RD = 0 ;
735797 public final static int SHUT_WR = 1 ;
736798}
737-
738- class InetAddressContainer {
739- InetAddress addr ;
740- }
0 commit comments