Groups > Symbian > Symbian EPOC connect > Re: Sockets again...




Sockets again...

Sockets again...
Thu, 16 Feb 2006 15:38:21 +010
Dear Symbian-Developers,

I've got the following problem: My Symbian-web-server just doesn't work as 
it should...
As mentioned in other tutorials, I'm doing the following:

//member-vars:
RSocket iListener;
RSocketServ iServer;
RSocket iblankSocket;
TBuf8<1000> iBuffer;
RFile iFile;

User::LeaveIfError(iServer.Connect(2));
User::LeaveIfError(iFs.Connect());
TInetAddr address(KInetAddrLoop, 80);
User::LeaveIfError(iListener.Open(iServer, KAfInet, KSockStream, 
KProtocolInetTcp));
User::LeaveIfError(iListener.Bind(address));
User::LeaveIfError(iListener.Listen(5));
AcceptNextConnectionL();

AcceptNextConnectionL:
User::LeaveIfError(iblankSocket.Open(iServer));
iListener.Accept(iblankSocket, iStatus);
SetActive();

RunL:
if (iStatus.Int() == KErrNone) {
    iblankSocket.RecvOneOrMore(iBuffer, 0, iStatus, iLength);
}
if (iStatus.Int() == KErrNone) {
    ParseRequestL();
    AcceptNextConnectionL();
}

