JackNetUnixSocket.cpp 14.1 KB
Newer Older
sletz's avatar
sletz committed
1
/*
sletz's avatar
sletz committed
2
Copyright (C) 2008-2011 Romain Moret at Grame
sletz's avatar
sletz committed
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

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 option) 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., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

#include "JackNetUnixSocket.h"
sletz's avatar
sletz committed
21
22
#include "JackError.h"

sletz's avatar
sletz committed
23
24
#include <unistd.h>
#include <fcntl.h>
sletz's avatar
sletz committed
25

Stephane Letz's avatar
Stephane Letz committed
26
27
using namespace std;

sletz's avatar
sletz committed
28
namespace Jack
29
30
{
    //utility *********************************************************************************************************
Stephane Letz's avatar
Stephane Letz committed
31
    int GetHostName(char * name, int size)
32
    {
Stephane Letz's avatar
Stephane Letz committed
33
34
35
        if (gethostname(name, size) == SOCKET_ERROR) {
            jack_error("Can't get 'hostname' : %s", strerror(NET_ERROR_CODE));
            strcpy(name, "default");
moret's avatar
moret committed
36
            return SOCKET_ERROR;
37
38
39
40
41
42
43
44
        }
        return 0;
    }

    //construct/destruct***********************************************************************************************
    JackNetUnixSocket::JackNetUnixSocket()
    {
        fSockfd = 0;
moret's avatar
moret committed
45
        fPort = 0;
sletz's avatar
sletz committed
46
        fTimeOut = 0;
47
        fSendAddr.sin_family = AF_INET;
Stephane Letz's avatar
Stephane Letz committed
48
49
        fSendAddr.sin_addr.s_addr = htonl(INADDR_ANY);
        memset(&fSendAddr.sin_zero, 0, 8);
50
        fRecvAddr.sin_family = AF_INET;
Stephane Letz's avatar
Stephane Letz committed
51
52
        fRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
        memset(&fRecvAddr.sin_zero, 0, 8);
53
54
    }

Stephane Letz's avatar
Stephane Letz committed
55
    JackNetUnixSocket::JackNetUnixSocket(const char* ip, int port)
56
57
58
    {
        fSockfd = 0;
        fPort = port;
sletz's avatar
sletz committed
59
        fTimeOut = 0;
60
        fSendAddr.sin_family = AF_INET;
Stephane Letz's avatar
Stephane Letz committed
61
62
63
        fSendAddr.sin_port = htons(port);
        inet_aton(ip, &fSendAddr.sin_addr);
        memset(&fSendAddr.sin_zero, 0, 8);
64
        fRecvAddr.sin_family = AF_INET;
Stephane Letz's avatar
Stephane Letz committed
65
66
67
        fRecvAddr.sin_port = htons(port);
        fRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
        memset(&fRecvAddr.sin_zero, 0, 8);
68
69
    }

Stephane Letz's avatar
Stephane Letz committed
70
    JackNetUnixSocket::JackNetUnixSocket(const JackNetUnixSocket& socket)
71
    {
72
        fSockfd = 0;
sletz's avatar
sletz committed
73
        fTimeOut = 0;
74
75
76
77
78
        fPort = socket.fPort;
        fSendAddr = socket.fSendAddr;
        fRecvAddr = socket.fRecvAddr;
    }

79
80
81
82
83
    JackNetUnixSocket::~JackNetUnixSocket()
    {
        Close();
    }

Stephane Letz's avatar
Stephane Letz committed
84
    JackNetUnixSocket& JackNetUnixSocket::operator=(const JackNetUnixSocket& socket)
85
    {
Stephane Letz's avatar
Stephane Letz committed
86
        if (this != &socket) {
87
88
89
90
91
            fSockfd = 0;
            fPort = socket.fPort;
            fSendAddr = socket.fSendAddr;
            fRecvAddr = socket.fRecvAddr;
        }
92
        return *this;
93
94
    }

95
96
97
    //socket***********************************************************************************************************
    int JackNetUnixSocket::NewSocket()
    {
Stephane Letz's avatar
Stephane Letz committed
98
        if (fSockfd) {
99
100
101
            Close();
            Reset();
        }
Stephane Letz's avatar
Stephane Letz committed
102
        fSockfd = socket(AF_INET, SOCK_DGRAM, 0);
sletz's avatar
sletz committed
103

sletz's avatar
sletz committed
104
105
        /* Enable address reuse */
        int res, on = 1;
