I use C # sockets to implement my own RTSP core server (for training). I am currently writing logic for a server to do a handshake with a client when negotiating media ports at the request of DESCRIBE.
The client application was not written by me, and I do not have access to software updates, it is a simple RTSP client that negotiates media ports on a Cisco router and then transfers audio to clients connected to it.
The payload that I want to send back is 1024 bytes and a 64-byte header, and from what I see when checking my client application, only 400 bytes are sent back to the client.
The response payload is defined in C # as:
// Build the RTSP Response string var body = "v=0\n" + "o=- 575000 575000 IN IP4 " + m_serverIP + "\n" + "s=" + stream + "\n" + "i=<No author> <No copyright>\n" + "c= IN IP4 0.0.0.0\n"+ "t=0 0\n" + "a=SdpplinVersion:1610641560\n" + "a=StreamCount:integer;1\n" + "a=control:*\n" + "a=Flags:integer;1\n" + "a=HasParam:integer;0\n" + "a=LatencyMode:integer;0\n" + "a=LiveStream:integer;1\n" + "a=mr:intgner;0\n" + "a=nr:integer;0\n" + "a=sr:integer;0\n" + "a=URL:string;\"Streams/" + stream + "\"\n" + "a=range:npt=0-\n" + "m=audio 0 RTP/AVP 8" + // 49170 is the RTP transport port and 8 is A-Law audio "b=AS:90\n" + "b=TIAS:64000\n" + "b=RR:1280\n" + "b=RS:640\n" + "a=maxprate:50.000000\n" + "a=control:streamid=1\n" + "a=range:npt=0-\n" + "a=length:npt=0\n" + "a=rtpmap:8 pcma/8000/1\n" + "a=fmtp:8" + "a=mimetype:string;\"audio/pcma\"\n" + "a=ASMRuleBook:string;\"marker=0, Avera**MSG 00053 TRUNCATED**\n" + "**MSG 0053 CONTINUATION #01**geBandwidth=64000, Priority=9, timestampdelivery=true;\"\n" + "a=3GPP-Adaptation-Support:1\n" + "a=Helix-Adaptation-Support:1\n" + "a=AvgBitRate:integer;64000\n" + "a=AvgPacketSize:integer;160\n" + "a=BitsPerSample:integer;16\n" + "a=LiveStream:integer;1\n" + "a=MaxBitRate:integer;64000\n" + "a=MaxPacketSize:integer;160\n" + "a=Preroll:integer;2000\n" + "a=StartTime:integer;0\n" + "a=OpaqueData:buffer;\"AAB2dwAGAAEAAB9AAAAfQAABABAAAA==\""; var header = "RTSP/1.0 200 OK\n" + "Content-Length: " + body.Length + "\n" + "x-real-usestrackid:1\n" + "Content-Type: application/sdp\n" + "Vary: User-Agent, ClientID\n" + "Content-Base: " + requestURI + "\n" + "vsrc:" + m_serverIP + "/viewsource/template.html\n" + "Set-Cookie: " + Auth.getCookie() + "\n" + "Date: " + System.DateTime.Now + "\n" + "CSeq: 0\n"; var response = header + body; var byteArray = System.Text.Encoding.UTF8.GetBytes(response); respondToClient(byteArray, socket);
The respondToClient method respondToClient implemented as:
private static void respondToClient(byte[] byteChunk, Socket socket) { socket.BeginSend(byteChunk, 0, byteChunk.Length, SocketFlags.None, new AsyncCallback(SendCallback), socket); socket.BeginReceive(m_dataBuffer, 0, m_dataBuffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), socket); }
Using SendCallback to determine when a packet was sent to a client:
private static void SendCallback(IAsyncResult res) { try { var socket = (Socket)res.AsyncState; socket.EndSend(res); } catch (Exception e) { Console.Write(e.Message); } }
Why is my client application receiving only 400 bytes, and if so, how can I make sure the whole packet is sent (I use TCP)? Is this a hard limit set by C #? I consulted with MSDN and could not find any information to support this theory.
If you need more information about the implementation of my server, please ask.
EDIT Here is some food for thought, and I donβt know why this would happen if someone could enlighten me, which would be great ... @ Gregory A Beamer suggested in the comments that EndSend might work prematurely, is this possible? In my opinion, I thought that the async callback would only work once, and only after all the bytes were sent from the server to the client socket for listening.
To indicate that the packet was not completely received by the client, the following information indicates that the client application receives only 400 bytes:

