简单分析

https://github.com/lammertb/libhttp
c语言  WIN/UNIX
httplib_set_ports_option.c 线程:根据串创定[仅ipv4]或[仅ipv6]或[兼容4_6]的服务端监听,监听套接字入监听缓冲区
master_thread_run(void*thread_func_param)线程:监听缓冲区中的有效socket轮询poll查看,并
XX_httplib_accept_new_connection,掩码和属性设置,新连接套接字入客户端缓冲区
https://tools.ietf.org/html/rfc3513#section-2.2
so.sock = socket( so.lsa.sa.sa_family, SOCK_STREAM, 6 )
//the same port can be used again in the same process  /linux和WIN不一样
 setsockopt( so.sock, SOL_SOCKET, SO_REUSEADDR, (SOCK_OPT_TYPE)&on, sizeof(on) ) != 0 
only  ipv4========
so.lsa.sa.sa_family == AF_INET
len = sizeof(so.lsa.sin);
bind( so.sock, &so.lsa.sa, len ) != 0
only  ipv6========
int    off         = 0;
so.lsa.sa.sa_family == AF_INET6
  setsockopt( so.sock, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&off, sizeof(off)
len = sizeof(so.lsa.sin6);
both  ipv4-ipv6====
 sizeof(so.lsa.sin6);
bind( so.sock, &so.lsa.sa, len ) != 0 )
----------------------------------------------------------
 listen( so.sock, SOMAXCONN )
getsockname( so.sock, &(usa.sa), &len ) != 0  ||  usa.sa.sa_family  !=  so.lsa.sa.sa_family
if ( so.lsa.sa.sa_family == AF_INET6 ) so.lsa.sin6.sin6_port = usa.sin6.sin6_port;
		else             so.lsa.sin.sin_port   = usa.sin.sin_port;
//
httplib_master_thread.c
select   accept--

 

 connect() returns “invalid argument” with ipv6 address

https://stackoverflow.com/questions/12260003/connect-returns-invalid-argument-with-ipv6-address
即图部分文字,作为客户端使用getaddrinfo,使用本地连接【fe80..】需要指定接口id

Addresses starting with ff... are multicast addresses. Connecting a stream to a multicast address does not work.

Addresses starting with fe80... are link-local addresses, which have an interface identifier associated with them. Try looking at the sockaddr returned from getaddrinfo, is the scope field filled out?
share edit
answered Sep 4 '12 at 10:01
Simon Richter
24.6k11 gold badge3737 silver badges5757 bronze badges

    2
    This field should contain the interface number. Have you specified the scope with the %eth0 or %1 (1 being the interface number, which you can look up with the ip tool) notation?\ – Simon Richter Sep 4 '12 at 10:55
    Nope. When I do that, this scope field is filled with some value and it seems to work (although I need to configure my specific FW, but I get no invalid argument anymore). But I seem to miss something and in all the materials connected with ipv6 I was reading I didn't come across this - do I need to specify the interface whenever I use link-local address? – flyjohny Sep 4 '12 at 12:43
    4
    Yes, you do. Link-local address means precisely that uniqueness of the address is only guaranteed on this particular link, so the system has no way of finding out which interface to send the data to unless you tell it. The alternative is to assign addresses with global scope and use a routing table. – Simon Richter Sep 4 '12 at 15:01
    @SimonRichter - If I am using the local link address, does it mean that the scope_id field will be always 0 and we need to explicitly specify it ? Can system pick this automatically with any config in /etc/hosts ot any other config ? (Note : I have no DNS in place in my network) – kaps Jan 17 '19 at 5:26
    1
    @kaps, no, there is no way to have the system auto-select the interface. It is perfectly legal to have ppp0, ppp1 and ppp2 all configured to use a local address of fe80::1 and a peer address of fe80::2, so the OS could not decide which interface to use for a destination address of fe80::2. So the program needs to fill in the scope_id. When the addresses are configured by the user, getaddrinfo will fill it out when the user uses the % notation, when you use multicast for discovery, you can use the scope ID from the discovery packet's origin. – Simon Richter Jan 18 '19 at 2:07

Makefile编译make

obj= c2.o   ipv4_6s.o  ci6.o
CC=gcc  
CFLAGS= -Wall -g
CPPFLAGS= -lpthread
.PHONY:th
th:$(obj)
$(obj):%.o:%.c
	$(CC)  $(CFLAGS) $(<) $(CPPFLAGS) -o $(@)
clean:
	rm *.o

运行

 

 

./ipv4_6.s.o
./c2.o
./ci6.o  ::1/128  8080

 

c2.c  ipv4 客户端

 

