diff --git a/core/config.c b/core/config.c index 7e56baaf2..524d27fd6 100644 --- a/core/config.c +++ b/core/config.c @@ -176,7 +176,7 @@ CONFIG_CONTEXT *obj; { char *servers = config_get_value(obj->parameters, "servers"); char *roptions = config_get_value(obj->parameters, "router_options"); - if (servers) + if (servers && obj->element) { char *s = strtok(servers, ","); while (s) @@ -191,7 +191,7 @@ CONFIG_CONTEXT *obj; s = strtok(NULL, ","); } } - if (roptions) + if (roptions && obj->element) { char *s = strtok(roptions, ","); while (s) diff --git a/core/dcb.c b/core/dcb.c index 6db392d14..59d5aa7d0 100644 --- a/core/dcb.c +++ b/core/dcb.c @@ -35,6 +35,10 @@ * 28/06/13 Mark Riddoch Changed the free mechanism ti * introduce a zombie state for the * dcb + * 02/07/2013 Massimiliano Pinto Addition of delayqlock, delayq and authlock + * for handling backend asynchronous protocol connection + * and a generic lock for backend authentication + * * @endverbatim */ #include @@ -77,7 +81,10 @@ DCB *rval; return NULL; } spinlock_init(&rval->writeqlock); + spinlock_init(&rval->delayqlock); + spinlock_init(&rval->authlock); rval->writeq = NULL; + rval->delayq = NULL; rval->remote = NULL; rval->state = DCB_STATE_ALLOC; rval->next = NULL; @@ -251,7 +258,8 @@ GWPROTOCOL *funcs; } if ((funcs = (GWPROTOCOL *)load_module(protocol, MODULE_PROTOCOL)) == NULL) { - dcb_free(dcb); + dcb_final_free(dcb); + fprintf(stderr, "Failed to load protocol module for %s, feee dcb %p\n", protocol, dcb); return NULL; } memcpy(&(dcb->func), funcs, sizeof(GWPROTOCOL)); @@ -259,7 +267,8 @@ GWPROTOCOL *funcs; if ((dcb->fd = dcb->func.connect(dcb, server, session)) == -1) { - dcb_free(dcb); + dcb_final_free(dcb); + fprintf(stderr, "Failed to connect to server, feee dcb %p\n", dcb); return NULL; } atomic_add(&server->stats.n_connections, 1); diff --git a/core/depend.mk b/core/depend.mk deleted file mode 100644 index f72230a07..000000000 --- a/core/depend.mk +++ /dev/null @@ -1,474 +0,0 @@ -atomic.o: atomic.c -buffer.o: buffer.c /usr/include/stdlib.h /usr/include/features.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ - /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \ - /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \ - /usr/include/endian.h /usr/include/bits/endian.h \ - /usr/include/bits/byteswap.h /usr/include/sys/types.h \ - /usr/include/bits/types.h /usr/include/bits/typesizes.h \ - /usr/include/time.h /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/alloca.h ../include/buffer.h -spinlock.o: spinlock.c ../include/spinlock.h ../include/thread.h \ - /usr/include/pthread.h /usr/include/features.h /usr/include/sys/cdefs.h \ - /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ - /usr/include/gnu/stubs-64.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sched.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h \ - /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \ - /usr/include/time.h /usr/include/bits/sched.h /usr/include/bits/time.h \ - /usr/include/xlocale.h /usr/include/bits/pthreadtypes.h \ - /usr/include/bits/setjmp.h ../include/atomic.h -gateway.o: gateway.c ../include/gw.h /usr/include/stdio.h \ - /usr/include/features.h /usr/include/sys/cdefs.h \ - /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ - /usr/include/gnu/stubs-64.h \ - /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \ - /usr/include/bits/types.h /usr/include/bits/typesizes.h \ - /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/ctype.h /usr/include/endian.h /usr/include/bits/endian.h \ - /usr/include/bits/byteswap.h /usr/include/xlocale.h /usr/include/errno.h \ - /usr/include/bits/errno.h /usr/include/linux/errno.h \ - /usr/include/asm/errno.h /usr/include/asm-generic/errno.h \ - /usr/include/asm-generic/errno-base.h /usr/include/netdb.h \ - /usr/include/netinet/in.h /usr/include/stdint.h \ - /usr/include/bits/wchar.h /usr/include/sys/socket.h \ - /usr/include/sys/uio.h /usr/include/sys/types.h /usr/include/time.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/bits/uio.h /usr/include/bits/socket.h \ - /usr/include/bits/sockaddr.h /usr/include/asm/socket.h \ - /usr/include/asm-generic/socket.h /usr/include/asm/sockios.h \ - /usr/include/asm-generic/sockios.h /usr/include/bits/in.h \ - /usr/include/rpc/netdb.h /usr/include/bits/netdb.h /usr/include/fcntl.h \ - /usr/include/bits/fcntl.h /usr/include/bits/stat.h /usr/include/unistd.h \ - /usr/include/bits/posix_opt.h /usr/include/bits/environments.h \ - /usr/include/bits/confname.h /usr/include/getopt.h /usr/include/syslog.h \ - /usr/include/sys/syslog.h /usr/include/bits/syslog-path.h \ - /usr/include/string.h /usr/include/stdlib.h \ - /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \ - /usr/include/alloca.h /usr/include/pwd.h /usr/include/sys/epoll.h \ - /usr/include/signal.h /usr/include/bits/signum.h \ - /usr/include/bits/siginfo.h /usr/include/bits/sigaction.h \ - /usr/include/bits/sigcontext.h /usr/include/bits/sigstack.h \ - /usr/include/sys/ucontext.h /usr/include/bits/sigthread.h \ - /usr/include/sys/ioctl.h /usr/include/bits/ioctls.h \ - /usr/include/asm/ioctls.h /usr/include/asm-generic/ioctls.h \ - /usr/include/linux/ioctl.h /usr/include/asm/ioctl.h \ - /usr/include/asm-generic/ioctl.h /usr/include/bits/ioctl-types.h \ - /usr/include/sys/ttydefaults.h /usr/include/arpa/inet.h \ - /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdbool.h \ - ../include/gateway_mysql.h ../include/dcb.h ../include/spinlock.h \ - ../include/thread.h /usr/include/pthread.h /usr/include/sched.h \ - /usr/include/bits/sched.h /usr/include/bits/setjmp.h ../include/buffer.h \ - ../include/mysql_protocol.h ../include/dcb.h ../include/service.h \ - ../include/server.h ../include/session.h ../include/modules.h \ - ../include/config.h ../include/poll.h -gateway_mysql_protocol.o: gateway_mysql_protocol.c ../include/gw.h \ - /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \ - /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ - /usr/include/gnu/stubs-64.h \ - /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \ - /usr/include/bits/types.h /usr/include/bits/typesizes.h \ - /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/ctype.h /usr/include/endian.h /usr/include/bits/endian.h \ - /usr/include/bits/byteswap.h /usr/include/xlocale.h /usr/include/errno.h \ - /usr/include/bits/errno.h /usr/include/linux/errno.h \ - /usr/include/asm/errno.h /usr/include/asm-generic/errno.h \ - /usr/include/asm-generic/errno-base.h /usr/include/netdb.h \ - /usr/include/netinet/in.h /usr/include/stdint.h \ - /usr/include/bits/wchar.h /usr/include/sys/socket.h \ - /usr/include/sys/uio.h /usr/include/sys/types.h /usr/include/time.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/bits/uio.h /usr/include/bits/socket.h \ - /usr/include/bits/sockaddr.h /usr/include/asm/socket.h \ - /usr/include/asm-generic/socket.h /usr/include/asm/sockios.h \ - /usr/include/asm-generic/sockios.h /usr/include/bits/in.h \ - /usr/include/rpc/netdb.h /usr/include/bits/netdb.h /usr/include/fcntl.h \ - /usr/include/bits/fcntl.h /usr/include/bits/stat.h /usr/include/unistd.h \ - /usr/include/bits/posix_opt.h /usr/include/bits/environments.h \ - /usr/include/bits/confname.h /usr/include/getopt.h /usr/include/syslog.h \ - /usr/include/sys/syslog.h /usr/include/bits/syslog-path.h \ - /usr/include/string.h /usr/include/stdlib.h \ - /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \ - /usr/include/alloca.h /usr/include/pwd.h /usr/include/sys/epoll.h \ - /usr/include/signal.h /usr/include/bits/signum.h \ - /usr/include/bits/siginfo.h /usr/include/bits/sigaction.h \ - /usr/include/bits/sigcontext.h /usr/include/bits/sigstack.h \ - /usr/include/sys/ucontext.h /usr/include/bits/sigthread.h \ - /usr/include/sys/ioctl.h /usr/include/bits/ioctls.h \ - /usr/include/asm/ioctls.h /usr/include/asm-generic/ioctls.h \ - /usr/include/linux/ioctl.h /usr/include/asm/ioctl.h \ - /usr/include/asm-generic/ioctl.h /usr/include/bits/ioctl-types.h \ - /usr/include/sys/ttydefaults.h /usr/include/arpa/inet.h \ - /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdbool.h \ - ../include/gateway_mysql.h ../include/dcb.h ../include/spinlock.h \ - ../include/thread.h /usr/include/pthread.h /usr/include/sched.h \ - /usr/include/bits/sched.h /usr/include/bits/setjmp.h ../include/buffer.h \ - ../include/mysql_protocol.h ../include/dcb.h ../include/session.h \ - /usr/include/openssl/sha.h /usr/include/openssl/e_os2.h \ - /usr/include/openssl/opensslconf.h \ - /usr/include/openssl/opensslconf-x86_64.h -gw_utils.o: gw_utils.c ../include/gw.h /usr/include/stdio.h \ - /usr/include/features.h /usr/include/sys/cdefs.h \ - /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ - /usr/include/gnu/stubs-64.h \ - /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \ - /usr/include/bits/types.h /usr/include/bits/typesizes.h \ - /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/ctype.h /usr/include/endian.h /usr/include/bits/endian.h \ - /usr/include/bits/byteswap.h /usr/include/xlocale.h /usr/include/errno.h \ - /usr/include/bits/errno.h /usr/include/linux/errno.h \ - /usr/include/asm/errno.h /usr/include/asm-generic/errno.h \ - /usr/include/asm-generic/errno-base.h /usr/include/netdb.h \ - /usr/include/netinet/in.h /usr/include/stdint.h \ - /usr/include/bits/wchar.h /usr/include/sys/socket.h \ - /usr/include/sys/uio.h /usr/include/sys/types.h /usr/include/time.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/bits/uio.h /usr/include/bits/socket.h \ - /usr/include/bits/sockaddr.h /usr/include/asm/socket.h \ - /usr/include/asm-generic/socket.h /usr/include/asm/sockios.h \ - /usr/include/asm-generic/sockios.h /usr/include/bits/in.h \ - /usr/include/rpc/netdb.h /usr/include/bits/netdb.h /usr/include/fcntl.h \ - /usr/include/bits/fcntl.h /usr/include/bits/stat.h /usr/include/unistd.h \ - /usr/include/bits/posix_opt.h /usr/include/bits/environments.h \ - /usr/include/bits/confname.h /usr/include/getopt.h /usr/include/syslog.h \ - /usr/include/sys/syslog.h /usr/include/bits/syslog-path.h \ - /usr/include/string.h /usr/include/stdlib.h \ - /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \ - /usr/include/alloca.h /usr/include/pwd.h /usr/include/sys/epoll.h \ - /usr/include/signal.h /usr/include/bits/signum.h \ - /usr/include/bits/siginfo.h /usr/include/bits/sigaction.h \ - /usr/include/bits/sigcontext.h /usr/include/bits/sigstack.h \ - /usr/include/sys/ucontext.h /usr/include/bits/sigthread.h \ - /usr/include/sys/ioctl.h /usr/include/bits/ioctls.h \ - /usr/include/asm/ioctls.h /usr/include/asm-generic/ioctls.h \ - /usr/include/linux/ioctl.h /usr/include/asm/ioctl.h \ - /usr/include/asm-generic/ioctl.h /usr/include/bits/ioctl-types.h \ - /usr/include/sys/ttydefaults.h /usr/include/arpa/inet.h \ - /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdbool.h \ - ../include/gateway_mysql.h ../include/dcb.h ../include/spinlock.h \ - ../include/thread.h /usr/include/pthread.h /usr/include/sched.h \ - /usr/include/bits/sched.h /usr/include/bits/setjmp.h ../include/buffer.h \ - ../include/mysql_protocol.h ../include/dcb.h ../include/session.h -utils.o: utils.c ../include/gw.h /usr/include/stdio.h \ - /usr/include/features.h /usr/include/sys/cdefs.h \ - /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ - /usr/include/gnu/stubs-64.h \ - /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \ - /usr/include/bits/types.h /usr/include/bits/typesizes.h \ - /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/ctype.h /usr/include/endian.h /usr/include/bits/endian.h \ - /usr/include/bits/byteswap.h /usr/include/xlocale.h /usr/include/errno.h \ - /usr/include/bits/errno.h /usr/include/linux/errno.h \ - /usr/include/asm/errno.h /usr/include/asm-generic/errno.h \ - /usr/include/asm-generic/errno-base.h /usr/include/netdb.h \ - /usr/include/netinet/in.h /usr/include/stdint.h \ - /usr/include/bits/wchar.h /usr/include/sys/socket.h \ - /usr/include/sys/uio.h /usr/include/sys/types.h /usr/include/time.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/bits/uio.h /usr/include/bits/socket.h \ - /usr/include/bits/sockaddr.h /usr/include/asm/socket.h \ - /usr/include/asm-generic/socket.h /usr/include/asm/sockios.h \ - /usr/include/asm-generic/sockios.h /usr/include/bits/in.h \ - /usr/include/rpc/netdb.h /usr/include/bits/netdb.h /usr/include/fcntl.h \ - /usr/include/bits/fcntl.h /usr/include/bits/stat.h /usr/include/unistd.h \ - /usr/include/bits/posix_opt.h /usr/include/bits/environments.h \ - /usr/include/bits/confname.h /usr/include/getopt.h /usr/include/syslog.h \ - /usr/include/sys/syslog.h /usr/include/bits/syslog-path.h \ - /usr/include/string.h /usr/include/stdlib.h \ - /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \ - /usr/include/alloca.h /usr/include/pwd.h /usr/include/sys/epoll.h \ - /usr/include/signal.h /usr/include/bits/signum.h \ - /usr/include/bits/siginfo.h /usr/include/bits/sigaction.h \ - /usr/include/bits/sigcontext.h /usr/include/bits/sigstack.h \ - /usr/include/sys/ucontext.h /usr/include/bits/sigthread.h \ - /usr/include/sys/ioctl.h /usr/include/bits/ioctls.h \ - /usr/include/asm/ioctls.h /usr/include/asm-generic/ioctls.h \ - /usr/include/linux/ioctl.h /usr/include/asm/ioctl.h \ - /usr/include/asm-generic/ioctl.h /usr/include/bits/ioctl-types.h \ - /usr/include/sys/ttydefaults.h /usr/include/arpa/inet.h \ - /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdbool.h \ - ../include/gateway_mysql.h ../include/dcb.h ../include/spinlock.h \ - ../include/thread.h /usr/include/pthread.h /usr/include/sched.h \ - /usr/include/bits/sched.h /usr/include/bits/setjmp.h ../include/buffer.h \ - ../include/mysql_protocol.h ../include/dcb.h ../include/session.h \ - ../include/mysql_protocol.h /usr/include/openssl/sha.h \ - /usr/include/openssl/e_os2.h /usr/include/openssl/opensslconf.h \ - /usr/include/openssl/opensslconf-x86_64.h ../include/poll.h -dcb.o: dcb.c /usr/include/stdio.h /usr/include/features.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ - /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \ - /usr/include/bits/types.h /usr/include/bits/typesizes.h \ - /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/stdlib.h /usr/include/bits/waitflags.h \ - /usr/include/bits/waitstatus.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/types.h /usr/include/time.h /usr/include/sys/select.h \ - /usr/include/bits/select.h /usr/include/bits/sigset.h \ - /usr/include/bits/time.h /usr/include/sys/sysmacros.h \ - /usr/include/bits/pthreadtypes.h /usr/include/alloca.h \ - /usr/include/string.h /usr/include/xlocale.h ../include/dcb.h \ - ../include/spinlock.h ../include/thread.h /usr/include/pthread.h \ - /usr/include/sched.h /usr/include/bits/sched.h \ - /usr/include/bits/setjmp.h ../include/buffer.h ../include/server.h \ - ../include/session.h ../include/service.h ../include/modules.h \ - ../include/router.h /usr/include/errno.h /usr/include/bits/errno.h \ - /usr/include/linux/errno.h /usr/include/asm/errno.h \ - /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \ - ../include/gw.h /usr/include/ctype.h /usr/include/netdb.h \ - /usr/include/netinet/in.h /usr/include/stdint.h \ - /usr/include/bits/wchar.h /usr/include/sys/socket.h \ - /usr/include/sys/uio.h /usr/include/bits/uio.h \ - /usr/include/bits/socket.h /usr/include/bits/sockaddr.h \ - /usr/include/asm/socket.h /usr/include/asm-generic/socket.h \ - /usr/include/asm/sockios.h /usr/include/asm-generic/sockios.h \ - /usr/include/bits/in.h /usr/include/rpc/netdb.h \ - /usr/include/bits/netdb.h /usr/include/fcntl.h /usr/include/bits/fcntl.h \ - /usr/include/bits/stat.h /usr/include/unistd.h \ - /usr/include/bits/posix_opt.h /usr/include/bits/environments.h \ - /usr/include/bits/confname.h /usr/include/getopt.h /usr/include/syslog.h \ - /usr/include/sys/syslog.h /usr/include/bits/syslog-path.h \ - /usr/include/pwd.h /usr/include/sys/epoll.h /usr/include/signal.h \ - /usr/include/bits/signum.h /usr/include/bits/siginfo.h \ - /usr/include/bits/sigaction.h /usr/include/bits/sigcontext.h \ - /usr/include/bits/sigstack.h /usr/include/sys/ucontext.h \ - /usr/include/bits/sigthread.h /usr/include/sys/ioctl.h \ - /usr/include/bits/ioctls.h /usr/include/asm/ioctls.h \ - /usr/include/asm-generic/ioctls.h /usr/include/linux/ioctl.h \ - /usr/include/asm/ioctl.h /usr/include/asm-generic/ioctl.h \ - /usr/include/bits/ioctl-types.h /usr/include/sys/ttydefaults.h \ - /usr/include/arpa/inet.h \ - /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdbool.h \ - ../include/gateway_mysql.h ../include/mysql_protocol.h ../include/dcb.h \ - ../include/poll.h ../include/atomic.h -load_utils.o: load_utils.c /usr/include/sys/param.h \ - /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/limits.h \ - /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/syslimits.h \ - /usr/include/limits.h /usr/include/features.h /usr/include/sys/cdefs.h \ - /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ - /usr/include/gnu/stubs-64.h /usr/include/bits/posix1_lim.h \ - /usr/include/bits/local_lim.h /usr/include/linux/limits.h \ - /usr/include/bits/posix2_lim.h /usr/include/linux/param.h \ - /usr/include/asm/param.h /usr/include/asm-generic/param.h \ - /usr/include/sys/types.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/time.h \ - /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \ - /usr/include/endian.h /usr/include/bits/endian.h \ - /usr/include/bits/byteswap.h /usr/include/sys/select.h \ - /usr/include/bits/select.h /usr/include/bits/sigset.h \ - /usr/include/bits/time.h /usr/include/sys/sysmacros.h \ - /usr/include/bits/pthreadtypes.h /usr/include/stdio.h \ - /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/stdlib.h /usr/include/bits/waitflags.h \ - /usr/include/bits/waitstatus.h /usr/include/alloca.h \ - /usr/include/unistd.h /usr/include/bits/posix_opt.h \ - /usr/include/bits/environments.h /usr/include/bits/confname.h \ - /usr/include/getopt.h /usr/include/string.h /usr/include/xlocale.h \ - /usr/include/dlfcn.h /usr/include/bits/dlfcn.h ../include/modules.h \ - ../include/dcb.h ../include/spinlock.h ../include/thread.h \ - /usr/include/pthread.h /usr/include/sched.h /usr/include/bits/sched.h \ - /usr/include/bits/setjmp.h ../include/buffer.h -session.o: session.c /usr/include/stdio.h /usr/include/features.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ - /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \ - /usr/include/bits/types.h /usr/include/bits/typesizes.h \ - /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/stdlib.h /usr/include/bits/waitflags.h \ - /usr/include/bits/waitstatus.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/types.h /usr/include/time.h /usr/include/sys/select.h \ - /usr/include/bits/select.h /usr/include/bits/sigset.h \ - /usr/include/bits/time.h /usr/include/sys/sysmacros.h \ - /usr/include/bits/pthreadtypes.h /usr/include/alloca.h \ - /usr/include/unistd.h /usr/include/bits/posix_opt.h \ - /usr/include/bits/environments.h /usr/include/bits/confname.h \ - /usr/include/getopt.h /usr/include/string.h /usr/include/xlocale.h \ - ../include/session.h ../include/service.h ../include/spinlock.h \ - ../include/thread.h /usr/include/pthread.h /usr/include/sched.h \ - /usr/include/bits/sched.h /usr/include/bits/setjmp.h ../include/dcb.h \ - ../include/buffer.h ../include/server.h ../include/router.h \ - ../include/atomic.h -service.o: service.c /usr/include/stdio.h /usr/include/features.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ - /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \ - /usr/include/bits/types.h /usr/include/bits/typesizes.h \ - /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/stdlib.h /usr/include/bits/waitflags.h \ - /usr/include/bits/waitstatus.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/types.h /usr/include/time.h /usr/include/sys/select.h \ - /usr/include/bits/select.h /usr/include/bits/sigset.h \ - /usr/include/bits/time.h /usr/include/sys/sysmacros.h \ - /usr/include/bits/pthreadtypes.h /usr/include/alloca.h \ - /usr/include/string.h /usr/include/xlocale.h ../include/session.h \ - ../include/service.h ../include/spinlock.h ../include/thread.h \ - /usr/include/pthread.h /usr/include/sched.h /usr/include/bits/sched.h \ - /usr/include/bits/setjmp.h ../include/dcb.h ../include/buffer.h \ - ../include/server.h ../include/router.h ../include/modules.h \ - ../include/users.h ../include/hashtable.h ../include/atomic.h \ - ../include/dbusers.h ../include/poll.h -server.o: server.c /usr/include/stdio.h /usr/include/features.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ - /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \ - /usr/include/bits/types.h /usr/include/bits/typesizes.h \ - /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/stdlib.h /usr/include/bits/waitflags.h \ - /usr/include/bits/waitstatus.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/types.h /usr/include/time.h /usr/include/sys/select.h \ - /usr/include/bits/select.h /usr/include/bits/sigset.h \ - /usr/include/bits/time.h /usr/include/sys/sysmacros.h \ - /usr/include/bits/pthreadtypes.h /usr/include/alloca.h \ - /usr/include/string.h /usr/include/xlocale.h ../include/session.h \ - ../include/server.h ../include/dcb.h ../include/spinlock.h \ - ../include/thread.h /usr/include/pthread.h /usr/include/sched.h \ - /usr/include/bits/sched.h /usr/include/bits/setjmp.h ../include/buffer.h -poll.o: poll.c /usr/include/stdio.h /usr/include/features.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ - /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \ - /usr/include/bits/types.h /usr/include/bits/typesizes.h \ - /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/string.h /usr/include/xlocale.h /usr/include/unistd.h \ - /usr/include/bits/posix_opt.h /usr/include/bits/environments.h \ - /usr/include/bits/confname.h /usr/include/getopt.h /usr/include/stdlib.h \ - /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \ - /usr/include/endian.h /usr/include/bits/endian.h \ - /usr/include/bits/byteswap.h /usr/include/sys/types.h \ - /usr/include/time.h /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/alloca.h /usr/include/sys/epoll.h /usr/include/stdint.h \ - /usr/include/bits/wchar.h ../include/poll.h ../include/dcb.h \ - ../include/spinlock.h ../include/thread.h /usr/include/pthread.h \ - /usr/include/sched.h /usr/include/bits/sched.h \ - /usr/include/bits/setjmp.h ../include/buffer.h ../include/atomic.h -config.o: config.c /usr/include/stdio.h /usr/include/features.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ - /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \ - /usr/include/bits/types.h /usr/include/bits/typesizes.h \ - /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/string.h /usr/include/xlocale.h /usr/include/stdlib.h \ - /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \ - /usr/include/endian.h /usr/include/bits/endian.h \ - /usr/include/bits/byteswap.h /usr/include/sys/types.h \ - /usr/include/time.h /usr/include/sys/select.h /usr/include/bits/select.h \ - /usr/include/bits/sigset.h /usr/include/bits/time.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/alloca.h ../inih/ini.h ../include/config.h \ - ../include/service.h ../include/spinlock.h ../include/thread.h \ - /usr/include/pthread.h /usr/include/sched.h /usr/include/bits/sched.h \ - /usr/include/bits/setjmp.h ../include/dcb.h ../include/buffer.h \ - ../include/server.h ../include/users.h ../include/hashtable.h \ - ../include/atomic.h -users.o: users.c /usr/include/stdio.h /usr/include/features.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ - /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \ - /usr/include/bits/types.h /usr/include/bits/typesizes.h \ - /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/stdlib.h /usr/include/bits/waitflags.h \ - /usr/include/bits/waitstatus.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/types.h /usr/include/time.h /usr/include/sys/select.h \ - /usr/include/bits/select.h /usr/include/bits/sigset.h \ - /usr/include/bits/time.h /usr/include/sys/sysmacros.h \ - /usr/include/bits/pthreadtypes.h /usr/include/alloca.h \ - /usr/include/string.h /usr/include/xlocale.h ../include/users.h \ - ../include/hashtable.h ../include/spinlock.h ../include/thread.h \ - /usr/include/pthread.h /usr/include/sched.h /usr/include/bits/sched.h \ - /usr/include/bits/setjmp.h ../include/atomic.h ../include/dcb.h \ - ../include/buffer.h -hashtable.o: hashtable.c /usr/include/stdio.h /usr/include/features.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ - /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \ - /usr/include/bits/types.h /usr/include/bits/typesizes.h \ - /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/stdlib.h /usr/include/bits/waitflags.h \ - /usr/include/bits/waitstatus.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/types.h /usr/include/time.h /usr/include/sys/select.h \ - /usr/include/bits/select.h /usr/include/bits/sigset.h \ - /usr/include/bits/time.h /usr/include/sys/sysmacros.h \ - /usr/include/bits/pthreadtypes.h /usr/include/alloca.h \ - /usr/include/string.h /usr/include/xlocale.h ../include/hashtable.h \ - ../include/spinlock.h ../include/thread.h /usr/include/pthread.h \ - /usr/include/sched.h /usr/include/bits/sched.h \ - /usr/include/bits/setjmp.h ../include/atomic.h ../include/dcb.h \ - ../include/buffer.h -dbusers.o: dbusers.c /usr/include/stdio.h /usr/include/features.h \ - /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ - /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ - /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \ - /usr/include/bits/types.h /usr/include/bits/typesizes.h \ - /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ - /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdarg.h \ - /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ - /usr/include/mysql/mysql.h /usr/include/sys/types.h /usr/include/time.h \ - /usr/include/endian.h /usr/include/bits/endian.h \ - /usr/include/bits/byteswap.h /usr/include/sys/select.h \ - /usr/include/bits/select.h /usr/include/bits/sigset.h \ - /usr/include/bits/time.h /usr/include/sys/sysmacros.h \ - /usr/include/bits/pthreadtypes.h /usr/include/mysql/mysql_version.h \ - /usr/include/mysql/mysql_com.h /usr/include/mysql/mysql_time.h \ - /usr/include/mysql/my_list.h /usr/include/mysql/typelib.h \ - /usr/include/mysql/my_alloc.h ../include/dcb.h ../include/spinlock.h \ - ../include/thread.h /usr/include/pthread.h /usr/include/sched.h \ - /usr/include/bits/sched.h /usr/include/xlocale.h \ - /usr/include/bits/setjmp.h ../include/buffer.h ../include/service.h \ - ../include/server.h ../include/users.h ../include/hashtable.h \ - ../include/atomic.h -thread.o: thread.c ../include/thread.h /usr/include/pthread.h \ - /usr/include/features.h /usr/include/sys/cdefs.h \ - /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ - /usr/include/gnu/stubs-64.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sched.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h \ - /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \ - /usr/include/time.h /usr/include/bits/sched.h /usr/include/bits/time.h \ - /usr/include/xlocale.h /usr/include/bits/pthreadtypes.h \ - /usr/include/bits/setjmp.h diff --git a/core/gw_utils.c b/core/gw_utils.c index 39e0cb1c6..f9ab33b82 100644 --- a/core/gw_utils.c +++ b/core/gw_utils.c @@ -87,7 +87,7 @@ int gw_read_gwbuff(DCB *dcb, GWBUF **head, int b) { int n = -1; if (b <= 0) { - fprintf(stderr, "||| read_gwbuff called with 0 bytes for %i, closing\n", dcb->fd); + //fprintf(stderr, "||| read_gwbuff called with 0 bytes for %i, closing\n", dcb->fd); dcb->func.close(dcb); return 1; } diff --git a/core/poll.c b/core/poll.c index 32154c239..b911176c7 100644 --- a/core/poll.c +++ b/core/poll.c @@ -141,6 +141,7 @@ struct epoll_event events[MAX_EVENTS]; int i, nfds; int thread_id = (int)arg; + /* Add this thread to the bitmask of running polling threads */ bitmask_set(&poll_mask, thread_id); while (1) { @@ -174,11 +175,15 @@ int thread_id = (int)arg; { atomic_add(&pollStats.n_error, 1); dcb->func.error(dcb); + if (DCB_ISZOMBIE(dcb)) + continue; } if (ev & EPOLLHUP) { atomic_add(&pollStats.n_hup, 1); dcb->func.hangup(dcb); + if (DCB_ISZOMBIE(dcb)) + continue; } if (ev & EPOLLOUT) { @@ -203,6 +208,7 @@ int thread_id = (int)arg; dcb_process_zombies(thread_id); if (shutdown) { + /* Remove this thread from the bitmask of running polling threads */ bitmask_clear(&poll_mask, thread_id); return; } diff --git a/include/dcb.h b/include/dcb.h index fe9047397..4f818039f 100644 --- a/include/dcb.h +++ b/include/dcb.h @@ -39,6 +39,9 @@ struct service; * 11/06/13 Mark Riddoch Updated GWPROTOCOL structure with new * entry points * 18/06/13 Mark Riddoch Addition of the listener entry point + * 02/06/2013 Massimiliano Pinto Addition of delayqlock, delayq and authlock + * for handling backend asynchronous protocol connection + * and a generic lock for backend authentication * * @endverbatim */ @@ -134,6 +137,7 @@ typedef struct dcb { GWBUF *writeq; /**< Write Data Queue */ SPINLOCK delayqlock; /**< Delay Backend Write Queue spinlock */ GWBUF *delayq; /**< Delay Backend Write Data Queue */ + SPINLOCK authlock; /**< Generic Authorization spinlock */ DCBSTATS stats; /**< DCB related statistics */ diff --git a/modules/include/mysql_client_server_protocol.h b/modules/include/mysql_client_server_protocol.h index 167511ff3..fbd8f28b6 100644 --- a/modules/include/mysql_client_server_protocol.h +++ b/modules/include/mysql_client_server_protocol.h @@ -25,6 +25,8 @@ * 01-06-2013 Mark Riddoch Initial implementation * 14-06-2013 Massimiliano Pinto Added specific data * for MySQL session + * 04-07-2013 Massimiliano Pinto Added new MySQL protocol status for asynchronous connection + * Added authentication reply status */ #include @@ -103,14 +105,19 @@ typedef struct mysql_session { } MYSQL_session; /* MySQL Protocol States */ -#define MYSQL_ALLOC 0 /* Allocate data */ -#define MYSQL_AUTH_SENT 1 /* Authentication handshake has been sent */ -#define MYSQL_AUTH_RECV 2 /* Received user, password, db and capabilities */ -#define MYSQL_AUTH_FAILED 3 /* Auth failed, return error packet */ -#define MYSQL_IDLE 4 /* Auth done. Protocol is idle, waiting for statements */ -#define MYSQL_ROUTING 5 /* The received command has been routed to backend(s) */ -#define MYSQL_WAITING_RESULT 6 /* Waiting for result set */ -#define MYSQL_CONNECTED 7 /* Backend socket Connected */ +#define MYSQL_ALLOC 0 /* Allocate data */ +#define MYSQL_PENDING_CONNECT 1 /* Backend socket pending connect */ +#define MYSQL_CONNECTED 2 /* Backend socket Connected */ +#define MYSQL_AUTH_SENT 3 /* Authentication handshake has been sent */ +#define MYSQL_AUTH_RECV 4 /* Received user, password, db and capabilities */ +#define MYSQL_AUTH_FAILED 5 /* Auth failed, return error packet */ +#define MYSQL_IDLE 6 /* Auth done. Protocol is idle, waiting for statements */ +#define MYSQL_ROUTING 7 /* The received command has been routed to backend(s) */ +#define MYSQL_WAITING_RESULT 8 /* Waiting for result set */ + +/* MySQL states for authentication reply */ +#define MYSQL_FAILED_AUTHENTICATION 1 +#define MYSQL_SUCCESFUL_AUTHENTICATION 0 /* Protocol packing macros. */ #define gw_mysql_set_byte2(__buffer, __int) do { \ @@ -210,6 +217,9 @@ int gw_receive_backend_auth(MySQLProtocol *conn); int gw_decode_mysql_server_handshake(MySQLProtocol *conn, uint8_t *payload); int gw_read_backend_handshake(MySQLProtocol *conn); int gw_send_authentication_to_backend(char *dbname, char *user, uint8_t *passwd, MySQLProtocol *conn); +const char *gw_mysql_protocol_state2string(int state); +int gw_do_connect_to_backend(char *host, int port, MySQLProtocol *conn); +int mysql_send_custom_error (DCB *dcb, int packet_number, int in_affected_rows, const char* mysql_message); extern void gw_sha1_str(const uint8_t *in, int in_len, uint8_t *out); extern void gw_sha1_2_str(const uint8_t *in, int in_len, const uint8_t *in2, int in2_len, uint8_t *out); diff --git a/modules/protocol/httpd.c b/modules/protocol/httpd.c new file mode 100644 index 000000000..93e886594 --- /dev/null +++ b/modules/protocol/httpd.c @@ -0,0 +1,429 @@ +/* + * This file is distributed as part of the SkySQL Gateway. It is free + * software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, + * version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright SkySQL Ab 2013 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * @file httpd.c - HTTP daemon protocol module + * + * The httpd protocol module is intended as a mechanism to allow connections + * into the gateway for the purpose of accessing information within + * the gateway with a REST interface + * databases. + * + * In the first instance it is intended to allow a debug connection to access + * internal data structures, however it may also be used to manage the + * configuration of the gateway via REST interface. + * + * @verbatim + * Revision History + * Date Who Description + * 08/07/2013 Massimiliano Pinto Initial version + * + * @endverbatim + */ + +#define ISspace(x) isspace((int)(x)) +#define HTTP_SERVER_STRING "Gateway(c) v.1.0.0\r\n" +static char *version_str = "V1.0.0"; + +static int httpd_read_event(DCB* dcb); +static int httpd_write_event(DCB *dcb); +static int httpd_write(DCB *dcb, GWBUF *queue); +static int httpd_error(DCB *dcb); +static int httpd_hangup(DCB *dcb); +static int httpd_accept(DCB *dcb); +static int httpd_close(DCB *dcb); +static int httpd_listen(DCB *dcb, char *config); +static int httpd_get_line(int sock, char *buf, int size); +static void httpd_send_headers(int client, const char *filename); + +/** + * The "module object" for the httpd protocol module. + */ +static GWPROTOCOL MyObject = { + httpd_read_event, /**< Read - EPOLLIN handler */ + httpd_write, /**< Write - data from gateway */ + httpd_write_event, /**< WriteReady - EPOLLOUT handler */ + httpd_error, /**< Error - EPOLLERR handler */ + httpd_hangup, /**< HangUp - EPOLLHUP handler */ + httpd_accept, /**< Accept */ + NULL, /**< Connect */ + httpd_close, /**< Close */ + httpd_listen /**< Create a listener */ + }; + +static void +httpd_command(DCB *, char *cmd); + +/** + * Implementation of the mandatory version entry point + * + * @return version string of the module + */ +char * +version() +{ + return version_str; +} + +/** + * The module initialisation routine, called when the module + * is first loaded. + */ +void +ModuleInit() +{ + fprintf(stderr, "Initialise HTTPD Protocol module.\n"); +} + +/** + * The module entry point routine. It is this routine that + * must populate the structure that is referred to as the + * "module object", this is a structure with the set of + * external entry points for this module. + * + * @return The module object + */ +GWPROTOCOL * +GetModuleObject() +{ + return &MyObject; +} + +/** + * Read event for EPOLLIN on the httpd protocol module. + * + * @param dcb The descriptor control block + * @return + */ +static int +httpd_read_event(DCB* dcb) +{ +int n = -1; +GWBUF *head = NULL; +SESSION *session = dcb->session; +ROUTER_OBJECT *router = session->service->router; +ROUTER *router_instance = session->service->router_instance; +void *rsession = session->router_session; + +int numchars = 1; +char buf[1024]; +char *query_string = NULL; +char *path_info = NULL; +char method[255]; +char url[255]; +char path[512]; +int cgi = 0; +size_t i, j; +GWBUF *buffer=NULL; + + dcb->state = DCB_STATE_PROCESSING; + + numchars = httpd_get_line(dcb->fd, buf, sizeof(buf)); + i = 0; j = 0; + while (!ISspace(buf[j]) && (i < sizeof(method) - 1)) { + method[i] = buf[j]; + i++; j++; + } + method[i] = '\0'; + + if (strcasecmp(method, "GET") && strcasecmp(method, "POST")) { + //httpd_unimplemented(dcb->fd); + return 0; + } + + if ((buffer = gwbuf_alloc(1024)) == NULL) { + //httpd_error(dcb->fd); + return 0; + } + + if (strcasecmp(method, "POST") == 0) + cgi = 1; + + i = 0; + while (ISspace(buf[j]) && (j < sizeof(buf))) + j++; + while (!ISspace(buf[j]) && (i < sizeof(url) - 1) && (j < sizeof(buf))) { + url[i] = buf[j]; + i++; j++; + } + url[i] = '\0'; + + if (strcasecmp(method, "GET") == 0) { + query_string = url; + while ((*query_string != '?') && (*query_string != '\0')) + query_string++; + if (*query_string == '?') { + cgi = 1; + *query_string = '\0'; + query_string++; + } + } + + while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */ + numchars = httpd_get_line(dcb->fd, buf, sizeof(buf)); + + httpd_send_headers(dcb->fd, NULL); + + strcpy(GWBUF_DATA(buffer), "Welcome to HTTPD Gateway (c)\n"); + + dcb->func.write(dcb, buffer); + + dcb_close(dcb); + + dcb->state = DCB_STATE_POLLING; + + return n; +} + +/** + * EPOLLOUT handler for the HTTPD protocol module. + * + * @param dcb The descriptor control block + * @return + */ +static int +httpd_write_event(DCB *dcb) +{ + return dcb_drain_writeq(dcb); +} + +/** + * Write routine for the HTTPD protocol module. + * + * Writes the content of the buffer queue to the socket + * observing the non-blocking principles of the gateway. + * + * @param dcb Descriptor Control Block for the socket + * @param queue Linked list of buffes to write + */ +static int +httpd_write(DCB *dcb, GWBUF *queue) +{ + return dcb_write(dcb, queue); +} + +/** + * Handler for the EPOLLERR event. + * + * @param dcb The descriptor control block + */ +static int +httpd_error(DCB *dcb) +{ + return 0; +} + +/** + * Handler for the EPOLLHUP event. + * + * @param dcb The descriptor control block + */ +static int +httpd_hangup(DCB *dcb) +{ + return 0; +} + +/** + * Handler for the EPOLLIN event when the DCB refers to the listening + * socket for the protocol. + * + * @param dcb The descriptor control block + */ +static int +httpd_accept(DCB *dcb) +{ +int n_connect = 0; + + while (1) + { + int so; + struct sockaddr_in addr; + socklen_t addrlen; + DCB *client; + + if ((so = accept(dcb->fd, (struct sockaddr *)&addr, &addrlen)) == -1) + return n_connect; + else + { + atomic_add(&dcb->stats.n_accepts, 1); + client = dcb_alloc(); + client->fd = so; + client->remote = strdup(inet_ntoa(addr.sin_addr)); + memcpy(&client->func, &MyObject, sizeof(GWPROTOCOL)); + client->session = session_alloc(dcb->session->service, client); + + client->state = DCB_STATE_IDLE; + + if (poll_add_dcb(client) == -1) + { + return n_connect; + } + n_connect++; + + client->state = DCB_STATE_POLLING; + } + } + return n_connect; +} + +/** + * The close handler for the descriptor. Called by the gateway to + * explicitly close a connection. + * + * @param dcb The descriptor control block + */ + +static int +httpd_close(DCB *dcb) +{ + dcb_close(dcb); + return 0; +} + +/** + * HTTTP daemon listener entry point + * + * @param listener The Listener DCB + * @param config Configuration (ip:port) + */ +static int +httpd_listen(DCB *listener, char *config) +{ +struct sockaddr_in addr; +char *port; +int one = 1; +short pnum; + + memcpy(&listener->func, &MyObject, sizeof(GWPROTOCOL)); + + port = strrchr(config, ':'); + if (port) + port++; + else + port = "6442"; + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + pnum = atoi(port); + addr.sin_port = htons(pnum); + + if ((listener->fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { + return 0; + } + + /* socket options */ + setsockopt(listener->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)); + + /* set NONBLOCKING mode */ + setnonblocking(listener->fd); + + /* bind address and port */ + if (bind(listener->fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) + { + return 0; + } + + listener->state = DCB_STATE_LISTENING; + listen(listener->fd, SOMAXCONN); + + if (poll_add_dcb(listener) == -1) + { + return 0; + } + return 1; +} + +/** + * HTTPD command implementation + * + * Called for each command in the HTTP stream. + * + * Currently we do no command execution + * + * @param dcb The client DCB + * @param cmd The command stream + */ +static void +httpd_command(DCB *dcb, char *cmd) +{ +} + +static int httpd_get_line(int sock, char *buf, int size) { + int i = 0; + char c = '\0'; + int n; + + while ((i < size - 1) && (c != '\n')) + { + n = recv(sock, &c, 1, 0); + /* DEBUG printf("%02X\n", c); */ + if (n > 0) + { + if (c == '\r') + { + n = recv(sock, &c, 1, MSG_PEEK); + /* DEBUG printf("%02X\n", c); */ + if ((n > 0) && (c == '\n')) + recv(sock, &c, 1, 0); + else + c = '\n'; + } + buf[i] = c; + i++; + } + else + c = '\n'; + } + buf[i] = '\0'; + + return(i); +} + +static void httpd_send_headers(int client, const char *filename) +{ + char buf[1024]; + (void)filename; /* could use filename to determine file type */ + + strcpy(buf, "HTTP/1.0 200 OK\r\n"); + send(client, buf, strlen(buf), 0); + strcpy(buf, HTTP_SERVER_STRING); + send(client, buf, strlen(buf), 0); + sprintf(buf, "Content-Type: text/html\r\n"); + send(client, buf, strlen(buf), 0); + strcpy(buf, "\r\n"); + send(client, buf, strlen(buf), 0); +} +/// diff --git a/modules/protocol/mysql_backend.c b/modules/protocol/mysql_backend.c index 663aed9af..dbb0df332 100644 --- a/modules/protocol/mysql_backend.c +++ b/modules/protocol/mysql_backend.c @@ -34,10 +34,11 @@ * and necessary headers. * 01/07/2013 Massimiliano Pinto Put Log Manager example code behind SS_DEBUG macros. * 03/07/2013 Massimiliano Pinto Added delayq for incoming data before mysql connection + * 04/07/2013 Massimiliano Pinto Added asyncrhronous MySQL protocol connection to backend + * 05/07/2013 Massimiliano Pinto Added closeSession if backend auth fails */ -static char *version_str = "V1.0.0"; -extern char *gw_strend(register const char *s); +static char *version_str = "V2.0.0"; int gw_mysql_connect(char *host, int port, char *dbname, char *user, uint8_t *passwd, MySQLProtocol *conn); static int gw_create_backend_connection(DCB *client_dcb, SERVER *server, SESSION *in_session); static int gw_read_backend_event(DCB* dcb); @@ -45,15 +46,18 @@ static int gw_write_backend_event(DCB *dcb); static int gw_MySQLWrite_backend(DCB *dcb, GWBUF *queue); static int gw_error_backend_event(DCB *dcb); static int gw_backend_close(DCB *dcb); +static int gw_backend_hangup(DCB *dcb); static int backend_write_delayqueue(DCB *dcb); static void backend_set_delayqueue(DCB *dcb, GWBUF *queue); +extern char *gw_strend(register const char *s); + static GWPROTOCOL MyObject = { gw_read_backend_event, /* Read - EPOLLIN handler */ gw_MySQLWrite_backend, /* Write - data from gateway */ gw_write_backend_event, /* WriteReady - EPOLLOUT handler */ gw_error_backend_event, /* Error - EPOLLERR handler */ - NULL, /* HangUp - EPOLLHUP handler */ + gw_backend_hangup, /* HangUp - EPOLLHUP handler */ NULL, /* Accept */ gw_create_backend_connection, /* Connect */ gw_backend_close, /* Close */ @@ -101,58 +105,106 @@ GetModuleObject() } -////////////////////////////////////////// -//backend read event triggered by EPOLLIN -////////////////////////////////////////// +/** + * Backend Read Event for EPOLLIN on the MySQL backend protocol module + * @param dcb The backend Descriptor Control Block + * @return 1 on operation, 0 for no action + */ static int gw_read_backend_event(DCB *dcb) { - int n; MySQLProtocol *client_protocol = NULL; + MySQLProtocol *backend_protocol = NULL; + MYSQL_session *current_session = NULL; - if (dcb) - if(dcb->session) - client_protocol = SESSION_PROTOCOL(dcb->session, MySQLProtocol); + if(dcb->session) { + client_protocol = SESSION_PROTOCOL(dcb->session, MySQLProtocol); + } -#ifdef GW_DEBUG_READ_EVENT - fprintf(stderr, "Backend ready! Read from Backend %i, write to client %i, client state %i\n", dcb->fd, dcb->session->client->fd, client_protocol->state); -#endif + backend_protocol = (MySQLProtocol *) dcb->protocol; + current_session = (MYSQL_session *)dcb->session->data; + + //fprintf(stderr, ">>> backend EPOLLIN from %i, protocol state [%s]\n", dcb->fd, gw_mysql_protocol_state2string(backend_protocol->state)); + + /* backend is connected: + * + * 1. read server handshake + * 2. and write auth request + * 3. and return + */ + if (backend_protocol->state == MYSQL_CONNECTED) { + + gw_read_backend_handshake(backend_protocol); + + gw_send_authentication_to_backend(current_session->db, current_session->user, current_session->client_sha1, backend_protocol); + return 1; + } + + /* ready to check the authentication reply from backend */ + + if (backend_protocol->state == MYSQL_AUTH_RECV) { + ROUTER_OBJECT *router = NULL; + ROUTER *router_instance = NULL; + void *rsession = NULL; + int rv = -1; + SESSION *session = dcb->session; + + if (session) { + router = session->service->router; + router_instance = session->service->router_instance; + rsession = session->router_session; + } + + /* read backed auth reply */ + rv = gw_receive_backend_auth(backend_protocol); + + switch (rv) { + case MYSQL_FAILED_AUTHENTICATION: + fprintf(stderr, ">>>> Backend Auth failed for user [%s], fd %i\n", current_session->user, dcb->fd); + + backend_protocol->state = MYSQL_AUTH_FAILED; + + /* send an error to the client */ + mysql_send_custom_error(dcb->session->client, 1, 0, "Connection to backend lost right now"); + + /* close the active session */ + router->closeSession(router_instance, rsession); + + /* force the router_session to NULL + * Later we will implement a proper status for the session + */ + session->router_session = NULL; + + return 1; + + case MYSQL_SUCCESFUL_AUTHENTICATION: + spinlock_acquire(&dcb->authlock); + + backend_protocol->state = MYSQL_IDLE; + + /* check the delay queue and flush the data */ + if(dcb->delayq) { + backend_write_delayqueue(dcb); + spinlock_release(&dcb->authlock); + return 1; + } + spinlock_release(&dcb->authlock); + + return 1; + + default: + /* no other authentication state here right now, so just return */ + return 0; + } + } + + /* reading MySQL command output from backend and writing to the client */ if ((client_protocol->state == MYSQL_WAITING_RESULT) || (client_protocol->state == MYSQL_IDLE)) { - int b = -1; - GWBUF *buffer, *head; + GWBUF *head = NULL; - if (ioctl(dcb->fd, FIONREAD, &b)) { - fprintf(stderr, "Backend Ioctl FIONREAD error %i, %s\n", errno , strerror(errno)); - } else { - //fprintf(stderr, "Backend IOCTL FIONREAD bytes to read = %i\n", b); - } + /* read available backend data */ + dcb_read(dcb, &head); - /* - * Read all the data that is available into a chain of buffers - */ - head = NULL; - while (b > 0) - { - int bufsize = b < MAX_BUFFER_SIZE ? b : MAX_BUFFER_SIZE; - if ((buffer = gwbuf_alloc(bufsize)) == NULL) - { - /* Bad news, we have run out of memory */ - return 0; - } - GW_NOINTR_CALL(n = read(dcb->fd, GWBUF_DATA(buffer), bufsize); dcb->stats.n_reads++); - if (n < 0) - { - // if eerno == EAGAIN || EWOULDBLOCK is missing - // do the right task, not just break - break; - } - - head = gwbuf_append(head, buffer); - - // how many bytes left - b -= n; - } - - // write the gwbuffer to client + /* and write the gwbuffer to client */ dcb->session->client->func.write(dcb->session->client, head); return 1; @@ -168,6 +220,22 @@ static int gw_read_backend_event(DCB *dcb) { * @return The number of bytes written */ static int gw_write_backend_event(DCB *dcb) { + MySQLProtocol *backend_protocol = dcb->protocol; + + //fprintf(stderr, ">>> backend EPOLLOUT %i, protocol state [%s]\n", backend_protocol->fd, gw_mysql_protocol_state2string(backend_protocol->state)); + + // spinlock_acquire(&dcb->connectlock); + + if (backend_protocol->state == MYSQL_PENDING_CONNECT) { + backend_protocol->state = MYSQL_CONNECTED; + + // spinlock_release(&dcb->connectlock); + + return 1; + } + + // spinlock_release(&dcb->connectlock); + return dcb_drain_writeq(dcb); } @@ -181,87 +249,123 @@ static int gw_write_backend_event(DCB *dcb) { static int gw_MySQLWrite_backend(DCB *dcb, GWBUF *queue) { + MySQLProtocol *backend_protocol = dcb->protocol; + + spinlock_acquire(&dcb->authlock); + + /** + * Now put the incoming data to the delay queue unless backend is connected with auth ok + */ + if (backend_protocol->state != MYSQL_IDLE) { + //fprintf(stderr, ">>> Writing in the backend %i delay queue\n", dcb->fd); + + backend_set_delayqueue(dcb, queue); + spinlock_release(&dcb->authlock); + return 1; + } + + spinlock_release(&dcb->authlock); + return dcb_write(dcb, queue); } +/** + * Backend Error Handling + * + */ static int gw_error_backend_event(DCB *dcb) { - fprintf(stderr, "#### Handle Backend error function for %i\n", dcb->fd); + fprintf(stderr, ">>> Handle Backend error function for %i\n", dcb->fd); - if (dcb->state != DCB_STATE_LISTENING) { - if (poll_remove_dcb(dcb) == -1) { - fprintf(stderr, "Backend poll_remove_dcb: from events check failed to delete %i, [%i]:[%s]\n", dcb->fd, errno, strerror(errno)); - } - -#ifdef GW_EVENT_DEBUG - fprintf(stderr, "Backend closing fd [%i]=%i, from events check\n", dcb->fd, protocol->fd); -#endif - if (dcb->fd) { - dcb->state = DCB_STATE_DISCONNECTED; - fprintf(stderr, "Freeing backend MySQL conn %p, %p\n", dcb->protocol, &dcb->protocol); - gw_mysql_close((MySQLProtocol **)&dcb->protocol); - fprintf(stderr, "Freeing backend MySQL conn %p, %p\n", dcb->protocol, &dcb->protocol); - } - } + dcb_close(dcb); return 1; } /* - * Create a new MySQL backend connection. + * Create a new backend connection. * - * This routine performs the MySQL connection to the backend and fills the session->backends of the callier dcb - * with the new allocatetd dcb and adds the new socket to the poll set + * This routine will connect to a backend server and it is called by dbc_connect in router->newSession * - * - backend dcb allocation - * - MySQL session data fetch - * - backend connection using data in MySQL session - * - * @param client_dcb The client DCB struct + * @param backend The Backend DCB allocated from dcb_connect + * @param server The selected server to connect to + * @param session The current session from Client DCB * @return 0 on Success or 1 on Failure. */ static int gw_create_backend_connection(DCB *backend, SERVER *server, SESSION *session) { - MySQLProtocol *ptr_proto = NULL; + MySQLProtocol *protocol = NULL; MYSQL_session *s_data = NULL; + int rv = -1; - fprintf(stderr, "HERE, the server to connect is [%s]:[%i]\n", server->name, server->port); + //fprintf(stderr, "HERE, the server to connect is [%s]:[%i]\n", server->name, server->port); - backend->protocol = (MySQLProtocol *) calloc(1, sizeof(MySQLProtocol)); + protocol = (MySQLProtocol *) calloc(1, sizeof(MySQLProtocol)); + protocol->state = MYSQL_ALLOC; + + backend->protocol = protocol; + + /* put the backend dcb in the protocol struct */ + protocol->descriptor = backend; - ptr_proto = (MySQLProtocol *)backend->protocol; s_data = (MYSQL_session *)session->client->data; -// fprintf(stderr, "HERE before connect, s_data is [%p]\n", s_data); -// fprintf(stderr, "HERE before connect, username is [%s]\n", s_data->user); + /** + * let's try to connect to a backend server, only connect sys call + * The socket descriptor is in Non Blocking status, this is set in the function + */ + rv = gw_do_connect_to_backend(server->name, server->port, protocol); - // this is blocking until auth done - if (gw_mysql_connect(server->name, server->port, s_data->db, s_data->user, s_data->client_sha1, backend->protocol) == 0) { - memcpy(&backend->fd, &ptr_proto->fd, sizeof(backend->fd)); + // we could also move later, this in to the gw_do_connect_to_backend using protocol->descriptor - setnonblocking(backend->fd); - fprintf(stderr, "Connected to backend mysql server. fd is %i\n", backend->fd); - } else { - fprintf(stderr, "<<<< NOT Connected to backend mysql server!!!\n"); - backend->fd = -1; - return -1; + memcpy(&backend->fd, &protocol->fd, sizeof(backend->fd)); + + switch (rv) { + + case 0: + //fprintf(stderr, "Connected to backend mysql server: fd is %i\n", backend->fd); + protocol->state = MYSQL_CONNECTED; + + break; + + case 1: + //fprintf(stderr, ">>> Connection is PENDING to backend mysql server: fd is %i\n", backend->fd); + protocol->state = MYSQL_PENDING_CONNECT; + + break; + + default: + fprintf(stderr, ">>> ERROR: NOT Connected to the backend mysql server!!!\n"); + backend->fd = -1; + + break; } - // if connected, it will be addeed to the epoll from the caller of connect() + fprintf(stderr, ">>> Backend [%s:%i] added [%i], in the client session [%i]\n", server->name, server->port, backend->fd, session->client->fd); - if (backend->fd <= 0) { - perror("ERROR: epoll_ctl: backend sock"); - backend->fd = -1; - return -1; - } else { - fprintf(stderr, "--> Backend conn added, bk_fd [%i], scramble [%s], is session with client_fd [%i]\n", backend->fd, ptr_proto->scramble, session->client->fd); - backend->state = DCB_STATE_POLLING; + backend->state = DCB_STATE_POLLING; - return backend->fd; - } - return -1; + return backend->fd; } +/** + * Hangup routine the backend dcb: it does nothing right now + * + * @param dcb The current Backend DCB + * @return 1 always + */ +static int +gw_backend_hangup(DCB *dcb) +{ + return 1; +} + +/** + * Close the backend dcb + * + * @param dcb The current Backend DCB + * @return 1 always + */ static int gw_backend_close(DCB *dcb) { @@ -269,444 +373,6 @@ gw_backend_close(DCB *dcb) return 1; } -/* - * Create a new MySQL connection. - * - * This routine performs the full MySQL connection to the specified server. - * It does - * - socket init - * - socket connect - * - server handshake parsing - * - authenticatio reply - * - the Auth ack receive - * - * Please note, all socket operation are in blocking state - * Status: work in progress. - * - * @param host The TCP/IP host address to connect to - * @param port The TCP/IP host port to connect to - * @param dbname The optional database name. Use NULL if not interested in - * @param user The MySQL database Username: required - * @param passwd The MySQL database Password: required - * @param conn The MySQLProtocol structure to be filled: must be preallocated with gw_mysql_init() - * @return 0 on Success or 1 on Failure. - */ -int gw_mysql_connect(char *host, int port, char *dbname, char *user, uint8_t *passwd, MySQLProtocol *conn) { - - struct sockaddr_in serv_addr; - int compress = 0; - int rv; - int so = 0; - int ciclo = 0; - uint8_t buffer[SMALL_CHUNK]; - uint8_t packet_buffer[SMALL_CHUNK]; - uint8_t *payload = NULL; - int server_protocol; - uint8_t *server_version_end = NULL; - uint16_t mysql_server_capabilities_one; - uint16_t mysql_server_capabilities_two; - unsigned long tid =0; - long bytes; - uint8_t scramble_data_1[8 + 1] = ""; - uint8_t scramble_data_2[12 + 1] = ""; - uint8_t capab_ptr[4]; - int scramble_len; - uint8_t scramble[GW_MYSQL_SCRAMBLE_SIZE + 1]; - uint8_t client_scramble[GW_MYSQL_SCRAMBLE_SIZE + 1]; - uint8_t client_capabilities[4]; - uint32_t server_capabilities; - uint32_t final_capabilities; - char dbpass[129]=""; - - char *curr_db = NULL; - uint8_t *curr_passwd = NULL; - - if (strlen(dbname)) - curr_db = dbname; - - if (strlen((char *)passwd)) - curr_passwd = passwd; - - conn->state = MYSQL_ALLOC; - conn->fd = -1; - - memset(&server_capabilities, '\0', sizeof(server_capabilities)); - memset(&final_capabilities, '\0', sizeof(final_capabilities)); - -#ifdef MYSQL_CONN_DEBUG - //fprintf(stderr, ")))) Connect to MySQL: user[%s], SHA1(passwd)[%s], db [%s]\n", user, passwd, dbname); -#endif - - memset(&serv_addr, 0, sizeof serv_addr); - serv_addr.sin_family = AF_INET; - - so = socket(AF_INET,SOCK_STREAM,0); - if (so < 0) { - fprintf(stderr, "Errore creazione socket: [%s] %i\n", strerror(errno), errno); - return 1; - } - - conn->fd = so; - - setipaddress(&serv_addr.sin_addr, host); - serv_addr.sin_port = htons(port); - -#ifdef MYSQL_CONN_DEBUG - fprintf(stderr, "Socket initialized\n"); - fflush(stderr); -#endif - - while(1) { - if ((rv = connect(so, (struct sockaddr *)&serv_addr, sizeof(serv_addr))) < 0) { - fprintf(stderr, "Errore connect %i, %s: RV = [%i]\n", errno, strerror(errno), rv); - - if (errno == EINPROGRESS) { - continue; - } else { - close(so); - return -1; - } - } else { - break; - } - } - -#ifdef MYSQL_CONN_DEBUG - fprintf(stderr, "CONNECT is DONE\n"); - fprintf(stderr, "Socket FD is %i\n", so); - fflush(stderr); -#endif - - - memset(&buffer, '\0', sizeof(buffer)); - - bytes = SMALL_CHUNK; - - rv = read(so, buffer, bytes); - - if ( rv >0 ) { -#ifdef MYSQL_CONN_DEBUG - fprintf(stderr, "RESPONSE ciclo %i HO letto [%s] bytes %li\n",ciclo, buffer, bytes); - fflush(stderr); -#endif - ciclo++; - } else { - if (rv == 0 && errno == EOF) { -#ifdef MYSQL_CONN_DEBUG - fprintf(stderr, "EOF reached. Bytes = %li\n", bytes); - fflush(stderr); -#endif - } else { -#ifdef MYSQL_CONN_DEBUG - fprintf(stderr, "###### Receive error FINAL : connection not completed %i %s: RV = [%i]\n", errno, strerror(errno), rv); -#endif - close(so); - - return -1; - } - } - -#ifdef MYSQL_CONN_DEBUG - fwrite(buffer, bytes, 1, stderr); - fflush(stderr); -#endif - - //decode mysql handshake - - payload = buffer + 4; - server_protocol= payload[0]; - -#ifdef MYSQL_CONN_DEBUG - fprintf(stderr, "Server Protocol [%i]\n", server_protocol); - -#endif - payload++; - -#ifdef MYSQL_CONN_DEBUG - fprintf(stderr, "Protocol Version [%s]\n", payload); - fflush(stderr); -#endif - - server_version_end = (uint8_t *) gw_strend((char*) payload); - payload = server_version_end + 1; - - // TID - tid = gw_mysql_get_byte4(payload); - memcpy(&conn->tid, &tid, 4); - -#ifdef MYSQL_CONN_DEBUG - fprintf(stderr, "Thread ID is %lu\n", conn->tid); - fflush(stderr); -#endif - - payload +=4; - - // scramble_part 1 - memcpy(scramble_data_1, payload, 8); - payload += 8; - - // 1 filler - payload++; - - mysql_server_capabilities_one = gw_mysql_get_byte2(payload); - -#ifdef MYSQL_CONN_DEBUG - fprintf(stderr, "Capab_1[\n"); - fwrite(&mysql_server_capabilities_one, 2, 1, stderr); - fflush(stderr); -#endif - - //2 capab_part 1 + 1 language + 2 server_status - payload +=5; - - mysql_server_capabilities_two = gw_mysql_get_byte2(payload); - -#ifdef MYSQL_CONN_DEBUG - fprintf(stderr, "]Capab_2[\n"); - fwrite(&mysql_server_capabilities_two, 2, 1, stderr); - fprintf(stderr, "]\n"); - fflush(stderr); -#endif - - memcpy(&capab_ptr, &mysql_server_capabilities_one, 2); - -#ifdef MYSQL_CONN_DEBUG - fprintf(stderr, "Capab_1[\n"); - fwrite(capab_ptr, 2, 1, stderr); - fflush(stderr); -#endif - - memcpy(&(capab_ptr[2]), &mysql_server_capabilities_two, 2); - -#ifdef MYSQL_CONN_DEBUG - fprintf(stderr, "Capab_2[\n"); - fwrite(capab_ptr, 2, 1, stderr); - fflush(stderr); -#endif - - // 2 capab_part 2 - payload+=2; - - scramble_len = payload[0] -1; - -#ifdef MYSQL_CONN_DEBUG - fprintf(stderr, "Scramble_len [%i]\n", scramble_len); - fflush(stderr); -#endif - - payload += 11; - - memcpy(scramble_data_2, payload, scramble_len - 8); - -#ifdef MYSQL_CONN_DEBUG - fprintf(stderr, "Scramble_buff1["); - fwrite(scramble_data_1, 8, 1, stderr); - fprintf(stderr, "]\nScramble_buff2 ["); - fwrite(scramble_data_2, scramble_len - 8, 1, stderr); - fprintf(stderr, "]\n"); - fflush(stderr); -#endif - - memcpy(scramble, scramble_data_1, 8); - memcpy(scramble + 8, scramble_data_2, scramble_len - 8); - -#ifdef MYSQL_CONN_DEBUG - fprintf(stderr, "Full Scramble 20 bytes is [\n"); - fwrite(scramble, GW_MYSQL_SCRAMBLE_SIZE, 1, stderr); - fprintf(stderr, "\n]\n"); - fflush(stderr); -#endif - - memcpy(conn->scramble, scramble, GW_MYSQL_SCRAMBLE_SIZE); - -#ifdef MYSQL_CONN_DEBUG - fprintf(stderr, "Scramble from MYSQL_Conn is [\n"); - fwrite(scramble, GW_MYSQL_SCRAMBLE_SIZE, 1, stderr); - fprintf(stderr, "\n]\n"); - fflush(stderr); - fprintf(stderr, "Now sending user, pass & db\n["); - fwrite(&server_capabilities, 4, 1, stderr); - fprintf(stderr, "]\n"); -#endif - - final_capabilities = gw_mysql_get_byte4((uint8_t *)&server_capabilities); - -#ifdef MYSQL_CONN_DEBUG - fprintf(stderr, "CAPABS [%u]\n", final_capabilities); - fflush(stderr); -#endif - memset(packet_buffer, '\0', sizeof(packet_buffer)); - //packet_header(byte3 +1 pack#) - packet_buffer[3] = '\x01'; - - final_capabilities |= GW_MYSQL_CAPABILITIES_PROTOCOL_41; - final_capabilities |= GW_MYSQL_CAPABILITIES_CLIENT; - if (compress) { - final_capabilities |= GW_MYSQL_CAPABILITIES_COMPRESS; - fprintf(stderr, "Backend Connection with compression\n"); - fflush(stderr); - } - - if (curr_passwd != NULL) { - uint8_t hash1[GW_MYSQL_SCRAMBLE_SIZE]=""; - uint8_t hash2[GW_MYSQL_SCRAMBLE_SIZE]=""; - uint8_t new_sha[GW_MYSQL_SCRAMBLE_SIZE]=""; - - - memcpy(hash1, passwd, GW_MYSQL_SCRAMBLE_SIZE); - gw_sha1_str(hash1, GW_MYSQL_SCRAMBLE_SIZE, hash2); - gw_bin2hex(dbpass, hash2, GW_MYSQL_SCRAMBLE_SIZE); - gw_sha1_2_str(scramble, GW_MYSQL_SCRAMBLE_SIZE, hash2, GW_MYSQL_SCRAMBLE_SIZE, new_sha); - gw_str_xor(client_scramble, new_sha, hash1, GW_MYSQL_SCRAMBLE_SIZE); - -#ifdef MYSQL_CONN_DEBUG - fprintf(stderr, "Hash1 [%s]\n", hash1); - fprintf(stderr, "Hash2 [%s]\n", hash2); - fprintf(stderr, "SHA1(SHA1(password in hex)\n"); - fprintf(stderr, "PAss [%s]\n", dbpass); - fflush(stderr); - fprintf(stderr, "newsha [%s]\n", new_sha); - fprintf(stderr, "Client send scramble 20 [\n"); - fwrite(client_scramble, GW_MYSQL_SCRAMBLE_SIZE, 1, stderr); - fprintf(stderr, "\n]\n"); - fflush(stderr); -#endif - } - - if (curr_db == NULL) { - // now without db!! - final_capabilities &= ~GW_MYSQL_CAPABILITIES_CONNECT_WITH_DB; - } else { - final_capabilities |= GW_MYSQL_CAPABILITIES_CONNECT_WITH_DB; - } - - payload = packet_buffer + 4; - - final_capabilities |= GW_MYSQL_CAPABILITIES_PLUGIN_AUTH; - - gw_mysql_set_byte4(client_capabilities, final_capabilities); - memcpy(payload, client_capabilities, 4); - - //packet_buffer[4] = '\x8d'; - //packet_buffer[5] = '\xa6'; - //packet_buffer[6] = '\x0f'; - //packet_buffer[7] = '\x00'; - - // set now the max-packet size - payload += 4; - gw_mysql_set_byte4(payload, 16777216); - - // set the charset - payload += 4; - *payload = '\x08'; - - payload++; - -#ifdef MYSQL_CONN_DEBUG - fprintf(stderr, "User is [%s]\n", user); - fflush(stderr); -#endif - - - // 4 + 4 + 4 + 1 + 23 = 36 - payload += 23; - memcpy(payload, user, strlen(user)); - - // 4 + 4 + 1 + 23 = 32 + 1 (scramble_len) + 20 (fixed_scramble) + 1 (user NULL term) + 1 (db NULL term) = 55 - bytes = 32; - - bytes += strlen(user); - // the NULL - bytes++; - - payload += strlen(user); - payload++; - - if (curr_passwd != NULL) { - // set the auth-length - *payload = GW_MYSQL_SCRAMBLE_SIZE; - payload++; - bytes++; - - //copy the 20 bytes scramble data after packet_buffer+36+user+NULL+1 (byte of auth-length) - memcpy(payload, client_scramble, GW_MYSQL_SCRAMBLE_SIZE); - - payload += GW_MYSQL_SCRAMBLE_SIZE; - bytes += GW_MYSQL_SCRAMBLE_SIZE; - - } else { - // skip the auth-length and write a NULL - payload++; - bytes++; - } - - // if the db is not NULL append it - if (curr_db) { - memcpy(payload, curr_db, strlen(curr_db)); - payload += strlen(curr_db); - payload++; - bytes += strlen(curr_db); - // the NULL - bytes++; - } - - memcpy(payload, "mysql_native_password", strlen("mysql_native_password")); - - payload += strlen("mysql_native_password"); - payload++; - - bytes +=strlen("mysql_native_password"); - bytes++; - - gw_mysql_set_byte3(packet_buffer, bytes); - - // the packet header - bytes += 4; - - rv = write(so, packet_buffer, bytes); - -#ifdef MYSQL_CONN_DEBUG - fprintf(stderr, "Sent [%s], [%i] bytes\n", packet_buffer, bytes); - fflush(stderr); -#endif - - if (rv == -1) { - fprintf(stderr, "CONNECT Error in send auth\n"); - } - - bytes = SMALL_CHUNK; - - memset(buffer, '\0', sizeof (buffer)); - - rv = read(so, buffer, SMALL_CHUNK); - - if (rv == -1) { - fprintf(stderr, "CONNCET Error in recv OK for auth\n"); - } - -#ifdef MYSQL_CONN_DEBUG - fprintf(stderr, "ok packet\["); - fwrite(buffer, bytes, 1, stderr); - fprintf(stderr, "]\n"); - fflush(stderr); -#endif - if (buffer[4] == '\x00') { -#ifdef MYSQL_CONN_DEBUG - fprintf(stderr, "OK packet received, packet # %i\n", buffer[3]); - fflush(stderr); -#endif - conn->state = MYSQL_IDLE; - - return 0; - } else { - - close(so); - } - - return 1; - -} - /** * This routine put into the delay queue the input queue * The input is what backend DCB is receiving diff --git a/modules/protocol/mysql_client.c b/modules/protocol/mysql_client.c index b3da2b733..e15761391 100644 --- a/modules/protocol/mysql_client.c +++ b/modules/protocol/mysql_client.c @@ -179,87 +179,6 @@ mysql_send_ok(DCB *dcb, int packet_number, int in_affected_rows, const char* mys return sizeof(mysql_packet_header) + mysql_payload_size; } -/** - * mysql_send_auth_error - * - * Send a MySQL protocol Generic ERR message, to the dcb - * Note the errno and state are still fixed now - * - * @param dcb Descriptor Control Block for the connection to which the OK is sent - * @param packet_number - * @param in_affected_rows - * @param mysql_message - * @return packet length - * - */ - -int -mysql_send_custom_error (DCB *dcb, int packet_number, int in_affected_rows, const char* mysql_message) { - uint8_t *outbuf = NULL; - uint8_t mysql_payload_size = 0; - uint8_t mysql_packet_header[4]; - uint8_t *mysql_payload = NULL; - uint8_t field_count = 0; - uint8_t mysql_err[2]; - uint8_t mysql_statemsg[6]; - unsigned int mysql_errno = 0; - const char *mysql_error_msg = NULL; - const char *mysql_state = NULL; - - GWBUF *buf; - - mysql_errno = 2003; - mysql_error_msg = "An errorr occurred ..."; - mysql_state = "HY000"; - - field_count = 0xff; - gw_mysql_set_byte2(mysql_err, mysql_errno); - mysql_statemsg[0]='#'; - memcpy(mysql_statemsg+1, mysql_state, 5); - - if (mysql_message != NULL) { - mysql_error_msg = mysql_message; - } - - mysql_payload_size = sizeof(field_count) + sizeof(mysql_err) + sizeof(mysql_statemsg) + strlen(mysql_error_msg); - - // allocate memory for packet header + payload - if ((buf = gwbuf_alloc(sizeof(mysql_packet_header) + mysql_payload_size)) == NULL) - { - return 0; - } - outbuf = GWBUF_DATA(buf); - - // write packet header with packet number - gw_mysql_set_byte3(mysql_packet_header, mysql_payload_size); - mysql_packet_header[3] = packet_number; - - // write header - memcpy(outbuf, mysql_packet_header, sizeof(mysql_packet_header)); - - mysql_payload = outbuf + sizeof(mysql_packet_header); - - // write field - memcpy(mysql_payload, &field_count, sizeof(field_count)); - mysql_payload = mysql_payload + sizeof(field_count); - - // write errno - memcpy(mysql_payload, mysql_err, sizeof(mysql_err)); - mysql_payload = mysql_payload + sizeof(mysql_err); - - // write sqlstate - memcpy(mysql_payload, mysql_statemsg, sizeof(mysql_statemsg)); - mysql_payload = mysql_payload + sizeof(mysql_statemsg); - - // write err messg - memcpy(mysql_payload, mysql_error_msg, strlen(mysql_error_msg)); - - // writing data in the Client buffer queue - dcb->func.write(dcb, buf); - - return sizeof(mysql_packet_header) + mysql_payload_size; -} - /** * mysql_send_auth_error * @@ -542,8 +461,6 @@ static int gw_mysql_do_authentication(DCB *dcb, GWBUF *queue) { fprintf(stderr, "<<< Client is NOT connected with db\n"); } - fprintf(stderr, "HERE auth token len is %i\n", auth_token_len); - // allocate memory for token only if auth_token_len > 0 if (auth_token_len) { auth_token = (uint8_t *)malloc(auth_token_len); @@ -558,10 +475,8 @@ static int gw_mysql_do_authentication(DCB *dcb, GWBUF *queue) { if (auth_token) free(auth_token); - if (auth_ret == 0) { - fprintf(stderr, "<<< CLIENT AUTH is OK\n"); - } else { - fprintf(stderr, "<<< CLIENT AUTH FAILED\n"); + if (auth_ret != 0) { + fprintf(stderr, "<<< CLIENT AUTH FAILEDi for user [%s]\n", username); } return auth_ret; @@ -586,7 +501,6 @@ static int gw_find_mysql_user_password_sha1(char *username, uint8_t *gateway_pas fprintf(stderr, ">>> MYSQL user NOT FOUND: %s\n", username); return 1; } - fprintf(stderr, ">>> MYSQL user FOUND !!!!: [%s]:[%s]\n", username, user_password); // convert hex data (40 bytes) to binary (20 bytes) // gateway_password represents the SHA1(SHA1(real_password)) @@ -618,16 +532,14 @@ static int gw_check_mysql_scramble_data(DCB *dcb, uint8_t *token, unsigned int t if (ret_val) { fprintf(stderr, "<<<< User [%s] was not found\n", username); return 1; - } else { - fprintf(stderr, "<<<< User [%s] OK\n", username); } if (token && token_len) { - fprintf(stderr, ">>> continue with auth\n"); // convert in hex format: this is the content of mysql.user table, field password without the '*' prefix - // an it is 40 bytes long + // and it is 40 bytes long gw_bin2hex(hex_double_sha1, password, SHA_DIGEST_LENGTH); } else { + // check if the password is not set in the user table if (!strlen((char *)password)) { fprintf(stderr, ">>> continue WITHOUT auth, no password\n"); return 0; @@ -673,14 +585,12 @@ static int gw_check_mysql_scramble_data(DCB *dcb, uint8_t *token, unsigned int t gw_sha1_str(step2, SHA_DIGEST_LENGTH, check_hash); - fprintf(stderr, "<<<< Client_SHA1 [%20s]\n", stage1_hash); - #ifdef GW_DEBUG_CLIENT_AUTH { char inpass[128]=""; gw_bin2hex(inpass, check_hash, SHA_DIGEST_LENGTH); - //fprintf(stderr, "The CLIENT hex(SHA1(SHA1(password))) for \"%s\" is [%s]", username, inpass); + fprintf(stderr, "The CLIENT hex(SHA1(SHA1(password))) for \"%s\" is [%s]", username, inpass); } #endif @@ -865,6 +775,8 @@ int gw_read_client_event(DCB* dcb) { int ret = -1; session = dcb->session; + + // get the backend session, if available if (session) { router = session->service->router; router_instance = session->service->router_instance; @@ -877,65 +789,66 @@ int gw_read_client_event(DCB* dcb) { if ((ret = gw_read_gwbuff(dcb, &gw_buffer, b)) != 0) return ret; - // Now assuming in the first buffer there is the information form mysql command + /* Now, we are assuming in the first buffer there is the information form mysql command */ - // following code is only for debug now queue = gw_buffer; len = GWBUF_LENGTH(queue); ptr_buff = GWBUF_DATA(queue); - // get mysql commang + /* get mysql commang at fourth byte */ if (ptr_buff) mysql_command = ptr_buff[4]; if (mysql_command == '\x03') { - /// this is a query !!!! - //fprintf(stderr, "<<< MySQL Query from Client %i bytes: [%s]\n", len, ptr_buff+5); - //else - //fprintf(stderr, "<<< Reading from Client %i bytes: [%s]\n", len, ptr_buff); + /// this is a standard MySQL query !!!! } - + /** + * Routing Client input to Backend + */ + + /* Do not route the query without session! */ if(!rsession) { - if (mysql_command == '\x01') { - fprintf(stderr, "COM_QUIT received with no connected backends\n"); + /* COM_QUIT handling */ + //fprintf(stderr, "COM_QUIT received with no connected backends from %i\n", dcb->fd); (dcb->func).close(dcb); + return 1; + } else { + /* Send a custom error as MySQL command reply */ + mysql_send_custom_error(dcb, 1, 0, "Connection to backend lost"); + + protocol->state = MYSQL_IDLE; + return 1; } - mysql_send_custom_error(dcb, 1, 0, "Connection to backend lost"); - protocol->state = MYSQL_IDLE; - - break; } - - /////////////////////////// - // Handling the COM_QUIT - ////////////////////////// - if (mysql_command == '\x01') { - fprintf(stderr, "COM_QUIT received\n"); - // uncomment the following lines for closing - // client and backend conns - // dcb still to be freed + + /* We can route the query */ - // this will propagate COM_QUIT to backends + /* COM_QUIT handling */ + if (mysql_command == '\x01') { + //fprintf(stderr, "COM_QUIT received from %i and passed to backed\n", dcb->fd); + + /* this will propagate COM_QUIT to backend(s) */ + //fprintf(stderr, "<<< Routing the COM_QUIT ...\n"); router->routeQuery(router_instance, rsession, queue); - // close client + + /* close client connection */ (dcb->func).close(dcb); - // call errors, it will be removed after tests - //(dcb->func).error(dcb); return 1; } + /* MySQL Command Routing */ + protocol->state = MYSQL_ROUTING; - /////////////////////////////////////// - // writing in the backend buffer queue, via routeQuery - /////////////////////////////////////// + /* writing in the backend buffer queue, via routeQuery */ + //fprintf(stderr, "<<< Routing the Query ...\n"); router->routeQuery(router_instance, rsession, queue); protocol->state = MYSQL_WAITING_RESULT; @@ -1085,7 +998,6 @@ int gw_MySQLAccept(DCB *listener) { if (c_sock == -1) { if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { - fprintf(stderr, ">>>> NO MORE conns for MySQL Listener: errno is %i for %i\n", errno, listener->fd); /* We have processed all incoming connections. */ break; } else { @@ -1145,7 +1057,8 @@ int gw_MySQLAccept(DCB *listener) { /* */ static int gw_error_client_event(DCB *dcb) { - fprintf(stderr, "#### Handle error function gw_error_client_event, for [%i] is [%s]\n", dcb->fd, gw_dcb_state2string(dcb->state)); + //fprintf(stderr, "#### Handle error function gw_error_client_event, for [%i] is [%s]\n", dcb->fd, gw_dcb_state2string(dcb->state)); + //dcb_close(dcb); return 1; } diff --git a/modules/protocol/mysql_common.c b/modules/protocol/mysql_common.c index 18d935d8e..92c7bcf4e 100644 --- a/modules/protocol/mysql_common.c +++ b/modules/protocol/mysql_common.c @@ -432,4 +432,162 @@ int gw_send_authentication_to_backend(char *dbname, char *user, uint8_t *passwd, else return 0; } + +/** + * Only backend connect syscall + */ +int gw_do_connect_to_backend(char *host, int port, MySQLProtocol *conn) { + struct sockaddr_in serv_addr; + int rv; + int so = 0; + + memset(&serv_addr, 0, sizeof serv_addr); + serv_addr.sin_family = AF_INET; + + so = socket(AF_INET,SOCK_STREAM,0); + + conn->fd = so; + + if (so < 0) { + fprintf(stderr, "Error creating backend socket: [%s] %i\n", strerror(errno), errno); + /* this is an error */ + return -1; + } + + setipaddress(&serv_addr.sin_addr, host); + serv_addr.sin_port = htons(port); + + /* set NON BLOCKING here */ + setnonblocking(so); + + if ((rv = connect(so, (struct sockaddr *)&serv_addr, sizeof(serv_addr))) < 0) { + /* If connection is not yet completed just return 1 */ + if (errno == EINPROGRESS) { + //fprintf(stderr, ">>> Connection is not yet completed for backend server [%s:%i]: errno %i, %s: RV = [%i]\n", host, port, errno, strerror(errno), rv); + + return 1; + } else { + /* this is a real error */ + fprintf(stderr, ">>> ERROR connecting to backend server [%s:%i]: errno %i, %s: RV = [%i]\n", host, port, errno, strerror(errno), rv); + return -1; + } + } + + /* The connection succesfully completed now */ + + return 0; +} + +/** + * Return a string representation of a MySQL protocol state. + * + * @param state The protocol state + * @return String representation of the state + * + */ +const char * +gw_mysql_protocol_state2string (int state) { + switch(state) { + case MYSQL_ALLOC: + return "MySQL Protocl struct allocated"; + case MYSQL_PENDING_CONNECT: + return "MySQL Backend socket PENDING connect"; + case MYSQL_CONNECTED: + return "MySQL Backend socket CONNECTED"; + case MYSQL_AUTH_SENT: + return "MySQL Authentication handshake has been sent"; + case MYSQL_AUTH_RECV: + return "MySQL Received user, password, db and capabilities"; + case MYSQL_AUTH_FAILED: + return "MySQL Authentication failed"; + case MYSQL_IDLE: + return "MySQL Auth done. Protocol is idle, waiting for statements"; + case MYSQL_ROUTING: + return "MySQL received command has been routed to backend(s)"; + case MYSQL_WAITING_RESULT: + return "MySQL Waiting for result set"; + default: + return "MySQL (unknown protocol state)"; + } +} + +/** + * mysql_send_custom_error + * + * Send a MySQL protocol Generic ERR message, to the dcb + * Note the errno and state are still fixed now + * + * @param dcb Descriptor Control Block for the connection to which the OK is sent + * @param packet_number + * @param in_affected_rows + * @param mysql_message + * @return packet length + * + */ +int +mysql_send_custom_error (DCB *dcb, int packet_number, int in_affected_rows, const char* mysql_message) { + uint8_t *outbuf = NULL; + uint8_t mysql_payload_size = 0; + uint8_t mysql_packet_header[4]; + uint8_t *mysql_payload = NULL; + uint8_t field_count = 0; + uint8_t mysql_err[2]; + uint8_t mysql_statemsg[6]; + unsigned int mysql_errno = 0; + const char *mysql_error_msg = NULL; + const char *mysql_state = NULL; + + GWBUF *buf; + + mysql_errno = 2003; + mysql_error_msg = "An errorr occurred ..."; + mysql_state = "HY000"; + + field_count = 0xff; + gw_mysql_set_byte2(mysql_err, mysql_errno); + mysql_statemsg[0]='#'; + memcpy(mysql_statemsg+1, mysql_state, 5); + + if (mysql_message != NULL) { + mysql_error_msg = mysql_message; + } + + mysql_payload_size = sizeof(field_count) + sizeof(mysql_err) + sizeof(mysql_statemsg) + strlen(mysql_error_msg); + + // allocate memory for packet header + payload + if ((buf = gwbuf_alloc(sizeof(mysql_packet_header) + mysql_payload_size)) == NULL) + { + return 0; + } + outbuf = GWBUF_DATA(buf); + + // write packet header with packet number + gw_mysql_set_byte3(mysql_packet_header, mysql_payload_size); + mysql_packet_header[3] = packet_number; + + // write header + memcpy(outbuf, mysql_packet_header, sizeof(mysql_packet_header)); + + mysql_payload = outbuf + sizeof(mysql_packet_header); + + // write field + memcpy(mysql_payload, &field_count, sizeof(field_count)); + mysql_payload = mysql_payload + sizeof(field_count); + + // write errno + memcpy(mysql_payload, mysql_err, sizeof(mysql_err)); + mysql_payload = mysql_payload + sizeof(mysql_err); + + // write sqlstate + memcpy(mysql_payload, mysql_statemsg, sizeof(mysql_statemsg)); + mysql_payload = mysql_payload + sizeof(mysql_statemsg); + + // write err messg + memcpy(mysql_payload, mysql_error_msg, strlen(mysql_error_msg)); + + // writing data in the Client buffer queue + dcb->func.write(dcb, buf); + + return sizeof(mysql_packet_header) + mysql_payload_size; +} /////