JackNetUnixSocket.cpp 12.8 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
26

namespace Jack
27
28
{
    //utility *********************************************************************************************************
Stephane Letz's avatar
Stephane Letz committed
29
    int GetHostName(char * name, int size)
30
    {
Stephane Letz's avatar
Stephane Letz committed
31
32
33
        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
34
            return SOCKET_ERROR;
35
36
37
38
39
40
41
42
        }
        return 0;
    }

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

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

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

77
78
79
80
81
    JackNetUnixSocket::~JackNetUnixSocket()
    {
        Close();
    }

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

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

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

Stephane Letz's avatar
Stephane Letz committed
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
    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;
        }
    }

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

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

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

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

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

    void JackNetUnixSocket::Close()
    {
Stephane Letz's avatar
Stephane Letz committed
172
173
        if (fSockfd)
            close(fSockfd);
174
175
176
177
178
179
        fSockfd = 0;
    }

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

    bool JackNetUnixSocket::IsSocket()
    {
Stephane Letz's avatar
Stephane Letz committed
191
        return(fSockfd) ? true : false;
192
193
194
    }

    //IP/PORT***********************************************************************************************************
Stephane Letz's avatar
Stephane Letz committed
195
    void JackNetUnixSocket::SetPort(int port)
196
197
    {
        fPort = port;
Stephane Letz's avatar
Stephane Letz committed
198
199
        fSendAddr.sin_port = htons(port);
        fRecvAddr.sin_port = htons(port);
200
201
202
203
204
205
206
207
    }

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

    //address***********************************************************************************************************
Stephane Letz's avatar
Stephane Letz committed
208
    int JackNetUnixSocket::SetAddress(const char* ip, int port)
209
    {
Stephane Letz's avatar
Stephane Letz committed
210
211
        int addr_conv = inet_aton(ip, &fSendAddr.sin_addr);
        if (addr_conv < 0)
212
            return addr_conv;
Stephane Letz's avatar
Stephane Letz committed
213
        fSendAddr.sin_port = htons(port);
214
215
216
217
218
        return 0;
    }

    char* JackNetUnixSocket::GetSendIP()
    {
Stephane Letz's avatar
Stephane Letz committed
219
        return inet_ntoa(fSendAddr.sin_addr);
220
221
222
223
    }

    char* JackNetUnixSocket::GetRecvIP()
    {
Stephane Letz's avatar
Stephane Letz committed
224
        return inet_ntoa(fRecvAddr.sin_addr);
225
226
227
    }

    //utility************************************************************************************************************
Stephane Letz's avatar
Stephane Letz committed
228
    int JackNetUnixSocket::GetName(char* name)
229
    {
Stephane Letz's avatar
Stephane Letz committed
230
        return gethostname(name, 255);
231
232
    }

Stephane Letz's avatar
Stephane Letz committed
233
    int JackNetUnixSocket::JoinMCastGroup(const char* ip)
234
235
    {
        struct ip_mreq multicast_req;
Stephane Letz's avatar
Stephane Letz committed
236
237
238
        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));
239
240
241
    }

    //options************************************************************************************************************
Stephane Letz's avatar
Stephane Letz committed
242
    int JackNetUnixSocket::SetOption(int level, int optname, const void* optval, socklen_t optlen)
243
    {
Stephane Letz's avatar
Stephane Letz committed
244
        return setsockopt(fSockfd, level, optname, optval, optlen);
245
246
    }

Stephane Letz's avatar
Stephane Letz committed
247
    int JackNetUnixSocket::GetOption(int level, int optname, void* optval, socklen_t* optlen)
248
    {
Stephane Letz's avatar
Stephane Letz committed
249
        return getsockopt(fSockfd, level, optname, optval, optlen);
250
251
    }

moret's avatar
moret committed
252
    //timeout************************************************************************************************************
sletz's avatar
sletz committed
253
254

#if defined(__sun__) || defined(sun)
Stephane Letz's avatar
Stephane Letz committed
255
    int JackNetUnixSocket::SetTimeOut(int us)
