LIBPQ for WIN32

Started by Hiroshi Inoueover 27 years ago11 messages
#1Hiroshi Inoue
Inoue@tpf.co.jp

Hi All.
I tested libpq for win32 coming with 6.4-BETA and have a question about
LIBPQ.

I used LIBPQ from a C program,but coundn't connect PostgreSQL DB.

Calling pg_connect() without WSAStartup() failed because of gethostbyname()
error in LIBPQ.
so I modified DllMain in LIBPQ as follows.

BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason,
LPVOID lpReserved ){

WSADATA wsaData;
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
WSAStartup( WSAStartup(MAKEWORD(1, 1), &wsaData);
break;
case DLL_PROCESS_DETACH:
WSACleanup();
break;
}

return (TRUE);
}

and the connection to DB was OK.

Why WSAStartup() is not called in LIBPQ?

Thanks.

Hiroshi Inoue
Inoue@tpf.co.jp

#2Magnus Hagander
mha@edu.sollentuna.se
In reply to: Hiroshi Inoue (#1)
RE: [HACKERS] LIBPQ for WIN32

Hi All.
I tested libpq for win32 coming with 6.4-BETA and have a
question about
LIBPQ.

I used LIBPQ from a C program,but coundn't connect PostgreSQL DB.

Calling pg_connect() without WSAStartup() failed because of
gethostbyname()
error in LIBPQ.
so I modified DllMain in LIBPQ as follows.

BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason,
LPVOID lpReserved ){

WSADATA wsaData;
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
WSAStartup( WSAStartup(MAKEWORD(1, 1), &wsaData);
break;
case DLL_PROCESS_DETACH:
WSACleanup();
break;
}

return (TRUE);
}

and the connection to DB was OK.

Why WSAStartup() is not called in LIBPQ?

This is probably a good thing to do :-)
When I wrote the code, I thought that I was only allowed to
a) Call WSAStartup() once or
b) All calls to WSAStartup() had to have the same version number
But after reading the specs a little more careful, I see that this is not
the case.

The specs say:
An application or DLL can call WSAStartup more than once if it needs to
obtain the WSAData structure information more than once. On each such call
the application can specify any version number supported by the DLL.

The question is - what will happen when you call it with different versions.
Say the application asks for Winsock 2.0, and then the Libpq library goes in
and asks for Winsock 1.1. Will the application still have access to Winsock
2.0 functions?
With the current implementation, I don't beleive it will make a difference -
I don't think that any part of the Winsock system is actually hidden if you
ask for a lower version. But it is _permitted_ by the specification that the
DLL can hide parts that belong to a higher version than the one requested.

So I'm not 100% sure... Does anybody have access to a Winsock that actually
hides some details when you ask for the wrong version?

//Magnus

#3Hiroshi Inoue
Inoue@tpf.co.jp
In reply to: Magnus Hagander (#2)
RE: [HACKERS] LIBPQ for WIN32

Hi All.
I tested libpq for win32 coming with 6.4-BETA and have a
question about
LIBPQ.

I used LIBPQ from a C program,but coundn't connect PostgreSQL DB.

Calling pg_connect() without WSAStartup() failed because of
gethostbyname()
error in LIBPQ.
so I modified DllMain in LIBPQ as follows.

BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason,
LPVOID lpReserved ){

WSADATA wsaData;
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
WSAStartup( WSAStartup(MAKEWORD(1, 1), &wsaData);
break;
case DLL_PROCESS_DETACH:
WSACleanup();
break;
}

return (TRUE);
}

and the connection to DB was OK.

Why WSAStartup() is not called in LIBPQ?

This is probably a good thing to do :-)
When I wrote the code, I thought that I was only allowed to
a) Call WSAStartup() once or
b) All calls to WSAStartup() had to have the same version number
But after reading the specs a little more careful, I see that this is not
the case.

The specs say:
An application or DLL can call WSAStartup more than once if it needs to
obtain the WSAData structure information more than once. On each such call
the application can specify any version number supported by the DLL.

The question is - what will happen when you call it with different

versions.

Say the application asks for Winsock 2.0, and then the Libpq library goes

in

and asks for Winsock 1.1. Will the application still have access to

Winsock

2.0 functions?

