summaryrefslogtreecommitdiff
path: root/sql/Attic/net_serv.c
diff options
context:
space:
mode:
Diffstat (limited to 'sql/Attic/net_serv.c')
-rw-r--r--sql/Attic/net_serv.c616
1 files changed, 616 insertions, 0 deletions
diff --git a/sql/Attic/net_serv.c b/sql/Attic/net_serv.c
new file mode 100644
index 00000000000..8f5ba20664a
--- /dev/null
+++ b/sql/Attic/net_serv.c
@@ -0,0 +1,616 @@
+/* Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+/* Write and read of logical packets to/from socket
+** Writes are cached into net_buffer_length big packets.
+** Read packets are reallocated dynamicly when reading big packets.
+** Each logical packet has the following pre-info:
+** 3 byte length & 1 byte package-number.
+*/
+
+#ifdef _WIN32
+#include <winsock.h>
+#endif
+#include <global.h>
+#include <violite.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include "mysql.h"
+#include <signal.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <violite.h>
+
+#if !defined(__WIN32__) && !defined(MSDOS)
+#include <sys/socket.h>
+#endif
+#if !defined(MSDOS) && !defined(__WIN32__) && !defined(HAVE_BROKEN_NETINET_INCLUDES) && !defined(__BEOS__)
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#if !defined(alpha_linux_port)
+#include <netinet/tcp.h>
+#endif
+#endif
+#include "mysqld_error.h"
+#ifdef MYSQL_SERVER
+#include "my_pthread.h"
+#include "thr_alarm.h"
+void sql_print_error(const char *format,...);
+#define RETRY_COUNT mysqld_net_retry_count
+extern ulong mysqld_net_retry_count;
+#else
+typedef my_bool thr_alarm_t;
+#define thr_alarm_init(A) (*A)=0
+#define thr_alarm_in_use(A) (A)
+#define thr_end_alarm(A)
+#define thr_alarm(A,B) local_thr_alarm((A),(B))
+static inline int local_thr_alarm(my_bool *A,int B __attribute__((unused)))
+{
+ *A=1;
+ return 0;
+}
+#define thr_got_alarm(A) 0
+#define RETRY_COUNT 1
+#endif
+
+#ifdef MYSQL_SERVER
+extern ulong bytes_sent, bytes_received;
+extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received;
+#else
+#undef thread_safe_add
+#define thread_safe_add(A,B,C)
+#endif
+
+/*
+** Give error if a too big packet is found
+** The server can change this with the -O switch, but because the client
+** can't normally do this the client should have a bigger max-buffer.
+*/
+
+#ifdef MYSQL_SERVER
+ulong max_allowed_packet=65536;
+extern uint test_flags;
+#else
+ulong max_allowed_packet=16*1024*1024L;
+#endif
+ulong net_buffer_length=8192; /* Default length. Enlarged if necessary */
+
+#define TEST_BLOCKING 8
+static int net_write_buff(NET *net,const char *packet,uint len);
+
+
+ /* Init with packet info */
+
+int my_net_init(NET *net, Vio* vio)
+{
+ if (!(net->buff=(uchar*) my_malloc(net_buffer_length,MYF(MY_WME))))
+ return 1;
+ if (net_buffer_length > max_allowed_packet)
+ max_allowed_packet=net_buffer_length;
+ net->buff_end=net->buff+(net->max_packet=net_buffer_length);
+ net->vio = vio;
+ net->error=net->return_errno=0;
+ net->timeout=NET_READ_TIMEOUT; /* Timeout for read */
+ net->pkt_nr=0;
+ net->write_pos=net->read_pos = net->buff;
+ net->last_error[0]=0;
+ net->compress=0; net->reading_or_writing=0;
+ net->where_b = net->remain_in_buf=0;
+ net->last_errno=0;
+
+ if (vio != 0) /* If real connection */
+ {
+ net->fd = vio_fd(vio); /* For perl DBI/DBD */
+#if defined(MYSQL_SERVER) && !defined(___WIN32__) && !defined(__EMX__)
+ if (!(test_flags & TEST_BLOCKING))
+ vio_blocking(vio, FALSE);
+#endif
+ vio_fastsend(vio,TRUE);
+ }
+ return 0;
+}
+
+void net_end(NET *net)
+{
+ my_free((gptr) net->buff,MYF(MY_ALLOW_ZERO_PTR));
+ net->buff=0;
+}
+
+/* Realloc the packet buffer */
+
+static my_bool net_realloc(NET *net, ulong length)
+{
+ uchar *buff;
+ ulong pkt_length;
+ if (length >= max_allowed_packet)
+ {
+ DBUG_PRINT("error",("Packet too large (%ld)", length));
+#ifdef MYSQL_SERVER
+ sql_print_error("Packet too large (%ld)\n", length);
+#else
+ fprintf(stderr,"Packet too large (%ld)\n", length);
+#endif
+ net->error=1;
+#ifdef MYSQL_SERVER
+ net->last_errno=ER_NET_PACKET_TOO_LARGE;
+#endif
+ return 1;
+ }
+ pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1);
+ if (!(buff=(uchar*) my_realloc((char*) net->buff, pkt_length, MYF(MY_WME))))
+ {
+ net->error=1;
+#ifdef MYSQL_SERVER
+ net->last_errno=ER_OUT_OF_RESOURCES;
+#endif
+ return 1;
+ }
+ net->buff=net->write_pos=buff;
+ net->buff_end=buff+(net->max_packet=pkt_length);
+ return 0;
+}
+
+ /* Remove unwanted characters from connection */
+
+void net_clear(NET *net)
+{
+#ifndef EXTRA_DEBUG
+ int count;
+ bool is_blocking=vio_is_blocking(net->vio);
+ if (is_blocking)
+ vio_blocking(net->vio, FALSE);
+ if (!vio_is_blocking(net->vio)) /* Safety if SSL */
+ {
+ while ( (count = vio_read(net->vio, (char*) (net->buff),
+ net->max_packet)) > 0)
+ DBUG_PRINT("info",("skipped %d bytes from file: %s",
+ count,vio_description(net->vio)));
+ if (is_blocking)
+ vio_blocking(net->vio, TRUE);
+ }
+#endif /* EXTRA_DEBUG */
+ net->pkt_nr=0; /* Ready for new command */
+ net->write_pos=net->buff;
+}
+
+ /* Flush write_buffer if not empty. */
+
+int net_flush(NET *net)
+{
+ int error=0;
+ DBUG_ENTER("net_flush");
+ if (net->buff != net->write_pos)
+ {
+ error=net_real_write(net,(char*) net->buff,
+ (uint) (net->write_pos - net->buff));
+ net->write_pos=net->buff;
+ }
+ DBUG_RETURN(error);
+}
+
+
+/*****************************************************************************
+** Write something to server/client buffer
+*****************************************************************************/
+
+
+/*
+** Write a logical packet with packet header
+** Format: Packet length (3 bytes), packet number(1 byte)
+** When compression is used a 3 byte compression length is added
+** NOTE: If compression is used the original package is destroyed!
+*/
+
+int
+my_net_write(NET *net,const char *packet,ulong len)
+{
+ uchar buff[NET_HEADER_SIZE];
+ int3store(buff,len);
+ buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
+ if (net_write_buff(net,(char*) buff,NET_HEADER_SIZE))
+ return 1;
+ return net_write_buff(net,packet,len);
+}
+
+int
+net_write_command(NET *net,uchar command,const char *packet,ulong len)
+{
+ uchar buff[NET_HEADER_SIZE+1];
+ uint length=len+1; /* 1 extra byte for command */
+
+ int3store(buff,length);
+ buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
+ buff[4]=command;
+ if (net_write_buff(net,(char*) buff,5))
+ return 1;
+ return test(net_write_buff(net,packet,len) || net_flush(net));
+}
+
+
+static int
+net_write_buff(NET *net,const char *packet,uint len)
+{
+ uint left_length=(uint) (net->buff_end - net->write_pos);
+
+ while (len > left_length)
+ {
+ memcpy((char*) net->write_pos,packet,left_length);
+ if (net_real_write(net,(char*) net->buff,net->max_packet))
+ return 1;
+ net->write_pos=net->buff;
+ packet+=left_length;
+ len-=left_length;
+ left_length=net->max_packet;
+ }
+ memcpy((char*) net->write_pos,packet,len);
+ net->write_pos+=len;
+ return 0;
+}
+
+/* Read and write using timeouts */
+
+int
+net_real_write(NET *net,const char *packet,ulong len)
+{
+ int length;
+ char *pos,*end;
+ thr_alarm_t alarmed;
+ uint retry_count=0;
+ my_bool net_blocking = vio_is_blocking(net->vio);
+ DBUG_ENTER("net_real_write");
+
+ net->reading_or_writing=2;
+#ifdef HAVE_COMPRESS
+ if (net->compress)
+ {
+ ulong complen;
+ uchar *b;
+ uint header_length=NET_HEADER_SIZE+COMP_HEADER_SIZE;
+ if (!(b=(uchar*) my_malloc(len + NET_HEADER_SIZE + COMP_HEADER_SIZE,
+ MYF(MY_WME))))
+ {
+#ifdef MYSQL_SERVER
+ net->last_errno=ER_OUT_OF_RESOURCES;
+ net->error=1;
+#endif
+ net->reading_or_writing=0;
+ DBUG_RETURN(1);
+ }
+ memcpy(b+header_length,packet,len);
+
+ if (my_compress((byte*) b+header_length,&len,&complen))
+ {
+ DBUG_PRINT("warning",
+ ("Compression error; Continuing without compression"));
+ complen=0;
+ }
+ int3store(&b[NET_HEADER_SIZE],complen);
+ int3store(b,len);
+ b[3]=(uchar) (net->pkt_nr++);
+ len+= header_length;
+ packet= (char*) b;
+ }
+#endif /* HAVE_COMPRESS */
+
+ /* DBUG_DUMP("net",packet,len); */
+#ifdef MYSQL_SERVER
+ thr_alarm_init(&alarmed);
+ if (net_blocking)
+ thr_alarm(&alarmed,NET_WRITE_TIMEOUT);
+#else
+ alarmed=0;
+#endif /* MYSQL_SERVER */
+
+ pos=(char*) packet; end=pos+len;
+ while (pos != end)
+ {
+ if ((int) (length=vio_write(net->vio,pos,(size_t) (end-pos))) <= 0)
+ {
+ my_bool interrupted = vio_should_retry(net->vio);
+#if (!defined(__WIN32__) && !defined(__EMX__))
+ if ((interrupted || length==0) && !thr_alarm_in_use(alarmed))
+ {
+ if (!thr_alarm(&alarmed,NET_WRITE_TIMEOUT))
+ { /* Always true for client */
+ if (!vio_is_blocking(net->vio))
+ {
+ while (vio_blocking(net->vio, TRUE) < 0)
+ {
+ if (vio_should_retry(net->vio) && retry_count++ < RETRY_COUNT)
+ continue;
+#ifdef EXTRA_DEBUG
+ fprintf(stderr,
+ "%s: my_net_write: fcntl returned error %d, aborting thread\n",
+ my_progname,vio_errno(net->vio));
+#endif /* EXTRA_DEBUG */
+ net->error=1; /* Close socket */
+ goto end;
+ }
+ }
+ retry_count=0;
+ continue;
+ }
+ }
+ else
+#endif /* (!defined(__WIN32__) && !defined(__EMX__)) */
+ if (thr_alarm_in_use(alarmed) && !thr_got_alarm(alarmed) &&
+ interrupted)
+ {
+ if (retry_count++ < RETRY_COUNT)
+ continue;
+#ifdef EXTRA_DEBUG
+ fprintf(stderr, "%s: write looped, aborting thread\n",
+ my_progname);
+#endif /* EXTRA_DEBUG */
+ }
+#if defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER)
+ if (vio_errno(net->vio) == EINTR)
+ {
+ DBUG_PRINT("warning",("Interrupted write. Retrying..."));
+ continue;
+ }
+#endif /* defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER) */
+ net->error=1; /* Close socket */
+#ifdef MYSQL_SERVER
+ net->last_errno= (interrupted ? ER_NET_WRITE_INTERRUPTED :
+ ER_NET_ERROR_ON_WRITE);
+#endif /* MYSQL_SERVER */
+ break;
+ }
+ pos+=length;
+ thread_safe_add(bytes_sent,length,&LOCK_bytes_sent);
+ }
+#ifndef __WIN32__
+ end:
+#endif
+#ifdef HAVE_COMPRESS
+ if (net->compress)
+ my_free((char*) packet,MYF(0));
+#endif
+ if (thr_alarm_in_use(alarmed))
+ {
+ thr_end_alarm(&alarmed);
+ vio_blocking(net->vio, net_blocking);
+ }
+ net->reading_or_writing=0;
+ DBUG_RETURN(((int) (pos != end)));
+}
+
+
+/*****************************************************************************
+** Read something from server/clinet
+*****************************************************************************/
+
+
+static uint
+my_real_read(NET *net, ulong *complen)
+{
+ uchar *pos;
+ long length;
+ uint i,retry_count=0;
+ ulong len=packet_error;
+ thr_alarm_t alarmed;
+ my_bool net_blocking=vio_is_blocking(net->vio);
+ ulong remain= (net->compress ? NET_HEADER_SIZE+COMP_HEADER_SIZE :
+ NET_HEADER_SIZE);
+ *complen = 0;
+
+ net->reading_or_writing=1;
+ thr_alarm_init(&alarmed);
+#ifdef MYSQL_SERVER
+ if (net_blocking)
+ thr_alarm(&alarmed,net->timeout);
+#endif /* MYSQL_SERVER */
+
+ pos = net->buff + net->where_b; /* net->packet -4 */
+ for (i=0 ; i < 2 ; i++)
+ {
+ while (remain > 0)
+ {
+ /* First read is done with non blocking mode */
+ if ((int) (length=vio_read(net->vio,(char*) pos,remain)) <= 0L)
+ {
+ my_bool interrupted = vio_should_retry(net->vio);
+
+ DBUG_PRINT("info",("vio_read returned %d, errno: %d",
+ length, vio_errno(net->vio)));
+#if (!defined(__WIN32__) && !defined(__EMX__)) || !defined(MYSQL_SERVER)
+ /*
+ We got an error that there was no data on the socket. We now set up
+ an alarm to not 'read forever', change the socket to non blocking
+ mode and try again
+ */
+ if ((interrupted || length == 0) && !thr_alarm_in_use(alarmed))
+ {
+ if (!thr_alarm(&alarmed,net->timeout)) /* Don't wait too long */
+ {
+ if (!vio_is_blocking(net->vio))
+ {
+ while (vio_blocking(net->vio,TRUE) < 0)
+ {
+ if (vio_should_retry(net->vio) &&
+ retry_count++ < RETRY_COUNT)
+ continue;
+ DBUG_PRINT("error",
+ ("fcntl returned error %d, aborting thread",
+ vio_errno(net->vio)));
+#ifdef EXTRA_DEBUG
+ fprintf(stderr,
+ "%s: read: fcntl returned error %d, aborting thread\n",
+ my_progname,vio_errno(net->vio));
+#endif /* EXTRA_DEBUG */
+ len= packet_error;
+ net->error=1; /* Close socket */
+#ifdef MYSQL_SERVER
+ net->last_errno=ER_NET_FCNTL_ERROR;
+#endif
+ goto end;
+ }
+ }
+ retry_count=0;
+ continue;
+ }
+ }
+#endif /* (!defined(__WIN32__) && !defined(__EMX__)) || !defined(MYSQL_SERVER) */
+ if (thr_alarm_in_use(alarmed) && !thr_got_alarm(alarmed) &&
+ interrupted)
+ { /* Probably in MIT threads */
+ if (retry_count++ < RETRY_COUNT)
+ continue;
+#ifdef EXTRA_DEBUG
+ fprintf(stderr, "%s: read looped with error %d, aborting thread\n",
+ my_progname,vio_errno(net->vio));
+#endif /* EXTRA_DEBUG */
+ }
+#if defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER)
+ if (vio_should_retry(net->vio))
+ {
+ DBUG_PRINT("warning",("Interrupted read. Retrying..."));
+ continue;
+ }
+#endif
+ DBUG_PRINT("error",("Couldn't read packet: remain: %d errno: %d length: %d alarmed: %d", remain,vio_errno(net->vio),length,alarmed));
+ len= packet_error;
+ net->error=1; /* Close socket */
+#ifdef MYSQL_SERVER
+ net->last_errno= (interrupted ? ER_NET_READ_INTERRUPTED :
+ ER_NET_READ_ERROR);
+#endif
+ goto end;
+ }
+ remain -= (ulong) length;
+ pos+= (ulong) length;
+ thread_safe_add(bytes_received,(ulong) length,&LOCK_bytes_received);
+ }
+ if (i == 0)
+ { /* First parts is packet length */
+ ulong helping;
+ if (net->buff[net->where_b + 3] != (uchar) net->pkt_nr)
+ {
+ if (net->buff[net->where_b] != (uchar) 255)
+ {
+ DBUG_PRINT("error",
+ ("Packets out of order (Found: %d, expected %d)",
+ (int) net->buff[net->where_b + 3],
+ (uint) (uchar) net->pkt_nr));
+#ifdef EXTRA_DEBUG
+ fprintf(stderr,"Packets out of order (Found: %d, expected %d)\n",
+ (int) net->buff[net->where_b + 3],
+ (uint) (uchar) net->pkt_nr);
+#endif
+ }
+ len= packet_error;
+#ifdef MYSQL_SERVER
+ net->last_errno=ER_NET_PACKETS_OUT_OF_ORDER;
+#endif
+ goto end;
+ }
+ net->pkt_nr++;
+#ifdef HAVE_COMPRESS
+ if (net->compress)
+ {
+ /* complen is > 0 if package is really compressed */
+ *complen=uint3korr(&(net->buff[net->where_b + NET_HEADER_SIZE]));
+ }
+#endif
+
+ len=uint3korr(net->buff+net->where_b);
+ helping = max(len,*complen) + net->where_b;
+ /* The necessary size of net->buff */
+ if (helping >= net->max_packet)
+ {
+ /* We must allocate one extra byte for the end null */
+ if (net_realloc(net,helping+1))
+ {
+ len= packet_error; /* Return error */
+ goto end;
+ }
+ }
+ pos=net->buff + net->where_b;
+ remain = len;
+ }
+ }
+
+end:
+ if (thr_alarm_in_use(alarmed))
+ {
+ thr_end_alarm(&alarmed);
+ vio_blocking(net->vio, net_blocking);
+ }
+ net->reading_or_writing=0;
+ return(len);
+}
+
+
+uint
+my_net_read(NET *net)
+{
+ ulong len,complen;
+
+#ifdef HAVE_COMPRESS
+ if (!net->compress)
+ {
+#endif
+ len = my_real_read (net,&complen);
+ net->read_pos = net->buff + net->where_b;
+ if (len != packet_error)
+ net->read_pos[len]=0; /* Safeguard for mysql_use_result */
+ return len;
+#ifdef HAVE_COMPRESS
+ }
+ if (net->remain_in_buf)
+ net->buff[net->buf_length - net->remain_in_buf]=net->save_char;
+ for (;;)
+ {
+ if (net->remain_in_buf)
+ {
+ uchar *pos = net->buff + net->buf_length - net->remain_in_buf;
+ if (net->remain_in_buf >= 4)
+ {
+ net->length = uint3korr(pos);
+ if (net->length <= net->remain_in_buf - 4)
+ {
+ /* We have a full packet */
+ len=net->length;
+ net->remain_in_buf -= net->length + 4;
+ net->read_pos=pos + 4;
+ break; /* We have a full packet */
+ }
+ }
+ /* Move data down to read next data packet after current one */
+ if (net->buf_length != net->remain_in_buf)
+ {
+ memmove(net->buff,pos,net->remain_in_buf);
+ net->buf_length=net->remain_in_buf;
+ }
+ net->where_b=net->buf_length;
+ }
+ else
+ {
+ net->where_b=0;
+ net->buf_length=0;
+ }
+
+ if ((len = my_real_read(net,&complen)) == packet_error)
+ break;
+ if (my_uncompress((byte*) net->buff + net->where_b, &len, &complen))
+ {
+ len= packet_error;
+ net->error=1; /* caller will close socket */
+#ifdef MYSQL_SERVER
+ net->last_errno=ER_NET_UNCOMPRESS_ERROR;
+#endif
+ break;
+ }
+ net->buf_length+=len;
+ net->remain_in_buf+=len;
+ }
+ if (len != packet_error)
+ {
+ net->save_char= net->read_pos[len]; /* Must be saved */
+ net->read_pos[len]=0; /* Safeguard for mysql_use_result */
+ }
+ return len;
+#endif
+}