JackNetUnixSocket.cpp 12.7 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;
102
103
        //if ((res = setsockopt(fSockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) < 0) {
        if ((res = setsockopt(fSockfd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on))) < 0) {
sletz's avatar
sletz committed
104
105
            StrError(NET_ERROR_CODE);
        }
106
107
108
        return fSockfd;
    }

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

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

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

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

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

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

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

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

    bool JackNetUnixSocket::IsSocket()
    {
Stephane Letz's avatar
Stephane Letz committed
186
        return(fSockfd) ? true : false;
187
188
189
    }

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

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

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

    char* JackNetUnixSocket::GetSendIP()
    {
Stephane Letz's avatar
Stephane Letz committed
214
        return inet_ntoa(fSendAddr.sin_addr);
215
216
217
218
    }

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

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

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

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

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

moret's avatar
moret committed
247
    //timeout************************************************************************************************************
sletz's avatar
sletz committed
248
249

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

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

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

sletz's avatar
sletz committed
277
278
            tv.tv_sec = fTimeOut / 1000000;
	        tv.tv_usec = fTimeOut % 1000000;
sletz's avatar
sletz committed
279

sletz's avatar
sletz committed
280
281
	        FD_ZERO(&fdset);
	        FD_SET(fSockfd, &fdset);
sletz's avatar
sletz committed
282

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

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

sletz's avatar
sletz committed
306
            tv.tv_sec = fTimeOut / 1000000;
sletz's avatar
sletz committed
307
308
            tv.tv_usec = fTimeOut % 1000000;

sletz's avatar
sletz committed
309
310
	        FD_ZERO(&fdset);
	        FD_SET(fSockfd, &fdset);
sletz's avatar
sletz committed
311

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

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

        return 0;
    }

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

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

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

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

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

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

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

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

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

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

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

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

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