Skip to contentSkip to conversation

DCCP support in VLC

DISCUSSION Rémi Denis-Courmont 4 participants 8 messages Sep 27, 2007 – Oct 6, 2007

lore
Share & tools
lore
#0 lore raw

Hello (again)!

Le Thursday 27 September 2007 11:36:27, vous avez écrit :

Quoted 16 lines
|  I am having a few API problems now:
|
|  First, TCP-like non-blocking connect() error handling does not seem to
| work properly (2.6.22). I don't know if this is an intended difference
| from TCP. VLC follows a pretty typical non-blocking connect flow:
|
|  socket()
|  fcntl(F_SETFL, O_NONBLOCK)
|  connect() = -1 (errno = EINPROGRESS)
|  poll(POLLOUT) = 1
|  getsockopt(SOL_SOCKET, SO_ERROR) = 0 (val = ECONNREFUSED)
|
|  Alas with DCCP, getsockopt returns 0 instead of ECONNREFUSED, even
| though tcpdump reports a reset packet on the wire. And then VLC thinks
| the connection succeeded, and well, tries to read from the socket...
Quoted 4 lines

Two questions - first, are you ok with me copying the above to dccp@vger? My hands are full with other work, yet I believe the API should match that of TCP as close as possible (and that has been a main emphasis of the work).

No problem. Here goes.

Quoted 34 lines

Second question: did you try the patches I sent you? I believed that I had solved the problem, see the hunk below from src/network/udp.c. This works fine (I watched a full DVD over DCCPv6 with CCID2 yesterday and have been using this for weeks). It is another technique for non-blocking connect.

If you can teach me why your approach leads to the above error and why the approach below works, we would be one step further - so do let me know.

(quoted diff) +16 -0
@@ -667,6 +669,30 @@ int __net_ConnectDgram( vlc_object_t *p_
 #endif
             b_unreach = VLC_TRUE;
         else
+        if ( errno = EINPROGRESS )
+        {
+            fd_set wfds;
+            int so_error = -1;
+            socklen_t optlen = sizeof (int);
+
+            FD_ZERO(&wfds);
+            FD_SET(fd, &wfds);
+            msg_Warn( p_this, "IN PROGRESS %s port %d : %s", psz_host,
 i_port, +                      strerror( errno ) );
+            if (select(fd + 1, NULL, &wfds, NULL, NULL) < 0)
+            {
+                msg_Err( p_this, "cannot connect to %s port %d : %s",
 psz_host, i_port, +                         strerror( errno ) );
+                return -1;
+            }
+            i_handle = fd;
+            if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &so_error, &optlen) <

0) + msg_Err( p_this, "cannot get SO_ERROR: %s", strerror(
errno ) ); + else
+ msg_Dbg( p_this, "connect completed %fully", so_error?
"UNSUCCESS" : "success"); + break;

Review

Quoted 5 lines
(quoted diff) +2 -0
+        }
+        else
         {
             msg_Warn( p_this, "%s port %d : %s", psz_host, i_port,
                       strerror( errno ) );

The issue with the above patch was, it does actually check the so_error (apart from printing a debug message), so the caller does not know whether connect() succeeded or failed. (Another problem is that it broke the lame way VLC does thread cancellation but that's my problem, not yours).
But your other kernel patch solved that now :-)

So so, now I have yet another API problem :-$ When the peer shutdowns/closes the connection, recv() returns 0 (as with TCP). When the peer sends a zero-byte payload datagram, recv() also seems to return 0 (as with UDP). How do I differentiate? With TCP and UDP, this is unambiguous because UDP has no such thing as shutdown, and TCP has no framing, so no empty payloads at application-layer. Is the idea to assume that 0 means shutdown and the peer is anyway brain-dead if it sends empty datagrams?

N.B.: please cc me on replies.

Signature · 2 lines
Rémi Denis-Courmont
http://www.remlab.net/
#1 lore raw

Quoting Rémi Denis-Courmont:

|  > |  I am having a few API problems now:
|  > |
|  > |  First, TCP-like non-blocking connect() error handling does not seem to
|  > | work properly (2.6.22). I don't know if this is an intended difference
|  > | from TCP. VLC follows a pretty typical non-blocking connect flow:
|  > |
|  > |  socket()
|  > |  fcntl(F_SETFL, O_NONBLOCK)
|  > |  connect() = -1 (errno = EINPROGRESS)
|  > |  poll(POLLOUT) = 1
|  > |  getsockopt(SOL_SOCKET, SO_ERROR) = 0 (val = ECONNREFUSED)
|  > |
|  > |  Alas with DCCP, getsockopt returns 0 instead of ECONNREFUSED, even
|  > | though tcpdump reports a reset packet on the wire. And then VLC thinks
|  > | the connection succeeded, and well, tries to read from the socket...

<snip>
| But your other kernel patch solved that now :-)
Thanks, this is good to know, but the patch that I sent you privately is not in a submittable state; I will tidy that up and resubmit it to the list.

