libhttp服務端ipv6相容ipv4程式碼抽取重組
阿新 • • 發佈:2019-01-06
簡單分析
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--
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/64 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 ffcslh_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 ffcslh_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 FFCSXX_httplib_set_ports_option( struct ffcslh_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);
} /* ffcsXX_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 xjylibhttp 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 FFCSXX_httplib_accept_new_connection( const struct socket *listener, struct ffcslh_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 FFcsmaster_thread_run(void*thread_func_param)
{
int i;
struct ffcslh_ctx_t*ctx = (struct ffcslh_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))
{
FFCSXX_httplib_accept_new_connection( & ctx->listening_sockets[i], ctx );
}
}
}
}
}
int main()
{
struct ffcslh_ctx_t ctx;
memset(&ctx,0,sizeof(struct ffcslh_ctx_t));
ctx.listening_ports="+8080";//sever ipv4+ipv6 可監聽多種埠
if(0==FFCSXX_httplib_set_ports_option(&ctx))//socket-bind->listen
{
printf("FFCSXX_httplib_set_ports_option error\n");
exit(1);
}
FFcsmaster_thread_run(&ctx);//poll --accept--
/*
* Stop signal received: somebody called httplib_stop. Quit.
*/
XX_httplib_close_all_listening_sockets( &ctx );
return 0;
}