ParseRequest parses my http-request, and if a (simple in this case) 
.html-file is requested, the following function is called:
  HBufC* uri = HBufC::NewL(aURI.Length());
  TPtr uriPtr = uri->Des();
  uriPtr.Copy(aURI);

  CleanupStack::PushL(uri);
  TFileName fileName(KSrcHTML);
  fileName.Append(uri->Mid(1));
  HBufC* file_path = fileName.AllocL();
  CleanupStack::PushL(file_path);

  CleanupStack::PopAndDestroy(2);

  if (BaflUtils::FileExists(iFs, *file_path)) {
    User::LeaveIfError(iFile.Open(iFs, *file_path, EFileShareReadersOnly | 
EFileRead));

    HBufC8* buffer = HBufC8::NewL(4000);
    TPtr8 bufferPtr = buffer->Des();

    bufferPtr.Copy(KStatus);

    TInt s;
    iFile.Size(s);

    bufferPtr.Append(KContentLength);
    bufferPtr.Append(s);
    bufferPtr.Append(KCRLF8);
    bufferPtr.Append(KContentType);
    bufferPtr.Append(KHTMLContent);
    bufferPtr.Append(KCRLF8);
    bufferPtr.Append(KCRLF8); //empty row
    HBufC8* fileBuffer = HBufC8::NewL(s);
    TPtr8 filePointer = fileBuffer->Des();
    User::LeaveIfError(iFile.Read(filePointer));

    bufferPtr.Append(filePointer);

    TRequestStatus iStatus;
    iblankSocket.Write(*buffer, iStatus);

    iblankSocket.Close();

    iFile.Close();

Well, reading the request (RecvOneOrMore) just works fine - I get the right 
"string".
But as soon as I click on a link of my page in the browser, requesting a 
page from my server, the server crashes... I don't see what the problem is. 
Maybe it's not that good to have the RSocket blank-socket as a 
member-variable? It's right to open and close the (same) socket for every 
connection, isn't it? When using the active-object-concept, it can't be that 
the server just "stops" when i close the blank-socket?

Hopefully anyone can help me, I'm quite stuck...
Thanks in advance
Ronald 

Post Reply
Re: Sockets again...
16 Feb 2006 21:15:50 +0200
"Ronald Petrlic" <petrlic@gmx.at> writes:

> Dear Symbian-Developers,
> 
> I've got the following problem: My Symbian-web-server just doesn't work as

> it should...
> As mentioned in other tutorials, I'm doing the following:
> 
> //member-vars:
> RSocket iListener;
> RSocketServ iServer;
> RSocket iblankSocket;
> TBuf8<1000> iBuffer;
> RFile iFile;
> 
> User::LeaveIfError(iServer.Connect(2));
> User::LeaveIfError(iFs.Connect());
> TInetAddr address(KInetAddrLoop, 80);
> User::LeaveIfError(iListener.Open(iServer, KAfInet, KSockStream, 
> KProtocolInetTcp));
> User::LeaveIfError(iListener.Bind(address));
> User::LeaveIfError(iListener.Listen(5));
> AcceptNextConnectionL();
> 
> AcceptNextConnectionL:
> User::LeaveIfError(iblankSocket.Open(iServer));
> iListener.Accept(iblankSocket, iStatus);
> SetActive();

How does your RunL know whether it's being called because Accept
completed or RecvOneOrMore completed? You need a state variable, say
after Accept:

  iState = EAccept;


> 
> RunL:
> if (iStatus.Int() == KErrNone) {
>     iblankSocket.RecvOneOrMore(iBuffer, 0, iStatus, iLength);
> }
> if (iStatus.Int() == KErrNone) {
>     ParseRequestL();
>     AcceptNextConnectionL();
> }

Above is not working. Your RunL gets called on Accept completion. Then
you issue RecvOneOrMore, which may complete at once (if data has been
received) or not. The correct RunL should be

  if (iStatus.Int() != KErrNone)
     {
     // Something is wrong, just abort serving this connection.
     iblankSocket.Close();
     AcceptNextConnectionL();
     }
  else if (iState == EAccept)
     {
     iblankSocket.RecvOneOrMore(iBuffer, 0, iStatus, iLength);
     iState = EReading;
     SetActive();
     }
  else if (iState == EReading)
     {
     // Except you never know whether you read has received all
     // of the request. RecvOneOrMore may return 1 byte. But,
     // that's for you to redesign your application... (you really need
     // to keep reading and buffering until your request is completely
     // received, and only then call parse...)
     ParseRequestL();
     AcceptNextConnectionL();
     }
  else if (iState == EWriting)
     {
     iblankSocket.Close();
     AcceptNextConnectionL();
     }
  return;

> ParseRequest parses my http-request, and if a (simple in this case) 
> .html-file is requested, the following function is called:
>   HBufC* uri = HBufC::NewL(aURI.Length());
>   TPtr uriPtr = uri->Des();
>   uriPtr.Copy(aURI);
> 
>   CleanupStack::PushL(uri);
>   TFileName fileName(KSrcHTML);
>   fileName.Append(uri->Mid(1));
>   HBufC* file_path = fileName.AllocL();
>   CleanupStack::PushL(file_path);
> 
>   CleanupStack::PopAndDestroy(2);

Ugh.. in above you are destroying your "file_path", all bets are off
when you use it below..

>   if (BaflUtils::FileExists(iFs, *file_path)) {
>     User::LeaveIfError(iFile.Open(iFs, *file_path, EFileShareReadersOnly |

> EFileRead));
> 
>     HBufC8* buffer = HBufC8::NewL(4000);
>     TPtr8 bufferPtr = buffer->Des();
> 
>     bufferPtr.Copy(KStatus);
> 
>     TInt s;
>     iFile.Size(s);
> 
>     bufferPtr.Append(KContentLength);
>     bufferPtr.Append(s);
>     bufferPtr.Append(KCRLF8);
>     bufferPtr.Append(KContentType);
>     bufferPtr.Append(KHTMLContent);
>     bufferPtr.Append(KCRLF8);
>     bufferPtr.Append(KCRLF8); //empty row
>     HBufC8* fileBuffer = HBufC8::NewL(s);
>     TPtr8 filePointer = fileBuffer->Des();
>     User::LeaveIfError(iFile.Read(filePointer));
> 
>     bufferPtr.Append(filePointer);
> 
> //    TRequestStatus iStatus; <--- bad!

NO! You cannot declare your local iStatus for active object. Use the
one in Active object!

>     iblankSocket.Write(*buffer, iStatus);

      iState = EWriting;
      SetActive();
> 
>///     iblankSocket.Close(); <-- do not close!
> 
>     iFile.Close();

Your "fileBuffer" and "buffer" are never released? Anyway,
you cannot
release/resuse the buffer until Write completes in the RunL. Thus, you
need to put buffer in to member variable! (probably allocate it
permanently and reuse the same buffer again, with possible resize, if
needed).





Post Reply
Re: Sockets again...
Tue, 21 Feb 2006 11:00:56 +010
Wow, thank you very much for your answer. It really helped me - now my 
server is working...
I think I got the conecpt of "cooperative multitasking" with active
objects 
now, and I must admit that it isn't that bad I had thought at the 
beginning...

Best regards,
Ronald

"Markku Savela" <msa@moth.iki.fi> schrieb im Newsbeitrag 
news:87accr9kt5.fsf@burp.tkv.asdf.org...
> "Ronald Petrlic" <petrlic@gmx.at> writes:
>
>> Dear Symbian-Developers,
>>
>> I've got the following problem: My Symbian-web-server just doesn't work

>> as
>> it should...
>> As mentioned in other tutorials, I'm doing the following:
>>
>> //member-vars:
>> RSocket iListener;
>> RSocketServ iServer;
>> RSocket iblankSocket;
>> TBuf8<1000> iBuffer;
>> RFile iFile;
>>
>> User::LeaveIfError(iServer.Connect(2));
>> User::LeaveIfError(iFs.Connect());
>> TInetAddr address(KInetAddrLoop, 80);
>> User::LeaveIfError(iListener.Open(iServer, KAfInet, KSockStream,
>> KProtocolInetTcp));
>> User::LeaveIfError(iListener.Bind(address));
>> User::LeaveIfError(iListener.Listen(5));
>> AcceptNextConnectionL();
>>
>> AcceptNextConnectionL:
>> User::LeaveIfError(iblankSocket.Open(iServer));
>> iListener.Accept(iblankSocket, iStatus);
>> SetActive();
>
> How does your RunL know whether it's being called because Accept
> completed or RecvOneOrMore completed? You need a state variable, say
> after Accept:
>
>  iState = EAccept;
>
>
>>
>> RunL:
>> if (iStatus.Int() == KErrNone) {
>>     iblankSocket.RecvOneOrMore(iBuffer, 0, iStatus, iLength);
>> }
>> if (iStatus.Int() == KErrNone) {
>>     ParseRequestL();
>>     AcceptNextConnectionL();
>> }
>
> Above is not working. Your RunL gets called on Accept completion. Then
> you issue RecvOneOrMore, which may complete at once (if data has been
> received) or not. The correct RunL should be
>
>  if (iStatus.Int() != KErrNone)
>     {
>     // Something is wrong, just abort serving this connection.
>     iblankSocket.Close();
>     AcceptNextConnectionL();
>     }
>  else if (iState == EAccept)
>     {
>     iblankSocket.RecvOneOrMore(iBuffer, 0, iStatus, iLength);
>     iState = EReading;
>     SetActive();
>     }
>  else if (iState == EReading)
>     {
>     // Except you never know whether you read has received all
>     // of the request. RecvOneOrMore may return 1 byte. But,
>     // that's for you to redesign your application... (you really need
>     // to keep reading and buffering until your request is completely
>     // received, and only then call parse...)
>     ParseRequestL();
>     AcceptNextConnectionL();
>     }
>  else if (iState == EWriting)
>     {
>     iblankSocket.Close();
>     AcceptNextConnectionL();
>     }
>  return;
>
>> ParseRequest parses my http-request, and if a (simple in this case)
>> .html-file is requested, the following function is called:
>>   HBufC* uri = HBufC::NewL(aURI.Length());
>>   TPtr uriPtr = uri->Des();
>>   uriPtr.Copy(aURI);
>>
>>   CleanupStack::PushL(uri);
>>   TFileName fileName(KSrcHTML);
>>   fileName.Append(uri->Mid(1));
>>   HBufC* file_path = fileName.AllocL();
>>   CleanupStack::PushL(file_path);
>>
>>   CleanupStack::PopAndDestroy(2);
>
> Ugh.. in above you are destroying your "file_path", all bets are
off
> when you use it below..
>
>>   if (BaflUtils::FileExists(iFs, *file_path)) {
>>     User::LeaveIfError(iFile.Open(iFs, *file_path,
EFileShareReadersOnly 
>> |
>> EFileRead));
>>
>>     HBufC8* buffer = HBufC8::NewL(4000);
>>     TPtr8 bufferPtr = buffer->Des();
>>
>>     bufferPtr.Copy(KStatus);
>>
>>     TInt s;
>>     iFile.Size(s);
>>
>>     bufferPtr.Append(KContentLength);
>>     bufferPtr.Append(s);
>>     bufferPtr.Append(KCRLF8);
>>     bufferPtr.Append(KContentType);
>>     bufferPtr.Append(KHTMLContent);
>>     bufferPtr.Append(KCRLF8);
>>     bufferPtr.Append(KCRLF8); //empty row
>>     HBufC8* fileBuffer = HBufC8::NewL(s);
>>     TPtr8 filePointer = fileBuffer->Des();
>>     User::LeaveIfError(iFile.Read(filePointer));
>>
>>     bufferPtr.Append(filePointer);
>>
>> //    TRequestStatus iStatus; <--- bad!
>
> NO! You cannot declare your local iStatus for active object. Use the
> one in Active object!
>
>>     iblankSocket.Write(*buffer, iStatus);
>
>      iState = EWriting;
>      SetActive();
>>
>>///     iblankSocket.Close(); <-- do not close!
>>
>>     iFile.Close();
>
> Your "fileBuffer" and "buffer" are never released?
Anyway, you cannot
> release/resuse the buffer until Write completes in the RunL. Thus, you
> need to put buffer in to member variable! (probably allocate it
> permanently and reuse the same buffer again, with possible resize, if
> needed).
>
>
>
>
>
> 

Post Reply
about | contact