sletz's avatar
sletz committed
256
257
258
    {
        int	flags;
        fTimeOut = us;
sletz's avatar
sletz committed
259

sletz's avatar
sletz committed
260
261
262
263
        if ((flags = fcntl(fSockfd, F_GETFL, 0)) < 0) {
		    jack_error("JackNetUnixSocket::SetTimeOut error in fcntl F_GETFL");
		    return -1;
	    }
sletz's avatar
sletz committed
264

sletz's avatar
sletz committed
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
	    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
281

sletz's avatar
sletz committed
282
283
            tv.tv_sec = fTimeOut / 1000000;
	        tv.tv_usec = fTimeOut % 1000000;
sletz's avatar
sletz committed
284

sletz's avatar
sletz committed
285
286
	        FD_ZERO(&fdset);
	        FD_SET(fSockfd, &fdset);
sletz's avatar
sletz committed
287

sletz's avatar
sletz committed
288
289
	        do {
		        res = select(fSockfd + 1, &fdset, NULL, NULL, &tv);
Stephane Letz's avatar
Stephane Letz committed
290
	        } while(res < 0 && errno == EINTR);
sletz's avatar
sletz committed
291

sletz's avatar
sletz committed
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
	        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
310

sletz's avatar
sletz committed
311
            tv.tv_sec = fTimeOut / 1000000;
sletz's avatar
sletz committed
312
313
            tv.tv_usec = fTimeOut % 1000000;

sletz's avatar
sletz committed
314
315
	        FD_ZERO(&fdset);
	        FD_SET(fSockfd, &fdset);
sletz's avatar
sletz committed
316

sletz's avatar
sletz committed
317
318
	        do {
		        res = select(fSockfd + 1, NULL, &fdset, NULL, &tv);
Stephane Letz's avatar
Stephane Letz committed
319
	        } while(res < 0 && errno == EINTR);
sletz's avatar
sletz committed
320

sletz's avatar
sletz committed
321
322
323
324
325
326
327
328
329
330
331
332
	        if (res < 0) {
		        return res;
            } else if (res == 0) {
                errno = ETIMEDOUT;
		        return -1;
	        }
        }

        return 0;
    }

#else
Stephane Letz's avatar
Stephane Letz committed
333
    int JackNetUnixSocket::SetTimeOut(int us)
334
    {
Stephane Letz's avatar
Stephane Letz committed
335
        jack_log("JackNetUnixSocket::SetTimeout %d usecs", us);
moret's avatar
moret committed
336

moret's avatar
moret committed
337
        //negative timeout, or exceding 10s, return
Stephane Letz's avatar
Stephane Letz committed
338
        if ((us < 0) ||(us > 10000000))
moret's avatar
moret committed
339
            return SOCKET_ERROR;
340
        struct timeval timeout;
moret's avatar
moret committed
341

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

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

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

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

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

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

Stephane Letz's avatar
Stephane Letz committed
405
    int JackNetUnixSocket::Recv(void* buffer, size_t nbytes, int flags)
406
    {
sletz's avatar
sletz committed
407
408
409
    #if defined(__sun__) || defined(sun)
        if (WaitRead() < 0)
            return -1;
sletz's avatar
sletz committed
410
    #endif
Stephane Letz's avatar
Stephane Letz committed
411
        return recv(fSockfd, buffer, nbytes, flags);
412
413
    }

Stephane Letz's avatar
Stephane Letz committed
414
    int JackNetUnixSocket::CatchHost(void* buffer, size_t nbytes, int flags)
415
    {
Stephane Letz's avatar
Stephane Letz committed
416
        socklen_t addr_len = sizeof(socket_address_t);
sletz's avatar
sletz committed
417
418
419
    #if defined(__sun__) || defined(sun)
        if (WaitRead() < 0)
            return -1;
sletz's avatar
sletz committed
420
    #endif
Stephane Letz's avatar
Stephane Letz committed
421
        return recvfrom(fSockfd, buffer, nbytes, flags, reinterpret_cast<socket_address_t*>(&fSendAddr), &addr_len);
422
423
424
425
    }

    net_error_t JackNetUnixSocket::GetError()
    {
Stephane Letz's avatar
Stephane Letz committed
426
        switch(errno)
427
        {
moret's avatar
moret committed
428
            case EAGAIN:
sletz's avatar
sletz committed
429
            case ETIMEDOUT:
moret's avatar
moret committed
430
                return NET_NO_DATA;
sletz's avatar
sletz committed
431

moret's avatar
moret committed
432
433
434
            case ECONNABORTED:
            case ECONNREFUSED:
            case ECONNRESET:
sletz's avatar
sletz committed
435
            case EINVAL:
moret's avatar
moret committed
436
437
            case EHOSTDOWN:
            case EHOSTUNREACH:
sletz's avatar
sletz committed
438
439
            case ENETDOWN:
            case ENETUNREACH:
moret's avatar
moret committed
440
                return NET_CONN_ERROR;
sletz's avatar
sletz committed
441

moret's avatar
moret committed
442
            default:
sletz's avatar
sletz committed
443
444
                //return NET_OP_ERROR;
                return NET_CONN_ERROR;
445
446
        }
    }
sletz's avatar
sletz committed
447
}