1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
|
MySQL Client/Server Protocol Documentation
Introduction
------------
This paper has the objective of presenting a through description
of the client/server protocol that is embodied in MySQL. Particularly,
this paper aims to document and describe:
- manner in which MySQL server detects client connection requests and
creates connection
- manner in which MySQL client C API call connects to server - the
entire protocol of sending/receiving data by MySQL server and C API
code
- manner in which queries are sent by client C API calls to server
- manner in which query results are sent by server
- manner in which query results are resolved by server
- sending and receiving of error messages
This paper does not have the goal or describing nor documenting other
related MySQL issues, like usage of thread libraries, MySQL standard
library set, MySQL strings library and other MySQL specific libraries,
type definitions and utilities.
Issues that are covered by this paper are contained in the following
source code files:
- libmysql/net.c and sql/net_serv.cc, the two being identical
- client/libmysql.c (not entire file is covered)
- include/mysql_com.h
- include/mysql.h
- sql/mysqld.cc (not entire file is covered)
- sql/net_pkg.cc
- sql/sql_base.cc (not entire file is covered)
- sql/sql_select.cc (not entire file is covered)
- sql/sql_parse.cc (not entire file is covered)
Note: libmysql/net.c was client/net.c prior to MySQL 3.23.11.
sql/net_serv.cc was sql/net_serv.c prior to MySQL 3.23.16.
Beside this introduction this paper presents basic definitions,
constants, structures and global variables, all related functions in
server and in C API. Textual description of the entire protocol
functioning is described in the last chapter of this paper.
Constants, structures and global variables
------------------------------------------
This chapter will describe all constants, structures and
global variables relevant to client/server protocol.
Constants
They are important as they contain default values, the ones
that are valid if options are not set in any other way. Beside that
MySQL source code does not contain a single non-defined constant in
its code. This description of constants does not include
configuration and conditional compilation #defines.
NAME_LEN - field and table name length, current value 64
HOSTNAME_LENGTH - length of the hostname, current value 64
USERNAME_LENGTH - username length, current value 16
MYSQL_PORT - default TCP/IP port number, current value 3306
MYSQL_UNIX_ADDR - full path of the default Unix socket file, current value
"/tmp/mysql.sock"
MYSQL_NAMEDPIPE - full path of the default NT pipe file, current value
"MySQL"
MYSQL_SERVICENAME - name of the MySQL Service on NT, current value "MySQL"
NET_HEADER_SIZE - size of the network header, when no
compression is used, current value 4
COMP_HEADER_SIZE - additional size of network header when
compression is used, current value 3
What follows are set of constants, defined in source only, which
define capabilities of the client built with that version of C
API. Simply, when some new feature is added in client, that client
feature is defined, so that server can detect what capabilities a
client program has.
CLIENT_LONG_PASSWORD - client supports new more secure passwords
CLIENT_LONG_FLAG - client uses longer flags
CLIENT_CONNECT_WITH_DB - client can specify db on connect
CLIENT_COMPRESS - client can use compression protocol
CLIENT_ODBC - ODBC client
CLIENT_LOCAL_FILES - client can use LOAD DATA INFILE LOCAL
CLIENT_IGNORE_SPACE - client can ignore spaces before '('
CLIENT_CHANGE_USER - client supports the mysql_change_user()
What follows are other constants, pertaining to timeouts and sizes
MYSQL_ERRMSG_SIZE - maximum size of error message string, current value 200
NET_READ_TIMEOUT - read timeout, current value 30 seconds
NET_WRITE_TIMEOUT - write timeout, current value 60 seconds
NET_WAIT_TIMEOUT - wait for new query timeout, current value 8*60*60
seconds, that is, 8 hours
packet_error - value returned in case of socket errors, current
value -1
TES_BLOCKING - used in debug mode for setting up blocking testing
RETRY COUNT - number of times network read and write will be
retried, current value 1
There are also error messages for last_errno, which depict system
errors, and are used on the server only.
ER_NET_PACKAGE_TOO_LARGE - packet is larger than max_allowed_packet
ER_OUT_OF_RESOURCES - practically no more memory
ER_NET_ERROR_ON_WRITE - error in writing to NT Named Pipe
ER_NET_WRITE_INTERRUPTED - some signal or interrupt happened
during write
ER_NET_READ_ERROR_FROM_PIPE - error in reading from NT Named Pipe
ER_NET_FCNTL_ERROR - error in trying to set fcntl on socket
descriptor
ER_NET_PACKETS_OUT_OF_ORDER - packet numbers on client and
server side differ
ER_NET_UNCOMPRESS_ERROR - error in uncompress of compressed packet
Structs and enums
struct NET
This is MySQL's network handle structure, used in all client/server
read/write functions. On the server, it is initialized and preserved
in each thread. On the client, it is a part of the MYSQL struct,
which is the MySQL handle used in all C API functions. This structure
uniquely identifies a connection, either on the server or client
side. It consists of the following fields:
Vio* vio - explained above
HANDLE hPipe - Handle for NT Named Pipe file
my_socket fd - file descriptor used for both TCP/IP socket and
Unix socket file
int fcntl - contains info on fcntl options used on fd. Mostly
used for saving info if blocking is used or not
unsigned char *buff - network buffer used for storing data for
reading from/writing to socket
unsigned char,*buff_end - points to the end of buff
unsigned char *write_pos - present writing position in buff
unsigned char *read_pos - present reading position in buff. This
pointer is used for reading data after
calling my_net_read function and function
that are just its wrappers
char last_error[MYSQL_ERRMSG_SIZE] - holds last error message
unsigned int last_errno - holds last error code of the network
protocol. Its possible values are listed
in above constants. It is used only on
the server side
unsigned int max_packet - holds current value of buff size
unsigned int timeout - stores read timeout value for that connection
unsigned int pkt_nr - stores the value of the current packet number in
a batch of packets. Used primarily for
detection of protocol errors resulting in a
mismatch
my_bool error - holds either 1 or 0 depending on the error condition
my_bool return_errno - if its value != 0 then there is an error in
protocol mismatch between client and server
my_bool compress - if true compression is used in the protocol
unsigned long remain_in_buf - used only in reading compressed packets.
Explained in my_net_read
unsigned long length - used only for storing the length of the read
packet. Explained in my_net_read
unsigned long buf_length - used only in reading compressed packets.
Explained in my_net_read
unsigned long where_b - used only in reading compressed packets.
Explained in my_net_read
short int more - used for reporting in mysql_list_processes
char save_char - used in reading compressed packets for saving chars
in order to make zero-delimited strings. Explained
in my_net_read
A few typedefs will be defined for easier understanding of the text that
follows.
typedef char **MYSQL_ROW - data containing one row of values
typedef unsigned int MYSQL_FIELD_OFFSET - offset in bytes of the current field
typedef MYSQL_ROWS *MYSQL_ROW_OFFSET - offset in bytes of the current row
struct MYSQL_FIELD - contains all info on the attributes of a
specific column in a result set, plus info on lengths of the column in
a result set. This struct is tagged as st_mysql_field. This structure
consists of the following fields:
char *name - name of column
char *table - table of column if column was a field and not
an expression or constant
char *def - default value (set by mysql_list_fields)
enum enum_field_types type - see above
unsigned int length - width of column in the current row
unsigned int max_length - maximum width of that column in entire
result set
unsigned int flags - corresponding to Extra in DESCRIBE
unsigned int decimals - number of decimals in field
struct MYSQL_ROWS - a node for each row in the single linked
list forming entire result set. This struct is tagged as
st_mysql_rows, and has two fields:
struct st_mysql_rows *next - pointer to the next one
MYSQL_ROW data - see above
struct MYSQL_DATA - contains all rows from result set. It is
tagged as st_mysql_data and has following fields:
my_ulonglong rows - how many rows
unsigned int fields - how many columns
MYSQL_ROWS *data - see above. This is the first node of the linked list
MEM_ROOT alloc - MEM_ROOT is MySQL memory allocation structure, and
this field is used to store all fields and rows.
struct st_mysql_options - holds various client options, and
contains following fields:
unsigned int connect_timeout - time in seconds for connection
unsigned int client_flag - used to hold client capabilities
my_bool compress - boolean for compression
my_bool named_pipe - is Named Pipe used? (on NT)
unsigned int port - what TCP port is used
char *host - host to connect to
char *init_command - command to be executed upon connection
char *user - account name on MySQL server
char *password - password for the above
char *unix_socket - full path for Unix socket file
char *db - default database
char *my_cnf_file - optional configuration file
char *my_cnf_group - optional header for options
struct MYSQL - MySQL client's handle. Required for any
operation issued from client to server. Tagged as st_mysql and having
following fields:
NET net - see above
char *host - host on which MySQL server is running
char *user - MySQL username
char *passwd - password for above
char *unix_socket- full path of Unix socket file
char *server_version - version of the server
char *host_info - contains info on how has connection been
established, TCP port, socket or Named Pipe
char *info - used to store information on the query results,
like number of rows affected etc.
char *db - current database
unsigned int port - TCP port in use
unsigned int client_flag - client capabilities
unsigned int server_capabilities - server capabilities
unsigned int protocol_version - version of the protocol
unsigned int field_count - used for storing number of fields
immediately upon execution of a query,
but before fetching rows
unsigned long thread_id - server thread to which this connection
is attached
my_ulonglong affected_rows - used for storing number of rows
immediately upon execution of a query,
but before fetching rows
my_ulonglong insert_id - fetching LAST_INSERT_ID() through client C API
my_ulonglong extra_info - used by mysqlshow
unsigned long packet_length - saving size of the first packet upon
execution of a query
enum mysql_status status - see above
MYSQL_FIELD *fields - see above
MEM_ROOT field_alloc - memory used for storing previous field (fields)
my_bool free_me - boolean that flags if MYSQL was allocated in mysql_init
my_bool reconnect - used to automatically reconnect
struct st_mysql_options options - see above
char scramble_buff[9] - key for scrambling password before sending it
to server
struct MYSQL_RES - tagged as st_mysql_res and used to store
entire result set from a single query. Contains following fields:
my_ulonglong row_count - number of rows
unsigned int field_count - number of columns
unsigned int current_field - cursor for fetching fields
MYSQL_FIELD *fields - see above
MYSQL_DATA *data - see above, and used in buffered reads, that is,
mysql_store_result only
MYSQL_ROWS *data_cursor - pointing to the field of above "data"
MEM_ROOT field_alloc - memory allocation for above "fields"
MYSQL_ROW row - used for storing row by row in unbuffered reads,
that is, in mysql_use_result
MYSQL_ROW current_row - cursor to the current row for buffered reads
unsigned long *lengths - column lengths of current row
MYSQL *handle - see above, used in unbuffered reads, that is, in
mysql_use_result
my_bool eof - used by mysql_fetch_row as a marker for end of data
Global variables
unsigned long max_allowed_packet - maximum allowable value of network
buffer. Default value - 1MB
unsigned long net_buffer_length - default, starting value of network
buffer - 8KB
unsigned long bytes_sent - total number of bytes written since startup
of the server
unsigned long bytes_received - total number of bytes read since startup
of the server
Synopsis of the basic client/server protocol
--------------------------------------------
Purpose of this chapter is to provide a complete picture of
the basic client/server protocol implemented in MySQL. It was felt
it is necessary after writing descriptions for all of the functions
involved in basic protocol. There are at present 11 functions
involved, with several structures, many constants etc, which are all
described in detail. But as a forest could not be seen from the trees,
so the concept of the protocol could not be deciphered easily from a
thorough documentation of minutiae.
Although the concept of the protocol was not changed with the
introduction of vio system, embodied in violate.cc source file and VIO
system, the introduction of these has changed the code substantially. Before
VIO was introduced, functions for reading from/writing to network
connection had to deal with various network standards. So, these functions
depended on whether TCP port or Unix socket file or NT Named Pipe file is
used. This is all changed now and single vio_ functions are called, while
all this diversity is covered by vio_ functions.
In MySQL a specific buffered network input/output transport model
has been implemented. Although each operating system may have its
own buffering for network connections, MySQL has added its own
buffering model. This same for each of the three transport protocol
types that are used in MySQL client/server communications, which
are TCP/IP sockets (on all systems), Unix socket files on Unix and
Unix-like operating systems and Named Pipe files on NT. Although
TCP/IP sockets are omnipresent, the latter two types have been added
for local connections. Those two connection types can be used in
local mode only, that is, when both client and server reside on the
same host, and are introduced because they enable better speeds for
local connections. This is especially useful for WWW type of
applications. Startup options of MySQL server allow that either
TCP/IP sockets or local connection (OS dependent) can be disallowed.
In order to implement buffered input/output, MySQL allocates a
buffer. The starting size of this buffer is determined by the value
of the global variable net_buffer_length, which can be changed at
MySQL server startup. This is, as explained, only the startup length
of MySQL network buffer. Because a single item that has to be read
or written can be larger than that value, MySQL will increase buffer
size as long as that size reaches value of the global variable
max_allowed_packet, which is also settable at server startup. Maximum
value of this variable is limited by the way MySQL stores/reads
sizes of packets to be sent/read, which means by the way MySQL
formats packages.
Basically each packet consists of two parts, a header and data. In
the case when compression is not used, header consists of 4 bytes
of which 3 contain the length of the packet to be sent and one holds
the packet number. When compression is used there are onother 3
bytes which store the size of uncompressed data. Because of the way
MySQL packs length into 3 bytes, plus due to the usage of some
special values in the most significant byte, maximum size of
max_allowed_packet is limited to 24MB at present. So, if compression
is not used, at first 4 bytes are written to the buffer and then
data itself. As MySQL buffers I/O logical packets are packet together
until packets fill up entire size of the buffer. That size no less
than net_buffer_size, but no greater than max_allowed_packet. So,
actual writing to the network is done when this buffer is filled
up. As frequently sequence of buffers make a logical unit, like a
result set, then at the end of sending data, even if buffer is not
full, data is written (flushed to the connection) with a call of
the net_flush function. So that no single packet can be larger than
this value, checks are made throughout the code to make sure that
no single field or command could exceed that value.
In order to maintain coherency in consecutive packets, each packet
is numbered and their number stored as a part of a header, as
explained above. Packets start with 0, so whenever a logical packet
is written, that number is incremented. On the other side when
packets are read, value that is fetched is compared with the value
stored and if there is no mismatch that value is incremented, too.
Packet number is reset on the client side when unwanted connections
are removed from the connection and on the server side when a new
command has been started.
So, before writing, the buffer contains a sequence of logical
packets, consisting of header plus data consecutively. If compression
is used, packet numbers are not stored in each header of the logical
packets, but a whole buffer, or a part of it if flushing is done,
containing one or more logical packets are compressed. In that case
a new larger header, is formed, and all logical packets contained
in the buffer are compressed together. This way only one packet is
formed which makes several logical packets, which improves both
speed and compression ratio. On the other side, when this large
compressed packet is read, it is first uncompressed, and then logical
packets are sent, one by one, to the calling functions.
All this functionality is described in detail in the following
chapter. It does not contain functions that form logical packets, or
that read and write to connections but also functions that are used
for initialization, clearing of connections. There are functions at
higher level dealing with sending fields, rows, establishing
connections, sending commands, but those are not explained in the
following chapter.
Functions utilized in client/server protocol
--------------------------------------------
First of all, functions are described that are involved in preparing,
reading, or writing data over TCP port, Unix socket file, or named
pipe, and functions directly related to those. All of these functions
are used both in server and client. Server and client specific code
segments are documented in each function description.
Each MySQL function checks for errors in memory allocation and
freeing, as well as in every OS call, like the one dealing with
files and sockets, and for errors in indigenous MySQL function
calls. This is expected, but has to be said here so as not to repeat
it in every function description.
Older versions of MySQL have utilized the following macros for
reading from or writing to a socket.
raw_net_read - calls OS function recv function that reads N bytes
from a socket into a buffer. Number of bytes read is returned.
raw_net_write - calls OS function send to write N bytes from a
buffer to socket. Number of bytes written is returned.
These macros are replaced with VIO (Virtual I/O) functions.
Function name: my_net_init
Parameters: struct NET *, enum_net_type, struct Vio
Return value: 1 for error, 0 for success
Function purpose: To initialize properly all NET fields,
allocate memory and set socket options
Function description
First of all, buff field of NET struct is allocated to the size of
net_buffer_length, and on failure function exits with 0. All fields
in NET are set to their default or starting values. As net_buffer_length
and max_allowed_packet are configurable, max_allowed_packet is set
equal to net_buffer_length if the latter one is greater. max_packet
is set for that NET to net_buffer_length, and buff_end points to
buff end. vio field is set to the second parameter. If it is a
real connection, which is the case when second parameter is not
null, then fd field is set by calling vio_fd function. read_pos and
write_pos to buff, while remaining integers are set to 0. If function
is run on the MySQL server on Unix and server is started in a test
mode that would require testing of blocking, then vio_blocking
function is called. Last, fast throughput mode is set by a call to
vio_fastsend function.
Function name: net_end
Parameters: struct NET *
Return value: void
Function purpose: To release memory allocated to buff
Function name: net_realloc (private, static function)
Parameters: struct NET, ulong (unsigned long)
Return value: 1 for error, 0 for success
Function purpose: To change memory allocated to buff
Function description
New length of buff field of NET struct is passed as second parameter.
It is first checked versus max_allowed_packet and if greater, an
error is returned. New length is aligned to 4096-byte boundary. Then,
buff is reallocated, buff_end, max_packet, and write_pas reset to
the same values as in my_net_init.
Function name: net_clear (used on client side only)
Parameters: struct NET *
Return value: void
Function purpose: To read unread packets
Function description
This function is used on client side only, and is executed
only if a program is not started in test mode. This function reads
unread packets without processing them. First, non-blocking mode is
set on systems that do not have non-blocking mode defined. This is
performed by checking the mode with vio_is_blocking function. and
setting non-blocking mode by vio_blocking function. If this operation
was successful, then packets are read by vio_read function, to which
vio field of NET is passed together with buff and max_packet field
values. field of the same struct at a length of max_packet. If
blocking was active before reading is performed, blocking is set with
vio_blocking function. After reading has been performed, pkt_nr is
reset to 0 and write_pos reset to buff. In order to clarify some
matters non-blocking mode enables executing program to dissociate from
a connection, so that error in connection would not hang entire
program or its thread.
Function name: net_flush
Parameters: struct NET *
Return value: 1 for error, 0 for success
Function purpose: To write remaining bytes in buff to socket
Function description
net_real_write (described below) is performed is write_pos
differs from buff, both being fields of the only parameter. write_pos
is reset to buff. This function has to be used, as MySQL uses buffered
writes (as will be explained more in the function net_write_buff).
Function name: my_net_write
Parameters: struct NET *, const char *, ulong
Return value: 1 for error, 0 for success
Function purpose: Write a logical packet in the second parameter
of third parameter length
Function description
The purpose of this function is to prepare a logical packet such
that entire content of data, pointed to by second parameter and in
length of third parameter is sent to the other side. In case of
server, it is used for sending result sets, and in case of client
it is used for sending local data. This function foremost prepares
a header for the packet. Normally, the header consists of 4 bytes,
of which the first 3 bytes contain the length of the packet, thereby
limiting a maximum allowable length of a packet to 16MB, while the
fourth byte contains the packet number, which is used when one large
packet has to be divided into sequence of packets. This way each
sub-packet gets its number which should be matched on the other
side. When compression is used another three bytes are added to
packet header, thus packet header is in that case increased to 7
bytes. Additional three bytes are used to save the length of
compressed data. As in connection that uses compression option,
code packs packets together,, a header prepared by this function
is later not used in writing to / reading from network, but only
to distinguish logical packets within a buffered read operation.
This function, first stores the value of the third parameter into the
first 3 bytes of local char variable of NET_HEADER_SIZE size by usage
of function int3store. Then, at this point, if compression is not
used, pkt_nr is increased, and its value stored in the last byte of
the said local char[] variable. If compression is used, 0 is stored in
both values. Then those four bytes are sent to other side by the usage
of the function net_write_buff(to be explained later on), and if
successful, entire packet in second parameter of the length described
in third parameter is sent by the usage of the same function.
Function name: net_write_command
Parameters: struct NET *, char, const char *, ulong
Return value: 1 for error, 0 for success
Function purpose: Send a command with a packet as in previous function
Function description
This function is very similar to the previous one. The only
difference is that first packet is enlarged by one byte, so that the
command precedes the packet to be sent. This is implemented by
increasing first packet by one byte, which contains a command code. As
command codes do not use the range of values that are used by character
sets, so when the other side receives a packet, first byte after
header contains a command code. This function is used by client for
sending all commands and queries, and by server in connection process
and for sending errors.
Function name: net_write_buff (private, static function)
Parameters: struct NET *, const char *, uint
Return value: 1 for error, 0 for success
Function purpose: To write a packet of any size by cutting it
and using next function for writing it
Function description
This function was created after compression feature has been
added to MySQL. This function supposes that packets have already been
properly formatted, regarding packet header etc. The principal reason for
this function to exist is because a packet that is sent by client or
server does not have to be less than max_packet. So this function
first calculates how much data has been left in a buff, by getting a
difference between buff_end and write_pos and storing it to local
variable left_length. Then a loop is run as long as the length to be
sent is greater than length of left bytes (left_length). In a loop
data from second parameter is copied to buff at write_pos, as much as
it can be, that is, by left_length. Then net_real_write function is called
(see below) with NET, buff, and max_packet parameters. This function
is the lowest level function that writes data over established
connection. In the loop, write_pos is reset to buff, the pointer to data
(second parameter) is moved by the amount of data sent (left_length),
length of data to be sent (third parameter) is decreased by the amount
sent (left_length) and left_length is reset to max_packet value, which
ends the loop. This logic was necessary, as there could have been some
data yet unsent (write_pos != buf), while data to be sent could be as
large as necessary, thus requiring many loops. At the end of function,
remaining data in second parameter are copied to buff at write_pos, by
the remaining length of data to be sent (third parameter). So, in the
next call of this function remaining data will be sent, as buff is
used in the call to net_real_write. It is very important to note that if
a packet to be sent is less than the number of bytes that are still
available in buff, then there will be no writing over network, but
only logical packets will be added one after another. This will
accelerate network traffic, plus if compression is used, the
expected compression rate would be higher. That is why server or
client functions that sends data uses at the end of data net_flush
function described above.
Function name: net_real_write
Parameters: struct NET *, const char *, ulong
Return value: 1 for error, 0 for success
Function purpose: To write data to a socket or pipe, with
compression if used
Function description
First, more field is set to 2, to enable reporting in
mysql_list_processes. Then if compression is enabled on that
connection, a new local buffer (variable b) is initialized to the
length of total header (normal header + compression header) and if no
memory is available, an error is returned. This buffer (b) is used for
holding the final, compressed packet to be written over the
connection. Furthermore in compression initialization, second
parameter at length of third parameter is copied to the local buffer
b, and MySQL's wrapped zlib's compression function is run at total
header offset of the local buffer. Please, do note that this function
does not test effectiveness of compression. If compression is turned
on in some connection, it is used all of the time. Also, it is very
important to be cognizant of the fact that this algorithm makes
possible that a single compressed packet contains several logical
packets. In this way compression rate is increased and network
throughput is increased as well. However, this algorithm has
consequences on the other side, that reads compressed packet, which
is covered in my_net_read function. After compression is done, the full
compression header is properly formed with the packet number,
compressed and uncompressed lengths. At the end of compression code,
third parameter is increased by total header length, as the original
header is not used (see above), and second parameter, pointer to data,
is set to point to local buffer b, in order that the further flow of
function is independent of compression. If a function is executed
on server side, a thread alarm initialized and if non-blocking is
active set at NET_WRITE_TIMEOUT. Two local (char *) pointers are
initialized, pos at beginning of second parameter, and end at end of
data. Then the loop is run as long as all data is written, which means
as long as pos != end. First vio_write function is called, with
parameters of vio field, pos and size of data (end - pos). Number of
bytes written over connection is saved in local variable (length). If
error is returned local bool variable (interrupted) is set according
to the return value of the vio_should_retry called with vio field as
parameter. This bool variable indicates whether writing was
interrupted in some way or not.
Further, error from vio_write is treated differently on Unix versus
other OS's (Win32 or OS/2). On Unix an alarm is set if one is not
in use, no bytes have been written and there has been no interruption.
Also, in that case, if connection is not in blocking mode, a sub-loop
is run as long as blocking is not set with vio_blocking function.
Within the loop another run of above vio_write is run based on
return value of vio_is_retry function, provided number of repeated
writes is less than RETRY_COUNT. If that is not the case, error
field of struct NET is set to 1 and function exits. At the exit
of sub-loop number of reruns already executed is reset to zero and
another run of above vio_write function is attempted. If the function
is run on Win32 and OS/2, and in the case that function flow was
not interrupted and thread alarm is not in use, again the main loop
is continued until pos != end. In the case that this function is
executed on thread safe client program, a communication flow is
tested on EINTR, caused by context switching, by use of vio_errno
function, in which case the loop is continued. At the end of
processing of the error from vio_write, error field of struct NET
is set, and if on server last_errno field is set to
ER_NET_WRITE_INTERRUPTED in the case that local bool variable
(interrupted) is true or to ER_NET_ERROR_ON_WRITE. Before the end
of loop, in order to make possible evaluation of the loop condition,
pos is increased by the value written in last iteration (length).
Also global variable bytes_sent is increased by the same value, for
status purposes. At the end of the functions more fields is reset,
in case of compression, compression buffer (b) memory is released
and if thread is still in use, it is ended and blocking state is
reset to its original state, and function returns error is all bytes
are not written.
Function name: my_real_read (private, static function)
Parameters: struct NET *, ulong *
Return value: length of bytes read
Function purpose: low level network connection read function
Function description
This function has made as a separate one when compression was
introduced in MySQL client/server protocol . It contains basic, low
level network reading functionality, while all dealings with
compressed packets are handled in next function. Compression in this
function is only handled in as much to unfold the length of uncompressed
data. First blocking state of connection is saved in local bool
variable net_blocking, and field more is set 1 for detailed reporting
in mysqld_list_processes. A new thread alarm is initialized, in order
to enable read timeout handling, and if on server and a connection can
block a program, the alarm is set at a value of timeout field. Local
pointer is set to the position of the next logical packet, with its
header skipped, which is at field where_b offset from buff. Next, a
two time run code is entered. A loop is run exactly two times because
first time number of bytes to be fetched (remain) are set to the
header size, which is different when compression is used or not used
on the connection. After first fetch has been done, number of packets
that will be received in second iteration is well known, as fetched
header contains the size of packet, packet number, and in the case of
compression, the size of the uncompressed packet. Then, as long as there are
bytes to read the loop is entered with first reading data from network
connection with vio_read function, called with parameters of field
vio, current position and remaining number of bytes, which value is
hold by local variable (remain) initialized at the value of header size,
which differs if compression is used. Number of bytes read are
returned in local length variable. If error is returned local bool
variable (interrupted) is set according to the return value of the
vio_should_retry called with vio field as parameter. This bool
variable indicates whether reading was interrupted in some way or not.
Further, error from vio_read is treated differently on Unix versus
other OS's (Win32 or OS/2). On Unix an alarm is set if one is not
in use, no bytes have been read and there has been no interruption.
Also, in that case, if connection is not in blocking mode, a sub-loop
is run as long as blocking is not set with vio_blocking function.
Within the loop another run of above vio_read is run based on return
value of vio_is_retry function, provided number of repeated writes
is less than RETRY_COUNT. If that is not the case, error field of
struct NET is set to 1 and function exits. At the exit of sub-loop
number of reruns already executed is reset to zero and another run
of above vio_read function is attempted. If the function is run on
Win32 and OS/2, and in the case that function flow was not interrupted
and thread alarm is not in use, again the main loop is continued
as long as there are bytes remaining. In the case that this function
is executed on thread safe client program, then if another run
should be made, which is decided by the output of vio_should_retry
function, in which case the loop is continued. At the end of
processing of the error from vio_read, error field of struct NET
is set, and if on server last_errno field is set to ER_NET_READ_INTERRUPTED
in the case that local bool variable (interrupted) is true or to
ER_NET_ERROR_ON_READ. In case of such an error this function exits
and returns error. In the case when there is no error, number of
remaining bytes (remain) is decreased by the number of bytes read,
which should be zero, but in case it is not the entire code is still
in while (remain > 0) loop, which will be exited immediately if it
is. This has been done to accommodate errors in the traffic level
and for the very slow connections. Current position in field buff
is also moved by the amount of bytes read by vio_read function, and
global variable bytes_received is increased by the same value in a
thread safe manner. When the loop that is run until necessary bytes
are read (remain) is finished, then if external loop is in its first
run, of the two, packet sequencing is tested for consistency by
comparing the number contained at 4th byte in header with pkt_nr
field. Header location is found at where_b offset to field_b. Usage
of where_b is obligatory due to the possible compression usage. If
there is no compression on a connection, then where_b is always 0.
If there is a discrepancy, then first byte of the header is checked
whether it is equal to 255, because when error is sent by the server,
or by a client if it is sending data (like in LOAD DATA INFILE
LOCAL...), then first byte in header is set to 255. If it is not
255, then an error on packets being out of order is printed. In any
case, on server, last_errno field is set to ER_NET_PACKETS_OUT_OF_ORDER
and the function returns with an error, that is, the value returned is
packet_error. If a check on serial number of packet is successful,
pkt_nr field is incremented in order to enable checking packet order
with next packet and if compression is used, uncompressed length
is extracted from a proper position in header and returned in the
second parameter of this function. Length of the packet is saved,
for the purpose of a proper return value from this function. Still
in the first iteration of the main loop, a check must be made if
field buff could accommodate entire package that comes, in its
compressed or uncompressed form. This is done in such a way, because
zlib's compress and uncompress functions use the same memory area
for compression and uncompression. Necessary field buff length is
equal to current offset where data are (where_b which is zero for
non-compression), plus the larger value of compressed or uncompressed
package to be read in a second run. If this value is larger than
the current length of field buff, which is read from field max_packet,
then field buff has to be reallocated. If reallocation with net_realloc
function fails, the function returns an error. Before a second
loop is started, length to be read is set to the length of expected
data and current position (pos) is set at where_b offset from field
buff. At the end of function, if alarm is set, which is the case
if it is run on server or on a client if a function is interrupted
and another run of vio_read is attempted, alarm is ended and blocking
state is restored from the saved local bool variable net_blocking.
Function returns number of bytes read or the error (packet_error).
Function name: my_net_read
Parameters: struct NET *
Return value: length of bytes read
Function purpose: Highest level general purpose reading function
Function description
First, if compression is not used, my_real_read is called, with
struct NET * a first parameter, and pointer to local ulong complen
as a second parameter, but its value is not used here. Number of
bytes read is returned in local ulong variable len. read_pos field
is set to an offset of value of where_b field from field buff.
where_b field actually denotes where in field buff is the current
packet. If returned number of bytes read (local variable len) does
not signal that an error in packet transmission occurred (that is,
it is not set to packet_error), then the string contained in read_pos
is zero terminated. Simply, the end of the string starting at
read_pos, and ending at read_pos + len, is set to zero. This is
done in that way, because mysql_use_result expects a zero terminated
string, and function returns with a value local variable len. This
ends this function in the case that compression is not used and the
remaining code is executed only if compression is enabled on the
connection.
In order to explain how a compressed packet logically is cut into
meningful packets, the full meaning of several NET fields should
be explained. First of all, fields in NET are used and not local
variables, as all values should be saved between consecutive calls
of this function. Simply, this function is called in order to return
logical packets, but this function does not need to call my_real_read
function everytime, because when a large packet is uncompressed,
it may, but not necessarily so, contain several logical packets.
Therefore, in order to preserve data on logical packets local
variables are not used. Instead fields in NET struct are used. Field
remain_in_buf denotes how many bytes of entire uncompressed packets
is still contained within buff. field buf_length saves the value
of the length of entire uncompressed packet. field save_char is
used to save the character at the position where the packet ends,
which character has to be replaced with a zero, '\0', in order to
make a logical packet zero delimited, for mysql_use_result. Field
length stores the value of the length of compressed packet. Field
read_pos as usual, points to the current reading position. This
char * pointer is used by all functions that call this function in
order to fetch their data. Field buff is not used for that purpose,
but read_pos is used instead. This change was introduced with
compression, when algorithm accommodated grouping of several packets
together.
Now that meanings of all relevant NET fields are explained,
we can proceed with the flow of this function for the case when
compression is active. First, if there are remaining portions of
compressed packet in a field buff, saved character value is set at
the position where zero char '\0' was inserted to enable the string
to be zero delimited for mysql_use_result. Then a loop is started.
In the first part of the loop, if there are remaining bytes, local
uchar *pos variable is set at the current position in field buff
where a new packet starts. This position is an (buf_length -
remain_in_buf) offset in field buff. As it is possible that next
logical packet is not read to the full length in the remaining of
the field buf, several things had to be inspected. It should be
noted that data that is read from net_real_read contains only logical
packets containing 4 byte headers only, being 4 byte headers prepared
by my_net_write or net_write_command. But, when written, logical
packet could be so divided that only a part of header is read in.
Therefore after pointer to the start of the next packet has been
saved, a check is made whether number of remaining bytes in buffer
is less than 4, being 3 bytes for length and one byte for packet
number. If it is greater, then the length of the logical packet is
extracted and saved a length field. Then a check is made whether
entire packet is contained within a buf, that is, a check is made
that the logical packet is fully contained in the buffer. In that
case, number of bytes remaining in buffer is decreased by the full
length of logical packet (4 + length field), read_pos is moved
forward by 4 bytes to skip header and be set at a beginning of data
in logical packet, length field is saved for the value to be returned
in function and the loop is exited. In the case that the entire
logical packet is not contained within the buffer, then if length of
the entire buffer differs from remaining length of logical packet,
it (logical packet) is moved to the beginning of the field buff.
If length of the entire buffer equals the remaining length of logical
packet, where_b and buf_length fields are set to 0. This is done
so that in both cases buffer is ready to accept next part of packet.
In order to get a next part of a packet, still within a loop,
my_real_read function is called and length of compressed packet is
returned to a local len variable, and length of compressed data is
returned in complen variable. In the case of non-compression value
of complen is zero. If packet_error is from my_real_read function,
this function returns also with packet_error. If it is not a
packet_error, my_uncompress function is called to uncompress data.
It is called with offset of where_b data from field buff, as it is
the position where compressed packet starts, and with len and complen
values, being lengths of compressed and uncompressed data. If there
is no compression, 0 is returned for uncompressed size from
my_real_read function, and my_uncompress wrapper function is made
to skip zlib uncompress in that case. If error is returned from
my_uncompress, error field is set to 1, if on server last_errno is
set to ER_NET_UNCOMPRESS_ERROR and loop is exited and function
returns with packet_error. If not, buf_length and remain_in_buf
fields are set to the uncompressed size of buffer and the loop is
continued. When the loop is exited save_char field is used to save
the char at end of a logical packet, which is an offset of field
len from position in field buff pointed by field read_pos, in order
that zero char is set at the same position, for mysql_use_result.
Function returns the length of the logical packet without its header.
|