1 | /****************************************************************************** |
---|
2 | * QUANTA - A toolkit for High Performance Data Sharing |
---|
3 | * Copyright (C) 2003 Electronic Visualization Laboratory, |
---|
4 | * University of Illinois at Chicago |
---|
5 | * |
---|
6 | * All rights reserved. |
---|
7 | * |
---|
8 | * Redistribution and use in source and binary forms, with or without |
---|
9 | * modification, are permitted provided that the following conditions are met: |
---|
10 | * |
---|
11 | * * Redistributions of source code must retain the above copyright |
---|
12 | * notice, this list of conditions and the following disclaimer. |
---|
13 | * * Redistributions in binary form must reproduce the above |
---|
14 | * copyright notice, this list of conditions and the following disclaimer |
---|
15 | * in the documentation and/or other materials provided with the distribution. |
---|
16 | * * Neither the name of the University of Illinois at Chicago nor |
---|
17 | * the names of its contributors may be used to endorse or promote |
---|
18 | * products derived from this software without specific prior written permission. |
---|
19 | * |
---|
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
---|
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
---|
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
---|
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
---|
24 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
---|
25 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
---|
26 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
---|
27 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
---|
28 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
---|
29 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
---|
30 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
---|
31 | * |
---|
32 | * Direct questions, comments etc about Quanta to cavern@evl.uic.edu |
---|
33 | *****************************************************************************/ |
---|
34 | |
---|
35 | /* |
---|
36 | This is a C++ class to support TCP/IP sockets. |
---|
37 | The 2 main classes are QUANTAnet_tcpClient_c and QUANTAnet_tcpServer_c. |
---|
38 | |
---|
39 | If you are writing a server you need to instantiate a tcpServer object. |
---|
40 | Likewise if you are writing a client you need to instantiate a tcpClient |
---|
41 | object. |
---|
42 | |
---|
43 | */ |
---|
44 | |
---|
45 | #ifndef _QUANTAPLUS_TCP_C |
---|
46 | #define _QUANTAPLUS_TCP_C |
---|
47 | |
---|
48 | #include "QUANTAnet_socketbase_c.hxx" |
---|
49 | #include "QUANTAnet_perfMonitor_c.hxx" |
---|
50 | #include "QUANTAnet_iovec_c.hxx" |
---|
51 | //#include <QUANTAnet_perfDaemon_c.hxx> |
---|
52 | |
---|
53 | class QUANTAnet_perfMonitor_c; |
---|
54 | class QUANTAnet_tcpServer_c; |
---|
55 | //class QUANTAnet_perfDaemon_c; |
---|
56 | |
---|
57 | /** TCP Class for creating client connections. This class bypasses QUANTA's standard method for establishing connections and provides the user with direct control of TCP connections. |
---|
58 | |
---|
59 | */ |
---|
60 | class QUANTAnet_tcpClient_c : public QUANTAnet_socketbase_c { |
---|
61 | |
---|
62 | // Allow QUANTAnet_tcpServer_c objects to call MakeNonBlocking. |
---|
63 | friend class QUANTAnet_tcpServer_c; |
---|
64 | |
---|
65 | protected: |
---|
66 | /* Not to be called by user */ |
---|
67 | void makeNonBlocking(); |
---|
68 | |
---|
69 | struct sockaddr_in clientInfo; |
---|
70 | int clientSockFd; |
---|
71 | int clientStatus; |
---|
72 | int timeOutStatus; |
---|
73 | int timeOutPeriod; |
---|
74 | QUANTAnet_perfMonitor_c pmonitor; |
---|
75 | public: |
---|
76 | |
---|
77 | /// Blocking parameter values for Read/Write method. |
---|
78 | //@{ |
---|
79 | /// Make the connection blocking but time out eventually. |
---|
80 | static const int BLOCKING/* = 1*/; |
---|
81 | |
---|
82 | /// Make the connection non blocking. |
---|
83 | static const int NON_BLOCKING/* = 2*/; |
---|
84 | |
---|
85 | // Make the conncection blocking and never time out. |
---|
86 | //static const int NEVER_TIME_OUT_BLOCKING/* = 3*/; |
---|
87 | |
---|
88 | //@} |
---|
89 | |
---|
90 | /// Time out values. |
---|
91 | //@{ |
---|
92 | /// Used to set time out period to never time out. |
---|
93 | static const int NO_TIME_OUT/* = -1*/; |
---|
94 | |
---|
95 | /// Default time out is no time out. |
---|
96 | static const int DEFAULT_TIME_OUT/* = NO_TIME_OUT*/; |
---|
97 | //@} |
---|
98 | |
---|
99 | /// Return values from Read/Write methods. |
---|
100 | //@{ |
---|
101 | /// Socket is not open. |
---|
102 | static const int SOCKET_NOT_OPEN/* = -1*/; |
---|
103 | |
---|
104 | /// Connection you attempted to read/write is terminated. |
---|
105 | static const int CONNECTION_TERMINATED/* = -2*/; |
---|
106 | |
---|
107 | /// You attempted to read with non blocking and there was not data. |
---|
108 | static const int NON_BLOCKING_HAS_NO_DATA/* = -3*/; |
---|
109 | |
---|
110 | /// The read/write timed out. |
---|
111 | static const int TIMED_OUT/* = -4*/; |
---|
112 | |
---|
113 | /// Read/Write succeeded. |
---|
114 | static const int OK/* = 1*/; |
---|
115 | |
---|
116 | /// You attempted to write with non blocking and socket was not ready. |
---|
117 | static const int NON_BLOCKING_NOT_READY_TO_WRITE/* = -6*/; |
---|
118 | |
---|
119 | /// Socket was not ready. |
---|
120 | static const int NOT_READY/* = -7*/; |
---|
121 | |
---|
122 | /// Socket ready to read. |
---|
123 | static const int READY_TO_READ/* = -8*/; |
---|
124 | |
---|
125 | /// Socket ready to write. |
---|
126 | static const int READY_TO_WRITE/* = -9*/; |
---|
127 | |
---|
128 | /// Socket ready to read and write. |
---|
129 | static const int READY_TO_READ_AND_WRITE/* = -10*/; |
---|
130 | |
---|
131 | /// Change the socket buffer size before Read(). |
---|
132 | static const int READ_BUFFER_SIZE/* = -11*/; |
---|
133 | |
---|
134 | /// Change the socket buffer size before Write(). |
---|
135 | static const int WRITE_BUFFER_SIZE/* = -12*/; |
---|
136 | //@} |
---|
137 | |
---|
138 | |
---|
139 | /** Set timeout period when performing read() or write() operations. |
---|
140 | @param t Time out period in seconds. Set to QUANTAnet_tcpClient_c::NO_TIME_OUT to set no time out period. |
---|
141 | */ |
---|
142 | void setTimeOut(int t) {timeOutPeriod = t;} |
---|
143 | |
---|
144 | /// Get timeout period |
---|
145 | int getTimeOut() {return timeOutPeriod;} |
---|
146 | |
---|
147 | /** Set client info. For internal use. |
---|
148 | @param info client information |
---|
149 | */ |
---|
150 | void setClientInfo(struct sockaddr_in* info) { clientInfo = *info; } |
---|
151 | |
---|
152 | /** Set client socket. For internal use. |
---|
153 | @param sockfd client socket |
---|
154 | */ |
---|
155 | void setClientSockFd(int sockfd) { clientSockFd = sockfd; } |
---|
156 | |
---|
157 | QUANTAnet_tcpClient_c(); |
---|
158 | virtual ~QUANTAnet_tcpClient_c() { if (clientSockFd) close(); } |
---|
159 | |
---|
160 | /// Accessor functions |
---|
161 | //@{ |
---|
162 | /** Get the IP address of remote connection. |
---|
163 | If you are a client this returns the ip of the destination server. |
---|
164 | If you are a server this returns the ip of the destination client. |
---|
165 | */ |
---|
166 | unsigned int getRemoteIP(); |
---|
167 | |
---|
168 | /** Get the IP address of remote connection. |
---|
169 | If you are a client this returns the ip of the destination server. |
---|
170 | If you are a server this returns the ip of the destination client. |
---|
171 | */ |
---|
172 | void getRemoteIP(char* name); |
---|
173 | |
---|
174 | /// Get port of self. |
---|
175 | int getSelfPort(); |
---|
176 | |
---|
177 | /// Get port of client. |
---|
178 | int getRemotePort(); |
---|
179 | |
---|
180 | /// Get socket id |
---|
181 | int getSocketId(); |
---|
182 | //@} |
---|
183 | |
---|
184 | /**@name Read and Write calls.*/ |
---|
185 | //@{ |
---|
186 | /** |
---|
187 | @param nbytes |
---|
188 | |
---|
189 | Fill nbytes with num bytes you want to read. |
---|
190 | nbytes will return with number of bytes successfully read. |
---|
191 | |
---|
192 | @param blockingtype |
---|
193 | |
---|
194 | BLOCKING means that it will block waiting for data or until |
---|
195 | the timeout period expires. Change the timeout period by |
---|
196 | calling setTimeOut(). |
---|
197 | |
---|
198 | NON_BLOCKING means that if there is no data to be read this call will |
---|
199 | return immediately. If it does get some data it will keep reading |
---|
200 | until the specified number of bytes is received, or if it timesout, or if |
---|
201 | the connection is broken. In the latter two cases the number of bytes |
---|
202 | it was able to read is returned. |
---|
203 | |
---|
204 | In either the BLOCKING or NON_BLOCKING case you can set the |
---|
205 | time out period to never time out by setting the timeout |
---|
206 | time to: NO_TIME_OUT. |
---|
207 | |
---|
208 | @return SOCKET_NOT_OPEN, NON_BLOCKING_HAS_NO_DATA, TIMED_OUT, CONNECTION_TERMINATED, OK, errno |
---|
209 | */ |
---|
210 | int read(char *ptr, int *nbytes, int blockingType); |
---|
211 | |
---|
212 | /** Allows you to change the parameters to the setsockopt() options.Currently this member allows you to change socket buffer size. |
---|
213 | |
---|
214 | @param option |
---|
215 | Specify QUANTAnet_tcpClient_c::READ_BUFFER_SIZE if you want to change the size of the receive buffer. |
---|
216 | Specify QUANTAnet_tcpClient_c::WRITE_BUFFER_SIZE if you want to change the size of the send buffer |
---|
217 | |
---|
218 | @param buffersize |
---|
219 | Specify the size. |
---|
220 | */ |
---|
221 | void setSockOptions(int option, int buffersize); |
---|
222 | |
---|
223 | |
---|
224 | /** Determines if a socket has data available to read. |
---|
225 | @return Either: QUANTAnet_tcpClient_c::NOT_READY |
---|
226 | or QUANTAnet_tcpClient_c::READY_TO_READ |
---|
227 | */ |
---|
228 | int isReadyToRead(); |
---|
229 | |
---|
230 | /** Determines if a socket is ready to write. |
---|
231 | @return Either: QUANTAnet_tcpClient_c::NOT_READY |
---|
232 | or QUANTAnet_tcpClient_c::READY_TO_WRITE |
---|
233 | */ |
---|
234 | int isReadyToWrite(); |
---|
235 | |
---|
236 | /** Determines if a socket is ready to write or read or both. |
---|
237 | @return Either: QUANTAnet_tcpClient_c::NOT_READY |
---|
238 | or QUANTAnet_tcpClient_c::READY_TO_WRITE |
---|
239 | or QUANTAnet_tcpClient_c::READY_TO_READ |
---|
240 | or QUANTAnet_tcpClient_c::READY_TO_READ_AND_WRITE |
---|
241 | */ |
---|
242 | int isReady(); |
---|
243 | |
---|
244 | /** Write data to socket. |
---|
245 | @return SOCKET_NOT_OPEN, NON_BLOCKING_NOT_READY_TO_WRITE, TIMED_OUT, CONNECTION_TERMINATED, OK |
---|
246 | */ |
---|
247 | int write(const char *ptr, int *nbytes, int blockingType); |
---|
248 | |
---|
249 | /// Show status of connection in English. |
---|
250 | void showStatus(int status, int nbytes); |
---|
251 | |
---|
252 | /// Close the current client connection. |
---|
253 | int close(); |
---|
254 | |
---|
255 | /** Connect to a server. |
---|
256 | @return A negative number(that is returned by a socket sonnect() call if failed. |
---|
257 | Else returns client's socket file descriptor. (note: the return value in the previous |
---|
258 | versions was a zero in case of an error - this has been changed to a negative value from version 1.2) |
---|
259 | */ |
---|
260 | int connectToServer(const char *ip, int port); |
---|
261 | |
---|
262 | |
---|
263 | //Functions added for performance monitoring interface |
---|
264 | /** |
---|
265 | Displays the resultant statistics instantaneously in the netlogger format - |
---|
266 | this should be typically done after a read/write is done over a network. |
---|
267 | |
---|
268 | Also, it should be noted that a showStats call should be made at the end of atleast one send |
---|
269 | and receive for two-way information (the same applies for logStats and sendStats) |
---|
270 | |
---|
271 | @param streamInfo |
---|
272 | A label describing the stream that is being monitored. |
---|
273 | |
---|
274 | @param comment |
---|
275 | A comment on the event that marks the time at which the stream is being monitored |
---|
276 | */ |
---|
277 | |
---|
278 | void showStats(char* streamInfo, char* comment); |
---|
279 | |
---|
280 | /** |
---|
281 | This logs performance statistics in a file. The user opens a file and passes the file pointer |
---|
282 | with this function and results of monitoring are written into the logfile. |
---|
283 | |
---|
284 | @param streamInfo |
---|
285 | A label describing the stream that is being monitored. |
---|
286 | |
---|
287 | @param comment |
---|
288 | A comment on the event that marks the time at which the stream is being monitored |
---|
289 | |
---|
290 | @param filePtr |
---|
291 | File pointer to the file in which the results of monitoring are to be stored |
---|
292 | |
---|
293 | @return |
---|
294 | Either QUANTAnet_perfMonitor_c::OK or QUANTAnet_perfMonitor_c::FAILED |
---|
295 | */ |
---|
296 | |
---|
297 | |
---|
298 | int logStats(char* streamInfo, char* comment, FILE* filePtr); |
---|
299 | |
---|
300 | /** |
---|
301 | Sends the performance statistics to a remote perfdaemon -for further analysis of the monitored data - |
---|
302 | the initSendStats API should be called first, before calling a sendStats (In order to connect to the perfdaemon initially) |
---|
303 | |
---|
304 | @param streamInfo |
---|
305 | A label describing the stream that is being monitored. |
---|
306 | |
---|
307 | @param comment |
---|
308 | A comment on the event that marks the time at which the stream is being monitored |
---|
309 | |
---|
310 | @return |
---|
311 | Either QUANTAnet_perfMonitor_c::OK or QUANTAnet_perfMonitor_c::FAILED |
---|
312 | |
---|
313 | */ |
---|
314 | |
---|
315 | int sendStats(char* streamInfo, char* comment); |
---|
316 | |
---|
317 | /** |
---|
318 | Initialize sendStats - provide the IP of the perfDaemon and an optional port number to connect to. |
---|
319 | This should be done initially before using the sendStats API. |
---|
320 | |
---|
321 | @param monitorClientIP |
---|
322 | IP address of the perfDameon to connect to |
---|
323 | |
---|
324 | @param port |
---|
325 | Port number at which the perfDaemon is running -this is optional. The default port number for perfDaemon is 9500 |
---|
326 | -so a different port number has to be specified if the perfDaemon is running ona different port. |
---|
327 | |
---|
328 | @return |
---|
329 | Either QUANTAnet_perfMonitor_c::OK or QUANTAnet_perfMonitor_c::FAILED |
---|
330 | */ |
---|
331 | |
---|
332 | int initSendStats(const char* monitorClientIP, int port = PERF_DAEMON_DEFAULT_PORT); |
---|
333 | |
---|
334 | /** |
---|
335 | Properly delete the perFDaemon Client after sendStats is done |
---|
336 | */ |
---|
337 | |
---|
338 | void exitSendStats(); |
---|
339 | |
---|
340 | //Set the instantaneous latency |
---|
341 | void setInstantaneousLatency(double latency); |
---|
342 | |
---|
343 | /** |
---|
344 | @param q_iovec QUANTAnet_iovec_c |
---|
345 | @param blockingtype QUANTAnet_tcpClient_c::BLOCKING or, NON_BLOCKING |
---|
346 | @return 1 if succed, or errno if fails |
---|
347 | comment:readv gives bad address error when iovec pointer is not initialized. |
---|
348 | */ |
---|
349 | int readv(QUANTAnet_iovec_c q_iovec, int blockingType); |
---|
350 | |
---|
351 | |
---|
352 | /** |
---|
353 | @param q_iovec QUANTAnet_iovec_c |
---|
354 | @param blockingtype QUANTAnet_tcpClient_c::BLOCKING or, NON_BLOCKING |
---|
355 | @return 1 if succed, or errno if fails |
---|
356 | comment:writev gives invalid argument error when iovec length is not initialized. |
---|
357 | */ |
---|
358 | int writev(QUANTAnet_iovec_c q_iovec, int blockingType); |
---|
359 | }; |
---|
360 | |
---|
361 | /** TCP Class for creating servers. This class bypasses QUANTA's standard method for |
---|
362 | establishing connections and provides the user with direct control of TCP connections. |
---|
363 | */ |
---|
364 | |
---|
365 | class QUANTAnet_tcpServer_c : public QUANTAnet_socketbase_c { |
---|
366 | |
---|
367 | |
---|
368 | protected: |
---|
369 | int serverPort; |
---|
370 | |
---|
371 | int timeOutPeriod; |
---|
372 | int sockfd; |
---|
373 | struct sockaddr_in serverInfo; |
---|
374 | |
---|
375 | public: |
---|
376 | |
---|
377 | //@{ |
---|
378 | /// Status ok. |
---|
379 | static const int OK/* = 1*/; |
---|
380 | |
---|
381 | /// Status failed. |
---|
382 | static const int FAILED/* = 0*/; |
---|
383 | |
---|
384 | /// Change the socket buffer size before read(). |
---|
385 | static const int READ_BUFFER_SIZE/* = 2*/; |
---|
386 | |
---|
387 | /// Change the socket buffer size before write(). |
---|
388 | static const int WRITE_BUFFER_SIZE/* = 3*/; |
---|
389 | |
---|
390 | //@} |
---|
391 | |
---|
392 | // static int QUANTAnet_tcpServer_c::NO_TIME_OUT; |
---|
393 | |
---|
394 | /** Set timeout period when performing read() or write() operations. |
---|
395 | @param t Time out period in seconds. Set to QUANTAnet_tcpClient_c::NO_TIME_OUT to set no time out period. |
---|
396 | */ |
---|
397 | void setTimeOut(int t) {timeOutPeriod = t;} |
---|
398 | |
---|
399 | /// Get timeout period. |
---|
400 | int getTimeOut() {return timeOutPeriod;} |
---|
401 | |
---|
402 | QUANTAnet_tcpServer_c(); |
---|
403 | virtual ~QUANTAnet_tcpServer_c() { if (sockfd) close(); } |
---|
404 | |
---|
405 | /// Get server's port. |
---|
406 | int getSelfPort() { |
---|
407 | return ntohs(serverInfo.sin_port); |
---|
408 | } |
---|
409 | |
---|
410 | /** Open the server on a port. |
---|
411 | Typically after this call you sit in a loop and call |
---|
412 | checkForNewConnections to wait for incoming connections. |
---|
413 | @return FAILED if failed, OK if success |
---|
414 | */ |
---|
415 | int init(int port); |
---|
416 | |
---|
417 | /** Allows you to change the parameters to the setsockopt() options.Currently this member allows you to change socket buffer size. |
---|
418 | |
---|
419 | @param option |
---|
420 | Specify QUANTAnet_tcpServer_c::READ_BUFFER_SIZE if you want to change the size of the receive buffer. |
---|
421 | Specify QUANTAnet_tcpServer_c::WRITE_BUFFER_SIZE if you want to change the size of the send buffer |
---|
422 | |
---|
423 | @param buffersize |
---|
424 | Specify the size. |
---|
425 | */ |
---|
426 | void setSockOptions(int option, int buffersize); |
---|
427 | |
---|
428 | /// Close the server port. |
---|
429 | int close(); |
---|
430 | |
---|
431 | /** Check to see if there is a request from clients for connection. |
---|
432 | This function checks for new connections. If there is a |
---|
433 | new connection, then a new QUANTAnet_tcpClient_c object is |
---|
434 | returned, and that object can be used to talk to the new |
---|
435 | client. |
---|
436 | |
---|
437 | @param blockingTime time to block while checking |
---|
438 | @return a new QUANTAnet_tcpClient_c object |
---|
439 | @see QUANTAnet_tcpClient_c class. |
---|
440 | */ |
---|
441 | QUANTAnet_tcpClient_c* checkForNewConnections(const int& blockingTime=0); |
---|
442 | |
---|
443 | /** Blocks while waiting for a new connection. |
---|
444 | While waiting for new connections to arrive, the server blocks |
---|
445 | until a new client has connected. This blocking wait results in |
---|
446 | better performance than the checkForNewConnections |
---|
447 | implementation. The server will block until a new client has |
---|
448 | connected, and when a client connects, a pointer to the new |
---|
449 | client object is returned. |
---|
450 | |
---|
451 | @return a new QUANTAnte_tcpClient_c object |
---|
452 | @see QUANTAnet_tcpClient_c class. |
---|
453 | */ |
---|
454 | QUANTAnet_tcpClient_c* waitForNewConnection(); |
---|
455 | |
---|
456 | }; |
---|
457 | |
---|
458 | #endif |
---|