JackNetUnixSocket.cpp 12.6 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);
336
        struct timeval timeout;
moret's avatar
moret committed
337

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

    //local loop**********************************************************************************************************
    int JackNetUnixSocket::SetLocalLoop()
    {
        char disable = 0;
Stephane Letz's avatar
Stephane Letz committed
357
        return SetOption(IPPROTO_IP, IP_MULTICAST_LOOP, &disable, sizeof(disable));
358
359
360
    }

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

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

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

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

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

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

    net_error_t JackNetUnixSocket::GetError()
    {
Stephane Letz's avatar
Stephane Letz committed
422
        switch(errno)
423
        {
moret's avatar
moret committed
424
            case EAGAIN:
sletz's avatar
sletz committed
425
            case ETIMEDOUT:
moret's avatar
moret committed
426
                return NET_NO_DATA;
sletz's avatar
sletz committed
427

moret's avatar
moret committed
428
429
430
            case ECONNABORTED:
            case ECONNREFUSED:
            case ECONNRESET:
sletz's avatar
sletz committed
431
            case EINVAL:
moret's avatar
moret committed
432
433
            case EHOSTDOWN:
            case EHOSTUNREACH:
sletz's avatar
sletz committed
434
435
            case ENETDOWN:
            case ENETUNREACH:
moret's avatar
moret committed
436
                return NET_CONN_ERROR;
sletz's avatar
sletz committed
437

moret's avatar
moret committed
438
            default:
sletz's avatar
sletz committed
439
440
                //return NET_OP_ERROR;
                return NET_CONN_ERROR;
441
442
        }
    }
sletz's avatar
sletz committed
443
}