初始提交
This commit is contained in:
212
lib/netutils.c
Normal file
212
lib/netutils.c
Normal file
@@ -0,0 +1,212 @@
|
||||
/**
|
||||
* Copyright (C) 2011-2012 Juho Vähä-Herttua
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
*==================================================================
|
||||
* modified by fduncanh 2022
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
int
|
||||
netutils_init()
|
||||
{
|
||||
#ifdef WIN32
|
||||
WORD wVersionRequested;
|
||||
WSADATA wsaData;
|
||||
int ret;
|
||||
|
||||
wVersionRequested = MAKEWORD(2, 2);
|
||||
ret = WSAStartup(wVersionRequested, &wsaData);
|
||||
if (ret) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (LOBYTE(wsaData.wVersion) != 2 ||
|
||||
HIBYTE(wsaData.wVersion) != 2) {
|
||||
/* Version mismatch, requested version not found */
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
netutils_cleanup()
|
||||
{
|
||||
#ifdef WIN32
|
||||
WSACleanup();
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned char *
|
||||
netutils_get_address(void *sockaddr, int *length, unsigned int *zone_id)
|
||||
{
|
||||
unsigned char ipv4_prefix[] = { 0,0,0,0,0,0,0,0,0,0,255,255 };
|
||||
struct sockaddr *address = sockaddr;
|
||||
|
||||
assert(address);
|
||||
assert(length);
|
||||
assert(zone_id);
|
||||
if (address->sa_family == AF_INET) {
|
||||
struct sockaddr_in *sin;
|
||||
*zone_id = 0;
|
||||
sin = (struct sockaddr_in *)address;
|
||||
*length = sizeof(sin->sin_addr.s_addr);
|
||||
return (unsigned char *)&sin->sin_addr.s_addr;
|
||||
} else if (address->sa_family == AF_INET6) {
|
||||
struct sockaddr_in6 *sin6;
|
||||
|
||||
sin6 = (struct sockaddr_in6 *)address;
|
||||
if (!memcmp(sin6->sin6_addr.s6_addr, ipv4_prefix, 12)) {
|
||||
/* Actually an embedded IPv4 address */
|
||||
*zone_id = 0;
|
||||
*length = sizeof(sin6->sin6_addr.s6_addr)-12;
|
||||
return (sin6->sin6_addr.s6_addr+12);
|
||||
}
|
||||
*zone_id = (unsigned int) sin6->sin6_scope_id;
|
||||
*length = sizeof(sin6->sin6_addr.s6_addr);
|
||||
return sin6->sin6_addr.s6_addr;
|
||||
}
|
||||
|
||||
*length = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
netutils_init_socket(unsigned short *port, int use_ipv6, int use_udp)
|
||||
{
|
||||
int family = use_ipv6 ? AF_INET6 : AF_INET;
|
||||
int type = use_udp ? SOCK_DGRAM : SOCK_STREAM;
|
||||
int proto = use_udp ? IPPROTO_UDP : IPPROTO_TCP;
|
||||
|
||||
struct sockaddr_storage saddr;
|
||||
socklen_t socklen;
|
||||
int server_fd;
|
||||
int ret;
|
||||
#ifndef _WIN32
|
||||
int reuseaddr = 1;
|
||||
#else
|
||||
const char reuseaddr = 1;
|
||||
#endif
|
||||
|
||||
assert(port);
|
||||
|
||||
server_fd = socket(family, type, proto);
|
||||
if (server_fd == -1) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof (reuseaddr));
|
||||
if (ret == -1) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
memset(&saddr, 0, sizeof(saddr));
|
||||
if (use_ipv6) {
|
||||
struct sockaddr_in6 *sin6ptr = (struct sockaddr_in6 *)&saddr;
|
||||
|
||||
/* Initialize sockaddr for bind */
|
||||
sin6ptr->sin6_family = family;
|
||||
sin6ptr->sin6_addr = in6addr_any;
|
||||
sin6ptr->sin6_port = htons(*port);
|
||||
|
||||
#ifndef _WIN32
|
||||
int v6only = 1;
|
||||
/* Make sure we only listen to IPv6 addresses */
|
||||
setsockopt(server_fd, IPPROTO_IPV6, IPV6_V6ONLY,
|
||||
(char *) &v6only, sizeof(v6only));
|
||||
#endif
|
||||
|
||||
socklen = sizeof(*sin6ptr);
|
||||
ret = bind(server_fd, (struct sockaddr *)sin6ptr, socklen);
|
||||
if (ret == -1) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = getsockname(server_fd, (struct sockaddr *)sin6ptr, &socklen);
|
||||
if (ret == -1) {
|
||||
goto cleanup;
|
||||
}
|
||||
*port = ntohs(sin6ptr->sin6_port);
|
||||
} else {
|
||||
struct sockaddr_in *sinptr = (struct sockaddr_in *)&saddr;
|
||||
|
||||
/* Initialize sockaddr for bind */
|
||||
sinptr->sin_family = family;
|
||||
sinptr->sin_addr.s_addr = INADDR_ANY;
|
||||
sinptr->sin_port = htons(*port);
|
||||
|
||||
socklen = sizeof(*sinptr);
|
||||
ret = bind(server_fd, (struct sockaddr *)sinptr, socklen);
|
||||
if (ret == -1) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = getsockname(server_fd, (struct sockaddr *)sinptr, &socklen);
|
||||
if (ret == -1) {
|
||||
goto cleanup;
|
||||
}
|
||||
*port = ntohs(sinptr->sin_port);
|
||||
}
|
||||
return server_fd;
|
||||
|
||||
cleanup:
|
||||
ret = SOCKET_GET_ERROR();
|
||||
if (server_fd != -1) {
|
||||
closesocket(server_fd);
|
||||
}
|
||||
SOCKET_SET_ERROR(ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Src is the ip address
|
||||
int
|
||||
netutils_parse_address(int family, const char *src, void *dst, int dstlen)
|
||||
{
|
||||
struct addrinfo *result;
|
||||
struct addrinfo *ptr;
|
||||
struct addrinfo hints;
|
||||
int length;
|
||||
int ret;
|
||||
|
||||
if (family != AF_INET && family != AF_INET6) {
|
||||
return -1;
|
||||
}
|
||||
if (!src || !dst) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = family;
|
||||
hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
|
||||
|
||||
ret = getaddrinfo(src, NULL, &hints, &result);
|
||||
if (ret != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
length = -1;
|
||||
for (ptr=result; ptr!=NULL; ptr=ptr->ai_next) {
|
||||
if (family == ptr->ai_family && (unsigned int)dstlen >= ptr->ai_addrlen) {
|
||||
memcpy(dst, ptr->ai_addr, ptr->ai_addrlen);
|
||||
length = ptr->ai_addrlen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
freeaddrinfo(result);
|
||||
return length;
|
||||
}
|
||||
Reference in New Issue
Block a user