Supported by wire tracing from S-> C

UPDATE . Speaking earlier with @usr, I did some additional tests and now I can confirm that the client application will receive a 400-byte response only from the server. i h
Jul 1 13:28:29: //-1//RTSP:/rtsp_read_svr_resp: Socket = 0 Jul 1 13:28:29: //-1//RTSP:/rtsp_read_svr_resp: NBYTES = 1384 Jul 1 13:28:29: //-1//RTSP:/rtsp_process_single_svr_resp: Jul 1 13:28:29: rtsp_process_single_svr_resp: 400 bytes of data: RTSP/1.0 200 OK Content-Length: 1012 x-real-usestrackid:1 Content-Type: application/sdp Vary: User-Agent, ClientID Content-Base: rtsp://10.96.134.50/streams/stream01.dcw vsrc:10.96.134.50/viewsource/template.html Set-Cookie: cbid=aabtvqjcldwjwjbatynprfpfltxaspyopoccbtewiddxuzhsesflnkzvkwibtikwfhuhhzzz;path=/;expires=09/10/2015 14:28:38 Date: 01/07/2015 14:28:38 CSeq: 0 v=0 o=- 575000 575000 IN IP4
^ This is the log trace reset by the client application when I dial the number on the server, here we see that it takes 1384 bytes back from the client, but its processing buffer can only store 400 bytes. I looked at the log for an existing application that handles streaming on the same device, and in a wirehark trace instead of sending a header in one block, sends several fragments back with information [TCP segment of a reassembled PDU] I'm not sure what this means (new to network material), but I assume that he broke the server payload and sent it in several fragments, and then reassembled it on the client to process the request.
How can I reproduce this behavior on my server application? I tried the following in my response method, hoping that it would return the package and collect it again on the client, however, I just kept getting the same error that was mentioned above:
private static void respondToClient(byte[] byteChunk, Socket socket) { // Divide the byte chunk into 300 byte chunks if (byteChunk.Length >= 400) { Console.WriteLine("Total bytes: " + byteChunk.Length); var totalBytes = byteChunk.Length; var chunkSize = 400; var tmp = new byte[chunkSize]; var packets = totalBytes / chunkSize; var overflow = totalBytes % chunkSize; Console.WriteLine("Sending " + totalBytes + " in " + packets + " packets, with an overflow packets of " + overflow + " bytes."); for (var i = 0; i < packets * chunkSize; i+=chunkSize) { Console.WriteLine("Sending chunk " + i + " to " + (i + chunkSize)); tmp = byteChunk.Skip(i).Take(chunkSize).ToArray(); socket.BeginSend(tmp, 0, tmp.Length, SocketFlags.None, new AsyncCallback(SendCallback), socket); } if (overflow > 0) { Console.WriteLine("Sending overflow chunk: " + overflow + " at index " + (totalBytes - overflow) + " to " + (totalBytes )); tmp = byteChunk.Skip(byteChunk.Length - overflow).Take(overflow).ToArray(); socket.BeginSend(tmp, 0, tmp.Length, SocketFlags.None, new AsyncCallback(SendCallback), socket); } } else { socket.BeginSend(byteChunk, 0, byteChunk.Length, SocketFlags.None, new AsyncCallback(SendCallback), socket); socket.BeginReceive(m_dataBuffer, 0, m_dataBuffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), socket); } }