acl/lib_acl/samples/udp/udp.cpp
2018-12-12 11:16:12 +08:00

378 lines
9.1 KiB
C++

/**
* Copyright (C) 2015-2018
* All rights reserved.
*
* AUTHOR(S)
* Zheng Shuxin
* E-mail: zhengshuxin@qiyi.com
*
* VERSION
* Thu 25 May 2017 05:25:43 PM CST
*/
#include "stdafx.h"
#include "udp.h"
static bool host_port(char *buf, char **host, char **port)
{
const char *ptr = acl_host_port(buf, host, "", port, (char*) NULL);
if (ptr != NULL) {
acl_msg_error("%s(%d): invalid addr %s, %s",
__FILE__, __LINE__, buf, ptr);
return false;
}
if (*port == NULL || atoi(*port) < 0) {
acl_msg_error("%s(%d): invalid port: %s, addr: %s",
__FILE__, __LINE__, *port ? *port : "null", buf);
return false;
}
if (*host && **host == 0)
*host = 0;
if (*host == NULL)
*host = "0";
return true;
}
static struct addrinfo *host_addrinfo(const char *addr)
{
int err;
struct addrinfo hints, *res0;
char *buf = acl_mystrdup(addr), *host = NULL, *port = NULL;
if (host_port(buf, &host, &port) == false) {
acl_myfree(buf);
return NULL;
}
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
#ifdef ACL_MACOSX
hints.ai_flags = AI_DEFAULT;
#elif defined(ACL_ANDROID)
hints.ai_flags = AI_ADDRCONFIG;
#elif defined(ACL_WINDOWS)
hints.ai_protocol = IPPROTO_UDP;
# if _MSC_VER >= 1500
hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG;
# endif
#else
hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG;
#endif
if ((err = getaddrinfo(host, port, &hints, &res0))) {
acl_msg_error("%s(%d): getaddrinfo error %s, peer=%s",
__FILE__, __LINE__, gai_strerror(err), host);
acl_myfree(buf);
return NULL;
}
acl_myfree(buf);
return res0;
}
static int bind_addr(struct addrinfo *res0, struct addrinfo **res)
{
struct addrinfo *it;
int on, fd;
for (it = res0; it != NULL ; it = it->ai_next) {
fd = socket(it->ai_family, it->ai_socktype, it->ai_protocol);
if (fd == ACL_SOCKET_INVALID) {
acl_msg_error("%s(%d): create socket %s",
__FILE__, __LINE__, acl_last_serror());
return ACL_SOCKET_INVALID;
}
on = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
(const void *) &on, sizeof(on)) < 0)
{
acl_msg_warn("%s(%d): setsockopt(SO_REUSEADDR): %s",
__FILE__, __LINE__, acl_last_serror());
}
#if defined(SO_REUSEPORT)
on = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT,
(const void *) &on, sizeof(on)) < 0)
{
acl_msg_warn("%s(%d): setsocket(SO_REUSEPORT): %s",
__FILE__, __LINE__, acl_last_serror());
}
#endif
#ifdef ACL_WINDOWS
if (bind(fd, it->ai_addr, (int) it->ai_addrlen) == 0)
#else
if (bind(fd, it->ai_addr, it->ai_addrlen) == 0)
#endif
{
*res = it;
return fd;
}
acl_msg_error("%s(%d): bind error %s",
__FILE__, __LINE__, acl_last_serror());
acl_socket_close(fd);
}
return ACL_SOCKET_INVALID;
}
static SOCK_UDP *sock_open(const char *addr)
{
SOCK_UDP *sock;
struct addrinfo *res0, *res;
int fd;
res0 = host_addrinfo(addr);
if (res0 == NULL)
return NULL;
fd = bind_addr(res0, &res);
if (fd == ACL_SOCKET_INVALID) {
acl_msg_error("%s(%d): invalid socket", __FILE__, __LINE__);
freeaddrinfo(res0);
return NULL;
}
sock = (SOCK_UDP *) acl_mycalloc(1, sizeof(SOCK_UDP));
sock->fd = fd;
memcpy(&sock->sa_local, res->ai_addr, res->ai_addrlen);
sock->sa_local_len = res->ai_addrlen;
freeaddrinfo(res0);
return sock;
}
SOCK_UDP *udp_client_open(const char *local, const char *peer)
{
struct addrinfo *peer_res0 = host_addrinfo(peer);
SOCK_UDP *sock;
if (peer_res0 == NULL)
return NULL;
sock = sock_open(local);
if (sock == NULL) {
freeaddrinfo(peer_res0);
return NULL;
}
memcpy(&sock->sa_peer, peer_res0->ai_addr, peer_res0->ai_addrlen);
sock->sa_peer_len = peer_res0->ai_addrlen;
freeaddrinfo(peer_res0);
return sock;
}
SOCK_UDP *udp_server_open(const char *local)
{
return sock_open(local);
}
void udp_close(SOCK_UDP *sock)
{
acl_socket_close(sock->fd);
acl_myfree(sock);
}
int udp_read(SOCK_UDP *sock, void *buf, size_t size)
{
ssize_t ret;
sock->sa_peer_len = sizeof(sock->sa_peer);
ret = recvfrom(sock->fd, buf, size, 0,
(struct sockaddr *) &sock->sa_peer, &sock->sa_peer_len);
return ret;
}
int udp_send(SOCK_UDP *sock, const void *data, size_t len)
{
ssize_t ret = sendto(sock->fd, data, len, 0,
(struct sockaddr *) &sock->sa_peer, sock->sa_peer_len);
return ret;
}
void udp_pkt_set_buf(SOCK_PKT *pkt, char *buf, size_t len)
{
pkt->iov.iov_base = buf;
pkt->iov.iov_len = len;
pkt->addr_len = (socklen_t) sizeof(SOCK_ADDR);
}
int udp_pkt_set_peer(SOCK_PKT *pkt, const char *addr)
{
struct addrinfo *peer_res0 = host_addrinfo(addr);
if (peer_res0 == NULL)
return -1;
memcpy(&pkt->addr, peer_res0->ai_addr, peer_res0->ai_addrlen);
pkt->addr_len = peer_res0->ai_addrlen;
freeaddrinfo(peer_res0);
return 0;
}
int udp_mread(SOCK_UDP *sock, SOCK_PKT pkts[], size_t pkts_cnt)
{
unsigned int flags = MSG_WAITFORONE /* | MSG_DONTWAIT */;
size_t i;
if (sock->msgvec == NULL) {
sock->vlen = pkts_cnt;
sock->msgvec = (struct mmsghdr *)
acl_mycalloc(pkts_cnt, sizeof(struct mmsghdr));
} else if (sock->vlen < pkts_cnt) {
acl_myfree(sock->msgvec);
sock->vlen = pkts_cnt;
sock->msgvec = (struct mmsghdr *)
acl_mycalloc(pkts_cnt, sizeof(struct mmsghdr));
}
sock->pkts = pkts;
sock->pkts_cnt = pkts_cnt;
memset(sock->msgvec, 0, sizeof(struct mmsghdr) * pkts_cnt);
for (i = 0; i < pkts_cnt; i++) {
sock->msgvec[i].msg_hdr.msg_iov = &pkts[i].iov;
sock->msgvec[i].msg_hdr.msg_iovlen = 1;
sock->msgvec[i].msg_hdr.msg_name = &pkts[i].addr;
sock->msgvec[i].msg_hdr.msg_namelen = sizeof(pkts[i].addr);
sock->msgvec[i].msg_len = 0;
}
return recvmmsg(sock->fd, sock->msgvec, pkts_cnt, flags, NULL);
}
int udp_msend(SOCK_UDP *sock, SOCK_PKT pkts[], size_t pkts_cnt)
{
size_t i;
unsigned int flags = 0;
#ifndef __linux3__
int n = 0;
#endif
if (sock->msgvec == NULL) {
sock->vlen = pkts_cnt;
sock->msgvec = (struct mmsghdr *)
acl_mycalloc(pkts_cnt, sizeof(struct mmsghdr));
} else if (sock->vlen < pkts_cnt) {
acl_myfree(sock->msgvec);
sock->vlen = pkts_cnt;
sock->msgvec = (struct mmsghdr *)
acl_mycalloc(pkts_cnt, sizeof(struct mmsghdr));
}
sock->pkts = pkts;
sock->pkts_cnt = pkts_cnt;
memset(sock->msgvec, 0, sizeof(struct mmsghdr) * pkts_cnt);
for (i = 0; i < pkts_cnt; i++) {
sock->msgvec[i].msg_hdr.msg_iov = &pkts[i].iov;
sock->msgvec[i].msg_hdr.msg_iovlen = 1;
sock->msgvec[i].msg_hdr.msg_name = &pkts[i].addr;
sock->msgvec[i].msg_hdr.msg_namelen = sizeof(pkts[i].addr);
sock->msgvec[i].msg_len = 0;
#ifndef __linux3__
if (sendmsg(sock->fd, &sock->msgvec[i].msg_hdr, flags) < 0)
return -1;
n++;
#endif
}
#ifdef __linux3__
return sendmmsg(sock->fd, sock->msgvec, pkts_cnt, flags);
#else
return n;
#endif
}
int pkt_port(SOCK_PKT *pkt)
{
if (pkt->addr.sa.sa.sa_family == AF_INET) {
struct sockaddr_in *in = &pkt->addr.sa.in;
return ntohs(in->sin_port);
}
#ifdef AF_INET6
else if (pkt->addr.sa.sa.sa_family == AF_INET6) {
struct sockaddr_in6 *in = &pkt->addr.sa.in6;
return ntohl(in->sin6_port);
}
#endif
else {
acl_msg_error("%s(%d): unkown sa_family=%d",
__FUNCTION__, __LINE__, pkt->addr.sa.sa.sa_family);
return -1;
}
}
int udp_port(SOCK_UDP *sock, size_t i)
{
if (sock->msgvec == NULL) {
acl_msg_error("%s(%d): msgvec NULL", __FUNCTION__, __LINE__);
return -1;
}
if (sock->pkts == NULL) {
acl_msg_error("%s(%d): pkts NULL", __FUNCTION__, __LINE__);
return -1;
}
if (sock->pkts_cnt == 0) {
acl_msg_error("%s(%d): pkts_cnt 0", __FUNCTION__, __LINE__);
return -1;
}
if (i >= sock->pkts_cnt) {
acl_msg_error("%s(%d): invalid i=%d >= %d",
__FUNCTION__, __LINE__, (int) i, (int) sock->pkts_cnt);
return -1;
}
return pkt_port(&sock->pkts[i]);
}
const char *pkt_ip(SOCK_PKT *pkt, char *buf, size_t size)
{
if (pkt->addr.sa.sa.sa_family == AF_INET) {
struct sockaddr_in *in = &pkt->addr.sa.in;
return inet_ntop(in->sin_family, &in->sin_addr, buf, size);
}
#ifdef AF_INET6
else if (pkt->addr.sa.sa.sa_family == AF_INET6) {
struct sockaddr_in6 *in = &pkt->addr.sa.in6;
return inet_ntop(in->sin6_family, &in->sin6_addr, buf, size);
}
#endif
else {
acl_msg_error("%s(%d): unkown sa_family=%d",
__FUNCTION__, __LINE__, pkt->addr.sa.sa.sa_family);
return NULL;
}
}
const char *udp_ip(SOCK_UDP *sock, size_t i, char *buf, size_t size)
{
if (sock->msgvec == NULL) {
acl_msg_error("%s(%d): msgvec NULL", __FUNCTION__, __LINE__);
return NULL;
}
if (sock->pkts == NULL) {
acl_msg_error("%s(%d): pkts NULL", __FUNCTION__, __LINE__);
return NULL;
}
if (sock->pkts_cnt == 0) {
acl_msg_error("%s(%d): pkts_cnt 0", __FUNCTION__, __LINE__);
return NULL;
}
if (i >= sock->pkts_cnt) {
acl_msg_error("%s(%d): invalid i=%d >= %d",
__FUNCTION__, __LINE__, (int) i, (int) sock->pkts_cnt);
return NULL;
}
return pkt_ip(&sock->pkts[i], buf, size);
}