#include<linux/sockios.h>
#include<sys/ioctl.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<string.h>
#include<stdio.h>
#include<errno.h>
void printfd(int sock)
{
	//thread  safe  C99
	socklen_t						peer_addr_size,selflen;
	struct sockaddr_in 			peer_addr,self;
	unsigned int				esme_port=0;
	char						esme_ip[200];
	int ern;
	int ret=0;
	peer_addr_size=sizeof(struct sockaddr);
	ret=getpeername(sock,(struct sockaddr*)&peer_addr,&peer_addr_size);
	ern=errno;
	if(!ret){
	printf("peer[%s]\n",inet_ntop(peer_addr.sin_family,&peer_addr.sin_addr,esme_ip,sizeof(esme_ip))); //ip  线程   inet_ntoa不安全  
	esme_port = ntohs(peer_addr.sin_port);
	printf("peer%d**[sock=%d] port[%d] ip[%s]\n",ret,sock,esme_port,esme_ip);
	}else
	{
		printf("peer %s\n",strerror(ern));
	}
	selflen=sizeof(struct sockaddr);
	ret=getsockname(sock, (struct sockaddr*)&self,&selflen);
	ern=errno;
	if(!ret){
	printf("self[%s]\n",inet_ntop(self.sin_family,&self.sin_addr,esme_ip,sizeof(esme_ip)));
	esme_port = ntohs(self.sin_port);
	printf("self%d**[sock=%d] port[%d] ip[%s]\n",ret,sock,esme_port,esme_ip);
	}else
	{
		printf("self %s\n",strerror(ern));
	}
}


int  main()
{
 
int sockClient;//客户端Socket
struct sockaddr_in addrServer;//服务端地址

//新建客户端socket
sockClient=socket(AF_INET,SOCK_STREAM,0);
if(sockClient<0)
{
	printf("socket errno\n");
	return 1;
}
//定义要连接的服务端地址
inet_pton(AF_INET, "127.0.0.1", &addrServer.sin_addr.s_addr);
//addrServer.sin_addr.s_addr=inet_addr("127.0.0.1");//目标IP(127.0.0.1是回送地址)
addrServer.sin_family=AF_INET;
addrServer.sin_port=htons(8080);//连接端口6000

//连接到服务端
if(connect(sockClient,(struct sockaddr*)&addrServer,sizeof(struct sockaddr))<0)
{
	printf("connect errno\n");
	return 1;
}

//发送数据
char message[100]="HelloSocket!";
send(sockClient,message,strlen(message)+1,0);
 printfd(sockClient);
//接受服务器返回,也可以用recv();并打印
int  bytes=0;
int ret;
sleep(1);
//ret=recv(sockClient,&bytes,sizeof(bytes),MSG_TRUNC );
//ret=ioctl(sockClient,SIOCINQ,&bytes);
//bytes=bytes>100?100:bytes;

//printf("ret%d Q-recv[%d]\n",ret,bytes);
//read(sockClient,message,bytes);
// printfd(sockClient);
//printf("%s",message);
 int sockfd=sockClient;


write(sockfd, "123", 3);  
    printf("wrote 3 bytes of normal data\n");  
    sleep(1);  
  
    send(sockfd, "4", 1, MSG_OOB);  
    printf("wrote 1 byte of OOB data\n");  
    sleep(1);  
  
    write(sockfd, "56", 2);  
    printf("wrote 2 bytes of normal data\n");  
    sleep(1);  
  
    send(sockfd, "mc7", 3, MSG_OOB);  
    printf("wrote 1 byte of OOB data\n");  
    sleep(1);  
  
    write(sockfd, "89", 2);  
    printf("wrote 2 bytes of normal data\n");  
    sleep(1);  
  
    exit(0);  



//关闭socket
close(sockClient);
return 0;}

 

ci6.c  ipv6客户端

 

