static void alsa_set_sw_params(struct alsa_dev *dev, snd_pcm_t *handle, int period, int thres) { int ret; snd_pcm_sw_params_t *sw_params; ret = snd_pcm_sw_params_malloc(&sw_params); if (ret < 0) syslog_panic("Cannot allocate software parameters: %s\n", snd_strerror(ret)); ret = snd_pcm_sw_params_current(handle, sw_params); if (ret < 0) syslog_panic("Cannot initialize software parameters: %s\n", snd_strerror(ret)); ret = snd_pcm_sw_params_set_avail_min(handle, sw_params, period); if (ret < 0) syslog_panic("Cannot set minimum available count: %s\n", snd_strerror(ret)); if (thres) { ret = snd_pcm_sw_params_set_start_threshold(handle, sw_params, period); if (ret < 0) syslog_panic("Cannot set start mode: %s\n", snd_strerror(ret)); } ret = snd_pcm_sw_params(handle, sw_params); if (ret < 0) syslog_panic("Cannot set software parameters: %s\n", snd_strerror(ret)); snd_pcm_sw_params_free(sw_params); }
static void daemonize(const char *lockfile) { char pidstr[8]; mode_t lperm = S_IRWXU | S_IRGRP | S_IXGRP; /* 0750 */ int lfp; if (getppid() == 1) return; if (daemon(0, 1)) panic("Cannot daemonize: %s", strerror(errno)); to_std_log(&stdout); to_std_log(&stderr); umask(lperm); if (lockfile) { lfp = open(lockfile, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP); if (lfp < 0) syslog_panic("Cannot create lockfile at %s! " "curvetun server already running?\n", lockfile); slprintf(pidstr, sizeof(pidstr), "%u", getpid()); if (write(lfp, pidstr, strlen(pidstr)) <= 0) syslog_panic("Could not write pid to pidfile %s", lockfile); close(lfp); } }
static void alsa_set_hw_params(struct alsa_dev *dev, snd_pcm_t *handle, unsigned int rate, int channels, int period) { int dir, ret; snd_pcm_uframes_t period_size; snd_pcm_uframes_t buffer_size; snd_pcm_hw_params_t *hw_params; ret = snd_pcm_hw_params_malloc(&hw_params); if (ret < 0) syslog_panic("Cannot allocate hardware parameters: %s\n", snd_strerror(ret)); ret = snd_pcm_hw_params_any(handle, hw_params); if (ret < 0) syslog_panic("Cannot initialize hardware parameters: %s\n", snd_strerror(ret)); ret = snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); if (ret < 0) syslog_panic("Cannot set access type: %s\n", snd_strerror(ret)); ret = snd_pcm_hw_params_set_format(handle, hw_params, SND_PCM_FORMAT_S16_LE); if (ret < 0) syslog_panic("Cannot set sample format: %s\n", snd_strerror(ret)); ret = snd_pcm_hw_params_set_rate_near(handle, hw_params, &rate, 0); if (ret < 0) syslog_panic("Cannot set sample rate: %s\n", snd_strerror(ret)); ret = snd_pcm_hw_params_set_channels(handle, hw_params, channels); if (ret < 0) syslog_panic("Cannot set channel number: %s\n", snd_strerror(ret)); period_size = period; dir = 0; ret = snd_pcm_hw_params_set_period_size_near(handle, hw_params, &period_size, &dir); if (ret < 0) syslog_panic("Cannot set period size: %s\n", snd_strerror(ret)); ret = snd_pcm_hw_params_set_periods(handle, hw_params, PERIODS, 0); if (ret < 0) syslog_panic("Cannot set period number: %s\n", snd_strerror(ret)); buffer_size = period_size * PERIODS; dir = 0; ret = snd_pcm_hw_params_set_buffer_size_near(handle, hw_params, &buffer_size); if (ret < 0) syslog_panic("Cannot set buffer size: %s\n", snd_strerror(ret)); ret = snd_pcm_hw_params(handle, hw_params); if (ret < 0) syslog_panic("Cannot set capture parameters: %s\n", snd_strerror(ret)); snd_pcm_hw_params_free(hw_params); }
static void thread_spawn_or_panic(unsigned int cpus, int efd, int refd, int tunfd, int ipv4, int udp) { int i, ret; cpu_set_t cpuset; unsigned int threads; threads = cpus * THREADS_PER_CPU; for (i = 0; i < threads; ++i) { CPU_ZERO(&cpuset); threadpool[i].cpu = i % cpus; CPU_SET(threadpool[i].cpu, &cpuset); ret = pipe2(threadpool[i].efd, O_NONBLOCK); if (ret < 0) syslog_panic("Cannot create event socket!\n"); threadpool[i].c = xmalloc_aligned(sizeof(*threadpool[i].c), 64); threadpool[i].parent.efd = efd; threadpool[i].parent.refd = refd; threadpool[i].parent.tunfd = tunfd; threadpool[i].parent.ipv4 = ipv4; threadpool[i].parent.udp = udp; threadpool[i].handler = udp ? handler_udp : handler_tcp; ret = pthread_create(&threadpool[i].trid, NULL, worker, &threadpool[i]); if (ret < 0) syslog_panic("Thread creation failed!\n"); ret = pthread_setaffinity_np(threadpool[i].trid, sizeof(cpuset), &cpuset); if (ret < 0) syslog_panic("Thread CPU migration failed!\n"); pthread_detach(threadpool[i].trid); } sleep(1); }
static void *worker(void *self) { int fd, old_state; ssize_t ret; size_t blen = TUNBUFF_SIZ; //FIXME const struct worker_struct *ws = self; struct pollfd fds; char *buff; fds.fd = ws->efd[0]; fds.events = POLLIN; ret = curve25519_alloc_or_maybe_die(ws->c); if (ret < 0) syslog_panic("Cannot init curve25519!\n"); buff = xmalloc_aligned(blen, 64); syslog(LOG_INFO, "curvetun thread on CPU%u up!\n", ws->cpu); pthread_cleanup_push(xfree_func, ws->c); pthread_cleanup_push(curve25519_free, ws->c); pthread_cleanup_push(xfree_func, buff); while (likely(!sigint)) { poll(&fds, 1, -1); if ((fds.revents & POLLIN) != POLLIN) continue; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state); while ((ret = read_exact(ws->efd[0], &fd, sizeof(fd), 1)) > 0) { if (ret != sizeof(fd)) { sched_yield(); continue; } ret = ws->handler(fd, ws, buff, blen); if (ret) write_exact(ws->parent.refd, &fd, sizeof(fd), 1); } pthread_setcancelstate(old_state, NULL); } syslog(LOG_INFO, "curvetun thread on CPU%u down!\n", ws->cpu); pthread_cleanup_pop(1); pthread_cleanup_pop(1); pthread_cleanup_pop(1); pthread_exit((void *) ((long) ws->cpu)); }
int server_main(char *home, char *dev, char *port, int udp, int ipv4, int log) { int lfd = -1, kdpfd, nfds, nfd, curfds, efd[2], refd[2], tunfd, i; unsigned int cpus = 0, threads, udp_cpu = 0; ssize_t ret; struct epoll_event *events; struct addrinfo hints, *ahead, *ai; auth_log = !!log; openlog("curvetun", LOG_PID | LOG_CONS | LOG_NDELAY, LOG_DAEMON); syslog(LOG_INFO, "curvetun server booting!\n"); syslog_maybe(!auth_log, LOG_INFO, "curvetun user logging disabled!\n"); parse_userfile_and_generate_user_store_or_die(home); memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = udp ? SOCK_DGRAM : SOCK_STREAM; hints.ai_protocol = udp ? IPPROTO_UDP : IPPROTO_TCP; hints.ai_flags = AI_PASSIVE; ret = getaddrinfo(NULL, port, &hints, &ahead); if (ret < 0) syslog_panic("Cannot get address info!\n"); for (ai = ahead; ai != NULL && lfd < 0; ai = ai->ai_next) { lfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (lfd < 0) continue; if (ai->ai_family == AF_INET6) { #ifdef IPV6_V6ONLY ret = set_ipv6_only(lfd); if (ret < 0) { close(lfd); lfd = -1; continue; } #else close(lfd); lfd = -1; continue; #endif /* IPV6_V6ONLY */ } set_reuseaddr(lfd); set_mtu_disc_dont(lfd); ret = bind(lfd, ai->ai_addr, ai->ai_addrlen); if (ret < 0) { close(lfd); lfd = -1; continue; } if (!udp) { ret = listen(lfd, 5); if (ret < 0) { close(lfd); lfd = -1; continue; } } if (ipv4 == -1) { ipv4 = (ai->ai_family == AF_INET6 ? 0 : (ai->ai_family == AF_INET ? 1 : -1)); } syslog_maybe(auth_log, LOG_INFO, "curvetun on IPv%d via %s " "on port %s!\n", ai->ai_family == AF_INET ? 4 : 6, udp ? "UDP" : "TCP", port); syslog_maybe(auth_log, LOG_INFO, "Allowed overlay proto is " "IPv%d!\n", ipv4 ? 4 : 6); } freeaddrinfo(ahead); if (lfd < 0 || ipv4 < 0) syslog_panic("Cannot create socket!\n"); tunfd = tun_open_or_die(dev ? dev : DEVNAME_SERVER, IFF_TUN | IFF_NO_PI); pipe_or_die(efd, O_NONBLOCK); pipe_or_die(refd, O_NONBLOCK); set_nonblocking(lfd); events = xzmalloc(MAX_EPOLL_SIZE * sizeof(*events)); for (i = 0; i < MAX_EPOLL_SIZE; ++i) events[i].data.fd = -1; kdpfd = epoll_create(MAX_EPOLL_SIZE); if (kdpfd < 0) syslog_panic("Cannot create socket!\n"); set_epoll_descriptor(kdpfd, EPOLL_CTL_ADD, lfd, udp ? EPOLLIN | EPOLLET | EPOLLONESHOT : EPOLLIN); set_epoll_descriptor(kdpfd, EPOLL_CTL_ADD, efd[0], EPOLLIN); set_epoll_descriptor(kdpfd, EPOLL_CTL_ADD, refd[0], EPOLLIN); set_epoll_descriptor(kdpfd, EPOLL_CTL_ADD, tunfd, EPOLLIN | EPOLLET | EPOLLONESHOT); curfds = 4; trie_init(); cpus = get_number_cpus_online(); threads = cpus * THREADS_PER_CPU; if (!ispow2(threads)) syslog_panic("Thread number not power of two!\n"); threadpool = xzmalloc(sizeof(*threadpool) * threads); thread_spawn_or_panic(cpus, efd[1], refd[1], tunfd, ipv4, udp); init_cpusched(threads); register_socket(tunfd); register_socket(lfd); syslog(LOG_INFO, "curvetun up and running!\n"); while (likely(!sigint)) { nfds = epoll_wait(kdpfd, events, curfds, -1); if (nfds < 0) { syslog(LOG_ERR, "epoll_wait error: %s\n", strerror(errno)); break; } for (i = 0; i < nfds; ++i) { if (unlikely(events[i].data.fd < 0)) continue; if (events[i].data.fd == lfd && !udp) { int ncpu; char hbuff[256], sbuff[256]; struct sockaddr_storage taddr; socklen_t tlen; tlen = sizeof(taddr); nfd = accept(lfd, (struct sockaddr *) &taddr, &tlen); if (nfd < 0) { syslog(LOG_ERR, "accept error: %s\n", strerror(errno)); continue; } if (curfds + 1 > MAX_EPOLL_SIZE) { close(nfd); continue; } curfds++; ncpu = register_socket(nfd); memset(hbuff, 0, sizeof(hbuff)); memset(sbuff, 0, sizeof(sbuff)); getnameinfo((struct sockaddr *) &taddr, tlen, hbuff, sizeof(hbuff), sbuff, sizeof(sbuff), NI_NUMERICHOST | NI_NUMERICSERV); syslog_maybe(auth_log, LOG_INFO, "New connection " "from %s:%s (%d active client connections) - id %d on CPU%d", hbuff, sbuff, curfds-4, nfd, ncpu); set_nonblocking(nfd); set_socket_keepalive(nfd); set_tcp_nodelay(nfd); ret = set_epoll_descriptor2(kdpfd, EPOLL_CTL_ADD, nfd, EPOLLIN | EPOLLET | EPOLLONESHOT); if (ret < 0) { close(nfd); curfds--; continue; } } else if (events[i].data.fd == refd[0]) { int fd_one; ret = read_exact(refd[0], &fd_one, sizeof(fd_one), 1); if (ret != sizeof(fd_one) || fd_one <= 0) continue; ret = set_epoll_descriptor2(kdpfd, EPOLL_CTL_MOD, fd_one, EPOLLIN | EPOLLET | EPOLLONESHOT); if (ret < 0) { close(fd_one); continue; } } else if (events[i].data.fd == efd[0]) { int fd_del, test; ret = read_exact(efd[0], &fd_del, sizeof(fd_del), 1); if (ret != sizeof(fd_del) || fd_del <= 0) continue; ret = read(fd_del, &test, sizeof(test)); if (ret < 0 && errno == EBADF) continue; ret = set_epoll_descriptor2(kdpfd, EPOLL_CTL_DEL, fd_del, 0); if (ret < 0) { close(fd_del); continue; } close(fd_del); curfds--; unregister_socket(fd_del); syslog_maybe(auth_log, LOG_INFO, "Closed connection " "with id %d (%d active client connections remain)\n", fd_del, curfds-4); } else { int cpu, fd_work = events[i].data.fd; if (!udp) cpu = socket_to_cpu(fd_work); else udp_cpu = (udp_cpu + 1) & (threads - 1); write_exact(threadpool[udp ? udp_cpu : cpu].efd[1], &fd_work, sizeof(fd_work), 1); } } } syslog(LOG_INFO, "curvetun prepare shut down!\n"); close(lfd); close(efd[0]); close(efd[1]); close(refd[0]); close(refd[1]); close(tunfd); thread_finish(cpus); xfree(threadpool); xfree(events); unregister_socket(lfd); unregister_socket(tunfd); destroy_cpusched(); trie_cleanup(); destroy_user_store(); syslog(LOG_INFO, "curvetun shut down!\n"); closelog(); return 0; }
int client_main(char *home, char *dev, char *host, char *port, int udp) { int fd = -1, tunfd = 0, retry_server = 0; int ret, try = 1, i; struct addrinfo hints, *ahead, *ai; struct pollfd fds[2]; struct curve25519_proto *p; struct curve25519_struct *c; char *buff; size_t blen = TUNBUFF_SIZ; //FIXME retry: if (!retry_server) { openlog("curvetun", LOG_PID | LOG_CONS | LOG_NDELAY, LOG_DAEMON); syslog(LOG_INFO, "curvetun client booting!\n"); } c = xmalloc(sizeof(struct curve25519_struct)); ret = curve25519_alloc_or_maybe_die(c); if (ret < 0) syslog_panic("Cannot init curve!\n"); p = get_serv_store_entry_proto_inf(); if (!p) syslog_panic("Cannot proto!\n"); memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = udp ? SOCK_DGRAM : SOCK_STREAM; hints.ai_protocol = udp ? IPPROTO_UDP : IPPROTO_TCP; hints.ai_flags = AI_NUMERICSERV; ret = getaddrinfo(host, port, &hints, &ahead); if (ret < 0) { syslog(LOG_ERR, "Cannot get address info! Retry!\n"); curve25519_free(c); xfree(c); fd = -1; retry_server = 1; closed_by_server = 0; sleep(1); goto retry; } for (ai = ahead; ai != NULL && fd < 0; ai = ai->ai_next) { fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (fd < 0) continue; ret = connect(fd, ai->ai_addr, ai->ai_addrlen); if (ret < 0) { syslog(LOG_ERR, "Cannot connect to remote, try %d: %s!\n", try++, strerror(errno)); close(fd); fd = -1; continue; } set_socket_keepalive(fd); set_mtu_disc_dont(fd); if (!udp) set_tcp_nodelay(fd); }
static void notify_init(int fd, int udp, struct curve25519_proto *p, struct curve25519_struct *c, char *home) { int fd2, i; ssize_t err, clen; size_t us_len, msg_len, pad; struct ct_proto hdr; char username[256], path[PATH_MAX], *us, *cbuff, *msg; unsigned char auth[crypto_auth_hmacsha512256_BYTES], *token; mt_init_by_random_device(); memset(&hdr, 0, sizeof(hdr)); hdr.flags |= PROTO_FLAG_INIT; memset(path, 0, sizeof(path)); slprintf(path, sizeof(path), "%s/%s", home, FILE_USERNAM); fd2 = open_or_die(path, O_RDONLY); memset(username, 0, sizeof(username)); err = read(fd2, username, sizeof(username)); username[sizeof(username) - 1] = 0; close(fd2); token = get_serv_store_entry_auth_token(); if (!token) syslog_panic("Cannot find auth token for server!\n"); us_len = sizeof(struct username_struct) + crypto_box_zerobytes; us = xzmalloc(us_len); err = username_msg(username, strlen(username) + 1, us + crypto_box_zerobytes, us_len - crypto_box_zerobytes); if (unlikely(err)) syslog_panic("Cannot create init message!\n"); clen = curve25519_encode(c, p, (unsigned char *) us, us_len, (unsigned char **) &cbuff); if (unlikely(clen <= 0)) syslog_panic("Init encrypt error!\n"); err = crypto_auth_hmacsha512256(auth, (unsigned char *) cbuff, clen, token); if (unlikely(err)) syslog_panic("Cannot create init hmac message!\n"); pad = mt_rand_int32() % 200; msg_len = clen + sizeof(auth) + pad; msg = xzmalloc(msg_len); memcpy(msg, auth, sizeof(auth)); memcpy(msg + sizeof(auth), cbuff, clen); for (i = sizeof(auth) + clen; i < msg_len; ++i) msg[i] = (uint8_t) mt_rand_int32(); hdr.payload = htons((uint16_t) msg_len); set_sock_cork(fd, udp); write_exact(fd, &hdr, sizeof(struct ct_proto), 0); write_exact(fd, msg, msg_len, 0); set_sock_uncork(fd, udp); xfree(msg); xfree(us); }
struct alsa_dev *alsa_open(char *devname, unsigned int rate, int channels, int period) { int ret; struct alsa_dev *dev; if (!devname) devname = "plughw:0,0"; dev = xzmalloc(sizeof(*dev)); dev->name = xstrdup(devname); dev->channels = channels; dev->period = period; ret = snd_pcm_open(&dev->capture_handle, dev->name, SND_PCM_STREAM_CAPTURE, 0); if (ret < 0) syslog_panic("Cannot open audio capture device %s: %s\n", dev->name, snd_strerror(ret)); alsa_set_hw_params(dev, dev->capture_handle, rate, channels, period); alsa_set_sw_params(dev, dev->capture_handle, period, 0); ret = snd_pcm_open(&dev->playback_handle, dev->name, SND_PCM_STREAM_PLAYBACK, 0); if (ret < 0) syslog_panic("Cannot open audio playback device %s: %s\n", dev->name, snd_strerror(ret)); alsa_set_hw_params(dev, dev->playback_handle, rate, channels, period); alsa_set_sw_params(dev, dev->playback_handle, period, 1); snd_pcm_link(dev->capture_handle, dev->playback_handle); ret = snd_pcm_prepare(dev->capture_handle); if (ret < 0) syslog_panic("Cannot prepare audio interface: %s\n", snd_strerror(ret)); ret = snd_pcm_prepare(dev->playback_handle); if (ret < 0) syslog_panic("Cannot prepare audio interface: %s\n", snd_strerror(ret)); dev->read_fds = snd_pcm_poll_descriptors_count(dev->capture_handle); dev->write_fds = snd_pcm_poll_descriptors_count(dev->playback_handle); dev->read_fd = xzmalloc(dev->read_fds * sizeof(*dev->read_fd)); ret = snd_pcm_poll_descriptors(dev->capture_handle, dev->read_fd, dev->read_fds); if (ret != dev->read_fds) syslog_panic("Cannot obtain capture file descriptors: %s\n", snd_strerror(ret)); dev->write_fd = xzmalloc(dev->write_fds * sizeof(*dev->write_fd)); ret = snd_pcm_poll_descriptors(dev->playback_handle, dev->write_fd, dev->write_fds); if (ret != dev->write_fds) syslog_panic("Cannot obtain playback file descriptors: %s\n", snd_strerror(ret)); return dev; }