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 <unistd.h>
#include <fcntl.h>
sletz's avatar
sletz committed
23
24

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

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

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

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

75
76
77
78
79
    JackNetUnixSocket::~JackNetUnixSocket()
    {
        Close();
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

moret's avatar
moret committed
250
    //timeout************************************************************************************************************
sletz's avatar
sletz committed
251
252

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

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

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

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

sletz's avatar
sletz committed
283
284
	        FD_ZERO(&fdset);
	        FD_SET(fSockfd, &fdset);
sletz's avatar
sletz committed
285

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

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

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

sletz's avatar
sletz committed
312
313
	        FD_ZERO(&fdset);
	        FD_SET(fSockfd, &fdset);
sletz's avatar
sletz committed
314

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

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

        return 0;
    }

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

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

340
        //less than 1sec
Stephane Letz's avatar
Stephane Letz committed
341
        if (us < 1000000) {
342
            timeout.tv_sec = 0;
moret's avatar
moret committed
343
            timeout.tv_usec = us;
Stephane Letz's avatar
Stephane Letz committed
344
        } else {
345
        //more than 1sec
Stephane Letz's avatar
Stephane Letz committed
346
347
348
349
            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;
350
        }
Stephane Letz's avatar
Stephane Letz committed
351
        return SetOption(SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
352
    }
sletz's avatar
sletz committed
353
#endif
354
355
356
357
358

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

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

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

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

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

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

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

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

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

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