#include <stdio.h>  
#include <string.h>  
#include <errno.h>  
#include <sys/socket.h>  
#include <resolv.h>  
#include <stdlib.h>  
#include <netinet/in.h>  
#include <arpa/inet.h>  
#include <unistd.h>  
#define MAXBUF 1024 
//源代码来自: https://blog.csdn.net/hepeng597/article/details/7803277
//仅ipv6  客户端
//ifconfig  inet6 看ipv6地址
//gcc ci6.c
//#运行  程序名  地址    端口
//run :./ci6.o  ::1/128  8080
//run :./ci6.o  fe40::20c:29ff:eec1:9896%eth0 8080 
int main(int argc, char **argv)  
{  
    int sockfd, len;  
    /* struct sockaddr_in dest; */ // IPv4  
    struct sockaddr_in6 dest;      // IPv6  
    char buffer[MAXBUF + 1];  
  
    if (argc != 3) {  
        printf  
            ("参数格式错误!正确用法如下:\n\t\t%s IP地址 端口\n\t比如:\t%s ::1/128 8080\n此程序用来从某个 IP 地址的服务器某个端口接收最多 MAXBUF 个字节的消息",  
             argv[0], argv[0]);  
        exit(0);  
    }  
    /* 创建一个 socket 用于 tcp 通信 */  
    /* if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { */ // IPv4  
    if ((sockfd = socket(AF_INET6, SOCK_STREAM, 0)) < 0) {      // IPv6  
        perror("Socket");  
        exit(errno);  
    }  
    printf("socket created\n");  
  
    /* 初始化服务器端(对方)的地址和端口信息 */  
    bzero(&dest, sizeof(dest));  
    /* dest.sin_family = AF_INET; */  // IPv4  
    dest.sin6_family = AF_INET6;     // IPv6  
    /* dest.sin_port = htons(atoi(argv[2])); */ // IPv4  
    dest.sin6_port = htons(atoi(argv[2]));     // IPv6  
    /* if (inet_aton(argv[1], (struct in_addr *) &dest.sin_addr.s_addr) == 0) { */ // IPv4  
    if ( inet_pton(AF_INET6, argv[1], &dest.sin6_addr) < 0 ) {                 // IPv6  
        perror(argv[1]);  
        exit(errno);  
    }  
    printf("address created\n");  
  
    /* 连接服务器 */  
    if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != 0) {  
        perror("Connect ");  
        exit(errno);  
    }  
    printf("server connected\n");  
  
    /* 接收对方发过来的消息,最多接收 MAXBUF 个字节 */  
    bzero(buffer, MAXBUF + 1);  
    /* 接收服务器来的消息 */  
    len = recv(sockfd, buffer, MAXBUF, 0);  
    if (len > 0)  
        printf("接收消息成功:'%s',共%d个字节的数据\n",  
               buffer, len);  
    else  
        printf  
            ("消息接收失败!错误代码是%d,错误信息是'%s'\n",  
             errno, strerror(errno));  
  
    bzero(buffer, MAXBUF + 1);  
    strcpy(buffer, "这是客户端发给服务器端的消息\n");  
    /* 发消息给服务器 */  
    len = send(sockfd, buffer, strlen(buffer), 0);  
    if (len < 0)  
        printf  
            ("消息'%s'发送失败!错误代码是%d,错误信息是'%s'\n",  
             buffer, errno, strerror(errno));  
    else  
        printf("消息'%s'发送成功,共发送了%d个字节!\n",  
               buffer, len);  
  
    /* 关闭连接 */  
    close(sockfd);  
    return 0;  
}  

 

ipv4_6s.c改造的服务端

 

#include<sys/socket.h>
#include<string.h>
#include<stdio.h>
#include <netdb.h>
#include <netinet/tcp.h>

#include<stdint.h>//uint64_t
#include <fcntl.h>
#include <poll.h>
#include<stdlib.h>//exit
#include<errno.h>
#include <stdbool.h>//bool
#include <unistd.h>//close
#include<malloc.h>
#include<pthread.h>

#if !defined(SOMAXCONN)
#define SOMAXCONN (100)
#endif

#define INVALID_SOCKET (-1)
#define IP_ADDR_STR_LEN (50) /* IPv6 hex string is 46 chars */
#define ERROR_STRING_LEN		(256)
#define ERRNO		errno
#define closesocket(fd)  close(fd)
#define IMGAPISTACKSIZE   10485760//10*1024*1024  线程栈  10MB

#define STRX(x) #x
#define STR(x) STRX(x)
#define __func__ __FILE__ ":" STR(__LINE__)
//
#define httplib_cry( a, ctx, b, format,...)  printf(format,##__VA_ARGS__)  

typedef int SOCKET;
/* Unified socket address. For IPv6 support, add IPv6 address structure in the
 * union u. */
union usa {
	struct sockaddr sa;
	struct sockaddr_in sin;
	struct sockaddr_in6 sin6;
};
/* Describes listening socket, or socket which was accept()-ed by the master
 * thread and queued for future handling by the worker thread. */
struct socket {
	SOCKET sock;			// Listening socket					
	union usa lsa;			// Local socket address				
	union usa rsa;			//Remote socket address				
	//bool has_ssl;			Is port SSL-ed					
	//bool has_redir;			Is port supposed to redirect everything to SSL port	
	unsigned char in_use;		// Is valid	
	
};

typedef const void *SOCK_OPT_TYPE;

/* Describes a string (chunk of memory). */
struct vec {
	const char *	ptr;
	size_t		len;
};
struct demolh_ctx_t {
	struct socket *listening_sockets;//malloc  relloc  free
	struct pollfd *listening_socket_fds;//malloc  relloc  free
	unsigned int num_listening_sockets;
	char *	listening_ports;//eg.+8080  #服务端ip46兼容   192.168.10.23:8080 #ipv4   [::1]:8080 #ipv6   192.168.10.23:6000,[::1]:8080 #多个 
};

//用一个size_t标记存的数据,因此a-1后申请空间
static int64_t				httplib_memory_blocks_used	= 0;
static int64_t				httplib_memory_bytes_used	= 0;
typedef void (*httplib_alloc_callback_func)( const char *file, unsigned line, const char *action, int64_t current_bytes, int64_t total_blocks, int64_t total_bytes );
static httplib_alloc_callback_func	alloc_log_func			= NULL;
#define					httplib_calloc(a, b) XX_httplib_calloc_ex(a, b, __FILE__, __LINE__)
#define					httplib_free(a) XX_httplib_free_ex(a, __FILE__, __LINE__)
#define					httplib_malloc(a) XX_httplib_malloc_ex(a, __FILE__, __LINE__)
#define					httplib_realloc(a, b) XX_httplib_realloc_ex(a, b, __FILE__, __LINE__)

