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
|
#ifndef _KVI_SOCKET_H_
#define _KVI_SOCKET_H_
//=============================================================================
//
// File : kvi_socket.h
// Creation date : Thu Sep 20 03:50:22 2001 GMT by Szymon Stefanek
//
// This file is part of the KVirc irc client distribution
// Copyright (C) 2001 Szymon Stefanek (pragma at kvirc dot net)
//
// This program is FREE software. You can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your opinion) any later version.
//
// This program is distributed in the HOPE that it will be USEFUL,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, write to the Free Software Foundation,
// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
//=============================================================================
//=============================================================================
// Socket stuff abstraction layer
//=============================================================================
#include "kvi_settings.h"
#include "kvi_sockettype.h" // <--- this includes <winsock2.h> if needed
#include <errno.h>
#include "kvi_inttypes.h"
//#ifndef _KVI_SOCKET_CPP_
extern KVILIB_API kvi_u64_t g_uOutgoingTraffic;
extern KVILIB_API kvi_u64_t g_uIncomingTraffic;
//#endif //!_KVI_SOCKET_CPP_
#ifdef COMPILE_ON_WINDOWS
#define KVI_INVALID_SOCKET INVALID_SOCKET
#else
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <unistd.h>
#define KVI_INVALID_SOCKET (-1)
#endif
#ifndef MSG_NOSIGNAL
// At least solaris seems to not have it
#define MSG_NOSIGNAL 0
#endif
//#include "kvi_socketcalls.h"
//================================================================================================
// Constants for kvi_socket_create
//
#define KVI_SOCKET_PF_INET PF_INET
#define KVI_SOCKET_PF_INET6 PF_INET6
#define KVI_SOCKET_PF_UNIX PF_UNIX
#define KVI_SOCKET_TYPE_STREAM SOCK_STREAM
#define KVI_SOCKET_TYPE_DGRAM SOCK_DGRAM
#define KVI_SOCKET_PROTO_TCP 0
//================================================================================================
// kvi_socket_create
// kvi_socket_open
//
// Open a socket of the specified protocol family , type and protocol
// You should always use the KVI_SOCKET_* constants as parameters
// Returns KVI_INVALID_SOCKET if the socket creation has failed.
// The returned socket is in blocking mode!
//
#define kvi_socket_open kvi_socket_create
inline kvi_socket_t kvi_socket_create(int pf,int type,int proto)
{
return (kvi_socket_t)socket(pf,type,proto);
};
//================================================================================================
// kvi_socket_isValid
//
// Check if a socket is valid or not
//
inline void kvi_socket_flushTrafficCounters()
{
g_uOutgoingTraffic = 0;
g_uIncomingTraffic = 0;
}
inline bool kvi_socket_isValid(kvi_socket_t sock)
{
return (sock != ((kvi_socket_t)(KVI_INVALID_SOCKET)));
}
//================================================================================================
// kvi_socket_destroy
// kvi_socket_close
//
// Close a socket...that's all :)
//
#define kvi_socket_close kvi_socket_destroy
inline void kvi_socket_destroy(kvi_socket_t sock)
{
#ifdef COMPILE_ON_WINDOWS
closesocket(sock);
#else
close(sock);
#endif
};
//================================================================================================
// kvi_socket_setNonBlocking
//
// Sets the socket in nonBlocking mode. Obviously returns false in case of failure
//
inline bool kvi_socket_setNonBlocking(kvi_socket_t sock)
{
#ifdef COMPILE_ON_WINDOWS
unsigned long arg = 1;
return (ioctlsocket(sock,FIONBIO,(unsigned long FAR *)&arg) == 0);
#else
return (fcntl(sock,F_SETFL,O_NONBLOCK) == 0);
#endif
};
//================================================================================================
// kvi_socket_bind
//
// Standard bind() call on the socket. Returns false in case of failure
//
inline bool kvi_socket_bind(kvi_socket_t sock,const struct sockaddr * sa,int salen)
{
return (::bind(sock,sa,salen) == 0);
};
//================================================================================================
// kvi_socket_connect
//
// Starts a connection to the specified remote address
// returns false if the connection can not be started.
// You might take a look at kvi_socket_errno() then.
//
inline bool kvi_socket_connect(kvi_socket_t sock,const struct sockaddr *sa,int salen)
{
#ifdef COMPILE_ON_WINDOWS
return (WSAConnect(sock,sa,salen,0,0,0,0) == 0);
#else
return (::connect(sock,sa,salen) == 0);
#endif
};
inline bool kvi_socket_recoverableConnectError(int err)
{
#ifdef COMPILE_ON_WINDOWS
return ((err == WSAEINPROGRESS) || (err == WSAEWOULDBLOCK));
#else
return (err == EINPROGRESS);
#endif
};
inline bool kvi_socket_recoverableError(int err)
{
#ifdef COMPILE_ON_WINDOWS
return ((err == WSAEWOULDBLOCK) || (err == EINTR) || (err == EAGAIN));
#else
return ((err == EINTR) || (err = EAGAIN));
#endif
}
//================================================================================================
// kvi_socket_accept
//
// Standard accept() call. Returns KVI_INVALID_SOCKET in case of failure
// You should check kvi_socket_errno() then.
//
inline kvi_socket_t kvi_socket_accept(kvi_socket_t sock,struct sockaddr *sa,int * salen)
{
#ifdef COMPILE_ON_WINDOWS
return (kvi_socket_t)::accept(sock,sa,salen);
#else
return (kvi_socket_t)::accept(sock,sa,(socklen_t *)salen);
#endif
};
//================================================================================================
// kvi_socket_listen
//
// Standard listen() call. Returns false in case of failure
// You should check kvi_socket_errno() then.
//
inline bool kvi_socket_listen(kvi_socket_t sock,int backlog)
{
return (::listen(sock,backlog) == 0);
};
//================================================================================================
// kvi_socket_select
//
// Standard select() call. This is complex so here is a mini-reminder:
// nhpo is the number of the highest file descriptor in the sets plus one!
// Returns the number of sockets with data available (or space available)
// or something that is less than 0 in case of error. You should check kvi_socket_errno() then.
//
inline int kvi_socket_select(int nhpo,fd_set *r,fd_set *w,fd_set *e,struct timeval * t)
{
return ::select(nhpo,r,w,e,t);
};
//================================================================================================
// kvi_socket_send
// kvi_socket_write
//
// Standard send() call. On UNIX ignores SIGPIPE. Returns the number of bytes sent or
// -1 in case of failure. You should check kvi_socket_errno() then.
//
#define kvi_socket_write kvi_socket_send
inline int kvi_socket_send(kvi_socket_t sock,const void * buf,int size)
{
g_uOutgoingTraffic+=size;
#ifdef COMPILE_ON_WINDOWS
return ::send(sock,(const char *)buf,size,0);
#else
return ::send(sock,buf,size,MSG_NOSIGNAL | MSG_DONTWAIT);
#endif
};
//================================================================================================
// kvi_socket_recv
// kvi_socket_read
//
// Standard read() call. On UNIX ignores SIGPIPE. Returns the number of bytes readed or
// -1 in case of failure. You should check kvi_socket_errno() then.
//
#define kvi_socket_read kvi_socket_recv
inline int kvi_socket_recv(kvi_socket_t sock,void * buf,int maxlen)
{
int iReceived;
#ifdef COMPILE_ON_WINDOWS
iReceived = ::recv(sock,(char *)buf,maxlen,0);
#else
iReceived = ::recv(sock,buf,maxlen,MSG_NOSIGNAL);
#endif
g_uIncomingTraffic+=iReceived;
return iReceived;
};
//================================================================================================
// kvi_socket_getsockopt
//
// Standard getsockopt() call. Returns false in case of failure.
// You should check kvi_socket_errno() then.
//
inline bool kvi_socket_getsockopt(kvi_socket_t sock,int level,int optname,void *optval,int *optlen)
{
#ifdef COMPILE_ON_WINDOWS
return (::getsockopt(sock,level,optname,(char FAR *)optval,optlen) == 0);
#else
return (::getsockopt(sock,level,optname,optval,(socklen_t *)optlen) == 0);
#endif
}
//================================================================================================
// kvi_socket_setsockopt
//
// Standard setsockopt() call. Returns false in case of failure.
// You should check kvi_socket_errno() then.
//
inline bool kvi_socket_setsockopt(kvi_socket_t sock,int level,int optname,const void *optval,int optlen)
{
#ifdef COMPILE_ON_WINDOWS
return (::setsockopt(sock,level,optname,(char FAR *)optval,optlen) == 0);
#else
return (::setsockopt(sock,level,optname,optval,optlen) == 0);
#endif
}
//================================================================================================
// kvi_socket_disableNagle
//
// Disables the nagle algorithm (sets TCP_NODELAY)
//
/*
unused for now
inline bool kvi_socket_disableNagle(kvi_socket_t sock)
{
int opt = 1;
return kvi_socket_setsockopt(sock,IPPROTO_TCP,TCP_NODELAY,&opt,sizeof(opt));
};
*/
//================================================================================================
// kvi_socket_getsockname
//
// Standard getsockname() call. Returns false in case of failure.
// You should check kvi_socket_errno() then.
//
inline bool kvi_socket_getsockname(kvi_socket_t sock,struct sockaddr * addr,int * addrlen)
{
#ifdef COMPILE_ON_WINDOWS
return (::getsockname(sock,addr,addrlen) == 0);
#else
return (::getsockname(sock,addr,(socklen_t *)addrlen) == 0);
#endif
}
inline int kvi_socket_error()
{
#ifdef COMPILE_ON_WINDOWS
return WSAGetLastError();
#else
return errno;
#endif
}
#endif //_KVI_SOCKET_H_
|