|  So so, now I have yet another API problem :-$ When the peer shutdowns/closes 
|  the connection, recv() returns 0 (as with TCP). When the peer sends a 
|  zero-byte payload datagram, recv() also seems to return 0 (as with UDP).
|  How do I differentiate? With TCP and UDP, this is unambiguous because UDP has 
|  no such thing as shutdown, and TCP has no framing, so no empty payloads at 
|  application-layer.

It seems you are trying to use length=0 as End-Of-File? Works in TCP since it is byte-stream, but DCCP is between UDP and TCP, so an empty frame is a valid pay-`load'.

When the Reset closing the connection arrives, the same shutdown mask is set as in TCP. What I thus think you could do as a test-for-end-of-connection is to test whether the socket descriptor is still read/writeable.

Arnaldo, Ian - do you have suggestions?

A note on shutdown: this also works as in TCP. When you know that you will be using the connection only in one direction, calling shutdown() for the unused direction has distinct advantages, since it will mean that the CCID-halves which are not participating in the traffic will be bypassed, which improves the performance.

#2 lore raw
In reply to Rémi Denis-Courmont

Le Friday 28 September 2007 14:33:51 Gerrit Renker, vous avez écrit :

Quoted 4 lines

When the Reset closing the connection arrives, the same shutdown mask is set as in TCP. What I thus think you could do as a test-for-end-of-connection is to test whether the socket descriptor is still read/writeable.

If it works like TCP, shutdown-for-recv will make the socket always readable, and will not affect writeability at all, since the sending half may still be open. As such, I don't think it will solve the problem.

Currently, I am assuming that length = 0 means end-of-connection, because I only use RTP/RTCP, so zero bytes is not a valid packet length. But that's a little bit ugly.

Other than that, and apart from pending DCCP service code support I am happy to announce that the official VLC development tree now support DCCP out-of-the-box with RTP.

Manually, on the sender (assuming sender IP is 2001:db8::1):

$ vlc -vv /dev/dvd \
--sout '#rtp{dccp,mux=ts,portP04}'

On the receiver:

$ vlc -vv dccp://[2001:db8::1]:5004

Or advertized with SAP, on the sender:

$ vlc -vv /dev/dvd \
--sout '#rtp{dccp,mux=ts,portP04,dst 01:db8::1,sdp=sap,name=MyDVD}'

On the receiver, enable SAP service discovery and click MyDVD from the playlist.

We cannot support multiple streams per session, because the live555 library does not support DCCP at this time. But TS multiplexing works great anyway.

Thanks for your help!

Signature · 2 lines
Rémi Denis-Courmont
http://www.remlab.net/
#3 lore raw
In reply to Rémi Denis-Courmont
|  Other than that, and apart from pending DCCP service code support I am happy 
|  to announce that the official VLC development tree now support DCCP 
|  out-of-the-box with RTP.
|

Great! That means that the old hack (which you commented on earlier) on
http://www.erg.abdn.ac.uk/users/gerrit/dccp/apps/#VLC_Patch
can go in favour of something properly integrated with the VLC code. Many thanks for looking after this.

I am assuming that this relies on the non-blocking connect you described? If yes, I shall make sure that the patch to do this is tidied up and submit it early next week - this needs some more thought.

Excellent news!

|  Manually, on the sender (assuming sender IP is 2001:db8::1):
|  $ vlc -vv /dev/dvd \
|  --sout '#rtp{dccp,mux=ts,portP04}'
|  
|  On the receiver:
|  $ vlc -vv dccp://[2001:db8::1]:5004
|  
|  Or advertized with SAP, on the sender:
|  $ vlc -vv /dev/dvd \
|  --sout '#rtp{dccp,mux=ts,portP04,dst 01:db8::1,sdp=sap,name=MyDVD}'
|  
|  On the receiver, enable SAP service discovery and click MyDVD from the 
|  playlist.
|  
|  
|  We cannot support multiple streams per session, because the live555 library 
|  does not support DCCP at this time. But TS multiplexing works great anyway.
#4 lore raw
In reply to Rémi Denis-Courmont

Le Friday 28 September 2007 18:40:04 Gerrit Renker, vous avez écrit :

Quoted 4 lines
|  Other than that, and apart from pending DCCP service code support I am
| happy to announce that the official VLC development tree now support DCCP
| out-of-the-box with RTP.
Quoted 8 lines

Great! That means that the old hack (which you commented on earlier) on
http://www.erg.abdn.ac.uk/users/gerrit/dccp/apps/#VLC_Patch
can go in favour of something properly integrated with the VLC code. Many thanks for looking after this.

I am assuming that this relies on the non-blocking connect you described? If yes, I shall make sure that the patch to do this is tidied up and submit it early next week - this needs some more thought.

Indeed without the patch, VLC will fail to detect "refused" DCCP connection as failed.

Signature · 2 lines
Rémi Denis-Courmont
http://www.remlab.net/
#5 lore raw
In reply to Rémi Denis-Courmont
|  > When the Reset closing the connection arrives, the same shutdown mask is
|  > set as in TCP. What I thus think you could do as a
|  > test-for-end-of-connection is to test whether the socket descriptor is
|  > still read/writeable.
|  
|  If it works like TCP, shutdown-for-recv will make the socket always readable, 
|  and will not affect writeability at all, since the sending half may still be 
|  open. As such, I don't think it will solve the problem.

DCCP has no half-close (RFC 4340, 4.6), so closing the socket shuts down both the read and the write end (i.e. SHUT_RDWR is set by the kernel) - you could test for this.

|  Currently, I am assuming that length = 0 means end-of-connection, because I 
|  only use RTP/RTCP, so zero bytes is not a valid packet length. But that's a 
|  little bit ugly.

It would be better to use a different solution. There has also been discussion to use 0-sized packets for keep-alive or congestion messages (I hope that this remains talk only).

#6 lore raw
In reply to Rémi Denis-Courmont
Quoted 8 lines · Gerrit Renker
|  > When the Reset closing the connection arrives, the same shutdown mask is
|  > set as in TCP. What I thus think you could do as a
|  > test-for-end-of-connection is to test whether the socket descriptor is
|  > still read/writeable.
|  
|  If it works like TCP, shutdown-for-recv will make the socket always readable, 
|  and will not affect writeability at all, since the sending half may still be 
|  open. As such, I don't think it will solve the problem.
Quoted 9 lines

DCCP has no half-close (RFC 4340, 4.6), so closing the socket shuts down both the read and the write end (i.e. SHUT_RDWR is set by the kernel)
- you could test for this.

|  Currently, I am assuming that length = 0 means end-of-connection, because I 
|  only use RTP/RTCP, so zero bytes is not a valid packet length. But that's a 
|  little bit ugly.

It would be better to use a different solution.

I agree.

Quoted 4 lines

There has also been discussion to use
0-sized packets for keep-alive or congestion messages (I hope that this remains talk only).

It's my understanding that the use of zero-length DATA packets as transport-layer
keep alives (to probe for congestion status) was removed from the Faster Restart proposal at the last IETF DCCP WG meeting.
This use was omitted from the latest revision of the FR draft.

However, DCCP still does allow the application to send zero-sized DATA from the API, just as UDP currently permits. (You may never wish to use this if you have an application layered over RTP.)

Gorry

#7 lore raw
In reply to Rémi Denis-Courmont

A quick note on half-close.

The DCCP state machine has no half-closed state, but the Data Dropped option's Drop Code 1, "Application Not Listening", can be used like a TCP shutdown-for-receive.

Eddie

Quoted 42 lines · Gorry Fairhurst
Quoted 15 lines · Gerrit Renker

| > When the Reset closing the connection arrives, the same shutdown mask is

|  > set as in TCP. What I thus think you could do as a
|  > test-for-end-of-connection is to test whether the socket 
descriptor is
|  > still read/writeable.
|  |  If it works like TCP, shutdown-for-recv will make the socket 

always readable, | and will not affect writeability at all, since the sending half may still be | open. As such, I don't think it will solve the problem.
DCCP has no half-close (RFC 4340, 4.6), so closing the socket shuts down both the
read and the write end (i.e. SHUT_RDWR is set by the kernel) - you could test for this.

Quoted 5 lines

| Currently, I am assuming that length = 0 means end-of-connection, because I | only use RTP/RTCP, so zero bytes is not a valid packet length. But that's a | little bit ugly.
It would be better to use a different solution.

I agree.

Quoted 4 lines

There has also been discussion to use
0-sized packets for keep-alive or congestion messages (I hope that this remains talk only).

It's my understanding that the use of zero-length DATA packets as transport-layer
keep alives (to probe for congestion status) was removed from the Faster Restart proposal at the last IETF DCCP WG meeting.
This use was omitted from the latest revision of the FR draft.

However, DCCP still does allow the application to send zero-sized DATA from the API, just as UDP currently permits. (You may never wish to use this if you have an application layered over RTP.)

Gorry
-
To unsubscribe from this list: send the line "unsubscribe dccp" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html