I think that current DLL supports version 1.0,1.1,2.0,2.1 and 2.2 and we can
specify any version from 1.0 to 2.2 .
For example,if we call WSAStartup(MAKEWORD(1.0),&wsaData) from libpq
and call WSAStartup(MAKEWORD(2,2),&wsaData) from psql,both return OK
and wsaData.wVersion is 1.0 for libpq and 2.2 for psql.

With the current implementation, I don't beleive it will make a

difference -

I don't think that any part of the Winsock system is actually hidden if

you

ask for a lower version. But it is _permitted_ by the specification that

the

DLL can hide parts that belong to a higher version than the one requested.

So I'm not 100% sure... Does anybody have access to a Winsock that

actually

hides some details when you ask for the wrong version?

By the specs there may be the DLL that doesn't support lower versions.
In that case my code doesn't work well.
But we can delay to call WSAStartup() after the first socket call in LIBPQ.
My example code in fe-connect.c is such as follows.

hp = gethostbyname(conn->pghost);
#ifdef WIN32
if ((hp == NULL) && (GetLastError() == WSANOTINITIALISED))
{
WSADATA wsaData;
if (WSAStartup(MAKEWORD(1,1),&wsaData))
{
fprintf(stderr, "Failed to start winsock: %i\n", WSAGetLastError());
exit(1);
}
....
???? for WSACleanup() ????
....
hp = gethostbyname(conn->host);
}
#endif
if ((hp == NULL) || (hp->h_addrtype != AF_INET))
{
(void) sprintf(conn->errorMessage,
"connectDB() -- unknown hostname: %s\n",
conn->pghost);
goto connect_errReturn;
}

Hiroshi Inoue
inoue@tpf.co.jp