void *			XX_httplib_calloc_ex( size_t count, size_t size, const char *file, unsigned line );
void *			XX_httplib_free_ex( void *memory, const char *file, unsigned line );
void *			XX_httplib_malloc_ex( size_t size, const char *file, unsigned line );
void *			XX_httplib_realloc_ex( void *memory, size_t newsize, const char *file, unsigned line );

void XX_httplib_close_all_listening_sockets( struct demolh_ctx_t *ctx ) {

	unsigned int i;

	if ( ctx == NULL ) return;

	for (i=0; i<ctx->num_listening_sockets; i++) {

		closesocket( ctx->listening_sockets[i].sock );
		ctx->listening_sockets[i].sock = INVALID_SOCKET;
	}

	ctx->listening_sockets    = httplib_free( ctx->listening_sockets    );
	ctx->listening_socket_fds = httplib_free( ctx->listening_socket_fds );

}  /* XX_close_all_listening_sockets */

void XX_httplib_set_close_on_exec( SOCKET fd ) { 
	fcntl( fd, F_SETFD, FD_CLOEXEC );
}  /* XX_httplib_set_close_on_exec */
int XX_httplib_inet_pton( int af, const char *src, void *dst, size_t dstlen ) {

	struct addrinfo hints;
	struct addrinfo *res;
	struct addrinfo *ressave;
	int func_ret;
	int gai_ret;

	func_ret = 0;

	memset( & hints, 0, sizeof(struct addrinfo) );
	hints.ai_family = af;

	gai_ret = getaddrinfo( src, NULL, &hints, &res );

	if ( gai_ret != 0 ) {

		/*
		 * gai_strerror could be used to convert gai_ret to a string
		 * POSIX return values: see
		 * http://pubs.opengroup.org/onlinepubs/9699919799/functions/freeaddrinfo.html
		 *
		 * Windows return values: see
		 * https://msdn.microsoft.com/en-us/library/windows/desktop/ms738520%28v=vs.85%29.aspx
		 */

		return 0;
	}
	ressave = res;
	while ( res ) {

		if ( dstlen >= res->ai_addrlen ) {

			memcpy( dst, res->ai_addr, res->ai_addrlen );
			func_ret = 1;
		}
		res = res->ai_next;
	}
	freeaddrinfo( ressave );

	return func_ret;

}  /* XX_httplib_inet_pton */
int XX_httplib_is_valid_port( unsigned long port ) {

	return ( port < 0xffff );

}  
/*略过LWS 
 *,分隔
 *eg:
 *list:80, 443s, 127.0.0.1:3128, 192.0.2.3:8080s
 *list:[::]:80, [::1]:80, [2001:0db8:7654:3210:FEDC:BA98:7654:3210]:443s
 *list:+8080
 */
