"Fossies" - the Fresh Open Source Software Archive

Member "mariadb-connector-c-3.0.9-src/libmariadb/ma_net.c" (8 Feb 2019, 15901 Bytes) of package /linux/misc/mariadb-connector-c-3.0.9-src.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the last Fossies "Diffs" side-by-side code changes report for "ma_net.c": 3.0.5-src_vs_3.0.6-src.

    1 /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
    2    2012-2016 SkySQL AB, MariaDB Corporation AB
    3    This library is free software; you can redistribute it and/or
    4    modify it under the terms of the GNU Library General Public
    5    License as published by the Free Software Foundation; either
    6    version 2 of the License, or (at your option) any later version.
    7 
    8    This library is distributed in the hope that it will be useful,
    9    but WITHOUT ANY WARRANTY; without even the implied warranty of
   10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   11    Library General Public License for more details.
   12 
   13    You should have received a copy of the GNU Library General Public
   14    License along with this library; if not, write to the Free
   15    Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
   16    MA 02111-1301, USA */
   17 
   18 /* Write and read of logical packets to/from socket
   19  ** Writes are cached into net_buffer_length big packets.
   20  ** Read packets are reallocated dynamically when reading big packets.
   21  ** Each logical packet has the following pre-info:
   22  ** 3 byte length & 1 byte package-number.
   23  */
   24 
   25 
   26 #include <ma_global.h>
   27 #include <mysql.h>
   28 #include <ma_pvio.h>
   29 #include <ma_sys.h>
   30 #include <ma_string.h>
   31 #include "mysql.h"
   32 #include "ma_server_error.h"
   33 #include <signal.h>
   34 #include <errno.h>
   35 #include <sys/types.h>
   36 #include <ma_pvio.h>
   37 #include <ma_common.h>
   38 #ifndef _WIN32
   39 #include <poll.h>
   40 #endif
   41 
   42 #define MAX_PACKET_LENGTH (256L*256L*256L-1)
   43 
   44 /* net_buffer_length and max_allowed_packet are defined in mysql.h
   45    See bug conc-57
   46  */
   47 #undef net_buffer_length
   48 
   49 #undef max_allowed_packet
   50 ulong max_allowed_packet=1024L * 1024L * 1024L;
   51 ulong net_read_timeout=  NET_READ_TIMEOUT;
   52 ulong net_write_timeout= NET_WRITE_TIMEOUT;
   53 ulong net_buffer_length= 8192;  /* Default length. Enlarged if necessary */
   54 
   55 #if !defined(_WIN32) && !defined(MSDOS)
   56 #include <sys/socket.h>
   57 #else
   58 #undef MYSQL_SERVER         /* Win32 can't handle interrupts */
   59 #endif
   60 #if !defined(MSDOS) && !defined(_WIN32) && !defined(HAVE_BROKEN_NETINET_INCLUDES) && !defined(__BEOS__)
   61 #include <netinet/in_systm.h>
   62 #include <netinet/in.h>
   63 #include <netinet/ip.h>
   64 #if !defined(alpha_linux_port)
   65 #include <netinet/tcp.h>
   66 #endif
   67 #endif
   68 
   69 
   70 /*
   71  ** Give error if a too big packet is found
   72  ** The server can change this with the -O switch, but because the client
   73  ** can't normally do this the client should have a bigger max-buffer.
   74  */
   75 
   76 static int ma_net_write_buff(NET *net,const char *packet, size_t len);
   77 
   78 
   79 /* Init with packet info */
   80 
   81 int ma_net_init(NET *net, MARIADB_PVIO* pvio)
   82 {
   83   if (!(net->buff=(uchar*) malloc(net_buffer_length)))
   84     return 1;
   85   if (!net->extension)
   86     return 1;
   87 
   88   memset(net->buff, 0, net_buffer_length);
   89 
   90   max_allowed_packet= net->max_packet_size= MAX(net_buffer_length, max_allowed_packet);
   91   net->buff_end=net->buff+(net->max_packet=net_buffer_length);
   92   net->pvio = pvio;
   93   net->error=0; net->return_status=0;
   94   net->read_timeout=(uint) net_read_timeout;        /* Timeout for read */
   95   net->compress_pkt_nr= net->pkt_nr= 0;
   96   net->write_pos=net->read_pos = net->buff;
   97   net->last_error[0]= net->sqlstate[0] =0;
   98 
   99   net->compress=0; net->reading_or_writing=0;
  100   net->where_b = net->remain_in_buf=0;
  101   net->last_errno=0;
  102 
  103   if (pvio != 0)                    /* If real connection */
  104   {
  105     ma_pvio_get_handle(pvio, &net->fd);
  106     ma_pvio_blocking(pvio, 1, 0);
  107     ma_pvio_fast_send(pvio);
  108   }
  109   return 0;
  110 }
  111 
  112 void ma_net_end(NET *net)
  113 {
  114   free(net->buff);
  115   net->buff=0;
  116 }
  117 
  118 /* Realloc the packet buffer */
  119 
  120 static my_bool net_realloc(NET *net, size_t length)
  121 {
  122   uchar *buff;
  123   size_t pkt_length;
  124 
  125   if (length >= net->max_packet_size)
  126   {
  127     net->error=1;
  128     net->last_errno=ER_NET_PACKET_TOO_LARGE;
  129     return(1);
  130   }
  131   pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1);
  132   /* reallocate buffer:
  133      size= pkt_length + NET_HEADER_SIZE + COMP_HEADER_SIZE */
  134   if (!(buff=(uchar*) realloc(net->buff, 
  135           pkt_length + NET_HEADER_SIZE + COMP_HEADER_SIZE)))
  136   {
  137     net->error=1;
  138     return(1);
  139   }
  140   net->buff=net->write_pos=buff;
  141   net->buff_end=buff+(net->max_packet=(unsigned long)pkt_length);
  142   return(0);
  143 }
  144 
  145 /* Remove unwanted characters from connection */
  146 void ma_net_clear(NET *net)
  147 {
  148   if (net->extension->multi_status > COM_MULTI_OFF)
  149     return;
  150   net->compress_pkt_nr= net->pkt_nr=0;              /* Ready for new command */
  151   net->write_pos=net->buff;
  152   return;
  153 }
  154 
  155 /* Flush write_buffer if not empty. */
  156 int ma_net_flush(NET *net)
  157 {
  158   int error=0;
  159 
  160   /* don't flush if com_multi is in progress */
  161   if (net->extension->multi_status > COM_MULTI_OFF)
  162     return 0;
  163 
  164   if (net->buff != net->write_pos)
  165   {
  166     error=ma_net_real_write(net,(char*) net->buff,
  167         (size_t) (net->write_pos - net->buff));
  168     net->write_pos=net->buff;
  169   }
  170   if (net->compress)
  171     net->pkt_nr= net->compress_pkt_nr;
  172   return(error);
  173 }
  174 
  175 /*****************************************************************************
  176  ** Write something to server/client buffer
  177  *****************************************************************************/
  178 
  179 /*
  180  ** Write a logical packet with packet header
  181  ** Format: Packet length (3 bytes), packet number(1 byte)
  182  **         When compression is used a 3 byte compression length is added
  183  ** NOTE: If compression is used the original package is destroyed!
  184  */
  185 
  186 int ma_net_write(NET *net, const uchar *packet, size_t len)
  187 {
  188   uchar buff[NET_HEADER_SIZE];
  189   while (len >= MAX_PACKET_LENGTH)
  190   {
  191     const ulong max_len= MAX_PACKET_LENGTH;
  192     int3store(buff,max_len);
  193     buff[3]= (uchar)net->pkt_nr++;
  194     if (ma_net_write_buff(net,(char*) buff,NET_HEADER_SIZE) ||
  195         ma_net_write_buff(net, (char *)packet, max_len))
  196       return 1;
  197     packet+= max_len;
  198     len-= max_len;
  199   }
  200   /* write last remaining packet, size can be zero */
  201   int3store(buff, len);
  202   buff[3]= (uchar)net->pkt_nr++;
  203   if (ma_net_write_buff(net,(char*) buff,NET_HEADER_SIZE) ||
  204       ma_net_write_buff(net, (char *)packet, len))
  205     return 1;
  206   return 0;
  207 }
  208 
  209 int ma_net_write_command(NET *net, uchar command,
  210     const char *packet, size_t len,
  211     my_bool disable_flush)
  212 {
  213   uchar buff[NET_HEADER_SIZE+1];
  214   size_t buff_size= NET_HEADER_SIZE + 1;
  215   size_t length= 1 + len; /* 1 extra byte for command */
  216   int rc;
  217 
  218   buff[NET_HEADER_SIZE]= 0;
  219   buff[4]=command;
  220 
  221   if (length >= MAX_PACKET_LENGTH)
  222   {
  223     len= MAX_PACKET_LENGTH - 1;
  224     do
  225     {
  226       int3store(buff, MAX_PACKET_LENGTH);
  227       buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
  228 
  229       if (ma_net_write_buff(net, (char *)buff, buff_size) ||
  230           ma_net_write_buff(net, packet, len))
  231         return(1);
  232       packet+= len;
  233       length-= MAX_PACKET_LENGTH;
  234       len= MAX_PACKET_LENGTH;
  235       buff_size= NET_HEADER_SIZE; /* don't send command for further packets */
  236     } while (length >= MAX_PACKET_LENGTH);
  237     len= length;
  238   }
  239   int3store(buff,length);
  240   buff[3]= (net->compress) ? 0 :(uchar) (net->pkt_nr++);
  241   rc= test (ma_net_write_buff(net,(char *)buff, buff_size) || 
  242       ma_net_write_buff(net,packet,len));
  243   if (!rc && !disable_flush)
  244     return test(ma_net_flush(net)); 
  245   return rc;
  246 }
  247 
  248 
  249 static int ma_net_write_buff(NET *net,const char *packet, size_t len)
  250 {
  251   size_t left_length;
  252 
  253   if (net->max_packet > MAX_PACKET_LENGTH &&
  254       net->compress)
  255     left_length= (size_t)(MAX_PACKET_LENGTH - (net->write_pos - net->buff));
  256   else
  257     left_length=(size_t) (net->buff_end - net->write_pos);
  258 
  259   if (len > left_length)
  260   {
  261     if (net->write_pos != net->buff)
  262     {
  263       memcpy((char*) net->write_pos,packet,left_length);
  264       if (ma_net_real_write(net,(char*) net->buff,
  265             (size_t)(net->write_pos - net->buff) + left_length))
  266         return 1;
  267       packet+=left_length;
  268       len-=left_length;
  269       net->write_pos= net->buff;
  270     }
  271     if (net->compress)
  272     {
  273       /* uncompressed length is stored in 3 bytes,so
  274          packet can't be > 0xFFFFFF */
  275       left_length= MAX_PACKET_LENGTH;
  276       while (len > left_length)
  277       {
  278         if (ma_net_real_write(net, packet, left_length))
  279           return 1;
  280         packet+= left_length;
  281         len-= left_length;
  282       }
  283     }
  284     if (len > net->max_packet)
  285       return(test(ma_net_real_write(net, packet, len)));
  286   }
  287   memcpy((char*) net->write_pos,packet,len);
  288   net->write_pos+=len;
  289   return 0;
  290 }
  291 
  292 unsigned char *mysql_net_store_length(unsigned char *packet, size_t length);
  293 
  294 /*  Read and write using timeouts */
  295 
  296 int ma_net_real_write(NET *net, const char *packet, size_t len)
  297 {
  298   ssize_t length;
  299   char *pos,*end;
  300 
  301   if (net->error == 2)
  302     return(-1);             /* socket can't be used */
  303 
  304   net->reading_or_writing=2;
  305 #ifdef HAVE_COMPRESS
  306   if (net->compress)
  307   {
  308     size_t complen;
  309     uchar *b;
  310     uint header_length=NET_HEADER_SIZE+COMP_HEADER_SIZE;
  311     if (!(b=(uchar*) malloc(len + NET_HEADER_SIZE + COMP_HEADER_SIZE + 1)))
  312     {
  313       net->last_errno=ER_OUT_OF_RESOURCES;
  314       net->error=2;
  315       net->reading_or_writing=0;
  316       return(1);
  317     }
  318     memcpy(b+header_length,packet,len);
  319 
  320     if (_mariadb_compress((unsigned char*) b+header_length,&len,&complen))
  321     {
  322       complen=0;
  323     }
  324     int3store(&b[NET_HEADER_SIZE],complen);
  325     int3store(b,len);
  326     b[3]=(uchar) (net->compress_pkt_nr++);
  327     len+= header_length;
  328     packet= (char*) b;
  329   }
  330 #endif /* HAVE_COMPRESS */
  331 
  332   pos=(char*) packet; end=pos+len;
  333   while (pos != end)
  334   {
  335     if ((length=ma_pvio_write(net->pvio,(uchar *)pos,(size_t) (end-pos))) <= 0)
  336     {
  337       net->error=2;             /* Close socket */
  338       net->last_errno= ER_NET_ERROR_ON_WRITE;
  339       net->reading_or_writing=0;
  340       return(1);
  341     }
  342     pos+=length;
  343   }
  344 #ifdef HAVE_COMPRESS
  345   if (net->compress)
  346     free((char*) packet);
  347 #endif
  348   net->reading_or_writing=0;
  349   return(((int) (pos != end)));
  350 }
  351 
  352 /*****************************************************************************
  353  ** Read something from server/clinet
  354  *****************************************************************************/
  355 static ulong ma_real_read(NET *net, size_t *complen)
  356 {
  357   uchar *pos;
  358   ssize_t length;
  359   uint i;
  360   ulong len=packet_error;
  361   size_t remain= (net->compress ? NET_HEADER_SIZE+COMP_HEADER_SIZE :
  362       NET_HEADER_SIZE);
  363   *complen = 0;
  364 
  365   net->reading_or_writing=1;
  366 
  367   pos = net->buff + net->where_b;       /* net->packet -4 */
  368   for (i=0 ; i < 2 ; i++)
  369   {
  370     while (remain > 0)
  371     {
  372       /* First read is done with non blocking mode */
  373       if ((length=ma_pvio_cache_read(net->pvio, pos,remain)) <= 0L)
  374       {
  375         len= packet_error;
  376         net->error=2;               /* Close socket */
  377         goto end;
  378       }
  379       remain -= (ulong) length;
  380       pos+= (ulong) length;
  381     }
  382 
  383     if (i == 0)
  384     {                   /* First parts is packet length */
  385       ulong helping;
  386       net->pkt_nr= net->buff[net->where_b + 3];
  387       net->compress_pkt_nr= ++net->pkt_nr;
  388 #ifdef HAVE_COMPRESS
  389       if (net->compress)
  390       {
  391         /* complen is > 0 if package is really compressed */
  392         *complen=uint3korr(&(net->buff[net->where_b + NET_HEADER_SIZE]));
  393       }
  394 #endif
  395 
  396       len=uint3korr(net->buff+net->where_b);
  397       if (!len)
  398         goto end;
  399       helping = max(len,(ulong)*complen) + net->where_b;
  400       /* The necessary size of net->buff */
  401       if (helping >= net->max_packet)
  402       {
  403         if (net_realloc(net, helping))
  404         {
  405           len= packet_error;        /* Return error */
  406           goto end;
  407         }
  408       }
  409       pos=net->buff + net->where_b;
  410       remain = len;
  411     }
  412   }
  413 
  414 end:
  415   net->reading_or_writing=0;
  416   return(len);
  417 }
  418 
  419 ulong ma_net_read(NET *net)
  420 {
  421   size_t len,complen;
  422 
  423 #ifdef HAVE_COMPRESS
  424   if (!net->compress)
  425   {
  426 #endif
  427     len = ma_real_read (net,(size_t *)&complen);
  428     if (len == MAX_PACKET_LENGTH)
  429     {
  430       /* multi packet read */
  431       size_t length= 0;
  432       ulong last_pos= net->where_b;
  433 
  434       do 
  435       {
  436         length+= len;
  437         net->where_b+= (unsigned long)len;
  438         len= ma_real_read(net, &complen);
  439       } while (len == MAX_PACKET_LENGTH);
  440       net->where_b= last_pos;
  441       if (len != packet_error)
  442         len+= length;
  443     }
  444     net->read_pos = net->buff + net->where_b;
  445     if (len != packet_error)
  446       net->read_pos[len]=0;     /* Safeguard for mysql_use_result */
  447     return (ulong)len;
  448 #ifdef HAVE_COMPRESS
  449   }
  450   else
  451   {
  452     /* 
  453        compressed protocol:
  454 
  455        --------------------------------------
  456        packet_length       3
  457        sequence_id         1
  458        uncompressed_length 3
  459        --------------------------------------
  460        compressed data     packet_length - 7
  461        --------------------------------------
  462 
  463        Another packet will follow if:
  464        packet_length == MAX_PACKET_LENGTH
  465 
  466        Last package will be identified by
  467        - packet_length is zero (special case)
  468        - packet_length < MAX_PACKET_LENGTH
  469      */
  470 
  471     size_t packet_length,
  472            buffer_length;
  473     size_t current= 0, start= 0;
  474     my_bool is_multi_packet= 0;
  475 
  476     /* check if buffer is empty */
  477     if (!net->remain_in_buf)
  478     {
  479       buffer_length= 0;
  480     }
  481     else
  482     {
  483       /* save position and restore \0 character */
  484       buffer_length= net->buf_length;
  485       current= net->buf_length - net->remain_in_buf;
  486       start= current;
  487       net->buff[net->buf_length - net->remain_in_buf]=net->save_char;
  488     }
  489     for (;;)
  490     {
  491       if (buffer_length - current >= 4)
  492       {
  493         uchar *pos= net->buff + current;
  494         packet_length= uint3korr(pos);
  495 
  496         /* check if we have last package (special case: zero length) */
  497         if (!packet_length)
  498         {
  499           current+= 4; /* length + sequence_id,
  500                           no more data will follow */
  501           break;
  502         }
  503         if (packet_length + 4 <= buffer_length - current)
  504         {
  505           if (!is_multi_packet)
  506           {
  507             current= current + packet_length + 4;
  508           }
  509           else
  510           {
  511             /* remove packet_header */
  512             memmove(net->buff + current, 
  513                 net->buff + current + 4,
  514                 buffer_length - current);
  515             buffer_length-= 4;
  516             current+= packet_length;
  517           }
  518           /* do we have last packet ? */
  519           if (packet_length != MAX_PACKET_LENGTH)
  520           {
  521             is_multi_packet= 0;
  522             break;
  523           }
  524           else
  525             is_multi_packet= 1;
  526           if (start)
  527           {
  528             memmove(net->buff, net->buff + start,
  529                 buffer_length - start);
  530             /* decrease buflen*/
  531             buffer_length-= start;
  532             start= 0;
  533           }
  534           continue;
  535         }
  536       }
  537       if (start)
  538       { 
  539         memmove(net->buff, net->buff + start, buffer_length - start);
  540         /* decrease buflen and current */
  541         current -= start;
  542         buffer_length-= start;
  543         start= 0;
  544       }
  545 
  546       net->where_b=(unsigned long)buffer_length;
  547 
  548       if ((packet_length = ma_real_read(net,(size_t *)&complen)) == packet_error)
  549         return packet_error;
  550       if (_mariadb_uncompress((unsigned char*) net->buff + net->where_b, &packet_length, &complen))
  551       {
  552         net->error=2;           /* caller will close socket */
  553         net->last_errno=ER_NET_UNCOMPRESS_ERROR;
  554         break;
  555         return packet_error;
  556       }
  557       buffer_length+= complen;
  558     }
  559     /* set values */
  560     net->buf_length= (unsigned long)buffer_length;
  561     net->remain_in_buf= (unsigned long)(buffer_length - current);
  562     net->read_pos= net->buff + start + 4;
  563     len= current - start - 4;
  564     if (is_multi_packet)
  565       len-= 4;
  566     net->save_char= net->read_pos[len]; /* Must be saved */
  567     net->read_pos[len]=0;       /* Safeguard for mysql_use_result */
  568   }
  569 #endif
  570   return (ulong)len;
  571 }
  572 
  573 int net_add_multi_command(NET *net, uchar command, const uchar *packet,
  574     size_t length)
  575 {
  576   if (net->extension->multi_status == COM_MULTI_OFF)
  577   {
  578     return(1);
  579   }
  580   /* don't increase packet number */
  581   net->compress_pkt_nr= net->pkt_nr= 0;
  582   return ma_net_write_command(net, command, (const char *)packet, length, 1);
  583 }
  584