pike.git/lib/modules/Sql.pmod/pgsql.pike:1:
/*
* This is the PostgreSQL direct network module for Pike.
- *
- * TODO: support SSL connections
+
*/
//! This is an interface to the PostgreSQL database
//! server. This module is independent of external libraries.
//! Note that you @b{do not@} need to have a
//! PostgreSQL server running on your host to use this module: you can
//! connect to the database over a TCP/IP socket.
//!
//! This module replaces the functionality of the older @[Sql.postgres]
//! and @[Postgres.postgres] modules.
pike.git/lib/modules/Sql.pmod/pgsql.pike:157:
//!
//! The host argument can have the syntax @expr{"hostname"@} or
//! @expr{"hostname:portname"@}. This allows to specify the TCP/IP
//! port to connect to. If it is @expr{0@} or @expr{""@}, it will try
//! to connect to localhost, default port.
//!
//! The database argument specifies the database to connect to. If
//! @expr{0@} or @expr{""@}, it will try to connect to the specified
//! database.
//!
+ //! The options argument currently supports two options: use_ssl and force_ssl
+ //!
//! @note
//! You need to have a database selected before using the sql-object,
//! otherwise you'll get exceptions when you try to query it. Also
//! notice that this function @b{can@} raise exceptions if the db
//! server doesn't respond, if the database doesn't exist or is not
//! accessible by you.
//!
//! @seealso
//! @[Postgres.postgres], @[Sql.Sql], @[postgres->select_db]
protected void create(void|string _host, void|string _database,
void|string _user, void|string _pass, void|mapping(string:mixed) _options) {
pass = _pass; _pass = "CENSORED";
user = _user; database = _database; host = _host || PGSQL_DEFAULT_HOST;
- options = _options;
+ options = _options || ([]);
if(search(host,":")>=0 && sscanf(_host,"%s:%d",host,port)!=2)
ERROR("Error in parsing the hostname argument\n");
if(!port)
port = PGSQL_DEFAULT_PORT;
querymutex=Thread.Mutex();
stealmutex=Thread.Mutex();
reconnect();
}
//! @decl string error()
pike.git/lib/modules/Sql.pmod/pgsql.pike:218:
#define GETBYTE() conn.getbyte()
#define GETSTRING(x) conn.getstring(x)
#define GETINT16() conn.getint16()
#define GETINT32() conn.getint32()
#define FLUSHED conn.flushed
#ifdef USEPGsql
#define PEEK(x) conn.bpeek(x)
#else
#define PEEK(x) conn.peek(x)
-
+
#endif
#define plugstring(x) (sprintf x)
- #define plugbyte(x) sprintf("%c",x)
+ #define plugbyte(x) String.int2char(x)
inline final private string plugint16(int x) {
return sprintf("%c%c",x>>8&255,x&255);
}
inline final private string plugint32(int x) {
return sprintf("%c%c%c%c",x>>24&255,x>>16&255,x>>8&255,x&255);
}
inline final private string plugint64(int x) {
return sprintf("%c%c%c%c%c%c%c%c",
x>>56&255,x>>48&255,x>>40&255,x>>32&255,x>>24&255,x>>16&255,x>>8&255,x&255);
}
class PGassist {
- #ifdef UNBUFFEREDIO
- inherit Stdio.File:std;
- #else
- inherit Stdio.FILE:std;
- #endif
+
+ int(-1..1) peek(int timeout) {
+ }
+
+ string read(int len,void|int(0..1) not_all) {
+ }
+
+ int write(string|array(string) data) {
+ }
+
+ int getchar() {
+ }
+
+ int close() {
+ }
+
#ifdef USEPGsql
- inherit _PGsql.PGsql:pg;
+ inherit _PGsql.PGsql;
#else
int flushed;
#endif
-
+
void create(object pgsqlsess) {
- std::create();
+
#ifdef USEPGsql
- pg::setpgsqlsess(pgsqlsess);
+ ::create(pgsqlsess);
#else
flushed=-1;
#endif
}
- int connect(string host,int port) {
- int res=std::connect(host,port);
- #ifdef USEPGsql
- if(res)
- pg::create(std::query_fd());
- #endif
- return res;
- }
+
#ifndef USEPGsql
-
+
inline final int getbyte() {
if(!FLUSHED && !PEEK(0))
sendflush();
- #ifdef UNBUFFEREDIO
- return read(1)[0];
- #else
+
return getchar();
- #endif
+
}
final string getstring(void|int len) {
if(!zero_type(len)) {
string acc="",res;
do {
if(!FLUSHED && !PEEK(0))
sendflush();
res=conn.read(len,!FLUSHED);
if(res) {
pike.git/lib/modules/Sql.pmod/pgsql.pike:336:
data=({data,FLUSH});
else
data+=({FLUSH});
PD("Flush\n");
FLUSHED=1;
}
else if(FLUSHED!=-1)
FLUSHED=0;
return write(data);
}
+
+ final void sendterminate() {
+ PD("Terminate\n");
+ SENDCMD(({"X",plugint32(4)}));
+ close();
}
-
+ }
-
+ class PGconn {
+
+ inherit PGassist:pg;
+ #ifdef UNBUFFEREDIO
+ inherit Stdio.File:std;
+
+ inline int getchar() {
+ return std::read(1)[0];
+ }
+ #else
+ inherit Stdio.FILE:std;
+
+ inline int getchar() {
+ return std::getchar();
+ }
+ #endif
+
+ inline int(-1..1) peek(int timeout) {
+ return std::peek(timeout);
+ }
+
+ inline string read(int len,void|int(0..1) not_all) {
+ return std::read(len,not_all);
+ }
+
+ inline int write(string|array(string) data) {
+ return std::write(data);
+ }
+
+ int close() {
+ return std::close();
+ }
+
+ void create(Stdio.File stream,object pgsqlsess) {
+ std::create();
+ std::assign(stream);
+ pg::create(pgsqlsess);
+ }
+ }
+
+ #if constant(SSL.sslfile)
+ class PGconnS {
+ inherit SSL.sslfile:std;
+ inherit PGassist:pg;
+
+ Stdio.File rawstream;
+
+ inline int(-1..1) peek(int timeout) {
+ return rawstream.peek(timeout);
+ }
+
+ inline string read(int len,void|int(0..1) not_all) {
+ return std::read(len,not_all);
+ }
+
+ inline int write(string|array(string) data) {
+ return std::write(data);
+ }
+
+ void create(Stdio.File stream, SSL.context ctx,object pgsqlsess) {
+ rawstream=stream;
+ std::create(stream,ctx,1,1);
+ pg::create(pgsqlsess);
+ }
+ }
+ #endif
+
final private object getsocket() {
- object lcon = PGassist(this);
+ object lcon = Stdio.File();
if(!lcon.connect(host,port))
return UNDEFINED;
-
+
+ object fcon;
#if constant(SSL.sslfile)
- #if 0
+ if(options->use_ssl || options->force_ssl) {
+ PD("SSLRequest\n");
+ lcon.write(({plugint32(8),plugint32(PG_PROTOCOL(1234,5679))}));
+ switch(lcon.read(1)) {
+ case "S":
SSL.context context = SSL.context();
- #if 1
- context->preferred_suites = ({
- SSL_rsa_with_idea_cbc_sha,
- SSL_rsa_with_rc4_128_sha,
- SSL_rsa_with_rc4_128_md5,
- SSL_rsa_with_3des_ede_cbc_sha,
- SSL_rsa_export_with_rc4_40_md5,
- SSL_rsa_export_with_rc2_cbc_40_md5,
- SSL_rsa_export_with_des40_cbc_sha,
- });
- #endif
+
context->random = Crypto.Random.random_string;
- object read_callback=con->query_read_callback();
- object write_callback=con->query_write_callback();
- object close_callback=con->query_close_callback();
-
- ssl = SSL.sslfile(con, context, 1,blocking);
- if(!blocking) {
- ssl->set_read_callback(read_callback);
- ssl->set_write_callback(write_callback);
- ssl->set_close_callback(close_callback);
+ fcon=PGconnS(lcon, context, this);
+ if(fcon)
+ return fcon;
+ default:lcon.close();
+ if(!lcon.connect(host,port))
+ return UNDEFINED;
+ case "N":
+ if(options->force_ssl)
+ ERROR("Encryption not supported on connection to %s:%d\n",
+ host,port);
}
- con=ssl;
+ }
+ #else
+ if(options->force_ssl)
+ ERROR("Encryption library missing, cannot establish connection to %s:%d\n",
+ host,port);
#endif
- #endif
- return lcon;
+ fcon=PGconn(lcon, this);
+ return fcon;
}
//! Cancels the currently running query.
//!
//! This function is PostgreSQL-specific, and thus it is not available
//! through the generic SQL-interface.
void cancelquery() {
if(qstate==inquery) {
qstate=cancelpending;
object lcon;
PD("CancelRequest\n");
if(!(lcon=getsocket()))
ERROR("Cancel connect failed\n");
- lcon.write(({plugint32(16),plugint32(PG_PROTOCOL(1234,4567)),
+ lcon.write(({plugint32(16),plugint32(PG_PROTOCOL(1234,5678)),
plugint32(backendpid),cancelsecret}));
lcon.close();
}
}
//! Returns the old cachedepth, sets the new cachedepth for prepared
//! statements automatic caching.
//!
//! This function is PostgreSQL-specific, and thus it is not available
//! through the generic SQL-interface.
pike.git/lib/modules/Sql.pmod/pgsql.pike:838: Inside #if undefined(UNBUFFEREDIO)
#ifndef UNBUFFEREDIO
private int read_cb(mixed foo, string d) {
conn.unread(d);
do _decodemsg();
while(PEEK(0)==1);
return 0;
}
#endif
- final private void sendterminate() {
- PD("Terminate\n");
- SENDCMD(({"X",plugint32(4)}));
- conn.close();
- }
-
+
void destroy() {
- sendterminate();
+ conn.sendterminate();
}
private void reconnect(void|int force) {
if(conn) {
reconnected++;
#ifdef DEBUG
ERROR("While debugging, reconnects are forbidden\n");
exit(1);
#endif
if(!force)
- sendterminate();
+ conn.sendterminate();
foreach(prepareds;;mapping tprepared)
m_delete(tprepared,"preparedname");
}
if(!(conn=getsocket()))
ERROR("Couldn't connect to database on %s:%d\n",host,port);
_closesent=0;
mstate=unauthenticated;
qstate=queryidle;
runtimeparameter=([]);
array(string) plugbuf=({"",plugint32(PG_PROTOCOL(3,0))});