#4Vince Vielhaber
vev@michvhf.com
In reply to: Hiroshi Inoue (#3)
RE: [HACKERS] LIBPQ for WIN32

On 28-Sep-98 Hiroshi Inoue wrote:

I think that current DLL supports version 1.0,1.1,2.0,2.1 and 2.2 and we
can
specify any version from 1.0 to 2.2 .
For example,if we call WSAStartup(MAKEWORD(1.0),&wsaData) from libpq
and call WSAStartup(MAKEWORD(2,2),&wsaData) from psql,both return OK
and wsaData.wVersion is 1.0 for libpq and 2.2 for psql.

Whichever is done, try not to ever request a version higher than what is
required. It forces upgrades that may not even be necessary. It's been
awhile since I've done windows code, but I've been bitten by requiring a
higher version of a library than necessary - more than once without even
realising it. It's not very fun when it comes time to fix it.

Vince.
--
==========================================================================
Vince Vielhaber -- KA8CSH email: vev@michvhf.com flame-mail: /dev/null
# include <std/disclaimers.h> TEAM-OS2
Online Searchable Campground Listings http://www.camping-usa.com
"There is no outfit less entitled to lecture me about bloat
than the federal government" -- Tony Snow
==========================================================================

#5Hiroshi Inoue
Inoue@tpf.co.jp
In reply to: Vince Vielhaber (#4)
RE: [HACKERS] LIBPQ for WIN32

On 28-Sep-98 Hiroshi Inoue wrote:

I think that current DLL supports version 1.0,1.1,2.0,2.1 and 2.2 and we
can
specify any version from 1.0 to 2.2 .
For example,if we call WSAStartup(MAKEWORD(1.0),&wsaData) from libpq
and call WSAStartup(MAKEWORD(2,2),&wsaData) from psql,both return OK
and wsaData.wVersion is 1.0 for libpq and 2.2 for psql.

Whichever is done, try not to ever request a version higher than what is
required. It forces upgrades that may not even be necessary. It's been
awhile since I've done windows code, but I've been bitten by requiring a
higher version of a library than necessary - more than once without even
realising it. It's not very fun when it comes time to fix it.

How about my sample code at the end of my previous post.
In that code,libpq does nothing if main application calls WSAStartup().

Hiroshi Inoue
inoue@tpf.co.jp

#6Vince Vielhaber
vev@michvhf.com
In reply to: Hiroshi Inoue (#5)
RE: [HACKERS] LIBPQ for WIN32

On Tue, 29 Sep 1998, Hiroshi Inoue wrote:

On 28-Sep-98 Hiroshi Inoue wrote:

I think that current DLL supports version 1.0,1.1,2.0,2.1 and 2.2 and we
can
specify any version from 1.0 to 2.2 .
For example,if we call WSAStartup(MAKEWORD(1.0),&wsaData) from libpq
and call WSAStartup(MAKEWORD(2,2),&wsaData) from psql,both return OK
and wsaData.wVersion is 1.0 for libpq and 2.2 for psql.

Whichever is done, try not to ever request a version higher than what is
required. It forces upgrades that may not even be necessary. It's been
awhile since I've done windows code, but I've been bitten by requiring a
higher version of a library than necessary - more than once without even
realising it. It's not very fun when it comes time to fix it.

How about my sample code at the end of my previous post.
In that code,libpq does nothing if main application calls WSAStartup().

According to the winsock 1.1 spec an intermediate dll should handle it's
own startup and cleanup functions. Thinking about it, you really have
no way of knowing if the app is going to stop using and unload winsock
if you're not done with it. It may have loaded it for any number of
reasons not necessarily related to the database access.

Vince.
--
==========================================================================
Vince Vielhaber -- KA8CSH email: vev@michvhf.com flame-mail: /dev/null
# include <std/disclaimers.h> TEAM-OS2
Online Searchable Campground Listings http://www.camping-usa.com
"There is no outfit less entitled to lecture me about bloat
than the federal government" -- Tony Snow
==========================================================================

#7Magnus Hagander
mha@edu.sollentuna.se
In reply to: Vince Vielhaber (#6)
RE: [HACKERS] LIBPQ for WIN32

With the current implementation, I don't beleive it will make a

difference -

I don't think that any part of the Winsock system is

actually hidden if
you

ask for a lower version. But it is _permitted_ by the

specification that
the

DLL can hide parts that belong to a higher version than the

one requested.

So I'm not 100% sure... Does anybody have access to a

Winsock?@that
actually

hides some details when you ask for the wrong version?

By the specs there may be the DLL that doesn't support lower versions.
In that case my code doesn't work well.
But we can delay to call WSAStartup() after the first socket
call in LIBPQ.
My example code in fe-connect.c is such as follows.

This looks like a great way to do it :-)

hp = gethostbyname(conn->pghost);
#ifdef WIN32
if ((hp == NULL) && (GetLastError() == WSANOTINITIALISED))
{
WSADATA wsaData;
if (WSAStartup(MAKEWORD(1,1),&wsaData))
{
fprintf(stderr, "Failed to start
winsock: %i\n", WSAGetLastError());
exit(1);

This is not the way to do it, though - what if it's a gui program.
Should instead be, like the other error handling:

sprintf(conn->errorMessage,
"connectDB() -- Failed to start
winsock: %i\n",
WSAGetLstError());
goto connect_errReturn;

}
....
???? for WSACleanup() ????
....

Yes, this is the problem. Perhaps set a global flag in the DLL that is set
if we have ever called WSAStartup() from the DLL. Then we can check in
DllMain() at process detachment if we have to close the winsock?

Will you write up a patch or should I?

//Magnus

#8Magnus Hagander
mha@edu.sollentuna.se
In reply to: Magnus Hagander (#7)
RE: [HACKERS] LIBPQ for WIN32

On 28-Sep-98 Hiroshi Inoue wrote:

I think that current DLL supports version

1.0,1.1,2.0,2.1 and 2.2 and we

can
specify any version from 1.0 to 2.2 .
For example,if we call

WSAStartup(MAKEWORD(1.0),&wsaData) from libpq

and call WSAStartup(MAKEWORD(2,2),&wsaData) from

psql,both return OK

and wsaData.wVersion is 1.0 for libpq and 2.2 for psql.

Whichever is done, try not to ever request a version

higher than what is

required. It forces upgrades that may not even be

necessary. It's been

awhile since I've done windows code, but I've been bitten

by requiring a

higher version of a library than necessary - more than

once without even

realising it. It's not very fun when it comes time to fix it.

How about my sample code at the end of my previous post.
In that code,libpq does nothing if main application calls

WSAStartup().

According to the winsock 1.1 spec an intermediate dll should
handle it's
own startup and cleanup functions. Thinking about it, you
really have
no way of knowing if the app is going to stop using and unload winsock
if you're not done with it. It may have loaded it for any number of
reasons not necessarily related to the database access.

Yes, that is true. The problem lies in how Winsock really will handle
requests for different versions. If the DLL requires 1.1 and the main
program requires 2.0. Will it then open up 2.0 interfaces for both, just the
main app, or none of them? It can't very well do it for just the main app,
since they are both in the same process & thread.
On the other hand, thinking a bit more of it. If we load version 1.1 in
DllMain(), we are safe in most cases. Since if the app loads winsock later
with 2.0, it will probably switch to 2.0, and 2.0 is backwards compatible
with 1.1.
The problem with that scenario is if the DLL is loaded later on in the
program using LoadLibrary(). In that case, the application will have loaded
v2.0, and the DLL will then open up and load v1.1. Will the application then
still be able to use v2.0? With the current Microsoft implementation of
Winsock, it will. But reading the specs, I can't find out if we are allowed
to do this or not.
On the other hand, the specs say:
"An application or DLL can call WSAStartup more than once if it needs to
obtain the WSAData structure information more than once. On each such call
the application can specify any version number supported by the DLL."
And what would the point of this be, if a later call might break an earlier
code. So it will probably "unlock" parts of the Winsock to support all the
requested versions.

If that's the way it works, then we should just make sure we call
WSAStartup() once _and_ WSACleanup() once. And again, if this is how it
works, then the original change with putting it all in DllMain() seems like
the smartest move again. We should probably go with that one, unless
somebody knows another good reason not to :-)

//Magnus

#9Taral
taral@mail.utexas.edu
In reply to: Magnus Hagander (#7)
RE: [HACKERS] LIBPQ for WIN32

OK... Whether or not Winsock enables a 2.0 or 1.1 interface is pretty
irrelevant, unless you're using new features like
setsockopt(somethingorother) [I can't remember]. Otherwise, the standard BSD
socket functions (socket, bind, connect, listen, etc.) are unchanged.

A much better way to do this is to do a WSAStartup() in DllMain on
PROCESS_ATTACH requesting any interface from 1.1 to 2.2, and FAIL TO LOAD if
the WSAStartup() fails to provide a valid interface. That way, we just
always call WSACleanup() in DllMain on PROCESS_DETACH.

(Note that delaying WSAStartup() until the first socket call makes your code
ugly, and can delay the first socket call unnecessarily. Since we're almost
guaranteed to be calling sockets, we should initialize winsock when we
initialize.)

As for any applications that might not use libpq... They should delay-load
libpq.dll. I saw a reference to it in the MSDN library... dunno if win32
supports it.

Taral

Show quoted text

-----Original Message-----
From: owner-pgsql-hackers@postgreSQL.org
[mailto:owner-pgsql-hackers@postgreSQL.org]On Behalf Of Magnus Hagander
Sent: Tuesday, September 29, 1998 7:06 AM
To: 'Hiroshi Inoue'; pgsql-hackers
Subject: RE: [HACKERS] LIBPQ for WIN32

With the current implementation, I don't beleive it will make a

difference -

I don't think that any part of the Winsock system is

actually hidden if
you

ask for a lower version. But it is _permitted_ by the

specification that
the

DLL can hide parts that belong to a higher version than the

one requested.

So I'm not 100% sure... Does anybody have access to a

Winsock?@that
actually

hides some details when you ask for the wrong version?

By the specs there may be the DLL that doesn't support lower versions.
In that case my code doesn't work well.
But we can delay to call WSAStartup() after the first socket
call in LIBPQ.
My example code in fe-connect.c is such as follows.

This looks like a great way to do it :-)

hp = gethostbyname(conn->pghost);
#ifdef WIN32
if ((hp == NULL) && (GetLastError() == WSANOTINITIALISED))
{
WSADATA wsaData;
if (WSAStartup(MAKEWORD(1,1),&wsaData))
{
fprintf(stderr, "Failed to start
winsock: %i\n", WSAGetLastError());
exit(1);

This is not the way to do it, though - what if it's a gui program.
Should instead be, like the other error handling:

sprintf(conn->errorMessage,
"connectDB() -- Failed to start
winsock: %i\n",
WSAGetLstError());
goto connect_errReturn;

}
....
???? for WSACleanup() ????
....

Yes, this is the problem. Perhaps set a global flag in the DLL that is set
if we have ever called WSAStartup() from the DLL. Then we can check in
DllMain() at process detachment if we have to close the winsock?

Will you write up a patch or should I?

//Magnus

#10Hiroshi Inoue
Inoue@tpf.co.jp
In reply to: Magnus Hagander (#7)
RE: [HACKERS] LIBPQ for WIN32

With the current implementation, I don't beleive it will make a

difference -

I don't think that any part of the Winsock system is

actually hidden if
you

ask for a lower version. But it is _permitted_ by the

specification that
the

DLL can hide parts that belong to a higher version than the

one requested.

So I'm not 100% sure... Does anybody have access to a

Winsock?@that
actually

hides some details when you ask for the wrong version?

By the specs there may be the DLL that doesn't support lower versions.
In that case my code doesn't work well.
But we can delay to call WSAStartup() after the first socket
call in LIBPQ.
My example code in fe-connect.c is such as follows.

This looks like a great way to do it :-)

hp = gethostbyname(conn->pghost);
#ifdef WIN32
if ((hp == NULL) && (GetLastError() == WSANOTINITIALISED))
{
WSADATA wsaData;
if (WSAStartup(MAKEWORD(1,1),&wsaData))
{
fprintf(stderr, "Failed to start
winsock: %i\n", WSAGetLastError());
exit(1);

This is not the way to do it, though - what if it's a gui program.
Should instead be, like the other error handling:

sprintf(conn->errorMessage,
"connectDB() -- Failed to start
winsock: %i\n",
WSAGetLstError());
goto connect_errReturn;

}
....
???? for WSACleanup() ????
....

Yes, this is the problem. Perhaps set a global flag in the DLL that is set
if we have ever called WSAStartup() from the DLL. Then we can check in
DllMain() at process detachment if we have to close the winsock?

Will you write up a patch or should I?

Judging from your reply to Vince,it is preferable to call WSAStartup() and
corrspoiding WSACleanup() in DllMain.
If so,my original code is OK except error handling and the value of version
number ?

Hiroshi Inoue
Inoue@tpf.co.jp

#11Magnus Hagander
mha@edu.sollentuna.se
In reply to: Hiroshi Inoue (#10)
RE: [HACKERS] LIBPQ for WIN32

With the current implementation, I don't beleive it will make a

difference -

I don't think that any part of the Winsock system is

actually hidden if
you

ask for a lower version. But it is _permitted_ by the

specification that
the

DLL can hide parts that belong to a higher version than the

one requested.

So I'm not 100% sure... Does anybody have access to a

Winsock?@that
actually

hides some details when you ask for the wrong version?

By the specs there may be the DLL that doesn't support

lower versions.

In that case my code doesn't work well.
But we can delay to call WSAStartup() after the first socket
call in LIBPQ.
My example code in fe-connect.c is such as follows.

This looks like a great way to do it :-)

hp = gethostbyname(conn->pghost);
#ifdef WIN32
if ((hp == NULL) && (GetLastError() == WSANOTINITIALISED))
{
WSADATA wsaData;
if (WSAStartup(MAKEWORD(1,1),&wsaData))
{
fprintf(stderr, "Failed to start
winsock: %i\n", WSAGetLastError());
exit(1);

This is not the way to do it, though - what if it's a gui program.
Should instead be, like the other error handling:

sprintf(conn->errorMessage,
"connectDB() -- Failed to start
winsock: %i\n",
WSAGetLstError());
goto connect_errReturn;

}
....
???? for WSACleanup() ????
....

Yes, this is the problem. Perhaps set a global flag in the

DLL that is set

if we have ever called WSAStartup() from the DLL. Then we

can check in

DllMain() at process detachment if we have to close the winsock?

Will you write up a patch or should I?

Judging from your reply to Vince,it is preferable to call
WSAStartup() and
corrspoiding WSACleanup() in DllMain.
If so,my original code is OK except error handling and the
value of version
number ?

Yes, I think that is where we ended up :-)

BTW, I came to think of another thing - the Win32 library does _not_ support
crypt-password authentication as it is now. Because there is no crypt()
function.
Any chance to have a file with crypt() included in the source as we did with
getopt? If that can be done, and one of you FreeBSD (or someone else who has
it under BSD license) could mail it to me/put it in the tree, I can take a
look at implementing it - shouldn't bve hard at all.

//Magnus