ioFTPD General New releases, comments, questions regarding the latest version of ioFTPD. |
04-12-2005, 02:30 PM
|
#16
|
Member
ioFTPD Registered User
Join Date: Mar 2005
Posts: 26
|
Ipv6 - good idea!
In my honest network i have 1200 computers ,and we using ipv6 about 1.5 year.
So, if you going to add ipv6 support , im not need ipv6-ipv4 switch anymore!
Thank you
|
|
|
04-12-2005, 06:32 PM
|
#17
|
Senior Member
FlashFXP Beta Tester ioFTPD Scripter
Join Date: Sep 2002
Posts: 543
|
Great to see you back D1, we missed you.
|
|
|
05-03-2005, 05:58 AM
|
#18
|
Senior Member
FlashFXP Scripter ioFTPD Foundation User
Join Date: Sep 2003
Posts: 132
|
Any possibility we might be getting an update on the progress anytime soon? Would be fun to be able to follow the progress of the upcomming release!
No intentions to rush things or anything, would just be fun to get some updates every now and then.
|
|
|
05-03-2005, 07:09 AM
|
#19
|
Senior Member
ioFTPD Scripter
Join Date: Jan 2003
Posts: 179
|
nice to see ya back d1 and thx that u finally add ipv6 support. i remember a time nearly 2 years ago where i asked ya about that but u didnt want to do that... so nice to see that i finally reached ya *g*
greetz cal
|
|
|
05-04-2005, 08:56 AM
|
#20
|
Member
Join Date: May 2003
Posts: 33
|
lo
1 Month later and no news anymore from inicom or d1
Some info now and then about progress etc would be nice .......for sure after waiting over a year now.
|
|
|
05-06-2005, 02:30 AM
|
#21
|
Disabled
FlashFXP Registered User ioFTPD Administrator
Join Date: Dec 2001
Posts: 2,230
|
Ok
I guess it's time for status update.
I've been lately working on device/service/environment releated code, which is where the magic happends. I've discarded most of ordinary 'struct'ures for storing client related data and moved nearly everything to dynamic environment, which is far more flexible - and safer thanks to mandatory environment variable destructors.
I've also written new hostname caching algorithms - similar to old, but faster & neater.
The big thing that I can't yet fully describe, as it's still work in progress, is native database support. Instead of providing fixed tables, I decided to write somewhat more complex code that allows customizing database structures. (read; you can add and remove both columns & rows to any database - or even create your own cached databases) To minimize memory usage and amount of memory allocations, I decided to make it rely heavily on reference counting. (Reference counting adds to complexity of code, but removes much of the overhead caused by dynamic allocations) Obviously the programming interface is done so, that scripts and modules do not need any database specific code.
Only thing, that I haven't had time to study yet, is LUA. I'm planning to replace cookies with programming language (due to fact, that fixed cookies would not work too well with database), and LUA seems to be perfect choice for the purpose.
Sample code for changing password:
Code:
lpDatabase = GetUserDatabase();
lpUserCollection = GetDatabaseCollection(lpDatabase, L"darkone");
if (lpUserCollection != 0) {
lUserDataRowID = GetDatabaseRowID(lpDatabase, L"USER");
lPasswordColumnID = GetDatabaseColumnID(lpDatabase, lUserDataRowID, L"PASSWORD");
lpRow = GetDatabaseRow(lpUserCollection, lUserDataRowID);
if (lpRow != 0) {
/* get password */
lpValue = GetDatabaseValue(lpRow, lPasswordColumnID);
if (lpValue != 0) {
wsprintfW("Current password is: %s\n", lpValue->wszValue);
}
/* lock selected rows */
lRows[0] = lUserDataRowID;
if (LockDatabaseCollectionRows(&lpUserCollection, lRows, 1)) {
bResult = FALSE;
/* create new value */
lpValue = CreateDatabaseWStringValue(L"New password", INFINITE /* length of pass, infinite = wcslen() */);
if (lpValue != 0) {
/* set value to database (one can use same value on several columns/rows/collections by duplicating it using DuplicateDatabaseValue(), which only increments reference counter instead of allocation memory) */
if (SetDatabaseCollectionColumnValue(lpUserCollection, lUserDataRowID, 0 /* index of row, if more than one rows. eg. certificate hash list & stats */, lPasswordColumnID, lpValue)) {
/* flush... */
bResult = CommitDatabaseCollectionChanges(&lpUserCollection);
} else {
FreeDatabaseValue(lpValue);
}
}
if (! bResult ){
CancelDatabaseCollectionChanges(&lpUserCollection);
}
}
}
CloseUserCollection(lpUserCollection);
}
As some of you can see, it is very easy to write a generic routine for changing any value with single command. eg. 'SITE CHANGE <DATABASE NAME> <USERNAME> <ROW NAME> <COLUMN NAME> <NEW VALUE>'
|
|
|
05-06-2005, 02:08 PM
|
#22
|
Senior Member
ioFTPD Scripter
Join Date: Feb 2003
Posts: 458
|
ah.. LUA is da bombzzzz...
|
|
|
05-07-2005, 12:19 PM
|
#23
|
Disabled
FlashFXP Registered User ioFTPD Administrator
Join Date: Dec 2001
Posts: 2,230
|
Just to show off, how trivial it's to write database modules for the new interface, I decided to publish source of current file database module (still work in progress = incomplete notepad draft) But it gives you idea, how much (or should I say little) work it's to write eg. SQL module.
Code:
LPWSTR *TokenizeCommaSeperatedString(LPWSTR wszInput, PULONG pStringCount)
{
PWCHAR pFrom, pTo, pBegin;
WCHAR wCurrent;
LPVOID lpMemory;
BOOL bBackSlash = FALSE;
ULONG lResultSize = 16;
ULONG lResultCount = 0;
LPWSTR *wszResult = 0;
/* tokenize comma seperated string */
wszResult = (LPWSTR *)Allocate("Tokenized string", sizeof(LPWSTR) * lResultSize);
if (! wszResult) {
/* out of memory */
return 0;
}
for (pFrom = pBegin = pTo = wszInput;;++pFrom) {
switch ((wCurrent = pFrom[0])) {
case L',':
if (bBackSlash) {
/* escaped comma */
break;
}
case L'\0':
if (bBackSlash) {
/* escaped nul.. decode failure */
Free(wszResult);
return 0;
}
if (lResultCount == lResultSize) {
lpMemory = ReAllocate(wszResult, 0, sizeof(LPWSTR) * (lResultSize + 16));
if (! lpMemory) {
/* out of memory */
Free(wszResult);
return 0;
}
lResultSize += 16;
wszResult = (LPWSTR *)lpMemory;
}
wszResult[lResultCount++] = pBegin;
if (wCurrent == L'\0') {
/* nul char */
pTo[0] = L'\0';
return wszResult;
}
pTo[0] = L'\0';
pTo = &pFrom[1];
pBegin = pTo;
continue;
case L'\\':
/* escape character */
if (bBackSlash) {
/* escaped escape character */
break;
}
bBackSlash = TRUE;
continue;
}
bBackSlash = FALSE;
if (pTo != pFrom) {
pTo++[0] = wCurrent;
continue;
}
pTo++;
}
}
LONG EscapeStringCommas(LPWSTR wszInput, LPWSTR wszOutput, ULONG lOutputSize)
{
WCHAR wCurrent;
PWCHAR pFrom, pTo;
LPWSTR wszResult;
/* escape string commas */
for (pFrom = wszInput, pTo = wszOutput;;pFrom++,pTo++) {
switch ((wCurrent = pFrom[0])) {
case L'\0':
return pTo - wszOutput;
case L'\\':
/* escape character */
if (lOutputSize < 2) {
/* out of buffer space */
break;
}
pTo++[0] = L'\\';
pTo++[0] = L'\\';
lOutputSize -= 2;
continue;
case L',':
/* comma */
if (lOutputSize < 2) {
/* out of buffer space */
break;
}
pTo++[0] = L'\\';
pTo++[0] = L',';
lOutputSize -= 2;
continue;
default:
if (! lOutputSize) {
/* out of buffer space */
break;
}
pTo++[0] = wCurrent;
lOutputSize--;
continue;
}
break;
}
return -1;
}
BOOL LockCollection(LPDATABASE lpDatabase, LPDATABASE_COLLECTION *lpCollection)
{
/* lock and synchronize collection - does nothing for now */
return TRUE;
}
BOOL CommitCollectionChanges(LPDATABASE lpDatabase, LPDATABASE_COLLECTION *lpCollection)
{
LPDATABASE_ROW lpRow;
LPDATABASE_VALUE lpValue;
WCHAR wColumnName[16384], wColumnValue[16384];
LONG lColumnNameLength = 0;
LONG lColumnValueLength = 0;
LONG lResult;
DWORD dwBytesWritten;
ULONG lRowID, lRowIndex, lColumnID;
BOOL bError = FALSE;
BOOL bReturn = FALSE;
/* commit collection changes and release locks - no locks for now */
wColumnName[0] = L' ';
wColumnName[1] = L'{';
wColumnValue[0] = L'{';
hFile = CreateFileW(GetDatabaseCollectionName(lpCollection[0]),
GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (hFile != INVALID_HANDLE_VALUE) {
/* iterate all row ids */
for (lRowID = 0;lRowID < GetDatabaseRowIDCount(lpDatabase) && ! bError;lRowID++) {
/* iterate all rows */
for (lRowIndex = 0;lRowIndex < GetCollectionRowCount(lpCollection[0], lRowID);lRowIndex++) {
/* iterate all columns */
lpRow = GetCollectionRow(lpCollection[0], lRowID, lRowIndex);
if (! lpRow) {
continue;
}
lColumnValueLength = 1;
lColumnNameLength = _snwprintf(wColumnName,
sizeof(wColumnName) / sizeof(WCHAR) - 1, L"%s {", GetRowName(lpRow));
if (lColumnNameLength > 0) {
for (lColumnID = 0;lColumnID < GetRowColumnCount(lpRow);lColumnID++) {
lpValue = GetRowColumnValue(lpRow, lColumnID);
if (! lpValue) {
continue;
}
lResult = EscapeStringCommas(GetRowColumnName(lpRow, lColumnID),
&wColumnName[lColumnNameLength], sizeof(wColumnName) / sizeof(WCHAR) - lColumnNameLength - 2);
if (lResult <= 0) {
/* failure */
lColumnNameLength = INFINITE;
break;
}
lColumnNameLength += lResult;
wColumnName[lColumnNameLength++] = L',';
lResult = EscapeStringCommas(GetValueWString(lpValue),
&wColumnValue[lColumnValueLength], sizeof(wColumnValue) / sizeof(WCHAR) - lColumnValueLength - 3);
if (lResult < 0) {
/* failure */
lColumnValueLength = INFINITE;
break;
}
lColumnValueLength += lResult;
wColumnName[lColumnValueLength++] = L',';
}
if (lColumnValueLength != INFINITE && lColumnNameLength != INFINITE) {
/* prepend buffers */
wColumnName[lColumnNameLength - 1] = L'}';
wColumnName[lColumnNameLength++] = L' ';
wColumnValue[lColumnValueLength - 1] = L'}';
wColumnValue[lColumnValueLength++] = L'\r';
wColumnValue[lColumnValueLength++] = L'\n';
/* write to file */
if (WriteFile(hFile, wColumnName, lColumnNameLength * sizeof(WCHAR), &dwBytesWritten, 0)
&& WriteFile(hFile, wColumnValue, lColumnValueLength * sizeof(WCHAR), &dwBytesWritten, 0)) {
/* success */
continue;
}
}
} else {
/* out of buffer space */
lColumnNameLength = INFINITE;
}
bError = TRUE;
break;
}
}
CloseHandle(hFile);
if (! bError) {
bReturn = TRUE;
}
}
return bReturn;
}
BOOL CancelCollectionChanges(LPDATABASE lpDatabase, LPDATABASE_COLLECTION *lpCollection)
{
/* cancel collection changes and release locks - does nothing for now */
return TRUE;
}
BOOL QueryCollection(LPDATABASE lpDatabase, LPDATABASE_COLLECTION lpCollection)
{
LPDATABASE_VALUE lpValue;
HANDLE hFile;
LPWSTR *wszColumnName, *wszColumnValue;
PWCHAR pLine, pBuffer, pEnd, pCurrent, pOpeningBrace[2], pClosingBrace, pWordEnd;
ULONG lBufferLength, lRowID, lRowIndex, lColumnID, lColumnNameCount, lColumnValueCount, lWord, lWordCount;
BOOL bReturn = FALSE;
/* query collection */
hFile = CreateFileW(GetDatabaseCollectionName(lpCollection[0]),
GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (hFile != INVALID_HANDLE_VALUE) {
lBufferLength = GetFileSize(hFile, 0);
if (lBufferLength != INVALID_FILE_SIZE || GetLastError() == NO_ERROR) {
pBuffer = (WCHAR *)Allocate("Collection read buffer", lBufferLength + sizeof(WCHAR));
if (pBuffer != 0) {
if (ReadFile(hFile, pBuffer, lBufferLength, &lBufferLength, 0)) {
lBufferLength = (lBufferLength / 2) + 1;
pBuffer[lBufferLength - 1] = L'\n';
/* seek entries */
for (pLine = pBuffer;(pCurrent = wmemchr(pLine, L'\n', pEnd - pCurrent)) != 0;pLine = &pCurrent[1]) {
pCurrent[(pLine > pCurrent && pCurrent[-1] == L'\r' ? -1 : 0] = L'\0';
pOpeningBrace[0] = wmemchr(pLine, L'{', pCurrent - pLine);
if (! pOpeningBrace[0]) {
/* no opening brace */
continue;
}
pClosingBrace[0] = wmemchr(&pOpeningBrace[0][1], L'}', pCurrent - &pOpeningBrace[0][1]);
if (! pClosingBrace[0]) {
/* no closing brace */
continue;
}
pOpeningBrace[1] = wmemchr(&pClosingBrace[0][1], L'{', pCurrent - &pClosingBrace[0][1]);
if (! pOpeningBrace[1]) {
/* no opening brace */
continue;
}
pClosingBrace[1] = wmemchr(&pOpeningBrace[1][1], L'}', pCurrent - &pOpeningBrace[1][1]);
if (! pClosingBrace) {
/* no closign brace */
continue;
}
pClosingBrace[0][0] = '\0';
pClosingBrace[1][0] = '\0';
/* remove heading and tailing spaces */
for (pWordEnd = pOpeningBrace[0];pWordEnd > pLine && iswspace(pWordEnd[-1]);--pWordEnd);
pWordEnd[0] = L'\0';
for (;pLine < pWordEnd && iswspace(pLine[0]);++pLine);
for (lRowID = 0;lRowID < GetDatabaseRowIDCount(lpDatabase);lRowID++) {
if (! wcsicmp(GetDatabaseRowName(lpDatabase, lRowID), pLine)) {
/* create row and get known columns */
lRowIndex = CreateCollectionRow(lpCollection[0], lRowID);
if (lRowIndex == INFINITE) {
/* error could not create row */
break;
}
/* tokenize strings */
wszColumnName = TokenizeCommaSeperatedString(&pOpeningBrace[0][1], &lColumnNameCount);
if (wszColumnName != 0) {
wszColumnValue = TokenizeCommaSeperatedString(&pOpeningBrace[1][1], &lColumnValueCount);
if (wszColumnValue != 0) {
/* get known columns */
lWordCount = min(lColumnNameCount, lColumnValueCount);
for (lColumnID = 0;lColumnID < GetDatabaseRowColumnCount(lpDatabase, lRowID);++lColumnID) {
for (lWord = 0;lWord < lWordCount;lWord++) {
if (! _wcsicmp(GetDatabaseRowColumnName(lpDatabase, lRowID, lColumnID), wszColumnName[n])) {
/* create value */
lpValue = CreateWStringValue(wszColumnValue[n]);
if (lpValue != 0) {
if (! SetCollectionRowColumnValue(lpCollection, lRowID, lRowIndex, lColumnID, lpValue)) {
FreeValue(lpValue);
}
}
break;
}
}
}
Free(wszColumnValue);
}
Free(wszColumnName);
}
break;
}
}
}
}
Free(pBuffer);
}
}
CloseHandle(hFile);
}
return bReturn;
}
BOOL DeleteCollection(LPDATABASE lpDatabase, LPDATABASE_COLLECTION lpCollection)
{
/* delete collection */
return DeleteFileW(GetDatabaseCollectionName(lpCollection));
}
BOOL CreateCollection(LPDATABASE lpDatabase, LPWSTR wszCollectionName)
{
HANDLE hFile;
BOOL bReturn = FALSE;
/* create collection */
hFile = CreateFileW(wszCollectionName,
GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0;
if (hFile != INVALID_HANDLE_VALUE) {
bReturn = TRUE;
CloseHandle(hFile);
}
return bReturn;
}
BOOL Shutdown(LPDATABASE lpDatabase)
{
/* module shutdown */
return TRUE;
}
|
|
|
05-08-2005, 08:33 PM
|
#24
|
Disabled
FlashFXP Registered User ioFTPD Administrator
Join Date: Dec 2001
Posts: 2,230
|
File format for database files is following (if someone wants to write FILEDB to SQL converter)...
also we'd appreciate, if someone comes up with a script that converts existing files (v5) to new (v6) format.
Code:
USER_CERTIFICATE {HASH} {098323829328}
USER_CERTIFICATE {HASH} {098323829328}
USER_CERTIFICATE {HASH} {098323829328}
USER_GROUP {GROUP,IS_ADMIN} {500,1}
USER_GROUP {GROUP,IS_ADMIN} {200,1}
USER_GROUP {GROUP,IS_ADMIN} {400,1}
USER_RATIO {SECTION,RATIO} {PUB,3}
USER_RATIO {SECTION,RATIO} {PRIVATE,0}
USER_STATS {SECTION,WKDN,WKUP} {PUB,0,0}
USER_STATS {SECTION,WKDN,WKUP} {PRIVATE,100,500}
{},\ characters have been escaped with \ character. Files have are stored in unicode format (Just like with earlier versions, you still should not access them directly - you should not expect them to exist at all!).
|
|
|
05-12-2005, 04:10 AM
|
#25
|
Senior Member
ioFTPD Foundation User
Join Date: Dec 2003
Posts: 94
|
Everything seems promising, but it was promising 1 year ago too, so this kind of leaves me still by a simple question as this: any ETA or anything to tell me when this will be done. Im waiting long time and i would love to see the new ioFTPD, i know you people are working hard on the project, but could you give an estimate on when u should be done.
thank you, and don`t be mad at my question.
|
|
|
05-12-2005, 05:51 AM
|
#26
|
Senior Member
FlashFXP Scripter ioFTPD Foundation User
Join Date: Sep 2003
Posts: 132
|
As many before me has answerd to this sort of question, it's done when it's done! Since this is a new core being built and not just any simple upgrade, it will take time. Believe you me, you're not the only one waiting for the new io (which will probably by the way revolutionize the windows ftpd scene remarkably).
The only thing we can do is sit back and relax and wait for The Day to come!
|
|
|
05-13-2005, 06:19 AM
|
#27
|
Disabled
FlashFXP Registered User ioFTPD Administrator
Join Date: Dec 2001
Posts: 2,230
|
I'm currently somewhat behind the alpha schedule (there is actually such) due to some last minute changes/additions. Note that early alpha versions will be limited to httpd.
And just like peep said, most of the codebase is completely rewritten. Writing ftpd from ground up to match & surpass earlier version in terms of features, is a whole lot of work. Even some of the code that could have been recycled, such as configuration data reader and hostname resolver, has been completely rewritten.
|
|
|
05-22-2005, 03:55 AM
|
#28
|
Junior Member
Join Date: Jun 2004
Posts: 16
|
Personally I am still waiting for the other shoe to drop.
It has been a while since an update, a new company has taken over, D1 vanishes for months, and now everything and it's dog is being re-written.
When do we see the new license fees for the new and "improved" version?
Obviously IniCom is investing time and money in this venture and is looking to get paid on the backend. That isn't going to happen when the project is was deemed pretty much dead to the people that know/use it....
Like I said, when the other shoe drops we will totally know what is going on, or will be going on.
|
|
|
05-22-2005, 08:13 AM
|
#29
|
Disabled
FlashFXP Registered User ioFTPD Administrator
Join Date: Dec 2001
Posts: 2,230
|
I'm not fully aware of license changes that will follow release of next version. But there will be obviously some due to following reasons:
1) io is now what I do for living, while it used to be a mere hobby.
2) there are other people involved in the developement process & product support.
3) we have specific market segment that we target.
4) io should no longer be considered only as ftp daemon.
One you should all note is that I would have not continued working on io anymore, if there wasn't inicom. Even though they are paying me monthly salary on those months that I work on io, I've been forced to do other projects to cover my living expenses.
I do expect license prices of commerical licenses to go up. Also I expect to see some changes in license terms. (eg. 2 years of free product updates or 3 major updates - the one that lasts longer applies)
As usual these are my opinions, and they do not represent inicom's view in any way.
|
|
|
05-22-2005, 12:12 PM
|
#30
|
Senior Member
FlashFXP Scripter ioFTPD Foundation User
Join Date: Sep 2003
Posts: 132
|
Well it's a conciderable amount of hours you've put out on io and therefor I fully support that you should get paid for it, even tho' you once had a goal to make this one for free and not to go commercial.
I wouldn't either mind putting out a few extra $'s to get my hands on this next version, but IniCom only has a one-time fee on FlashFXP aswell don't they?
And finally, will you take the amount one has already paid for io into concideration, or will this be a new payment that will go straight to IniCom and has nothing to do with the previous?
|
|
|
Thread Tools |
|
Display Modes |
Rate This Thread |
Linear Mode
|
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
All times are GMT -5. The time now is 11:42 AM.
|