revert breaks some stupid old compilers
[oscam.git] / oscam-net.c
blob0d9c5675dbf90c0d04dbe059d919b04c9f100fe5
1 #define MODULE_LOG_PREFIX "net"
3 #include "globals.h"
4 #include "oscam-client.h"
5 #include "oscam-failban.h"
6 #include "oscam-lock.h"
7 #include "oscam-net.h"
8 #include "oscam-string.h"
9 #include "oscam-time.h"
10 #include "oscam-work.h"
12 extern CS_MUTEX_LOCK gethostbyname_lock;
13 extern int32_t exit_oscam;
15 #ifndef IPV6SUPPORT
16 static int32_t inet_byteorder = 0;
18 static in_addr_t cs_inet_order(in_addr_t n)
20 if(!inet_byteorder)
21 { inet_byteorder = (inet_addr("1.2.3.4") + 1 == inet_addr("1.2.3.5")) ? 1 : 2; }
22 switch(inet_byteorder)
24 case 1:
25 break;
26 case 2:
27 n = ((n & 0xff000000) >> 24) |
28 ((n & 0x00ff0000) >> 8) |
29 ((n & 0x0000ff00) << 8) |
30 ((n & 0x000000ff) << 24);
31 break;
33 return n;
35 #endif
37 char *cs_inet_ntoa(IN_ADDR_T addr)
39 #ifdef IPV6SUPPORT
40 static char buff[INET6_ADDRSTRLEN];
41 if(IN6_IS_ADDR_V4MAPPED(&addr) || IN6_IS_ADDR_V4COMPAT(&addr))
43 snprintf(buff, sizeof(buff), "%d.%d.%d.%d",
44 addr.s6_addr[12], addr.s6_addr[13], addr.s6_addr[14], addr.s6_addr[15]);
46 else
48 inet_ntop(AF_INET6, &(addr.s6_addr), buff, INET6_ADDRSTRLEN);
50 return buff;
51 #else
52 struct in_addr in;
53 in.s_addr = addr;
54 return (char *)inet_ntoa(in);
55 #endif
58 void cs_inet_addr(char *txt, IN_ADDR_T *out)
60 #ifdef IPV6SUPPORT
61 char buff[INET6_ADDRSTRLEN];
62 //trying as IPv6 address
63 if(inet_pton(AF_INET6, txt, out->s6_addr) == 0)
65 //now trying as mapped IPv4
66 snprintf(buff, sizeof(buff), "::ffff:%s", txt);
67 inet_pton(AF_INET6, buff, out->s6_addr);
69 #else
70 *out = inet_addr(txt);
71 #endif
74 void cs_resolve(const char *hostname, IN_ADDR_T *ip, struct SOCKADDR *sock, socklen_t *sa_len)
76 #ifdef IPV6SUPPORT
77 cs_getIPv6fromHost(hostname, ip, sock, sa_len);
78 #else
79 *ip = cs_getIPfromHost(hostname);
80 if(sa_len)
81 { *sa_len = sizeof(*sock); }
82 #endif
85 #ifdef IPV6SUPPORT
86 int32_t cs_in6addr_equal(struct in6_addr *a1, struct in6_addr *a2)
88 return memcmp(a1, a2, 16) == 0;
91 int32_t cs_in6addr_lt(struct in6_addr *a, struct in6_addr *b)
93 int i;
94 for(i = 0; i < 4; i++)
96 if((i == 2) && ((IN6_IS_ADDR_V4COMPAT(a) && IN6_IS_ADDR_V4MAPPED(b)) ||
97 (IN6_IS_ADDR_V4COMPAT(b) && IN6_IS_ADDR_V4MAPPED(a))))
98 { continue; } //skip comparing this part
100 if(a->s6_addr32[i] != b->s6_addr32[i])
101 { return ntohl(a->s6_addr32[i]) < ntohl(b->s6_addr32[i]); }
104 return 0;
107 int32_t cs_in6addr_isnull(struct in6_addr *addr)
109 int i;
110 for(i = 0; i < 16; i++)
111 if(addr->s6_addr[i])
112 { return 0; }
113 return 1;
116 void cs_in6addr_copy(struct in6_addr *dst, struct in6_addr *src)
118 memcpy(dst, src, 16);
121 void cs_in6addr_ipv4map(struct in6_addr *dst, in_addr_t src)
123 memset(dst->s6_addr, 0, 16);
124 dst->s6_addr[10] = 0xff;
125 dst->s6_addr[11] = 0xff;
126 memcpy(dst->s6_addr + 12, &src, 4);
128 #endif
130 IN_ADDR_T get_null_ip(void)
132 IN_ADDR_T ip;
133 #ifdef IPV6SUPPORT
134 cs_inet_addr("::", &ip);
135 #else
136 ip = 0;
137 #endif
138 return ip;
141 void set_null_ip(IN_ADDR_T *ip)
143 #ifdef IPV6SUPPORT
144 cs_inet_addr("::", ip);
145 #else
146 *ip = 0;
147 #endif
150 void set_localhost_ip(IN_ADDR_T *ip)
152 #ifdef IPV6SUPPORT
153 cs_inet_addr("::1", ip);
154 #else
155 cs_inet_addr("127.0.0.1", ip);
156 #endif
159 int32_t check_ip(struct s_ip *ip, IN_ADDR_T n)
161 struct s_ip *p_ip;
162 int32_t ok = 0;
163 #ifdef IPV6SUPPORT
164 for(p_ip = ip; (p_ip) && (!ok); p_ip = p_ip->next)
166 ok = cs_in6addr_lt(&n, &p_ip->ip[0]);
167 ok |= cs_in6addr_lt(&p_ip->ip[1], &n);
168 ok = !ok;
170 #else
171 for(p_ip = ip; (p_ip) && (!ok); p_ip = p_ip->next)
172 { ok = ((cs_inet_order(n) >= cs_inet_order(p_ip->ip[0])) && (cs_inet_order(n) <= cs_inet_order(p_ip->ip[1]))); }
173 #endif
174 return ok;
177 /* Returns the ip from the given hostname. If gethostbyname is configured in the config file, a lock
178 will be held until the ip has been resolved. */
179 uint32_t cs_getIPfromHost(const char *hostname)
181 uint32_t result = 0;
182 //Resolve with gethostbyname:
183 if(cfg.resolve_gethostbyname)
185 cs_writelock(__func__, &gethostbyname_lock);
186 struct hostent *rht = gethostbyname(hostname);
187 if(!rht)
188 { cs_log("can't resolve %s", hostname); }
189 else
190 { result = ((struct in_addr *)rht->h_addr)->s_addr; }
191 cs_writeunlock(__func__, &gethostbyname_lock);
193 else //Resolve with getaddrinfo:
195 struct addrinfo hints, *res = NULL;
196 memset(&hints, 0, sizeof(hints));
197 hints.ai_socktype = SOCK_STREAM;
198 hints.ai_family = AF_INET;
199 hints.ai_protocol = IPPROTO_TCP;
201 int32_t err = getaddrinfo(hostname, NULL, &hints, &res);
202 if(err != 0 || !res || !res->ai_addr)
204 cs_log("can't resolve %s, error: %s", hostname, err ? gai_strerror(err) : "unknown");
206 else
208 result = ((struct sockaddr_in *)(res->ai_addr))->sin_addr.s_addr;
210 if(res) { freeaddrinfo(res); }
212 return result;
215 #ifdef IPV6SUPPORT
216 void cs_getIPv6fromHost(const char *hostname, struct in6_addr *addr, struct sockaddr_storage *sa, socklen_t *sa_len)
218 uint32_t ipv4addr = 0;
219 struct addrinfo hints, *res = NULL;
220 memset(&hints, 0, sizeof(hints));
221 hints.ai_socktype = SOCK_STREAM;
222 hints.ai_family = AF_UNSPEC;
223 hints.ai_protocol = IPPROTO_TCP;
224 int32_t err = getaddrinfo(hostname, NULL, &hints, &res);
225 if(err != 0 || !res || !res->ai_addr)
227 cs_log("can't resolve %s, error: %s", hostname, err ? gai_strerror(err) : "unknown");
229 else
231 ipv4addr = ((struct sockaddr_in *)(res->ai_addr))->sin_addr.s_addr;
232 if(res->ai_family == AF_INET)
233 { cs_in6addr_ipv4map(addr, ipv4addr); }
234 else
235 { IP_ASSIGN(*addr, SIN_GET_ADDR(*res->ai_addr)); }
236 if(sa)
237 { memcpy(sa, res->ai_addr, res->ai_addrlen); }
238 if(sa_len)
239 { *sa_len = res->ai_addrlen; }
241 if(res)
242 { freeaddrinfo(res); }
244 #endif
246 int set_socket_priority(int fd, int priority)
248 #if defined(IP_TOS) || defined(SO_PRIORITY)
249 if (priority == 0) { return -1; } // default value, therefore leave it untouched (IPP=0; DSCP=CS0)
251 int ret = 0;
252 int cos __attribute__ ((unused)) = 0;
253 int tos __attribute__ ((unused)) = 0x00;
255 switch (priority) {
256 case 1: // IPP=1; DSCP=CS1
257 cos = 1;
258 tos = 0x20;
259 break;
260 case 2: // IPP=1; DSCP=AF11
261 cos = 1;
262 tos = 0x28;
263 break;
264 case 3: // IPP=1; DSCP=AF12
265 cos = 1;
266 tos = 0x30;
267 break;
268 case 4: // IPP=1; DSCP=AF13
269 cos = 1;
270 tos = 0x38;
271 break;
272 case 5: // IPP=2; DSCP=CS2
273 cos = 2;
274 tos = 0x40;
275 break;
276 case 6: // IPP=2; DSCP=AF21
277 cos = 2;
278 tos = 0x48;
279 break;
280 case 7: // IPP=2; DSCP=AF22
281 cos = 2;
282 tos = 0x50;
283 break;
284 case 8: // IPP=2; DSCP=AF23
285 cos = 2;
286 tos = 0x58;
287 break;
288 case 9: // IPP=3; DSCP=CS3
289 cos = 3;
290 tos = 0x60;
291 break;
292 case 10: // IPP=3; DSCP=AF31
293 cos = 3;
294 tos = 0x68;
295 break;
296 case 11: // IPP=3; DSCP=AF32
297 cos = 3;
298 tos = 0x70;
299 break;
300 case 12: // IPP=3; DSCP=AF33
301 cos = 3;
302 tos = 0x78;
303 break;
304 case 13: // IPP=4; DSCP=CS4
305 cos = 4;
306 tos = 0x80;
307 break;
308 case 14: // IPP=4; DSCP=AF41
309 cos = 4;
310 tos = 0x88;
311 break;
312 case 15: // IPP=4; DSCP=AF42
313 cos = 4;
314 tos = 0x90;
315 break;
316 case 16: // IPP=4; DSCP=AF43
317 cos = 4;
318 tos = 0x98;
319 break;
320 case 17: // IPP=5; DSCP=CS5
321 cos = 5;
322 tos = 0xa0;
323 break;
324 case 18: // IPP=5; DSCP=EF
325 cos = 5;
326 tos = 0xb8;
327 break;
328 case 19: // IPP=6; DSCP=CS6
329 cos = 6;
330 tos = 0xc0;
331 break;
332 case 20: // IPP=7; DSCP=CS7
333 cos = 7;
334 tos = 0xe0;
335 break;
338 # ifdef IP_TOS
339 if (setsockopt(fd, IPPROTO_IP, IP_TOS, (void *)&tos, sizeof(tos)) < 0) {
340 cs_log("Setting IP_TOS failed, errno=%d, %s", errno, strerror(errno));
341 } else {
342 ret = ret ^ 0x01;
344 # if defined(IPV6SUPPORT) && defined(IPV6_TCLASS)
345 if (setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, (void *)&tos, sizeof(tos)) < 0) {
346 cs_log("Setting IPV6_TCLASS failed, errno=%d, %s", errno, strerror(errno));
347 } else {
348 ret = ret ^ 0x02;
350 # endif
351 # endif
353 # ifdef SO_PRIORITY
354 if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, (void *)&cos, sizeof(cos)) < 0) {
355 cs_log("Setting SO_PRIORITY failed, errno=%d, %s", errno, strerror(errno));
356 } else {
357 ret = ret ^ 0x04;
359 # endif
361 return ret;
362 #else
363 (void)fd;
364 (void)priority;
365 return -1;
366 #endif
369 void setTCPTimeouts(int32_t sock)
371 int32_t flag = 1;
372 // this is not only for a real keepalive but also to detect closed connections so it should not be configurable
373 if(setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &flag, sizeof(flag)) && errno != EBADF)
375 cs_log("Setting SO_KEEPALIVE failed, errno=%d, %s", errno, strerror(errno));
377 #if defined(TCP_KEEPIDLE) && defined(TCP_KEEPCNT) && defined(TCP_KEEPINTVL)
378 flag = 10;
379 if(setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &flag, sizeof(flag)) && errno != EBADF) //send first keepalive packet after 10 seconds of last package received (keepalive packets included)
381 cs_log("Setting TCP_KEEPIDLE failed, errno=%d, %s", errno, strerror(errno));
383 flag = 3;
384 if(setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &flag, sizeof(flag)) && errno != EBADF) //send up to 3 keepalive packets out (in interval TCP_KEEPINTVL), then disconnect if no response
386 cs_log("Setting TCP_KEEPCNT failed, errno=%d, %s", errno, strerror(errno));
388 flag = 1;
389 if(setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &flag, sizeof(flag)) && errno != EBADF)
391 ; //send a keepalive packet out every second (until answer has been received or TCP_KEEPCNT has been reached)
392 cs_log("Setting TCP_KEEPINTVL failed, errno=%d, %s", errno, strerror(errno));
394 #endif
395 struct timeval tv;
396 tv.tv_sec = 60;
397 tv.tv_usec = 0;
398 if(setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(struct timeval)) && errno != EBADF)
401 cs_log("Setting SO_SNDTIMEO failed, errno=%d, %s", errno, strerror(errno));
403 tv.tv_sec = 600;
404 tv.tv_usec = 0;
405 if(setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval)) && errno != EBADF)
408 cs_log("Setting SO_RCVTIMEO failed, errno=%d, %s", errno, strerror(errno));
410 #if defined(TCP_USER_TIMEOUT)
411 int timeout = 60000; // RFC 5482 user timeout in milliseconds
412 setsockopt(sock, SOL_TCP, TCP_USER_TIMEOUT, (char *) &timeout, sizeof(timeout));
413 #endif
416 int set_nonblock(int32_t fd, bool nonblock)
418 int32_t flags = fcntl(fd, F_GETFL);
419 if (flags == -1)
420 return -1;
421 if (nonblock)
422 flags |= O_NONBLOCK;
423 else
424 flags &= (~O_NONBLOCK);
425 return fcntl(fd, F_SETFL, flags);
428 int8_t check_fd_for_data(int32_t fd)
430 int32_t rc;
431 struct pollfd pfd[1];
433 pfd[0].fd = fd;
434 pfd[0].events = (POLLIN | POLLPRI);
435 rc = poll(pfd, 1, 0);
437 if(rc == -1)
438 { cs_log("check_fd_for_data(fd=%d) failed: (errno=%d %s)", fd, errno, strerror(errno)); }
440 if(rc == -1 || rc == 0)
441 { return rc; }
443 if(pfd[0].revents & (POLLHUP | POLLNVAL | POLLERR))
444 { return -2; }
446 return 1;
449 int32_t recv_from_udpipe(uint8_t *buf)
451 uint16_t n;
452 if(buf[0] != 'U')
454 cs_log("INTERNAL PIPE-ERROR");
455 cs_exit(1);
457 memcpy(&n, buf + 1, 2);
458 memmove(buf, buf + 3, n);
459 return n;
462 int32_t process_input(uint8_t *buf, int32_t buflen, int32_t timeout)
464 int32_t rc, i, pfdcount;
465 int64_t polltime, timeoutms;
466 struct pollfd pfd[2];
467 struct s_client *cl = cur_client();
469 struct timeb starttime;
470 struct timeb currenttime;
471 timeoutms = 1000 * timeout;
472 cs_ftime(&starttime);
473 polltime = timeoutms; // initial polltime = timeoutms
474 while(1)
476 pfdcount = 0;
477 if(cl->pfd)
479 pfd[pfdcount].fd = cl->pfd;
480 pfd[pfdcount++].events = POLLIN | POLLPRI;
482 int32_t p_rc = poll(pfd, pfdcount, polltime);
484 cs_ftime(&currenttime);
485 int64_t gone = comp_timeb(&currenttime, &starttime);
486 polltime = timeoutms - gone; // calculate polltime left
487 if(polltime < 0)
489 polltime = 0;
491 if(p_rc < 0)
493 if(errno == EINTR)
494 { continue; }
495 else
496 { return 0; }
499 if((p_rc == 0) && (timeout != 0) && (gone >= timeoutms)) // client maxidle reached? timeout = 0, idle disconnect disabled
501 rc = -9;
502 break;
505 for(i = 0; i < pfdcount && p_rc > 0; i++)
507 if(pfd[i].revents & POLLHUP) // POLLHUP is only valid in revents so it doesn't need to be set above in events
509 return 0;
511 if(!(pfd[i].revents & (POLLIN | POLLPRI)))
512 { continue; }
514 if(pfd[i].fd == cl->pfd)
515 { return get_module(cl)->recv(cl, buf, buflen); }
518 return rc;
521 static struct s_client *find_client_by_ip(IN_ADDR_T ip, in_port_t port)
523 struct s_client *cl;
524 for(cl = first_client; cl; cl = cl->next)
526 if(!cl->kill &&
527 IP_EQUAL(cl->ip, ip) && cl->port == port &&
528 (cl->typ == 'c' || cl->typ == 'm'))
530 return cl;
533 return NULL;
536 int32_t accept_connection(struct s_module *module, int8_t module_idx, int8_t port_idx)
538 struct SOCKADDR cad;
539 int32_t scad = sizeof(cad), n;
540 struct s_client *cl;
541 struct s_port *port = &module->ptab.ports[port_idx];
543 memset(&cad, 0, sizeof(struct SOCKADDR));
544 if(module->type == MOD_CONN_UDP)
546 uchar *buf;
547 if(!cs_malloc(&buf, 1024))
548 { return -1; }
549 if((n = recvfrom(port->fd, buf + 3, 1024 - 3, 0, (struct sockaddr *)&cad, (socklen_t *)&scad)) > 0)
551 uint16_t rl;
552 cl = find_client_by_ip(SIN_GET_ADDR(cad), ntohs(SIN_GET_PORT(cad)));
553 rl = n;
554 buf[0] = 'U';
555 memcpy(buf + 1, &rl, 2);
557 if(cs_check_violation(SIN_GET_ADDR(cad), port->s_port))
559 NULLFREE(buf);
560 return 0;
563 cs_log_dbg(D_TRACE, "got %d bytes on port %d from ip %s:%d client %s",
564 n, port->s_port,
565 cs_inet_ntoa(SIN_GET_ADDR(cad)), SIN_GET_PORT(cad),
566 username(cl));
568 if(!cl)
570 cl = create_client(SIN_GET_ADDR(cad));
571 if(!cl) { return 0; }
573 cl->module_idx = module_idx;
574 cl->port_idx = port_idx;
575 cl->udp_fd = port->fd;
576 cl->udp_sa = cad;
577 cl->udp_sa_len = sizeof(cl->udp_sa);
579 cl->port = ntohs(SIN_GET_PORT(cad));
580 cl->typ = 'c';
582 add_job(cl, ACTION_CLIENT_INIT, NULL, 0);
584 add_job(cl, ACTION_CLIENT_UDP, buf, n + 3);
586 else
587 { NULLFREE(buf); }
589 else //TCP
591 int32_t pfd3;
592 if((pfd3 = accept(port->fd, (struct sockaddr *)&cad, (socklen_t *)&scad)) > 0)
595 if(cs_check_violation(SIN_GET_ADDR(cad), port->s_port))
597 close(pfd3);
598 return 0;
601 cl = create_client(SIN_GET_ADDR(cad));
602 if(cl == NULL)
604 close(pfd3);
605 return 0;
608 int32_t flag = 1;
609 setsockopt(pfd3, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag));
610 setTCPTimeouts(pfd3);
612 cl->module_idx = module_idx;
613 cl->udp_fd = pfd3;
614 cl->port_idx = port_idx;
616 cl->pfd = pfd3;
617 cl->port = ntohs(SIN_GET_PORT(cad));
618 cl->typ = 'c';
620 add_job(cl, ACTION_CLIENT_INIT, NULL, 0);
623 return 0;
626 void set_so_reuseport(int fd) {
627 #ifdef SO_REUSEPORT
628 // See: http://stackoverflow.com/questions/3261965/so-reuseport-on-linux
629 int32_t on = 1;
630 setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (void *)&on, sizeof(on));
631 #else
632 fd = fd; // Do nothing
633 #endif
636 int32_t start_listener(struct s_module *module, struct s_port *port)
638 int32_t ov = 1, timeout, is_udp, i;
639 char ptxt[2][45];
640 struct SOCKADDR sad; // structure to hold server's address
641 socklen_t sad_len;
643 ptxt[0][0] = ptxt[1][0] = '\0';
644 if(!port->s_port)
646 cs_log_dbg(D_TRACE, "%s: disabled", module->desc);
647 return 0;
649 is_udp = (module->type == MOD_CONN_UDP);
651 memset(&sad, 0 , sizeof(sad));
652 #ifdef IPV6SUPPORT
653 SIN_GET_FAMILY(sad) = AF_INET6;
654 SIN_GET_ADDR(sad) = in6addr_any;
655 sad_len = sizeof(struct sockaddr_in6);
656 #else
657 sad.sin_family = AF_INET;
658 sad_len = sizeof(struct sockaddr);
659 if(!module->s_ip)
660 { module->s_ip = cfg.srvip; }
661 if(module->s_ip)
663 sad.sin_addr.s_addr = module->s_ip;
664 snprintf(ptxt[0], sizeof(ptxt[0]), ", ip=%s", inet_ntoa(sad.sin_addr));
666 else
668 sad.sin_addr.s_addr = INADDR_ANY;
670 #endif
671 timeout = cfg.bindwait;
672 port->fd = 0;
674 if(port->s_port > 0) // test for illegal value
676 SIN_GET_PORT(sad) = htons((uint16_t)port->s_port);
678 else
680 cs_log("%s: Bad port %d", module->desc, port->s_port);
681 return 0;
684 int s_type = (is_udp ? SOCK_DGRAM : SOCK_STREAM);
685 int s_proto = (is_udp ? IPPROTO_UDP : IPPROTO_TCP);
687 if((port->fd = socket(DEFAULT_AF, s_type, s_proto)) < 0)
689 cs_log("%s: Cannot create socket (errno=%d: %s)", module->desc, errno, strerror(errno));
690 #ifdef IPV6SUPPORT
691 cs_log("%s: Trying fallback to IPv4", module->desc);
692 if((port->fd = socket(AF_INET, s_type, s_proto)) < 0)
694 cs_log("%s: Cannot create socket (errno=%d: %s)", module->desc, errno, strerror(errno));
695 return 0;
697 #else
698 return 0;
699 #endif
702 #ifdef IPV6SUPPORT
703 // azbox toolchain do not have this define
704 #ifndef IPV6_V6ONLY
705 #define IPV6_V6ONLY 26
706 #endif
707 // set the server socket option to listen on IPv4 and IPv6 simultaneously
708 int val = 0;
709 if(setsockopt(port->fd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&val, sizeof(val)) < 0)
711 cs_log("%s: setsockopt(IPV6_V6ONLY) failed (errno=%d: %s)", module->desc, errno, strerror(errno));
713 #endif
715 ov = 1;
716 if(setsockopt(port->fd, SOL_SOCKET, SO_REUSEADDR, (void *)&ov, sizeof(ov)) < 0)
718 cs_log("%s: setsockopt failed (errno=%d: %s)", module->desc, errno, strerror(errno));
719 close(port->fd);
720 port->fd = 0;
721 return 0;
724 set_so_reuseport(port->fd);
726 int prio_ret = set_socket_priority(port->fd, cfg.netprio);
727 if (prio_ret > -1) {
728 snprintf(ptxt[1], sizeof(ptxt[1]), ", prio=%d [%s%s%s ]", cfg.netprio, prio_ret&0x04 ? " SO_PRIORITY" : "", prio_ret&0x01 ? " IP_TOS" : "", prio_ret&0x02 ? " IPV6_TCLASS" : "");
731 if(!is_udp)
733 int32_t keep_alive = 1;
734 setsockopt(port->fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keep_alive, sizeof(keep_alive));
737 while(timeout-- && !exit_oscam)
739 if(bind(port->fd, (struct sockaddr *)&sad, sad_len) < 0)
741 if(timeout)
743 cs_log("%s: Bind request failed (%s), waiting another %d seconds",
744 module->desc, strerror(errno), timeout);
745 cs_sleepms(1000);
747 else
749 cs_log("%s: Bind request failed (%s), giving up", module->desc, strerror(errno));
750 close(port->fd);
751 port->fd = 0;
752 return 0;
755 else
757 timeout = 0;
761 if(!is_udp)
763 if(listen(port->fd, CS_QLEN) < 0)
765 cs_log("%s: Cannot start listen mode (errno=%d: %s)", module->desc, errno, strerror(errno));
766 close(port->fd);
767 port->fd = 0;
768 return 0;
772 cs_log("%s: initialized (fd=%d, port=%d%s%s)",
773 module->desc, port->fd,
774 port->s_port,
775 ptxt[0], ptxt[1]);
777 for(i = 0; port->ncd && i < port->ncd->ncd_ftab.nfilts; i++)
779 int32_t j, pos = 0;
780 char buf[30 + (8 * port->ncd->ncd_ftab.filts[i].nprids)];
781 pos += snprintf(buf, sizeof(buf), "-> CAID: %04X PROVID: ", port->ncd->ncd_ftab.filts[i].caid);
783 for(j = 0; j < port->ncd->ncd_ftab.filts[i].nprids; j++)
784 { pos += snprintf(buf + pos, sizeof(buf) - pos, "%06X, ", port->ncd->ncd_ftab.filts[i].prids[j]); }
786 if(pos > 2 && j > 0)
787 { buf[pos - 2] = '\0'; }
789 cs_log("%s", buf);
792 return port->fd;
795 #ifdef __CYGWIN__
797 * Workaround missing MSG_WAITALL implementation under Cygwin.
799 ssize_t cygwin_recv(int sock, void *buf, int count, int tflags)
801 char *bp = buf;
802 int n = 0;
804 if ((n = recv(sock, bp, count, tflags)) < 0)
806 return(n);
809 if (n < count && (tflags & MSG_WAITALL))
811 cs_log_dbg(D_TRACE, "Cygwin socket read retry. Got %d expected %d", n, count);
813 int n2 = recv(sock, bp + n, count - n, tflags);
814 if (n2 < 0 || n + n2 != count)
816 cs_log_dbg(D_TRACE, "Cygwin socket read retry failed. Got %d", n2);
817 if (n2 < 0)
819 return(n2);
822 else
824 cs_log_dbg(D_TRACE, "Cygwin socket read retry success. Got %d - Total: %d", n2, n + n2);
827 n+= n2;
830 return n;
832 #endif /* __CYGWIN__ */