/* XX_httplib_is_valid_port */
const char *XX_httplib_next_option( const char *list, struct vec *val, struct vec *eq_val ) {

	int end;

reparse:
	if ( val == NULL  ||  list == NULL  ||  *list == '\0' ) return NULL;
	
	/*
	 * Skip over leading LWS
	 */

	while ( *list == ' '  ||  *list == '\t' ) list++;

	val->ptr = list;
	if ( (list = strchr( val->ptr, ',' )) != NULL ) {

		/*
		 * Comma found. Store length and shift the list ptr
		 */

		val->len = ((size_t)(list - val->ptr));
		list++;
	}
	
	else {

		/*
		 * This value is the last one
		 */

		list     = val->ptr + strlen(val->ptr);
		val->len = ((size_t)(list - val->ptr));
	}

	/*
	 * Adjust length for trailing LWS
	 */

	end = (int)val->len - 1;
	while ( end >= 0  &&  ( val->ptr[end] == ' ' || val->ptr[end] == '\t' ) ) end--;

	val->len = (size_t)(end + 1);

	if ( val->len == 0 ) goto reparse; /* Ignore any empty entries. */

	if ( eq_val != NULL ) {

		/*
		 * Value has form "x=y", adjust pointers and lengths
		 * so that val points to "x", and eq_val points to "y".
		 */

		eq_val->len = 0;
		eq_val->ptr = (const char *)memchr( val->ptr, '=', val->len );

		if ( eq_val->ptr != NULL ) {

			eq_val->ptr++; /* Skip over '=' character */
			eq_val->len = ((size_t)(val->ptr - eq_val->ptr)) + val->len;
			val->len    = ((size_t)(eq_val->ptr - val->ptr)) - 1;
		}
	}

	return list;

}  /* XX_httplib_next_option */
char *httplib_error_string( int error_code, char *buf, size_t buf_len ) {

	if ( buf == NULL  ||  buf_len < 1 ) return NULL;
	strerror_r( error_code, buf, buf_len );
	return buf;

}  /* httplib_error_string */
static bool parse_port_string( const struct vec *vec, struct socket *so, int *ip_version ) {

	unsigned int a;
	unsigned int b;
	unsigned int c;
	unsigned int d;
	unsigned int port;
	int ch;
	int len;
	char buf[100] = {0};
	/*
	 * MacOS needs that. If we do not zero it, subsequent bind() will fail.
	 * Also, all-zeroes in the socket address means binding to all addresses
	 * for both IPv4 and IPv6 (INADDR_ANY and IN6ADDR_ANY_INIT).
	 */

	memset( so, 0, sizeof(*so) );
	so->lsa.sin.sin_family = AF_INET;
	*ip_version            = 0;
	if ( sscanf( vec->ptr, "%u.%u.%u.%u:%u%n", &a, &b, &c, &d, &port, &len ) == 5 ) {

		/*
		 * Bind to a specific IPv4 address, e.g. 192.168.1.5:8080
		 */

		so->lsa.sin.sin_addr.s_addr = htonl( (a << 24) | (b << 16) | (c << 8) | d );
		so->lsa.sin.sin_port        = htons( (uint16_t)port );

		*ip_version = 4;
	}
	else if ( sscanf( vec->ptr, "[%49[^]]]:%u%n", buf, &port, &len ) == 2  &&  XX_httplib_inet_pton( AF_INET6, buf, &so->lsa.sin6, sizeof(so->lsa.sin6) ) ) {

		/*
		 * IPv6 address, examples: see above
		 * so->lsa.sin6.sin6_family = AF_INET6; already set by httplib_inet_pton
		 */

		so->lsa.sin6.sin6_port = htons( (uint16_t)port );
		*ip_version = 6;
	}
	else if ( vec->ptr[0] == '+'  &&  sscanf( vec->ptr + 1, "%u%n", &port, &len ) == 1 ) {

		/*
		 * Port is specified with a +, bind to IPv6 and IPv4, INADDR_ANY
		 * Add 1 to len for the + character we skipped before
		 */

		len++;

		/*
		 * Set socket family to IPv6, do not use IPV6_V6ONLY
		 */
		so->lsa.sin6.sin6_family = AF_INET6;
		so->lsa.sin6.sin6_port   = htons(( uint16_t)port );

		*ip_version = 4 + 6;
	}
	else if ( sscanf( vec->ptr, "%u%n", &port, &len ) == 1 ) {

		/*
		 * If only port is specified, bind to IPv4, INADDR_ANY
		 */

		so->lsa.sin.sin_port = htons( (uint16_t)port );
		*ip_version = 4;

	}
	else {
		/*
		 * Parsing failure. Make port invalid.
		 */

		port = 0;
		len  = 0;
	}
	/*
	 * sscanf and the option splitting code ensure the following condition
	 */

	if ( len < 0 && ((unsigned)len) > ((unsigned)vec->len) ) {

		*ip_version = 0;
		return false;
	}

	ch            = vec->ptr[len]; /* Next character after the port number */
	//so->has_ssl   = ( ch == 's' );
	//so->has_redir = ( ch == 'r' );

	/*
	 * Make sure the port is valid and vector ends with 's', 'r' or ','
	 */

	if ( XX_httplib_is_valid_port( port )  &&  ( ch == '\0'  ||  ch == 's'  ||  ch == 'r'  ||  ch == ',' ) ) return true;

	/*
	 * Reset ip_version to 0 if there is an error
	 */

	*ip_version = 0;
	return false;

}  /* parse_port_string */

