Jump to content

Remy Lebeau

Members
  • Content Count

    2333
  • Joined

  • Last visited

  • Days Won

    94

Posts posted by Remy Lebeau


  1. 3 hours ago, Lajos Juhász said:

    No VCL application should try to compile DesignIntf.pas it is a violation of the licence. Only a runtime package can use it.

    I think you mean a design-time package.

    4 hours ago, Derrek Curtis said:

    That message is generated when the Vcl library is complied from within the project.

    Why are you recompiling the VCL?  Don't do that.  Your project is clearly not setup correctly.  Start over with a fresh project, and add your existing project source files to it.  And make sure your design-time package (not a runtime package!) has the DesignIDE package listed in its requires clause. You should not be compiling DesignIntf.pas directly.


  2. 8 hours ago, Arvid P. said:
    
    void MyTypes::first()
    {
    	mp1MyType = NULL;
    }

     

    That is absolutely the wrong thing to do.  There is no such concept as a "null iterator" in the standard library.  An iterator has to always point at something valid, whether it is the 1st item in a container/range, the end of a container/range, or anything in between.

     

    For what you are attempting, you would need to wrap the iterator inside a std::optional (or equivalent, like Roger Cigol suggested), eg:

    std::optional<std::list<MyType*>::const_iterator> mp1MyType;
    
    void MyTypes::first()
    {
    	mp1MyType = std::nullopt();
    }
    
    bool MyTypes::next()
    {
    	if ( !mp1MyType.has_value() )
    		mp1MyType = mLstMyTypes.begin();
    	else
    		++(*mp1MyType);
    
    	if ( *mp1MyType == mLstMyTypes.end() )
    	{
    		mp1MyType = std::nullopt();
    		return false;
    	}
    
    	return true;
    }
    
    MyType* MyTypes::getPresent() const
    {
    	return mp1MyType.has_value() ? *(*mp1MyType) : nullptr;
    }

    But, why are you waiting until next() is called to move the iterator to the 1st item?  Why can't you do it in first() instead?  Seems like first() should return a bool indicating whether the iterator is valid, just like next() does, eg:

    std::list<MyType*>::const_iterator mp1MyType;
    
    bool MyTypes::first()
    {
    	mp1MyType = mLstMyTypes.begin();
    	return ( mp1MyType != mLstMyTypes.end() );
    }
    
    bool MyTypes::next()
    {
    	if ( mp1MyType != mLstMyTypes.end() )
    	{
    		++mp1MyType;
    		if ( mp1MyType != mLstMyTypes.end() )
    			return true;
    	}
    	return false;
    }
    
    MyType* MyTypes::getPresent() const
    {
    	return ( mp1MyType != mLstMyTypes.end() ) ? *mp1MyType : nullptr;
    }
    • Like 1

  3. 3 minutes ago, bugdude said:

    The connection is a long lived websocket connection (just one), but with the client hitting so often I think it gets hit again before the shutdown waittimes can expire and may be talking to a partially torn down object. That was why I wondered if there was a 'clean' way to abort/disconnect the SSL connection from the server side that could be used before trying to set active false on the server.

    Again, without seeing the actual code, it is hard to answer definitively.  Ideally, you would just set a flag that your server's OnExecute event handler can look for periodically and close the connection of the calling thread so it can terminate gracefully.  But, if you absolutely had to close the connection quickly, then calling Binding.CloseSocket() from outside the server should suffice (like I said, modern Indy already does that, but maybe your older version is not), provided you are not swallowing any subsequent exceptions that may arise.


  4. 2 hours ago, bugdude said:

    I am a hobbyist on a budget, so I use dated versions of Delphi and Indy (10.3.3 Delphi and the included Indy).

    Just because you are on a budget doesn't mean you should use outdated tools.  Especially tools that can be obtained for free.

    2 hours ago, bugdude said:

    I ran into problems with a project which uses TidCustomTCPServer to implement a web server with websocket support using OpenSSL. Basically the issue is that if the server has an active SSL websocket connection and TCPServer.Active is set false, the application stalls and gets locked into a loop in Indy (I think). Looking in the debugger I see that even though StopListeners was already called the recv handler is still being called repeatedly and generating exceptions.

    What you describe sounds like the TCP server threads are not shutting down correctly.  There couple be a number of reasons for that to happen.  For instance:

     

    Are you catching and discarding the exceptions?  If so, don't discard them.  Rethrow them and let the server handle them.

     

    Are you shutting down the server in the main thread, and syncing with the main thread in your server events?  If so, that is a guaranteed deadlock.  Either shutdown the server from a worker thread so the main thread is free to continue processing sync requests.  Or simply get rid of the syncs during shutdown.

    2 hours ago, bugdude said:

    The browser code polls the server every 100ms for screen updates so the calls may originate from the client, but the connection does still seem to be active. (project based on sourceforge ThinVNC with SSL added and other things added).

     

    Is the client creating a new connection for each poll?  Or reusing connections?

    2 hours ago, bugdude said:

    saw some notes about this issue in issue in GitHub, but I tried the solution mentioned there and that alone did not help.. (replaced call to AContext.Connection.Disconnect with Binding.CloseSocket call)

    Simply closing the sockets may not be enough. The server has to be allowed to process the closures so it can terminate its worker threads.  Besides, TIdTCPServer already calls CloseSocket() internally during its shutdown.  At least it does in recent years - it USED to call Disconnect() instead, but that proved to cause problems with OpenSSL connections across thread boundaries.

    2 hours ago, bugdude said:

    Q1 - is there a particular code sequence I could follow to block out those active SSL connections before setting active False that would circumvent this problem without upgrading Indy ?

    Hard to say without seeing your actual code to see why it is not shutting down correctly.

    2 hours ago, bugdude said:

    Q2 - would upgrading Indy from GitHub fix this specific issue ?

    Possibly.  Again, hard to say without knowing the root cause first.

    2 hours ago, bugdude said:

    Q3 - would the Indy cleanup script work on Delphi 10.3.3 safely ?

    Define "safely".  Is there a particular problem you are thinking of?

    2 hours ago, bugdude said:

    Q4 - is upgrading Indy likely to break anything else in this older version of Delphi ?

    Known issues are documented in the Update instructions, ie:

    https://github.com/IndySockets/Indy/wiki/Updating-Indy#delphicbuilderradstudio-101-berlin-and-later


  5. 3 hours ago, michel.seicon said:

    In the example above, if you increase the loop so that it consumes 4gb, and at the end release the objects, the correct thing would be to release this memory to the OS

    Unfortunately, that is not how Delphi's memory manager works, on any OS.  Freed memory is held onto and reused, it is rarely returned to the OS until the app is exited.

    3 hours ago, michel.seicon said:

    The problem is that in our system, if we manipulate images, files, and send them via Sockets then over time the system simply consumes a lot of memory and never releases it.

    You should consider re-writing your code to make better use of memory buffers so they are (re-)allocated and freed less often.

    3 hours ago, michel.seicon said:

    As I mentioned, this problem simply does not occur on Windows and only on Linux.

    That is not true.  Memory management and fragmentation are important issues to be aware of on Windows too, or any OS for that matter.


  6. 7 hours ago, BruceV said:

    Your first suggestion threw up 40 (!) linker errors which are all way above my pay grade, and I wouldn't trouble you to go anywhere with them.

    You probably need to recreate the project and make sure the VCL library is enabled.

    7 hours ago, BruceV said:

    The second one, the standard WIN32 approach, works fine and will do what I want.

    That wasn't the point of the exercise, though.  It was to get more details about why the file is not opening correctly.  But, if CreateFile() succeeds and std::ifstream fails, then there has to be another factor at play that is not being accounted for.


  7. 3 hours ago, brk303 said:

    So, if I use a simple integer counter, as in the code above, and wait a bit, that should solve the problem, right ?

    You have a race condition.  You are incrementing the counter at the point where the work is actually performed, but if the work is merely queued but the work thread hasn't actually started the work yet, then the counter may not have been incremented yet by the time you compare it in your destructor.  You need to increment the counter at the point where the work is being queued, not where it is acted on.

     

    You didn't say which platform(s) you are targeting, On Windows for instance, a better strategy would be to put the thread's handles into an array, and then you can use (Msg)WaitForMultipleObjects() to wait for the handles to be signaled when the threads are fully terminated.  However, you mention anonymous threads, so be aware that TThread.CreateAnonymousThread() sets TThread.FreeOnTerminate=true, which doesn't mix well with waiting on thread handles.  So you would have to manually set FreeOnTerminate=false when starting the anonymous threads, and then free the threads yourself when they are finished running.


  8. 10 minutes ago, Arvid P. said:

    We have some classes that are wrappers for a list of other classes and have a publicly declared iterator for that list. This iterator was intialized as NULL, sometimes set to NULL and checked against NULL. This worked perfectly fine in 32 bit. But compiling in 64 bit gives linker errors

    Can you show the actual code?  Standard iterators are not initializable/comparable with NULL values.  So your code is likely wrong to begin with and just happened to work before due to implementation details of the old standard library, but the new standard library is exposing your bugs.

    10 minutes ago, Arvid P. said:

    Can anyone confirm that that is the case? And maybe give some hints how I can solve the issue without completely rewriting these classes? If it is at all possible...

    You need to fix your buggy code to use iterators correctly.  But it's hard to explain what you need to change until we see what you are actually doing.


  9. 12 hours ago, Kas Ob. said:

    @Clément Try this please:

    You are leaking the socket handle if connect() fails.  You have to close the handle if socket() succeeds, regardless of whether connect() succeeds.

    12 hours ago, Kas Ob. said:

    This is blocking mode, and you can reduce the timeout before connect to 1 second,

    You can't reduce (or even set) the timeout on a blocking connect().  You have to use a non-blocking connect() and then use select() or equivalent to implement the timeout.

    12 hours ago, Kas Ob. said:

    And i really angry now as i can't disable SACK for connect !

    AFAIK, you can't disable SACK on a per-socket basis.  You have to use the Registry or command-line netsh utility to disable it globally:

    https://superuser.com/questions/1808254/how-to-disable-tcp-sack-in-windows-xp

    https://www.linkedin.com/advice/3/how-can-tcp-selective-acknowledgment-sack-improve-heatc

     

    • Thanks 1

  10. 15 hours ago, xorpas said:

    How can Make memo support html that show readable text ?

    The standard FMX TMemo simply does not support HTML (or even basic text formatting in general).  You will have to use a 3rd party control (or make your own from scratch) to display rich/formatted text.


  11. The C++ standard file library really sucks what it comes to error reporting.  I would suggest using TFileStream or even CreateFile() directly to get better details about what the actual failure is.

     

    On a side note: kbhit() is a really old-school Borland function, it is not standard in either C or C++.  Consider using C++'s standard std::cin.get() method instead.

     

    Try this:

    #include <iostream>
    #include <memory>
    #include <System.SysUtils.hpp>
    #include <System.Classes.hpp>
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	try
    	{
    		auto ifs = std::make_unique<TFileStream>(_D("C:\\Junk\\testfile.txt"), fmOpenRead);
    		std::cout << "Opened OK\n";
    	}
    	catch (const Sysutils::Exception &e)
    	{
    		std::wcout << L"Can't open input file. Error: " << e.Message.c_str() << "\n";
    		std::cin.get();
    		return 1;
    	}
    
    	std::cin.get();
    	return 0;
    }

    Or:

    #include <iostream>
    #include <windows.h>
      
    int _tmain(int argc, _TCHAR* argv[])
    {
    	HANDLE hFile = CreateFileW(L"C:\\Junk\\testfile.txt", GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
    	if (hFile == INVALID_HANDLE_VALUE)
    	{
    		DWORD dwError = GetLastError();
    		cout << "Can't open input file. Error: " << dwError << "\n";
    		std::cin.get();
    		return 1;
    	}
    
    	std::cout << "Opened OK\n";
    	CloseHandle(hFile);
      
    	std::cin.get();
    	return 0;
    }

     

    • Thanks 1

  12. 4 hours ago, RayTmsk said:

    Hmm... but how to detect real type of T ? in first iterations I need for int, guid, string, float.

    For example:

    procedure TDataField.SetAsAnyArray<T>(SourceItems: TArray<T>);
    begin
      case GetTypeKind(T) of
        tkInteger: begin
          ...
        end;
        tkUString: begin
          ...
        end;
        tkFloat: begin
          ...
        end;
        tkRecord: begin
          if TypeInfo(T) <> TypeInfo(TGuid) then
            raise ...;
          ...
        end;
      else
        raise ...;
      end;
    end;

     


  13. On 4/26/2024 at 7:49 AM, RayTmsk said:

    What is modern way for do this without many code?

    You can use a Generic so you have only 1 method to declare and implement which can accept multiple types as input, eg:

    procedure TDataField.SetAsAnyArray<T>(SourceItems: TArray<T>);

    But, it looks like you have different data members for each array type, so you would have to use RTTI to detect the actual type used for T and write different code branches to handle each type that you want T to accept.  That's not much better than just writing a separate method for each type of T.


  14. 2 hours ago, Angus Robertson said:

    Windows supports none blocking DNS lookups and sockets by using a thread, what is the API to stop those threads early.

    DNS lookups and connect attempts are two different things.

     

    I don't think you can do non-blocking DNS lookups using the standard hostbyname()/getaddrinfo() APIs that most people's socket code uses. You would have to use platform-specific APIs (ie, like DnsQueryEx() on Windows), or send manual DNS queries over non-blocking sockets.

     

    A connect() timeout can be implemented by just using a non-blocking socket and close() the socket after the timeout elapses. If it uses a thread internally, that is just an implementation detail of the OS, but that shouldn't block the app from being able to move on.

    • Like 1

  15. 17 minutes ago, Angus Robertson said:

    The simplest way is with the TIcsIpStrmLog component

    Why TIcsIpStrmLog and not TSslWSocket directly?

    17 minutes ago, Angus Robertson said:

    Failing to open a normal TCP connection will timeout after about 30 to 40 seconds, you can not easily make this any shorter

    Are you saying that ICS does not support connect timeouts on TCP sockets at all? Or just that the TIcsIpStrmLog component specifically does not support this?

     

    In general, there are ways to implement a connect timeout on a TCP socket - namely:

    1. by using a non-blocking socket with select() or (e)poll() for the timeout.
    2. by aborting the socket from another thread.

    I would be surprised if ICS does not use the first one.

    • Like 1

  16. 2 hours ago, baka0815 said:

    However I'm not using different ports, but maybe I will still figure something out.

    You should use different ports for HTTP and HTTPS.  While it is technically possible to handle both HTTP and HTTPS on a single port, it requires extra coding to peek the raw TCP data before the HTTP server processes it. It is usually not worth the effort unless you are dealing with network restrictions.


  17. 3 hours ago, BranOWSKI said:

    I am still having issues with this problem and get the same error after changing the service url.
    Anyone have an updated solution for this issue?

    What version are you using? What service url are you using? Things have changed in recent years.


  18. 23 minutes ago, Uwe Raabe said:

    Another approach is to wrap the code into some TThread.ForceQueue construct...

    ...

    All the code is still executed in the main thread, but there is no loop blocking anything.

    It also has the added benefit that it has an optional Delay parameter, if you need a longer sleep between steps, similar to a timer.

    • Like 1

  19. On 4/18/2024 at 8:40 AM, Khorkhe said:

    according to the Embarcadero docs, these class operators are supposed to return a Boolean.

    Where do you see that documented?  According to this documentation, the return type of the LogicalAnd and LocicalOr operators is simply specified as "resultType", nothing says it is required to be Boolean, so it can be whatever type the implementation wants.


  20. On 4/18/2024 at 1:32 AM, Tommi Prami said:

    Last problem I had was that TryISO8601ToDate will raise exception on string it can't parse. Will handle/eat the exception but not most optimal solution I think.

    By definition, a TryXXX() function does not raise an exception into user code.  TryISO8601ToDate() is no different.

     

    Now, it may be that it generates an internal exception on failure, but that is merely an implementation detail, such an exception will certainly not escape into user code.  If you don't want to see the exception inside the debugger, you can configure it to ignore EDateTimeException and EConvertError exceptions.

     

    Regarding that exception, TryISO8601ToDate() is implemented backwards than other TryXXX() functions.  In most RTL functions, DoX() calls TryDoX() to do the actual work, and then raises an exception if TryDoX() fails.  But TryISO8601ToDate() is different - it calls ISO8601ToDate() to do the actual work, and then suppresses any exception that ISO8601ToDate() raises.

     

    What they SHOULD have done instead is move ISO8601ToDate()'s logic into TryISO8601ToDate(), and then make ISO8601ToDate() raise if TryISO8601ToDate() fails.  But, it turns out that ISO8601ToDate() raises a different exception message depending on why it fails.  Perhaps they could have created a new internal function do perform the actual work and have it report the failure reason to the caller, then TryISO8601ToDate() could ignore the reason, and ISO8601ToDate() could raise an exception based on the reason.  Oh well...

    • Like 1

  21. 14 hours ago, baka0815 said:

    Wouldn't that be something that could be automated in the CI of the Indy project (the creation of the cmd, without the txt file I mean)?

    Indy doesn't have a real CI system.  But yes, generation of the cmd script could be automated in some way using information that Indy already has (there is already some automation in place to generate the Package projects themselves).  To reduce duplication, I could auto-generate a separate cmd script that just deletes the known Indy files in the current directory, and then have Clean_IDE.cmd call that script where needed.

    9 hours ago, DelphiUdIT said:

    In the Embarcadero release, Indy packages, components and other stuffs may be differ from GitHub maintained release. For example IndyIPServer, IndyIPClient and others are not present in the GitHub version.

    Those files are not part of Indy itself, they are part of an internal wrapper on top of Indy which Embarcadero uses to separate its use of Indy from other Embarcadero code.  But, there are other differences Embarcadero does make to Indy itself - most notably, the Packages are changed to use LIBSUFFIX, etc.

×