#1 2014-10-04 01:35:06

avista
Member
Registered: 2014-01-06
Posts: 63

AV in TSQLHttpServer.Create() when port already in use

If I attempt to create an instance of the HTTP Server when the port is already in use, I get an AV:

To reproduce this error, I ran another server that binds the same port (8080 in this case), and then ran the Project14ServerHttpWeak project with this same port:

20141003 18173830  +    TSQLHttpServer(008285A8).00515016 
20141003 18174030 EXC   	ECommunicationException ("TSQLHttpServer.Create: Impossible to register URL for root") at 005152E0  stack trace API 0048FA84 
20141003 18174030 ERROR 	TSQLHttpServer(008285A8) {"ECommunicationException":"TSQLHttpServer.Create: Impossible to register URL for root"}{"ECommunicationException(008130C0)":[20141003 18174138 EXCOS 	EAccessViolation (C0000005) at 0047E7B5  stack trace API 0048FA84 00407CC0 76F7B46B 76F30133 0047F936 00492532 00490DA6 0051533C 0051ACCD 76A2338A 76F59F72 76F59F45 
 stack trace API 00490DA6 0051533C 0051ACCD 76A2338A 76F59F72 76F59F45 
20141003 18174139  -    03.139.726
20141003 18174140 EXCOS EAccessViolation (C0000005) at 0047E7B5  stack trace API 0048FA84 0040816E 76F7B46B 76F30133 0047F936 00492532 00490DA6 0051533C 0051ACCD 76A2338A 76F59F72 76F59F45 
20141003 18174140  +    TSQLRestServerFullMemory(00791670).Shutdown
20141003 18174140 info  	CurrentRequestCount=0
20141003 18174140  -    00.004.698
20141003 18174140 info  TSQLRestServerFullMemory.Destroy -> null

The problem occurs when the fHttpServer instance is freed in mORMotHttpServer.pas here:

constructor TSQLHttpServer.Create(const aPort: AnsiString;
  const aServers: array of TSQLRestServer; const aDomainName: AnsiString;
  aHttpServerKind: TSQLHttpServerOptions; ServerThreadPoolCount: Integer;
  aHttpServerSecurity: TSQLHttpServerSecurity);
...
  {$ifndef USETCPPREFIX}
  if aHttpServerKind in [useHttpApi,useHttpApiRegisteringURI] then
  try
    // first try to use fastest http.sys
    fHttpServer := THttpApiServer.Create(false);
    for i := 0 to high(aServers) do begin
      j := THttpApiServer(fHttpServer).AddUrl(
        aServers[i].Model.Root,aPort,(aHttpServerSecurity=secSSL),aDomainName,
        (aHttpServerKind=useHttpApiRegisteringURI));
      if j<>NO_ERROR then begin
        ErrMsg := 'Impossible to register URL';
        if j=ERROR_ACCESS_DENIED then
          ErrMsg := ErrMsg+' (administrator rights needed)';
        raise ECommunicationException.CreateFmt('%s.Create: %s for %s',
          [ClassName,ErrMsg,aServers[i].Model.Root]);
        break;
      end;
    end;
  except
    on E: Exception do begin
      {$ifdef WITHLOG}
      Log.Log(sllError,'% for %',[E,fHttpServer],self);
      {$endif}
      FreeAndNil(fHttpServer); // if http.sys initialization failed <<=================================================
    end;
  end;
  {$endif}
...

Also, the next thing it does is try to create a instance of the pure Delphi server, which will also fail:

  if fHttpServer=nil then begin
    // http.sys failed -> create one instance of our pure Delphi server
    fHttpServer := THttpServer.Create(aPort
      {$ifdef USETHREADPOOL},ServerThreadPoolCount{$endif});
    {$ifdef USETCPPREFIX}
    THttpServer(fHttpServer).TCPPrefix := 'magic';
    {$endif}
  end;

Aside from the error condition being unrecoverable (which is especially problematic for a service application), is there a way to ensure that the 'pure' Delphi server is never used?  I don't want to assume a server is running using the kernel http.sys when it might not be.

Thanks

Offline

#2 2014-10-04 10:04:07

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,662
Website

Re: AV in TSQLHttpServer.Create() when port already in use

Could you please create a ticket?
With a link to this forum thread, please.

Offline

#3 2014-10-07 17:46:01

avista
Member
Registered: 2014-01-06
Posts: 63

Re: AV in TSQLHttpServer.Create() when port already in use

Offline

#4 2014-10-08 17:40:12

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,662
Website

Re: AV in TSQLHttpServer.Create() when port already in use

In fact, I'm afraid this was as design.
Your server code has to protect and handle any exception.

For instance, Project27ServerTest.dpr should be written at least:

  SQLite3Log.Family.Level := LOG_VERBOSE;
  try
    Test;
  except
    on E: Exception do
     ; // handle error here
  end;

Then, in case of error, there is no Access Violation, but the succession of exceptions, as expected...

Do you have some code to show (a simple .dpr may be enough) to reproduce the issue?

Offline

#5 2014-10-10 17:10:50

avista
Member
Registered: 2014-01-06
Posts: 63

Re: AV in TSQLHttpServer.Create() when port already in use

If you run two instances of the Project14ServerHttpWeak application, you will see the issue when the second instance runs.  I just realized that the URL mapping has to be the same for the error to occur, not just the port.  Sorry I didn't make that clear.

Please let me know if you need any further clarification.

Offline

#6 2014-10-11 08:17:08

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,662
Website

Re: AV in TSQLHttpServer.Create() when port already in use

If you catch the error in a try...except block, there is no AV any more, right?

Project14ServerHttpWeak is a simple sample which does not catch the error, but on production, you should set the try...except block;

Offline

Board footer

Powered by FluxBB