int demoXX_httplib_set_ports_option( struct demolh_ctx_t *ctx ) {

	const char *list;
	char error_string[ERROR_STRING_LEN];
	int on;
	int off;
	struct vec vec;
	struct socket so;
	struct socket *ptr;
	struct pollfd *pfd;
	union usa usa;
	socklen_t len;
	int ip_version;
	int ports_total;
	int ports_ok;

	if ( ctx == NULL ) return 0;

	on          = 1;
	off         = 0;
	ports_total = 0;
	ports_ok    = 0;

	memset( & so,  0, sizeof(so)  );
	memset( & usa, 0, sizeof(usa) );

	len  = sizeof(usa);
	list = ctx->listening_ports;

	while ( (list = XX_httplib_next_option( list, &vec, NULL )) != NULL ) {

		ports_total++;

		if ( ! parse_port_string( &vec, &so, &ip_version ) ) {

			httplib_cry( LH_DEBUG_CRASH, ctx, NULL, "%s: %.*s: invalid port spec (entry %i). Expecting list of: %s", __func__, (int)vec.len, vec.ptr, ports_total, "[IP_ADDRESS:]PORT[s|r]" );
			continue;
		}
		if ( ( so.sock = socket( so.lsa.sa.sa_family, SOCK_STREAM, 6 ) ) == INVALID_SOCKET ) {

			httplib_cry( LH_DEBUG_CRASH, ctx, NULL, "%s: cannot create socket (entry %i)", __func__, ports_total );
			continue;
		}

		if ( setsockopt( so.sock, SOL_SOCKET, SO_REUSEADDR, (SOCK_OPT_TYPE)&on, sizeof(on) ) != 0 ) {

			/*
			 * Set reuse option, but don't abort on errors.
			 */

			httplib_cry( LH_DEBUG_CRASH, ctx, NULL, "%s: cannot set socket option SO_REUSEADDR (entry %i)", __func__, ports_total );
		}

		if ( ip_version > 4 ) {

			if ( ip_version == 6 ) {

				if ( so.lsa.sa.sa_family == AF_INET6  &&  setsockopt( so.sock, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&off, sizeof(off) ) != 0 ) {

					/*
					 * Set IPv6 only option, but don't abort on errors.
					 */

					httplib_cry( LH_DEBUG_CRASH, ctx, NULL, "%s: cannot set socket option IPV6_V6ONLY (entry %i)", __func__, ports_total );
				}
			}
		}

		if ( so.lsa.sa.sa_family == AF_INET ) {

			len = sizeof(so.lsa.sin);

			if ( bind( so.sock, &so.lsa.sa, len ) != 0 ) {

				httplib_cry( LH_DEBUG_CRASH, ctx, NULL, "%s: cannot bind to %.*s: %d (%s)", __func__, (int)vec.len, vec.ptr, (int)ERRNO, httplib_error_string( ERRNO, error_string, ERROR_STRING_LEN ) );
				closesocket( so.sock );
				so.sock = INVALID_SOCKET;
				continue;
			}
		}

		else if ( so.lsa.sa.sa_family == AF_INET6 ) {

			len = sizeof(so.lsa.sin6);

			if ( bind( so.sock, &so.lsa.sa, len ) != 0 ) {

				httplib_cry( LH_DEBUG_CRASH, ctx, NULL, "%s: cannot bind to IPv6 %.*s: %d (%s)", __func__, (int)vec.len, vec.ptr, (int)ERRNO, httplib_error_string( ERRNO, error_string, ERROR_STRING_LEN ) );
				closesocket( so.sock );
				so.sock = INVALID_SOCKET;
				continue;
			}
		}

		else {
			httplib_cry( LH_DEBUG_CRASH, ctx, NULL, "%s: cannot bind: address family not supported (entry %i)", __func__, ports_total );
			continue;
		}

		if ( listen( so.sock, SOMAXCONN ) != 0 ) {

			httplib_cry( LH_DEBUG_CRASH, ctx, NULL, "%s: cannot listen to %.*s: %d (%s)", __func__, (int)vec.len, vec.ptr, (int)ERRNO, httplib_error_string( ERRNO, error_string, ERROR_STRING_LEN ) );
			closesocket( so.sock );
			so.sock = INVALID_SOCKET;
			continue;
		}

		if ( getsockname( so.sock, &(usa.sa), &len ) != 0  ||  usa.sa.sa_family  !=  so.lsa.sa.sa_family ) {

			int err = (int)ERRNO;
			httplib_cry( LH_DEBUG_CRASH, ctx, NULL, "%s: call to getsockname failed %.*s: %d (%s)", __func__, (int)vec.len, vec.ptr, err, httplib_error_string( ERRNO, error_string, ERROR_STRING_LEN ) );
			closesocket( so.sock );
			so.sock = INVALID_SOCKET;
			continue;
		}

/*
 * Update lsa port in case of random free ports
 */

		if ( so.lsa.sa.sa_family == AF_INET6 ) so.lsa.sin6.sin6_port = usa.sin6.sin6_port;
		else                                   so.lsa.sin.sin_port   = usa.sin.sin_port;

		ptr = httplib_realloc( ctx->listening_sockets, (ctx->num_listening_sockets+1) * sizeof(ctx->listening_sockets[0]) );

		if ( ptr != NULL ) ctx->listening_sockets = ptr;
		else {
			httplib_cry( LH_DEBUG_CRASH, ctx, NULL, "%s: out of memory on listening sockets", __func__ );
			closesocket( so.sock );
			so.sock = INVALID_SOCKET;
			continue;
		}


		pfd = httplib_realloc( ctx->listening_socket_fds, (ctx->num_listening_sockets+1) * sizeof(ctx->listening_socket_fds[0]) );

		if ( pfd != NULL ) ctx->listening_socket_fds = pfd;
		else {
			httplib_cry( LH_DEBUG_CRASH, ctx, NULL, "%s: out of memory on fds", __func__ );
			closesocket( so.sock );
			so.sock = INVALID_SOCKET;
			continue;
		}


		XX_httplib_set_close_on_exec( so.sock );

		ctx->listening_sockets[ctx->num_listening_sockets] = so;
		ctx->num_listening_sockets++;

		ports_ok++;
	}

	if ( ports_ok != ports_total ) {

		XX_httplib_close_all_listening_sockets( ctx );
		ports_ok = 0;
	}

	return ports_ok;

}  /* XX_httplib_set_ports_option */


 void *XX_httplib_realloc_ex( void *memory, size_t newsize, const char *file, unsigned line ) {

	size_t *olddata;
	size_t *newdata;
	size_t oldsize;
	int64_t diff;

	if ( newsize == 0 ) {

		if ( memory != NULL ) XX_httplib_free_ex( memory, file, line );
		return NULL;
	}

	if ( memory == NULL ) return XX_httplib_malloc_ex( newsize, file, line );

	olddata = ((size_t *)memory) - 1;
	oldsize = *olddata;
	newdata = realloc( olddata, newsize + sizeof(size_t) );
	if ( newdata == NULL ) {
		
		if ( alloc_log_func != NULL ) alloc_log_func( file, line, "realloc", 0, httplib_memory_blocks_used, httplib_memory_bytes_used );
		return NULL;
	}

	httplib_memory_bytes_used -= oldsize;
	httplib_memory_bytes_used += newsize;

	*newdata = newsize;
	diff     = ((int64_t)newsize) - ((int64_t)oldsize);

	if ( alloc_log_func != NULL ) alloc_log_func( file, line, "realloc", diff, httplib_memory_blocks_used, httplib_memory_bytes_used );

	return (newdata+1);

}  /* demoXX_httplib_realloc_ex */
void *XX_httplib_malloc_ex( size_t size, const char *file, unsigned line ) {

	size_t *data;

	if ( size == 0 ) {

		if ( alloc_log_func != NULL ) alloc_log_func( file, line, "malloc", 0, httplib_memory_blocks_used, httplib_memory_bytes_used );
		return NULL;
	}

	data = malloc( size + sizeof(size_t) );

	if ( data == NULL ) {
	
		if ( alloc_log_func != NULL ) alloc_log_func( file, line, "malloc", 0, httplib_memory_blocks_used, httplib_memory_bytes_used );
		return NULL;
	}

	httplib_memory_bytes_used += size;
	httplib_memory_blocks_used++;

	*data = size;

	if ( alloc_log_func != NULL ) alloc_log_func( file, line, "malloc", size, httplib_memory_blocks_used, httplib_memory_bytes_used );

	return (data+1);

}  /* XX_httplib_malloc_ex */
void *XX_httplib_free_ex( void *memory, const char *file, unsigned line ) {

	size_t *data;

	if ( memory == NULL ) return NULL;

	data = ((size_t *)memory) - 1;

	httplib_memory_bytes_used -= *data;
	httplib_memory_blocks_used--;

	if ( alloc_log_func != NULL ) alloc_log_func( file, line, "free", - ((int64_t)*data), httplib_memory_blocks_used, httplib_memory_bytes_used );

	free( data );

	return NULL;

}  /* XX_httplib_free_ex */
void *XX_httplib_calloc_ex( size_t count, size_t size, const char *file, unsigned line ) {

	void *data;

	data = XX_httplib_malloc_ex( size*count, file, line );
	if ( data == NULL ) return NULL;

	memset( data, 0x00, size*count );

	return data;

}  /* XX_httplib_calloc_ex */