sletz's avatar
sletz committed
106
    #ifdef __APPLE__
107
        if ((res = setsockopt(fSockfd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on))) < 0) {
sletz's avatar
sletz committed
108
109
110
    #else
        if ((res = setsockopt(fSockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) < 0) {
    #endif
sletz's avatar
sletz committed
111
112
            StrError(NET_ERROR_CODE);
        }
113
114
115
        return fSockfd;
    }

Stephane Letz's avatar
Stephane Letz committed
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
    bool JackNetUnixSocket::IsLocal(char* ip)
    {
        if (strcmp(ip, "127.0.0.1") == 0) {
            return true;
        }

        char host_name[32];
        gethostname(host_name, sizeof(host_name));

        struct hostent* host = gethostbyname(host_name);
        if (host) {
            for (int i = 0; host->h_addr_list[i] != 0; ++i) {
                struct in_addr addr;
                memcpy(&addr, host->h_addr_list[i], sizeof(struct in_addr));
                if (strcmp(inet_ntoa(addr), ip) == 0) {
                    return true;
                }
            }
            return false;
        } else {
            return false;
        }
    }

140
141
    int JackNetUnixSocket::Bind()
    {
Stephane Letz's avatar
Stephane Letz committed
142
        return bind(fSockfd, reinterpret_cast<socket_address_t*>(&fRecvAddr), sizeof(socket_address_t));
143
144
    }

Stephane Letz's avatar
Stephane Letz committed
145
    int JackNetUnixSocket::BindWith(const char* ip)
146
    {
Stephane Letz's avatar
Stephane Letz committed
147
        int addr_conv = inet_aton(ip, &fRecvAddr.sin_addr);
Stephane Letz's avatar
Stephane Letz committed
148
        if (addr_conv < 0) {
149
            return addr_conv;
Stephane Letz's avatar
Stephane Letz committed
150
        }
151
152
153
        return Bind();
    }

Stephane Letz's avatar
Stephane Letz committed
154
    int JackNetUnixSocket::BindWith(int port)
155
    {
Stephane Letz's avatar
Stephane Letz committed
156
        fRecvAddr.sin_port = htons(port);
157
158
159
160
161
        return Bind();
    }

    int JackNetUnixSocket::Connect()
    {
Stephane Letz's avatar
Stephane Letz committed
162
        return connect(fSockfd, reinterpret_cast<socket_address_t*>(&fSendAddr), sizeof(socket_address_t));
163
164
    }

Stephane Letz's avatar
Stephane Letz committed
165
    int JackNetUnixSocket::ConnectTo(const char* ip)
166
    {
Stephane Letz's avatar
Stephane Letz committed
167
        int addr_conv = inet_aton(ip, &fSendAddr.sin_addr);
Stephane Letz's avatar
Stephane Letz committed
168
        if (addr_conv < 0) {
169
            return addr_conv;
Stephane Letz's avatar
Stephane Letz committed
170
        }
171
172
173
174
175
        return Connect();
    }

    void JackNetUnixSocket::Close()
    {
Stephane Letz's avatar
Stephane Letz committed
176
        if (fSockfd) {
Stephane Letz's avatar
Stephane Letz committed
177
            close(fSockfd);
Stephane Letz's avatar
Stephane Letz committed
178
        }
179
180
181
182
183
184
        fSockfd = 0;
    }

    void JackNetUnixSocket::Reset()
    {
        fSendAddr.sin_family = AF_INET;
Stephane Letz's avatar
Stephane Letz committed
185
186
187
        fSendAddr.sin_port = htons(fPort);
        fSendAddr.sin_addr.s_addr = htonl(INADDR_ANY);
        memset(&fSendAddr.sin_zero, 0, 8);
188
        fRecvAddr.sin_family = AF_INET;
Stephane Letz's avatar
Stephane Letz committed
189
190
191
        fRecvAddr.sin_port = htons(fPort);
        fRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
        memset(&fRecvAddr.sin_zero, 0, 8);
192
193
194
195
    }

    bool JackNetUnixSocket::IsSocket()
    {
Stephane Letz's avatar
Stephane Letz committed
196
        return(fSockfd) ? true : false;
197
198
199
    }

    //IP/PORT***********************************************************************************************************
Stephane Letz's avatar
Stephane Letz committed
200
    void JackNetUnixSocket::SetPort(int port)
201
202
    {
        fPort = port;
Stephane Letz's avatar
Stephane Letz committed
203
204
        fSendAddr.sin_port = htons(port);
        fRecvAddr.sin_port = htons(port);
205
206
207
208
209
210
211
212
    }

    int JackNetUnixSocket::GetPort()
    {
        return fPort;
    }

    //address***********************************************************************************************************
Stephane Letz's avatar
Stephane Letz committed
213
    int JackNetUnixSocket::SetAddress(const char* ip, int port)
214
    {
Stephane Letz's avatar
Stephane Letz committed
215
        int addr_conv = inet_aton(ip, &fSendAddr.sin_addr);
Stephane Letz's avatar
Stephane Letz committed
216
        if (addr_conv < 0) {
217
            return addr_conv;
Stephane Letz's avatar
Stephane Letz committed
218
        }
Stephane Letz's avatar
Stephane Letz committed
219
        fSendAddr.sin_port = htons(port);
220
221
222
223
224
        return 0;
    }

    char* JackNetUnixSocket::GetSendIP()
    {
Stephane Letz's avatar
Stephane Letz committed
225
        return inet_ntoa(fSendAddr.sin_addr);
226
227
228
229
    }

    char* JackNetUnixSocket::GetRecvIP()
    {
Stephane Letz's avatar
Stephane Letz committed
230
        return inet_ntoa(fRecvAddr.sin_addr);
231
232
233
    }

    //utility************************************************************************************************************
Stephane Letz's avatar
Stephane Letz committed
234
    int JackNetUnixSocket::GetName(char* name)
235
    {
Stephane Letz's avatar
Stephane Letz committed
236
        return gethostname(name, 255);
237
238
    }

Stephane Letz's avatar
Stephane Letz committed
239
    int JackNetUnixSocket::JoinMCastGroup(const char* ip)
240
241
    {
        struct ip_mreq multicast_req;
Stephane Letz's avatar
Stephane Letz committed
242
243
244
        inet_aton(ip, &multicast_req.imr_multiaddr);
        multicast_req.imr_interface.s_addr = htonl(INADDR_ANY);
        return SetOption(IPPROTO_IP, IP_ADD_MEMBERSHIP, &multicast_req, sizeof(multicast_req));
245
246
247
    }

    //options************************************************************************************************************
Stephane Letz's avatar
Stephane Letz committed
248
    int JackNetUnixSocket::SetOption(int level, int optname, const void* optval, socklen_t optlen)
249
    {
Stephane Letz's avatar
Stephane Letz committed
250
        return setsockopt(fSockfd, level, optname, optval, optlen);
251
252
    }

Stephane Letz's avatar
Stephane Letz committed
253
    int JackNetUnixSocket::GetOption(int level, int optname, void* optval, socklen_t* optlen)
254
    {
Stephane Letz's avatar
Stephane Letz committed
255
        return getsockopt(fSockfd, level, optname, optval, optlen);
256
257
    }

moret's avatar
moret committed
258
    //timeout************************************************************************************************************
sletz's avatar
sletz committed
259
260

#if defined(__sun__) || defined(sun)
Stephane Letz's avatar
Stephane Letz committed
261
    int JackNetUnixSocket::SetTimeOut(int us)
sletz's avatar
sletz committed
262
263
264
    {
        int	flags;
        fTimeOut = us;
sletz's avatar
sletz committed
265

sletz's avatar
sletz committed
266
267
268
269
        if ((flags = fcntl(fSockfd, F_GETFL, 0)) < 0) {
		    jack_error("JackNetUnixSocket::SetTimeOut error in fcntl F_GETFL");
		    return -1;
	    }
sletz's avatar
sletz committed
270

sletz's avatar
sletz committed
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
	    flags |= O_NONBLOCK;
	    if (fcntl(fSockfd, F_SETFL, flags) < 0) {
		    jack_error("JackNetUnixSocket::SetTimeOut error in fcntl F_SETFL");
		    return 1;
	    }

        return 0;
    }

    int JackNetUnixSocket::WaitRead()
    {
        if (fTimeOut > 0) {

            struct timeval tv;
	        fd_set fdset;
            ssize_t	res;
sletz's avatar
sletz committed
287

sletz's avatar
sletz committed
288
289
            tv.tv_sec = fTimeOut / 1000000;
	        tv.tv_usec = fTimeOut % 1000000;
sletz's avatar
sletz committed
290

sletz's avatar
sletz committed
291
292
	        FD_ZERO(&fdset);
	        FD_SET(fSockfd, &fdset);
sletz's avatar
sletz committed
293

sletz's avatar
sletz committed
294
295
	        do {
		        res = select(fSockfd + 1, &fdset, NULL, NULL, &tv);
Stephane Letz's avatar
Stephane Letz committed
296
	        } while (res < 0 && errno == EINTR);
sletz's avatar
sletz committed
297

sletz's avatar
sletz committed
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
	        if (res < 0) {
 		        return res;
            } else if (res == 0) {
                errno = ETIMEDOUT;
		        return -1;
	        }
        }

        return 0;
    }

    int JackNetUnixSocket::WaitWrite()
    {
        if (fTimeOut > 0) {

            struct timeval tv;
	        fd_set fdset;
            ssize_t	res;
sletz's avatar
sletz committed
316

sletz's avatar
sletz committed
317
            tv.tv_sec = fTimeOut / 1000000;
sletz's avatar
sletz committed
318
319
            tv.tv_usec = fTimeOut % 1000000;

sletz's avatar
sletz committed
320
321
	        FD_ZERO(&fdset);
	        FD_SET(fSockfd, &fdset);
sletz's avatar
sletz committed
322

sletz's avatar
sletz committed
323
324
	        do {
		        res = select(fSockfd + 1, NULL, &fdset, NULL, &tv);
Stephane Letz's avatar
Stephane Letz committed
325
	        } while (res < 0 && errno == EINTR);
sletz's avatar
sletz committed
326

sletz's avatar
sletz committed
327
328
329
330
331
332
333
334
335
336
337
338
	        if (res < 0) {
		        return res;
            } else if (res == 0) {
                errno = ETIMEDOUT;
		        return -1;
	        }
        }

        return 0;
    }

#else
Stephane Letz's avatar
Stephane Letz committed
339
    int JackNetUnixSocket::SetTimeOut(int us)
340
    {
Stephane Letz's avatar
Stephane Letz committed
341
        jack_log("JackNetUnixSocket::SetTimeout %d usecs", us);
342
        struct timeval timeout;
moret's avatar
moret committed
343

344
        //less than 1 sec
Stephane Letz's avatar
Stephane Letz committed
345
        if (us < 1000000) {
346
            timeout.tv_sec = 0;
moret's avatar
moret committed
347
            timeout.tv_usec = us;
Stephane Letz's avatar
Stephane Letz committed
348
        } else {
349
        //more than 1 sec
350
351
352
353
            float sec = float(us) / 1000000.f;
            timeout.tv_sec = (int)sec;
            float usec = (sec - float(timeout.tv_sec)) * 1000000;
            timeout.tv_usec =(int)usec;
354
        }
Stephane Letz's avatar
Stephane Letz committed
355
        return SetOption(SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
356
    }
sletz's avatar
sletz committed
357
#endif
358
359
360
361
362

    //local loop**********************************************************************************************************
    int JackNetUnixSocket::SetLocalLoop()
    {
        char disable = 0;
Stephane Letz's avatar
Stephane Letz committed
363
        return SetOption(IPPROTO_IP, IP_MULTICAST_LOOP, &disable, sizeof(disable));
364
365
366
    }

    //network operations**************************************************************************************************
Stephane Letz's avatar
Stephane Letz committed
367
    int JackNetUnixSocket::SendTo(const void* buffer, size_t nbytes, int flags)
368
    {
sletz's avatar
sletz committed
369
    #if defined(__sun__) || defined(sun)
Stephane Letz's avatar
Stephane Letz committed
370
        if (WaitWrite() < 0) {
sletz's avatar
sletz committed
371
            return -1;
Stephane Letz's avatar
Stephane Letz committed
372
        }
sletz's avatar
sletz committed
373
    #endif
Stephane Letz's avatar
Stephane Letz committed
374
        return sendto(fSockfd, buffer, nbytes, flags, reinterpret_cast<socket_address_t*>(&fSendAddr), sizeof(socket_address_t));
375
376
    }

Stephane Letz's avatar
Stephane Letz committed
377
    int JackNetUnixSocket::SendTo(const void* buffer, size_t nbytes, int flags, const char* ip)
378
    {
Stephane Letz's avatar
Stephane Letz committed
379
380
        int addr_conv = inet_aton(ip, &fSendAddr.sin_addr);
        if (addr_conv < 1)
381
            return addr_conv;
sletz's avatar
sletz committed
382
    #if defined(__sun__) || defined(sun)
Stephane Letz's avatar
Stephane Letz committed
383
        if (WaitWrite() < 0) {
sletz's avatar
sletz committed
384
            return -1;
Stephane Letz's avatar
Stephane Letz committed
385
        }
sletz's avatar
sletz committed
386
    #endif
Stephane Letz's avatar
Stephane Letz committed
387
        return SendTo(buffer, nbytes, flags);
388
389
    }

Stephane Letz's avatar
Stephane Letz committed
390
    int JackNetUnixSocket::Send(const void* buffer, size_t nbytes, int flags)
391
    {
sletz's avatar
sletz committed
392
    #if defined(__sun__) || defined(sun)
Stephane Letz's avatar
Stephane Letz committed
393
        if (WaitWrite() < 0) {
sletz's avatar
sletz committed
394
            return -1;
Stephane Letz's avatar
Stephane Letz committed
395
        }
sletz's avatar
sletz committed
396
    #endif
Stephane Letz's avatar
Stephane Letz committed
397
        return send(fSockfd, buffer, nbytes, flags);
398
399
    }

Stephane Letz's avatar
Stephane Letz committed
400
    int JackNetUnixSocket::RecvFrom(void* buffer, size_t nbytes, int flags)
401
    {
Stephane Letz's avatar
Stephane Letz committed
402
        socklen_t addr_len = sizeof(socket_address_t);
sletz's avatar
sletz committed
403
    #if defined(__sun__) || defined(sun)
Stephane Letz's avatar
Stephane Letz committed
404
        if (WaitRead() < 0) {
sletz's avatar
sletz committed
405
            return -1;
Stephane Letz's avatar
Stephane Letz committed
406
        }
sletz's avatar
sletz committed
407
    #endif
Stephane Letz's avatar
Stephane Letz committed
408
        return recvfrom(fSockfd, buffer, nbytes, flags, reinterpret_cast<socket_address_t*>(&fRecvAddr), &addr_len);
409
410
    }

Stephane Letz's avatar
Stephane Letz committed
411
    int JackNetUnixSocket::Recv(void* buffer, size_t nbytes, int flags)
412
    {
sletz's avatar
sletz committed
413
    #if defined(__sun__) || defined(sun)
Stephane Letz's avatar
Stephane Letz committed
414
        if (WaitRead() < 0) {
sletz's avatar
sletz committed
415
            return -1;
Stephane Letz's avatar
Stephane Letz committed
416
        }
sletz's avatar
sletz committed
417
    #endif
Stephane Letz's avatar
Stephane Letz committed
418
        return recv(fSockfd, buffer, nbytes, flags);
419
420
    }

Stephane Letz's avatar
Stephane Letz committed
421
    int JackNetUnixSocket::CatchHost(void* buffer, size_t nbytes, int flags)
422
    {
Stephane Letz's avatar
Stephane Letz committed
423
        socklen_t addr_len = sizeof(socket_address_t);
sletz's avatar
sletz committed
424
    #if defined(__sun__) || defined(sun)
Stephane Letz's avatar
Stephane Letz committed
425
        if (WaitRead() < 0) {
sletz's avatar
sletz committed
426
            return -1;
Stephane Letz's avatar
Stephane Letz committed
427
        }
sletz's avatar
sletz committed
428
    #endif
Stephane Letz's avatar
Stephane Letz committed
429
        return recvfrom(fSockfd, buffer, nbytes, flags, reinterpret_cast<socket_address_t*>(&fSendAddr), &addr_len);
430
431
432
433
    }

    net_error_t JackNetUnixSocket::GetError()
    {
Stephane Letz's avatar
Stephane Letz committed
434
        switch (errno) {
moret's avatar
moret committed
435
            case EAGAIN:
sletz's avatar
sletz committed
436
            case ETIMEDOUT:
moret's avatar
moret committed
437
                return NET_NO_DATA;
sletz's avatar
sletz committed
438

moret's avatar
moret committed
439
440
441
            case ECONNABORTED:
            case ECONNREFUSED:
            case ECONNRESET:
sletz's avatar
sletz committed
442
            case EINVAL:
moret's avatar
moret committed
443
444
            case EHOSTDOWN:
            case EHOSTUNREACH:
sletz's avatar
sletz committed
445
446
            case ENETDOWN:
            case ENETUNREACH:
moret's avatar
moret committed
447
                return NET_CONN_ERROR;
sletz's avatar
sletz committed
448

moret's avatar
moret committed
449
            default:
sletz's avatar
sletz committed
450
451
                //return NET_OP_ERROR;
                return NET_CONN_ERROR;
452
453
        }
    }
Stephane Letz's avatar
Stephane Letz committed
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
        
    void JackNetUnixSocket::PrintError()
    {
        switch (errno) {
                
            case EAGAIN:
                jack_error("JackNetUnixSocket : EAGAIN");
                break;
            case ETIMEDOUT:
                jack_error("JackNetUnixSocket : ETIMEDOUT");
                break;
            case ECONNABORTED:
                jack_error("JackNetUnixSocket : ECONNABORTED");
                break;
            case ECONNREFUSED:
                jack_error("JackNetUnixSocket : ECONNREFUSED");
                break;
            case ECONNRESET:
                jack_error("JackNetUnixSocket : ECONNRESET");
                break;
            case EINVAL:
                jack_error("JackNetUnixSocket : EINVAL");
                break;
            case EHOSTDOWN:
                jack_error("JackNetUnixSocket : EHOSTDOWN");
                break;
            case EHOSTUNREACH:
                jack_error("JackNetUnixSocket : EHOSTUNREACH");
                break;
            case ENETDOWN:
                jack_error("JackNetUnixSocket : ENETDOWN");
                break;
            case ENETUNREACH:
                jack_error("JackNetUnixSocket : ENETUNREACH");
                break;
            default:
                jack_error("JackNetUnixSocket : %d", errno);
                break;
        }
    }    
sletz's avatar
sletz committed
494
}