Merge branch 'develop' into MXS-329
This commit is contained in:
@ -72,20 +72,39 @@
|
||||
WHERE user.user IS NOT NULL AND user.user <> ''"
|
||||
|
||||
#else
|
||||
# define LOAD_MYSQL_USERS_QUERY "SELECT user, host, password, concat(user,host,password,Select_priv) AS userdata, Select_priv AS anydb FROM mysql.user WHERE user IS NOT NULL AND user <> ''"
|
||||
# define LOAD_MYSQL_USERS_QUERY "SELECT \
|
||||
user, host, password, concat(user,host,password,Select_priv) AS userdata, \
|
||||
Select_priv AS anydb FROM mysql.user WHERE user IS NOT NULL AND user <> ''"
|
||||
#endif
|
||||
#define MYSQL_USERS_COUNT "SELECT COUNT(1) AS nusers FROM mysql.user"
|
||||
|
||||
#define MYSQL_USERS_WITH_DB_ORDER " ORDER BY host DESC"
|
||||
#define LOAD_MYSQL_USERS_WITH_DB_QUERY "SELECT user.user AS user,user.host AS host,user.password AS password,concat(user.user,user.host,user.password,user.Select_priv,IFNULL(db,'')) AS userdata, user.Select_priv AS anydb,db.db AS db FROM mysql.user LEFT JOIN mysql.db ON user.user=db.user AND user.host=db.host WHERE user.user IS NOT NULL" MYSQL_USERS_WITH_DB_ORDER
|
||||
#define LOAD_MYSQL_USERS_WITH_DB_QUERY "SELECT \
|
||||
user.user AS user, \
|
||||
user.host AS host, \
|
||||
user.password AS password, \
|
||||
concat(user.user,user.host,user.password,user.Select_priv,IFNULL(db,'')) AS userdata, \
|
||||
user.Select_priv AS anydb, \
|
||||
db.db AS db \
|
||||
FROM mysql.user LEFT JOIN mysql.db \
|
||||
ON user.user=db.user AND user.host=db.host \
|
||||
WHERE user.user IS NOT NULL" MYSQL_USERS_WITH_DB_ORDER
|
||||
|
||||
#define MYSQL_USERS_WITH_DB_COUNT "SELECT COUNT(1) AS nusers_db FROM (" LOAD_MYSQL_USERS_WITH_DB_QUERY ") AS tbl_count"
|
||||
|
||||
#define LOAD_MYSQL_USERS_WITH_DB_QUERY_NO_ROOT "SELECT * FROM (" LOAD_MYSQL_USERS_WITH_DB_QUERY ") AS t1 WHERE user NOT IN ('root')" MYSQL_USERS_WITH_DB_ORDER
|
||||
#define LOAD_MYSQL_USERS_WITH_DB_QUERY_NO_ROOT "SELECT * \
|
||||
FROM (" LOAD_MYSQL_USERS_WITH_DB_QUERY ") AS t1 \
|
||||
WHERE user NOT IN ('root')" MYSQL_USERS_WITH_DB_ORDER
|
||||
|
||||
#define LOAD_MYSQL_DATABASE_NAMES "SELECT * FROM ( (SELECT COUNT(1) AS ndbs FROM INFORMATION_SCHEMA.SCHEMATA) AS tbl1, (SELECT GRANTEE,PRIVILEGE_TYPE from INFORMATION_SCHEMA.USER_PRIVILEGES WHERE privilege_type='SHOW DATABASES' AND REPLACE(GRANTEE, \'\\'\',\'\')=CURRENT_USER()) AS tbl2)"
|
||||
#define LOAD_MYSQL_DATABASE_NAMES "SELECT * \
|
||||
FROM ( (SELECT COUNT(1) AS ndbs \
|
||||
FROM INFORMATION_SCHEMA.SCHEMATA) AS tbl1, \
|
||||
(SELECT GRANTEE,PRIVILEGE_TYPE from INFORMATION_SCHEMA.USER_PRIVILEGES \
|
||||
WHERE privilege_type='SHOW DATABASES' AND REPLACE(GRANTEE, \'\\'\',\'\')=CURRENT_USER()) AS tbl2)"
|
||||
|
||||
#define ERROR_NO_SHOW_DATABASES "%s: Unable to load database grant information, MaxScale authentication will proceed without including database permissions. To correct this GRANT SHOW DATABASES ON *.* privilege to the user %s."
|
||||
#define ERROR_NO_SHOW_DATABASES "%s: Unable to load database grant information, \
|
||||
MaxScale authentication will proceed without including database permissions. \
|
||||
To correct this GRANT SHOW DATABASES ON *.* privilege to the user %s."
|
||||
/** Defined in log_manager.cc */
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
extern size_t log_ses_count[];
|
||||
@ -1238,7 +1257,7 @@ getUsers(SERVICE *service, USERS *users)
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Unable to get user data from backend database "
|
||||
"for service [%s]. Missing server information.",
|
||||
"for service [%s]. Failed to connect to any of the backend databases.",
|
||||
service->name)));
|
||||
mysql_close(con);
|
||||
return -1;
|
||||
@ -2175,6 +2194,7 @@ int tmp;
|
||||
free(dbkey);
|
||||
return NULL;
|
||||
}
|
||||
dbkey->resource[tmp] = 0; // NULL Terminate
|
||||
}
|
||||
else // NULL is valid, so represent with a length of -1
|
||||
{
|
||||
@ -2429,9 +2449,8 @@ bool check_service_permissions(SERVICE* service)
|
||||
{
|
||||
if(mysql_errno(mysql) == ER_TABLEACCESS_DENIED_ERROR)
|
||||
{
|
||||
skygw_log_write(LE,"%s: Error: User '%s' is missing SELECT privileges on mysql.db table. MySQL error message: %s",
|
||||
skygw_log_write(LE,"%s: Warning: User '%s' is missing SELECT privileges on mysql.db table. Database name will be ignored in authentication. MySQL error message: %s",
|
||||
service->name,user,mysql_error(mysql));
|
||||
rval = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -109,7 +109,9 @@ static inline void dcb_write_fake_code(DCB *dcb);
|
||||
static inline void dcb_write_when_already_queued(DCB *dcb, GWBUF *queue);
|
||||
static void dcb_log_write_failure(DCB *dcb, GWBUF *queue, int eno);
|
||||
static inline void dcb_write_tidy_up(DCB *dcb, bool below_water);
|
||||
static int dcb_write_SSL_error_report (DCB *dcb, int ret);
|
||||
static void dcb_write_SSL_error_report (DCB *dcb, int ret, int ssl_errno);
|
||||
int dcb_bytes_readable_SSL (DCB *dcb, int nread);
|
||||
void dcb_log_ssl_read_error(DCB *dcb, int ssl_errno, int rc);
|
||||
|
||||
size_t dcb_get_session_id(
|
||||
DCB *dcb)
|
||||
@ -956,208 +958,104 @@ int dcb_read(
|
||||
* @return -1 on error, otherwise the number of read bytes on the last
|
||||
* iteration of while loop. 0 is returned if no data available.
|
||||
*/
|
||||
int dcb_read_SSL(
|
||||
DCB *dcb,
|
||||
GWBUF **head)
|
||||
int dcb_read_SSL(DCB *dcb,
|
||||
GWBUF **head)
|
||||
{
|
||||
GWBUF *buffer = NULL;
|
||||
int b,pending;
|
||||
int rc;
|
||||
int n;
|
||||
int nread = 0;
|
||||
int ssl_errno = 0;
|
||||
CHK_DCB(dcb);
|
||||
GWBUF *buffer = NULL;
|
||||
int b, n, nread = 0;
|
||||
CHK_DCB(dcb);
|
||||
|
||||
if (dcb->fd <= 0)
|
||||
{
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Read failed, dcb is %s.",
|
||||
dcb->fd == DCBFD_CLOSED ? "closed" : "cloned, not readable")));
|
||||
n = 0;
|
||||
goto return_n;
|
||||
}
|
||||
if (dcb->fd <= 0)
|
||||
{
|
||||
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
|
||||
"Error : Read failed, dcb is %s.",
|
||||
dcb->fd == DCBFD_CLOSED ? "closed" : "cloned, not readable")));
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (true)
|
||||
while ((b = dcb_bytes_readable_SSL(dcb, nread)) > 0)
|
||||
{
|
||||
dcb->last_read = hkheartbeat;
|
||||
int bufsize = MIN(b, MAX_BUFFER_SIZE);
|
||||
|
||||
if ((buffer = gwbuf_alloc(bufsize)) == NULL)
|
||||
{
|
||||
int bufsize;
|
||||
ssl_errno = 0;
|
||||
rc = ioctl(dcb->fd, FIONREAD, &b);
|
||||
pending = SSL_pending(dcb->ssl);
|
||||
if (rc == -1)
|
||||
{
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : ioctl FIONREAD for dcb %p in "
|
||||
"state %s fd %d failed due error %d, %s.",
|
||||
dcb,
|
||||
STRDCBSTATE(dcb->state),
|
||||
dcb->fd,
|
||||
errno,
|
||||
strerror_r(errno, errbuf, sizeof(errbuf)))));
|
||||
n = -1;
|
||||
goto return_n;
|
||||
}
|
||||
/*<
|
||||
* This is a fatal error which should cause shutdown.
|
||||
* Todo shutdown if memory allocation fails.
|
||||
*/
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
|
||||
"Error : Failed to allocate read buffer "
|
||||
"for dcb %p fd %d, due %d, %s.",
|
||||
dcb,
|
||||
dcb->fd,
|
||||
errno,
|
||||
strerror_r(errno, errbuf, sizeof (errbuf)))));
|
||||
|
||||
if (b == 0 && pending == 0 && nread == 0)
|
||||
{
|
||||
/** Handle closed client socket */
|
||||
if (dcb_isclient(dcb))
|
||||
{
|
||||
char c = 0;
|
||||
int r = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* try to read 1 byte, without consuming the socket buffer */
|
||||
r = SSL_peek(dcb->ssl, &c, sizeof(char));
|
||||
if (r <= 0)
|
||||
{
|
||||
ssl_errno = SSL_get_error(dcb->ssl,r);
|
||||
if(ssl_errno != SSL_ERROR_WANT_READ &&
|
||||
ssl_errno != SSL_ERROR_WANT_WRITE &&
|
||||
ssl_errno != SSL_ERROR_NONE)
|
||||
n = -1;
|
||||
else
|
||||
n = 0;
|
||||
goto return_n;
|
||||
}
|
||||
}
|
||||
n = 0;
|
||||
goto return_n;
|
||||
}
|
||||
else if (b == 0 && pending == 0)
|
||||
{
|
||||
n = 0;
|
||||
goto return_n;
|
||||
}
|
||||
n = SSL_read(dcb->ssl, GWBUF_DATA(buffer), bufsize);
|
||||
dcb->stats.n_reads++;
|
||||
|
||||
if (n <= 0)
|
||||
{
|
||||
int ssl_errno = SSL_get_error(dcb->ssl, n);
|
||||
dcb_log_ssl_read_error(dcb, ssl_errno, n);
|
||||
|
||||
if (ssl_errno != SSL_ERROR_WANT_READ &&
|
||||
ssl_errno != SSL_ERROR_WANT_WRITE &&
|
||||
ssl_errno != SSL_ERROR_NONE)
|
||||
{
|
||||
nread = -1;
|
||||
gwbuf_free(buffer);
|
||||
}
|
||||
return nread;
|
||||
}
|
||||
|
||||
buffer = gwbuf_rtrim(buffer, bufsize - n);
|
||||
|
||||
if (buffer)
|
||||
{
|
||||
#ifdef SS_DEBUG
|
||||
else
|
||||
{
|
||||
skygw_log_write_flush(LD,"Total: %d Socket: %d Pending: %d",
|
||||
nread,b,pending);
|
||||
}
|
||||
skygw_log_write(LD, "%lu SSL: Truncated buffer from %d to %d bytes. "
|
||||
"Read %d bytes, %d bytes waiting.\n", pthread_self(),
|
||||
bufsize, GWBUF_LENGTH(buffer), n, b);
|
||||
|
||||
if (GWBUF_LENGTH(buffer) != n)
|
||||
{
|
||||
skygw_log_sync_all();
|
||||
}
|
||||
|
||||
ss_info_dassert((buffer->start <= buffer->end), "Buffer start has passed end.");
|
||||
ss_info_dassert(GWBUF_LENGTH(buffer) == n, "Buffer size not equal to read bytes.");
|
||||
#endif
|
||||
nread += n;
|
||||
|
||||
dcb->last_read = hkheartbeat;
|
||||
LOGIF(LD, (skygw_log_write(LOGFILE_DEBUG,
|
||||
"%lu [dcb_read_SSL] Read %d bytes from dcb %p in state %s "
|
||||
"fd %d.",
|
||||
pthread_self(),
|
||||
n,
|
||||
dcb,
|
||||
STRDCBSTATE(dcb->state),
|
||||
dcb->fd)));
|
||||
|
||||
bufsize = MIN(b, MAX_BUFFER_SIZE);
|
||||
/*< Append read data to the gwbuf */
|
||||
*head = gwbuf_append(*head, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
if ((buffer = gwbuf_alloc(bufsize)) == NULL)
|
||||
{
|
||||
/*<
|
||||
* This is a fatal error which should cause shutdown.
|
||||
* Todo shutdown if memory allocation fails.
|
||||
*/
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Failed to allocate read buffer "
|
||||
"for dcb %p fd %d, due %d, %s.",
|
||||
dcb,
|
||||
dcb->fd,
|
||||
errno,
|
||||
strerror_r(errno, errbuf, sizeof(errbuf)))));
|
||||
ss_dassert(gwbuf_length(*head) == nread);
|
||||
LOGIF(LD, skygw_log_write(LD, "%lu Read a total of %d bytes from dcb %p in state %s fd %d.",
|
||||
pthread_self(),
|
||||
nread,
|
||||
dcb,
|
||||
STRDCBSTATE(dcb->state),
|
||||
dcb->fd));
|
||||
|
||||
n = -1;
|
||||
goto return_n;
|
||||
}
|
||||
|
||||
n = SSL_read(dcb->ssl, GWBUF_DATA(buffer), bufsize);
|
||||
dcb->stats.n_reads++;
|
||||
|
||||
if (n < 0)
|
||||
{
|
||||
char errbuf[200];
|
||||
ssl_errno = SSL_get_error(dcb->ssl,n);
|
||||
#ifdef SS_DEBUG
|
||||
if(ssl_errno == SSL_ERROR_SSL ||
|
||||
ssl_errno == SSL_ERROR_SYSCALL)
|
||||
{
|
||||
int eno;
|
||||
while((eno = ERR_get_error()) != 0)
|
||||
{
|
||||
ERR_error_string_n(eno,errbuf,200);
|
||||
skygw_log_write(LE,
|
||||
"%s",
|
||||
errbuf);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if(ssl_errno == SSL_ERROR_WANT_READ ||
|
||||
ssl_errno == SSL_ERROR_WANT_WRITE ||
|
||||
ssl_errno == SSL_ERROR_NONE)
|
||||
{
|
||||
n = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Read failed, dcb %p in state "
|
||||
"%s fd %d, SSL error %d: %s.",
|
||||
dcb,
|
||||
STRDCBSTATE(dcb->state),
|
||||
dcb->fd,
|
||||
ssl_errno,
|
||||
strerror_r(errno, errbuf, sizeof(errbuf)))));
|
||||
|
||||
if(ssl_errno == SSL_ERROR_SSL ||
|
||||
ssl_errno == SSL_ERROR_SYSCALL)
|
||||
{
|
||||
while((ssl_errno = ERR_get_error()) != 0)
|
||||
{
|
||||
ERR_error_string_n(ssl_errno,errbuf,200);
|
||||
skygw_log_write(LE,
|
||||
"%s",
|
||||
errbuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
n = -1;
|
||||
gwbuf_free(buffer);
|
||||
goto return_n;
|
||||
}
|
||||
else if(n == 0)
|
||||
{
|
||||
gwbuf_free(buffer);
|
||||
goto return_n;
|
||||
}
|
||||
|
||||
buffer = gwbuf_rtrim(buffer,bufsize - n);
|
||||
if(buffer == NULL)
|
||||
{
|
||||
goto return_n;
|
||||
}
|
||||
#ifdef SS_DEBUG
|
||||
skygw_log_write(LD,"%lu SSL: Truncated buffer from %d to %d bytes. "
|
||||
"Read %d bytes, %d bytes waiting.\n",pthread_self(),
|
||||
bufsize,GWBUF_LENGTH(buffer),n,b);
|
||||
|
||||
if(GWBUF_LENGTH(buffer) != n){
|
||||
skygw_log_sync_all();
|
||||
}
|
||||
|
||||
ss_info_dassert((buffer->start <= buffer->end),"Buffer start has passed end.");
|
||||
ss_info_dassert(GWBUF_LENGTH(buffer) == n,"Buffer size not equal to read bytes.");
|
||||
#endif
|
||||
nread += n;
|
||||
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [dcb_read_SSL] Read %d bytes from dcb %p in state %s "
|
||||
"fd %d.",
|
||||
pthread_self(),
|
||||
n,
|
||||
dcb,
|
||||
STRDCBSTATE(dcb->state),
|
||||
dcb->fd)));
|
||||
|
||||
/*< Append read data to the gwbuf */
|
||||
*head = gwbuf_append(*head, buffer);
|
||||
} /*< while (true) */
|
||||
return_n:
|
||||
return nread;
|
||||
return nread;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1500,21 +1398,28 @@ dcb_write_SSL(DCB *dcb, GWBUF *queue)
|
||||
#if defined(FAKE_CODE)
|
||||
dcb_write_fake_code(dcb);
|
||||
#endif /* FAKE_CODE */
|
||||
do
|
||||
{
|
||||
do
|
||||
{
|
||||
w = gw_write_SSL(dcb->ssl, GWBUF_DATA(queue), GWBUF_LENGTH(queue));
|
||||
dcb->stats.n_writes++;
|
||||
dcb->stats.n_writes++;
|
||||
|
||||
if (w <= 0)
|
||||
{
|
||||
int ssl_errno = dcb_write_SSL_error_report (dcb, w);
|
||||
if(ssl_errno != SSL_ERROR_WANT_WRITE)
|
||||
if (w <= 0)
|
||||
{
|
||||
int ssl_errno = SSL_get_error(dcb->ssl, w);
|
||||
dcb_write_SSL_error_report(dcb, w, ssl_errno);
|
||||
if (ssl_errno != SSL_ERROR_WANT_WRITE)
|
||||
{
|
||||
atomic_add(&dcb->writeqlen, gwbuf_length(queue));
|
||||
dcb->stats.n_buffered++;
|
||||
dcb_write_tidy_up(dcb, below_water);
|
||||
return 1;
|
||||
}
|
||||
#ifdef SS_DEBUG
|
||||
else
|
||||
{
|
||||
skygw_log_write(LD, "SSL error: SSL_ERROR_WANT_WRITE, retrying SSL_write...");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
} while(w <= 0);
|
||||
|
||||
@ -1548,14 +1453,12 @@ dcb_write_SSL(DCB *dcb, GWBUF *queue)
|
||||
*
|
||||
* @param dcb The DCB of the client
|
||||
* @param ret The SSL operation return code
|
||||
* @return The final SSL error number
|
||||
* @param ssl_errno The SSL error code
|
||||
*/
|
||||
static int
|
||||
dcb_write_SSL_error_report (DCB *dcb, int ret)
|
||||
static void
|
||||
dcb_write_SSL_error_report (DCB *dcb, int ret, int ssl_errno)
|
||||
{
|
||||
int ssl_errno;
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
ssl_errno = SSL_get_error(dcb->ssl,ret);
|
||||
|
||||
if (LOG_IS_ENABLED(LOGFILE_DEBUG))
|
||||
{
|
||||
@ -1634,7 +1537,6 @@ dcb_write_SSL_error_report (DCB *dcb, int ret)
|
||||
} while((ssl_errno = ERR_get_error()) != 0);
|
||||
}
|
||||
}
|
||||
return SSL_ERROR_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3209,3 +3111,104 @@ char *name = NULL;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check how much data is readable from an SSL enabled DCB.
|
||||
* @param dcb DCB to check
|
||||
* @param nread Number of bytes we have already read
|
||||
* @return Number of bytes readable or -1 on error
|
||||
*/
|
||||
int dcb_bytes_readable_SSL(DCB *dcb, int nread)
|
||||
{
|
||||
int rval = 0;
|
||||
int nbytes;
|
||||
int rc = ioctl(dcb->fd, FIONREAD, &nbytes);
|
||||
|
||||
if (rc == -1)
|
||||
{
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
|
||||
"Error : ioctl FIONREAD for dcb %p in "
|
||||
"state %s fd %d failed due error %d, %s.",
|
||||
dcb,
|
||||
STRDCBSTATE(dcb->state),
|
||||
dcb->fd,
|
||||
errno,
|
||||
strerror_r(errno, errbuf, sizeof (errbuf)))));
|
||||
rval = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
int pending = SSL_pending(dcb->ssl);
|
||||
rval = nbytes + pending;
|
||||
if (rval == 0 && nread == 0)
|
||||
{
|
||||
/** Handle closed client socket */
|
||||
if (dcb_isclient(dcb))
|
||||
{
|
||||
char c = 0;
|
||||
int r = -1;
|
||||
|
||||
/* try to read 1 byte, without consuming the socket buffer */
|
||||
r = SSL_peek(dcb->ssl, &c, sizeof (char));
|
||||
if (r <= 0)
|
||||
{
|
||||
int ssl_errno = SSL_get_error(dcb->ssl, r);
|
||||
if (ssl_errno != SSL_ERROR_WANT_READ &&
|
||||
ssl_errno != SSL_ERROR_WANT_WRITE &&
|
||||
ssl_errno != SSL_ERROR_NONE)
|
||||
rval = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef SS_DEBUG
|
||||
else if (nbytes != 0 || pending != 0)
|
||||
{
|
||||
skygw_log_write_flush(LD, "Total: %d Socket: %d Pending: %d",
|
||||
nread, nbytes, pending);
|
||||
}
|
||||
else
|
||||
{
|
||||
skygw_log_write(LD, "Tried to read from socket, no data left. %d bytes read in total.", nread);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log SSL read error messages
|
||||
* @param dcb DCB from which the SSL_read was attempted
|
||||
* @param ssl_errno SSL error number
|
||||
* @param rc Return value of SSL_read
|
||||
*/
|
||||
void dcb_log_ssl_read_error(DCB *dcb, int ssl_errno, int rc)
|
||||
{
|
||||
if (ssl_errno != SSL_ERROR_WANT_READ &&
|
||||
ssl_errno != SSL_ERROR_WANT_WRITE &&
|
||||
ssl_errno != SSL_ERROR_NONE)
|
||||
{
|
||||
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
|
||||
"Error : Read failed, dcb %p in state "
|
||||
"%s fd %d, SSL error %d: %s.",
|
||||
dcb,
|
||||
STRDCBSTATE(dcb->state),
|
||||
dcb->fd,
|
||||
ssl_errno,
|
||||
strerror_r(errno, errbuf, sizeof (errbuf)))));
|
||||
|
||||
if (ssl_errno == SSL_ERROR_SSL ||
|
||||
ssl_errno == SSL_ERROR_SYSCALL)
|
||||
{
|
||||
while ((ssl_errno = ERR_get_error()) != 0)
|
||||
{
|
||||
ERR_error_string_n(ssl_errno, errbuf, STRERROR_BUFLEN);
|
||||
skygw_log_write(LE,
|
||||
"%s",
|
||||
errbuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -114,6 +114,7 @@ EXTERNCMD* externcmd_allocate(char* argstr)
|
||||
externcmd_free(cmd);
|
||||
return NULL;
|
||||
}
|
||||
skygw_log_write(LT, "Executing script %s.", cmd->parameters[0]);
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
|
@ -181,6 +181,7 @@ static struct option long_options[] = {
|
||||
{"version", no_argument, 0, 'v'},
|
||||
{"help", no_argument, 0, '?'},
|
||||
{"version-full", no_argument, 0, 'V'},
|
||||
{"log_augmentation", required_argument, 0, 'G'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
static int cnf_preparser(void* data, const char* section, const char* name, const char* value);
|
||||
@ -197,6 +198,7 @@ static int ntfw_cb(const char*, const struct stat*, int, struct FTW*);
|
||||
static bool file_is_readable(char* absolute_pathname);
|
||||
static bool file_is_writable(char* absolute_pathname);
|
||||
bool handle_path_arg(char** dest, char* path, char* arg, bool rd, bool wr);
|
||||
static void set_log_augmentation(const char* value);
|
||||
static void usage(void);
|
||||
static char* get_expanded_pathname(
|
||||
char** abs_path,
|
||||
@ -216,6 +218,7 @@ static bool resolve_maxscale_conf_fname(
|
||||
static char* check_dir_access(char* dirname,bool,bool);
|
||||
static int set_user();
|
||||
bool pid_file_exists();
|
||||
void write_child_exit_code(int fd, int code);
|
||||
/** SSL multi-threading functions and structures */
|
||||
|
||||
static SPINLOCK* ssl_locks;
|
||||
@ -1071,6 +1074,9 @@ int main(int argc, char **argv)
|
||||
int n_services;
|
||||
int eno = 0; /*< local variable for errno */
|
||||
int opt;
|
||||
int daemon_pipe[2];
|
||||
bool parent_process;
|
||||
int child_status;
|
||||
void** threads = NULL; /*< thread list */
|
||||
char mysql_home[PATH_MAX+1];
|
||||
char datadir_arg[10+PATH_MAX+1]; /*< '--datadir=' + PATH_MAX */
|
||||
@ -1128,7 +1134,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "dc:f:l:vVs:S:?L:D:C:B:U:A:P:",
|
||||
while ((opt = getopt_long(argc, argv, "dc:f:l:vVs:S:?L:D:C:B:U:A:P:G:",
|
||||
long_options, &option_index)) != -1)
|
||||
{
|
||||
bool succp = true;
|
||||
@ -1291,6 +1297,9 @@ int main(int argc, char **argv)
|
||||
succp = false;
|
||||
}
|
||||
break;
|
||||
case 'G':
|
||||
set_log_augmentation(optarg);
|
||||
break;
|
||||
case '?':
|
||||
usage();
|
||||
rc = EXIT_SUCCESS;
|
||||
@ -1321,6 +1330,13 @@ int main(int argc, char **argv)
|
||||
}
|
||||
else
|
||||
{
|
||||
if(pipe(daemon_pipe) == -1)
|
||||
{
|
||||
fprintf(stderr,"Error: Failed to create pipe for inter-process communication: %d %s",errno,strerror(errno));
|
||||
rc = MAXSCALE_INTERNALERROR;
|
||||
goto return_main;
|
||||
}
|
||||
|
||||
/*<
|
||||
* Maxscale must be daemonized before opening files, initializing
|
||||
* embedded MariaDB and in general, as early as possible.
|
||||
@ -1453,7 +1469,37 @@ int main(int argc, char **argv)
|
||||
rc = MAXSCALE_INTERNALERROR;
|
||||
goto return_main;
|
||||
}
|
||||
gw_daemonize();
|
||||
|
||||
/** Daemonize the process and wait for the child process to notify
|
||||
* the parent process of its exit status. */
|
||||
parent_process = gw_daemonize();
|
||||
|
||||
if(parent_process)
|
||||
{
|
||||
close(daemon_pipe[1]);
|
||||
int nread = read(daemon_pipe[0],(void*)&child_status,sizeof(int));
|
||||
close(daemon_pipe[0]);
|
||||
|
||||
if(nread == -1)
|
||||
{
|
||||
char* logerr = "Failed to read data from child process pipe.";
|
||||
print_log_n_stderr(true, true, logerr, logerr, errno);
|
||||
exit(MAXSCALE_INTERNALERROR);
|
||||
}
|
||||
else if(nread == 0)
|
||||
{
|
||||
/** Child process has exited or closed write pipe */
|
||||
char* logerr = "No data read from child process pipe.";
|
||||
print_log_n_stderr(true, true, logerr, logerr, 0);
|
||||
exit(MAXSCALE_INTERNALERROR);
|
||||
}
|
||||
|
||||
exit(child_status);
|
||||
}
|
||||
|
||||
/** This is the child process and we can close the read end of
|
||||
* the pipe. */
|
||||
close(daemon_pipe[0]);
|
||||
}
|
||||
/*<
|
||||
* Set signal handlers for SIGHUP, SIGTERM, SIGINT and critical signals like SIGSEGV.
|
||||
@ -1602,7 +1648,6 @@ int main(int argc, char **argv)
|
||||
|
||||
if (!resolve_maxscale_conf_fname(&cnf_file_path, pathbuf, cnf_file_arg))
|
||||
{
|
||||
ss_dassert(cnf_file_path == NULL);
|
||||
rc = MAXSCALE_BADCONFIG;
|
||||
goto return_main;
|
||||
}
|
||||
@ -1857,7 +1902,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
LOGIF(LM, (skygw_log_write(
|
||||
LOGFILE_MESSAGE,
|
||||
"MariaDB Corporation MaxScale %s (C) MariaDB Corporation Ab 2013-2014",
|
||||
"MariaDB Corporation MaxScale %s (C) MariaDB Corporation Ab 2013-2015",
|
||||
MAXSCALE_VERSION)));
|
||||
LOGIF(LM, (skygw_log_write(
|
||||
LOGFILE_MESSAGE,
|
||||
@ -1950,6 +1995,13 @@ int main(int argc, char **argv)
|
||||
CRYPTO_set_id_callback(pthread_self);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Successful start, notify the parent process that it can exit.
|
||||
*/
|
||||
ss_dassert(rc == MAXSCALE_SHUTDOWN);
|
||||
if(daemon_mode)
|
||||
write_child_exit_code(daemon_pipe[1], rc);
|
||||
|
||||
MaxScaleStarted = time(0);
|
||||
/*<
|
||||
* Serve clients.
|
||||
@ -1988,6 +2040,13 @@ int main(int argc, char **argv)
|
||||
unlink_pidfile();
|
||||
|
||||
return_main:
|
||||
|
||||
if(daemon_mode && rc != MAXSCALE_SHUTDOWN)
|
||||
{
|
||||
/** Notify the parent process that an error has occurred */
|
||||
write_child_exit_code(daemon_pipe[1], rc);
|
||||
}
|
||||
|
||||
if (threads)
|
||||
free(threads);
|
||||
if (cnf_file_path)
|
||||
@ -2312,6 +2371,21 @@ bool handle_path_arg(char** dest, char* path, char* arg, bool rd, bool wr)
|
||||
return rval;
|
||||
}
|
||||
|
||||
void set_log_augmentation(const char* value)
|
||||
{
|
||||
// Command line arguments are handled first, thus command line argument
|
||||
// has priority.
|
||||
|
||||
static bool augmentation_set = false;
|
||||
|
||||
if (!augmentation_set)
|
||||
{
|
||||
skygw_log_set_augmentation(atoi(value));
|
||||
|
||||
augmentation_set = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-parse the MaxScale.cnf for config, log and module directories.
|
||||
* @param data Parameter passed by inih
|
||||
@ -2423,6 +2497,10 @@ static int cnf_preparser(void* data, const char* section, const char* name, cons
|
||||
{
|
||||
cnf->maxlog = config_truth_value((char*)value);
|
||||
}
|
||||
else if(strcmp(name, "log_augmentation") == 0)
|
||||
{
|
||||
set_log_augmentation(value);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
@ -2481,3 +2559,15 @@ static int set_user(char* user)
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the exit status of the child process to the parent process.
|
||||
* @param fd File descriptor to write to
|
||||
* @param code Exit status of the child process
|
||||
*/
|
||||
void write_child_exit_code(int fd, int code)
|
||||
{
|
||||
/** Notify the parent process that an error has occurred */
|
||||
write(fd, &code, sizeof (int));
|
||||
close(fd);
|
||||
}
|
||||
|
||||
|
@ -141,7 +141,7 @@ setipaddress(struct in_addr *a, char *p) {
|
||||
* Daemonize the process by forking and putting the process into the
|
||||
* background.
|
||||
*/
|
||||
void gw_daemonize(void) {
|
||||
bool gw_daemonize(void) {
|
||||
pid_t pid;
|
||||
|
||||
pid = fork();
|
||||
@ -154,7 +154,7 @@ void gw_daemonize(void) {
|
||||
|
||||
if (pid != 0) {
|
||||
/* exit from main */
|
||||
exit(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (setsid() < 0) {
|
||||
@ -162,6 +162,7 @@ void gw_daemonize(void) {
|
||||
fprintf(stderr, "setsid() error %s\n", strerror_r(errno, errbuf, sizeof(errbuf)));
|
||||
exit(1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user