int httplib_poll( struct pollfd *pfd, unsigned int n, int milliseconds ) 
{
		return poll( pfd, n, milliseconds );
}


void XX_httplib_sockaddr_to_string( char *buf, size_t len, const union usa *usa ) {

	if ( usa == NULL  ||  buf == NULL  ||  len < 1 ) return;

	buf[0] = '\0';

	if      ( usa->sa.sa_family == AF_INET  ) getnameinfo(&usa->sa, sizeof(usa->sin),  buf, (unsigned)len, NULL, 0, NI_NUMERICHOST );
	else if ( usa->sa.sa_family == AF_INET6 ) getnameinfo(&usa->sa, sizeof(usa->sin6), buf, (unsigned)len, NULL, 0, NI_NUMERICHOST );

}  /* XX_httplib_sockaddr_to_string */

void*PostRoutine(void*pram) 
{//Linux
	struct socket *psock=(struct socket *)pram;
	int connfd=psock->sock;
	int ret;
	free(pram);
	psock=pram=NULL;
	write(connfd,"you link libhttp ok !",24);
     char buf[1024];
    fd_set read_fds;
    fd_set exception_fds;
    FD_ZERO(&read_fds);
    FD_ZERO(&exception_fds);

    while(1)
    {
        memset(buf, '\0', sizeof(buf));
        /* 每次调用select前都要重新在read_fds和exception_fds中设置文件描述符connfd,因为事件发生之后,文件描述符集合将被内核修改 */
        FD_SET(connfd, &read_fds);
        FD_SET(connfd, &exception_fds);
        ret = select(connfd + 1, &read_fds, NULL, &exception_fds, NULL);
        if(ret < 0)
        {
            printf("selection failure\n");
            break;
        }

        /* 对于可读事件,采用普通的recv函数读取数据 */
        if(FD_ISSET(connfd, &read_fds))
        {
            ret = recv(connfd, buf, sizeof(buf) - 1, 0);
            if(ret <= 0)
            {
                break;
            }
            printf("get %d bytes of normal data: %s\n", ret, buf);
        }
        /* 对于异常事件,采用带MSG_OOB标志的recv函数读取带外数据 */
        else if(FD_ISSET(connfd, &exception_fds))
        {
            ret = recv(connfd, buf, sizeof(buf) - 1, MSG_OOB);
            if(ret <= 0)
            {
                break;
            }
            printf("get %d bytes of oob data: %s\n", ret, buf);
        }
    }
    close(connfd);
	pthread_exit(NULL);
}
int pthreadFormPost(void* psock) 
{//Linux
	int ret = 0;
	int eno;
	pthread_attr_t  attr; 
	pthread_t  pthreadid;
	struct socket *pram=NULL;
	ret=pthread_attr_init(&attr);
	if (0 != ret) 
	{
		printf("pthread_attr_init()error\n");
		return ret;
	}
	ret = pthread_attr_setstacksize(&attr, IMGAPISTACKSIZE);
	if (0 != ret)
	{
		printf("pthread_attr_setstacksize()error\n");
		return ret;
	}
	ret= pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);//ChildThread quit and free source
	if (0 != ret)
	{
		printf("pthread_attr_setdetachstate()error\n");
		return ret;
	}
	pram=malloc(sizeof(struct socket));
	if(NULL==pram)
	{
		printf("pthread malloc()error\n");
		return -1;
	}
	
    memcpy(pram,psock,sizeof(struct socket));
	ret = pthread_create(&pthreadid,&attr,PostRoutine,pram);
	eno = errno;
	if (0 != ret) 
	{
		free(pram);
		printf("pthread_create() errno:%d", eno); 
		return ret;
	}
	pthread_attr_destroy(&attr);
	return 0;
}

