New test.
[mono.git] / mcs / class / FirebirdSql.Data.Firebird / FirebirdSql.Data.Gds / GdsConnection.cs
1 /*
2  *      Firebird ADO.NET Data provider for .NET and Mono 
3  * 
4  *         The contents of this file are subject to the Initial 
5  *         Developer's Public License Version 1.0 (the "License"); 
6  *         you may not use this file except in compliance with the 
7  *         License. You may obtain a copy of the License at 
8  *         http://www.firebirdsql.org/index.php?op=doc&id=idpl
9  *
10  *         Software distributed under the License is distributed on 
11  *         an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either 
12  *         express or implied. See the License for the specific 
13  *         language governing rights and limitations under the License.
14  * 
15  *      Copyright (c) 2002, 2005 Carlos Guzman Alvarez
16  *      All Rights Reserved.
17  */
18
19 using System;
20 using System.IO;
21 using System.Net;
22 using System.Net.Sockets;
23
24 using FirebirdSql.Data.Common;
25
26 namespace FirebirdSql.Data.Gds
27 {
28         internal sealed class GdsConnection
29         {
30                 #region Fields
31
32                 private Socket                  socket;
33                 private NetworkStream   networkStream;
34                 private XdrStream               send;
35                 private XdrStream               receive;
36                 private int                             operation;
37
38                 #endregion
39
40                 #region Internal Properties
41
42                 internal XdrStream Receive
43                 {
44                         get { return this.receive; }
45                 }
46
47                 internal XdrStream Send
48                 {
49                         get { return this.send; }
50                 }
51
52                 #endregion
53
54                 #region Constructors
55
56                 public GdsConnection()
57                 {
58                         this.operation = -1;
59
60                         GC.SuppressFinalize(this);
61                 }
62
63                 #endregion
64
65                 #region Methods
66
67                 public void Connect(string dataSource, int port)
68                 {
69                         this.Connect(dataSource, port, 8192, Charset.DefaultCharset);
70                 }
71
72                 public void Connect(string dataSource, int port, int packetSize, Charset charset)
73                 {
74                         try
75                         {
76                                 IPAddress hostadd = Dns.Resolve(dataSource).AddressList[0];
77                                 IPEndPoint EPhost = new IPEndPoint(hostadd, port);
78
79                                 this.socket = new Socket(
80                                         AddressFamily.InterNetwork,
81                                         SocketType.Stream,
82                                         ProtocolType.Tcp);
83
84 #if (!NETCF)
85
86                                 // Set Receive Buffer size.
87                                 this.socket.SetSocketOption(
88                                         SocketOptionLevel.Socket,
89                                         SocketOptionName.ReceiveBuffer,
90                                         packetSize);
91
92                                 // Set Send     Buffer size.
93                                 this.socket.SetSocketOption(
94                                         SocketOptionLevel.Socket,
95                                         SocketOptionName.SendBuffer,
96                                         packetSize);
97 #endif
98
99                                 // Disables     the     Nagle algorithm for     send coalescing.
100                                 this.socket.SetSocketOption(
101                                         SocketOptionLevel.Tcp,
102                                         SocketOptionName.NoDelay,
103                                         1);
104
105                                 // Make the     socket to connect to the Server
106                                 this.socket.Connect(EPhost);
107                                 this.networkStream = new NetworkStream(this.socket, true);
108
109 #if     (NETCF)
110                                 this.send        = new XdrStream(this.networkStream, charset);
111                                 this.receive = new XdrStream(this.networkStream, charset);
112 #else
113                                 this.send = new XdrStream(new BufferedStream(this.networkStream), charset);
114                                 this.receive = new XdrStream(new BufferedStream(this.networkStream), charset);
115 #endif
116
117                                 GC.SuppressFinalize(this.socket);
118                                 GC.SuppressFinalize(this.networkStream);
119                                 GC.SuppressFinalize(this.send);
120                                 GC.SuppressFinalize(this.receive);
121                         }
122                         catch (SocketException)
123                         {
124                                 throw new IscException(IscCodes.isc_arg_gds, IscCodes.isc_network_error, dataSource);
125                         }
126                 }
127
128                 public void Disconnect()
129                 {
130                         try
131                         {
132                                 if (this.receive != null)
133                                 {
134                                         this.receive.Close();
135                                 }
136                                 if (this.send != null)
137                                 {
138                                         this.send.Close();
139                                 }
140                                 if (this.networkStream != null)
141                                 {
142                                         this.networkStream.Close();
143                                 }
144                                 if (this.socket != null)
145                                 {
146                                         this.socket.Close();
147                                 }
148
149                                 this.receive            = null;
150                                 this.send                       = null;
151                                 this.socket                     = null;
152                                 this.networkStream      = null;
153                         }
154                         catch (IOException)
155                         {
156                                 throw;
157                         }
158                 }
159
160                 #endregion
161
162                 #region Internal Methods
163
164                 internal int ReadOperation()
165                 {
166                         int op = (this.operation >= 0) ? this.operation : this.NextOperation();
167                         this.operation = -1;
168
169                         return op;
170                 }
171
172                 internal int NextOperation()
173                 {
174                         do
175                         {
176                                 /* loop as long as we are receiving     dummy packets, just
177                                  * throwing     them away--note that if we are a server we won't
178                                  * be receiving them, but it is better to check for     them at
179                                  * this level rather than try to catch them     in all places where
180                                  * this routine is called 
181                                  */
182                                 this.operation = this.receive.ReadInt32();
183                         } while (this.operation == IscCodes.op_dummy);
184
185                         return this.operation;
186                 }
187
188                 internal GdsResponse ReadGenericResponse()
189                 {
190                         try
191                         {
192                                 if (this.ReadOperation() == IscCodes.op_response)
193                                 {
194                                         GdsResponse r = new GdsResponse(
195                                                 this.receive.ReadInt32(),
196                                                 this.receive.ReadInt64(),
197                                                 this.receive.ReadBuffer());
198
199                                         r.Warning = this.ReadStatusVector();
200
201                                         return r;
202                                 }
203                                 else
204                                 {
205                                         return null;
206                                 }
207                         }
208                         catch (IOException)
209                         {
210                                 throw new IscException(IscCodes.isc_net_read_err);
211                         }
212                 }
213
214                 internal IscException ReadStatusVector()
215                 {
216                         IscException exception = null;
217                         bool eof = false;
218
219                         try
220                         {
221                                 while (!eof)
222                                 {
223                                         int arg = this.receive.ReadInt32();
224
225                                         switch (arg)
226                                         {
227                                                 case IscCodes.isc_arg_gds:
228                                                         int er = this.receive.ReadInt32();
229                                                         if (er != 0)
230                                                         {
231                                                                 if (exception == null)
232                                                                 {
233                                                                         exception = new IscException();
234                                                                 }
235                                                                 exception.Errors.Add(arg, er);
236                                                         }
237                                                         break;
238
239                                                 case IscCodes.isc_arg_end:
240                                                         if (exception != null && exception.Errors.Count != 0)
241                                                         {
242                                                                 exception.BuildExceptionMessage();
243                                                         }
244                                                         eof = true;
245                                                         break;
246
247                                                 case IscCodes.isc_arg_interpreted:
248                                                 case IscCodes.isc_arg_string:
249                                                         exception.Errors.Add(arg, this.receive.ReadString());
250                                                         break;
251
252                                                 case IscCodes.isc_arg_number:
253                                                         exception.Errors.Add(arg, this.receive.ReadInt32());
254                                                         break;
255
256                                                 default:
257                                                         {
258                                                                 int e = this.receive.ReadInt32();
259                                                                 if (e != 0)
260                                                                 {
261                                                                         if (exception == null)
262                                                                         {
263                                                                                 exception = new IscException();
264                                                                         }
265                                                                         exception.Errors.Add(arg, e);
266                                                                 }
267                                                         }
268                                                         break;
269                                         }
270                                 }
271                         }
272                         catch (IOException)
273                         {
274                                 throw new IscException(IscCodes.isc_arg_gds, IscCodes.isc_net_read_err);
275                         }
276
277                         if (exception != null && !exception.IsWarning)
278                         {
279                                 throw exception;
280                         }
281
282                         return exception;
283                 }
284
285                 internal void SetOperation(int operation)
286                 {
287                         this.operation = operation;
288                 }
289
290                 #endregion
291         }
292 }