void demoXX_httplib_accept_new_connection( const struct socket *listener, struct demolh_ctx_t*ctx ) {

	struct socket so;
	//char src_addr[IP_ADDR_STR_LEN];
	char error_string[ERROR_STRING_LEN];
	socklen_t len;
	int on;

	if ( listener == NULL ) return;

	on  = 1;
	len = sizeof(so.rsa);

	so.sock = accept( listener->sock, &so.rsa.sa, &len );
	if ( so.sock == INVALID_SOCKET ) return;
		/*
		 * Put so socket structure into the queue
		 */
	//原来码此处 检验IP是否符合掩码要求
		XX_httplib_set_close_on_exec( so.sock );


		if ( getsockname( so.sock, &so.lsa.sa, &len ) != 0 ) {

			httplib_cry( LH_DEBUG_ERROR, ctx, NULL, "%s: getsockname() failed: %s", __func__, httplib_error_string( ERRNO, error_string, ERROR_STRING_LEN ) );
		}

	//原代码此处 开启TCP socket的 保活、 TCP Nagle's algorithm、收发超时设置 --此处删掉
	if(pthreadFormPost(&so)!=0)
	printf("pthreadFormPost error\n");

}  /* XX_httplib_accept_new_connection */
 void demomaster_thread_run(void*thread_func_param) 
{
	int i;
	struct demolh_ctx_t*ctx = (struct demolh_ctx_t*)thread_func_param;
	struct pollfd *pfd;
		pfd = ctx->listening_socket_fds;

	while (1) {

		for (i=0; i<(int)ctx->num_listening_sockets; i++) {

			pfd[i].fd     = ctx->listening_sockets[i].sock;
			pfd[i].events = POLLIN;
		}

		if ( httplib_poll( pfd, ctx->num_listening_sockets, 200 ) > 0 ) {

			for (i=0; i<(int)ctx->num_listening_sockets; i++) {

				/*
				 * NOTE(lsm): on QNX, poll() returns POLLRDNORM after the
				 * successful poll, and POLLIN is defined as
				 * (POLLRDNORM | POLLRDBAND)
				 * Therefore, we're checking pfd[i].revents & POLLIN, not
				 * pfd[i].revents == POLLIN.
				 */

				if ((pfd[i].revents & POLLIN)) 
				{	
					demoXX_httplib_accept_new_connection( & ctx->listening_sockets[i], ctx ); 
				}
			}
		}
	}
	
}
int  main()
{
	struct demolh_ctx_t ctx;
	memset(&ctx,0,sizeof(struct demolh_ctx_t));
	ctx.listening_ports="+8080";//sever  ipv4+ipv6  可监听多种端口
	  if(0==demoXX_httplib_set_ports_option(&ctx))//socket-bind->listen   
	  {
		  printf("demoXX_httplib_set_ports_option error\n");
		  exit(1);
	  }
	  
      demomaster_thread_run(&ctx);//poll --accept--
	 
	  /*
	 * Stop signal received: somebody called httplib_stop. Quit.
	 */
	XX_httplib_close_all_listening_sockets( &ctx );
		return 0;
}        
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