Fixed segfaulting access control, allowed change to acl via control socket.
This commit is contained in:
2
Rakefile
2
Rakefile
@@ -1,6 +1,6 @@
|
|||||||
DEBUG = true
|
DEBUG = true
|
||||||
|
|
||||||
SOURCES = %w( flexnbd ioutil readwrite serve util )
|
SOURCES = %w( flexnbd ioutil readwrite serve util parse )
|
||||||
OBJECTS = SOURCES.map { |s| "#{s}.o" }
|
OBJECTS = SOURCES.map { |s| "#{s}.o" }
|
||||||
LIBS = %w( pthread )
|
LIBS = %w( pthread )
|
||||||
CCFLAGS = %w( -Wall )
|
CCFLAGS = %w( -Wall )
|
||||||
|
79
flexnbd.c
79
flexnbd.c
@@ -17,89 +17,16 @@ void syntax()
|
|||||||
"Syntax: flexnbd serve <listen IP address> <port> <file> \\\n"
|
"Syntax: flexnbd serve <listen IP address> <port> <file> \\\n"
|
||||||
" [full path to control socket] \\\n"
|
" [full path to control socket] \\\n"
|
||||||
" [allowed connection addresses ...]\n"
|
" [allowed connection addresses ...]\n"
|
||||||
" flexnbd mirror <control socket> <dst IP address> <dst port>\n"
|
|
||||||
" flexnbd status <control socket>\n"
|
|
||||||
" flexnbd read <IP address> <port> <offset> <length> > data\n"
|
" flexnbd read <IP address> <port> <offset> <length> > data\n"
|
||||||
" flexnbd write <IP address> <port> <offset> <length> < data\n"
|
" flexnbd write <IP address> <port> <offset> <length> < data\n"
|
||||||
" flexnbd write <IP address> <port> <offset> <file to write>\n"
|
" flexnbd write <IP address> <port> <offset> <file to write>\n"
|
||||||
|
" flexnbd acl <control socket> [allowed connection addresses ...]\n"
|
||||||
|
" flexnbd mirror <control socket> <dst IP address> <dst port>\n"
|
||||||
|
" flexnbd status <control socket>\n"
|
||||||
);
|
);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define IS_IP_VALID_CHAR(x) ( ((x) >= '0' && (x) <= '9' ) || \
|
|
||||||
((x) >= 'a' && (x) <= 'f') || \
|
|
||||||
((x) >= 'A' && (x) <= 'F' ) || \
|
|
||||||
(x) == ':' || (x) == '.' \
|
|
||||||
)
|
|
||||||
int parse_ip_to_sockaddr(struct sockaddr* out, char* src)
|
|
||||||
{
|
|
||||||
char temp[64];
|
|
||||||
struct sockaddr_in *v4 = (struct sockaddr_in *) out;
|
|
||||||
struct sockaddr_in6 *v6 = (struct sockaddr_in6 *) out;
|
|
||||||
|
|
||||||
/* allow user to start with [ and end with any other invalid char */
|
|
||||||
{
|
|
||||||
int i=0, j=0;
|
|
||||||
if (src[i] == '[')
|
|
||||||
i++;
|
|
||||||
for (; i<64 && IS_IP_VALID_CHAR(src[i]); i++)
|
|
||||||
temp[j++] = src[i];
|
|
||||||
temp[j] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (temp[0] == '0' && temp[1] == '\0') {
|
|
||||||
v4->sin_family = AF_INET;
|
|
||||||
v4->sin_addr.s_addr = INADDR_ANY;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inet_pton(AF_INET, temp, &v4->sin_addr) == 1) {
|
|
||||||
out->sa_family = AF_INET;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inet_pton(AF_INET6, temp, &v6->sin6_addr) == 1) {
|
|
||||||
out->sa_family = AF_INET6;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int parse_acl(struct ip_and_mask*** out, int max, char **entries)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (max == 0) {
|
|
||||||
*out = NULL;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < max; i++) {
|
|
||||||
# define MAX_MASK_BITS (outentry->ip.family == AF_INET ? 32 : 128)
|
|
||||||
int j;
|
|
||||||
struct ip_and_mask* outentry = (*out)[i];
|
|
||||||
|
|
||||||
if (parse_ip_to_sockaddr(&outentry->ip.generic, entries[i]) == 0)
|
|
||||||
return i;
|
|
||||||
|
|
||||||
for (j=0; entries[i][j] && entries[i][j] != '/'; j++)
|
|
||||||
;
|
|
||||||
if (entries[i][j] == '/') {
|
|
||||||
outentry->mask = atoi(entries[i]+j+1);
|
|
||||||
if (outentry->mask < 1 || outentry->mask > MAX_MASK_BITS)
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
outentry->mask = MAX_MASK_BITS;
|
|
||||||
# undef MAX_MASK_BITS
|
|
||||||
|
|
||||||
debug("acl entry %d has mask %d", i, outentry->mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
return max;
|
|
||||||
}
|
|
||||||
|
|
||||||
void params_serve(
|
void params_serve(
|
||||||
struct mode_serve_params* out,
|
struct mode_serve_params* out,
|
||||||
char* s_ip_address,
|
char* s_ip_address,
|
||||||
|
17
ioutil.c
17
ioutil.c
@@ -137,4 +137,19 @@ int splice_via_pipe_loop(int fd_in, int fd_out, size_t len)
|
|||||||
return spliced < len ? -1 : 0;
|
return spliced < len ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int read_until_newline(int fd, char* buf, int bufsize)
|
||||||
|
{
|
||||||
|
int cur;
|
||||||
|
bufsize -=1;
|
||||||
|
|
||||||
|
for (cur=0; cur < bufsize; cur++) {
|
||||||
|
int result = read(fd, buf+cur, 1);
|
||||||
|
if (result < 0)
|
||||||
|
return -1;
|
||||||
|
if (buf[cur] == 10 || buf[cur] == 13)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buf[cur++] = 0;
|
||||||
|
|
||||||
|
return cur;
|
||||||
|
}
|
||||||
|
1
ioutil.h
1
ioutil.h
@@ -9,6 +9,7 @@ int writeloop(int filedes, const void *buffer, size_t size);
|
|||||||
int readloop(int filedes, void *buffer, size_t size);
|
int readloop(int filedes, void *buffer, size_t size);
|
||||||
int sendfileloop(int out_fd, int in_fd, off64_t *offset, size_t count);
|
int sendfileloop(int out_fd, int in_fd, off64_t *offset, size_t count);
|
||||||
int splice_via_pipe_loop(int fd_in, int fd_out, size_t len);
|
int splice_via_pipe_loop(int fd_in, int fd_out, size_t len);
|
||||||
|
int read_until_newline(int fd, char* buf, int bufsize);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
24
params.h
24
params.h
@@ -4,27 +4,14 @@
|
|||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
#define _LARGEFILE64_SOURCE
|
#define _LARGEFILE64_SOURCE
|
||||||
|
|
||||||
|
#include "parse.h"
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
union mysockaddr {
|
|
||||||
unsigned short family;
|
|
||||||
struct sockaddr generic;
|
|
||||||
struct sockaddr_in v4;
|
|
||||||
struct sockaddr_in6 v6;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ip_and_mask {
|
|
||||||
union mysockaddr ip;
|
|
||||||
int mask;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct mode_serve_params {
|
struct mode_serve_params {
|
||||||
union mysockaddr bind_to;
|
union mysockaddr bind_to;
|
||||||
int acl_entries;
|
int acl_entries;
|
||||||
struct ip_and_mask** acl;
|
struct ip_and_mask *acl[0];
|
||||||
char* filename;
|
char* filename;
|
||||||
int tcp_backlog;
|
int tcp_backlog;
|
||||||
char* control_socket_name;
|
char* control_socket_name;
|
||||||
@@ -54,6 +41,11 @@ struct client_params {
|
|||||||
char* block_allocation_map;
|
char* block_allocation_map;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct control_params {
|
||||||
|
int socket;
|
||||||
|
struct mode_serve_params* serve;
|
||||||
|
};
|
||||||
|
|
||||||
union mode_params {
|
union mode_params {
|
||||||
struct mode_serve_params serve;
|
struct mode_serve_params serve;
|
||||||
struct mode_readwrite_params readwrite;
|
struct mode_readwrite_params readwrite;
|
||||||
|
87
parse.c
Normal file
87
parse.c
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
#include "parse.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
int atoi(const char *nptr);
|
||||||
|
|
||||||
|
#define IS_IP_VALID_CHAR(x) ( ((x) >= '0' && (x) <= '9' ) || \
|
||||||
|
((x) >= 'a' && (x) <= 'f') || \
|
||||||
|
((x) >= 'A' && (x) <= 'F' ) || \
|
||||||
|
(x) == ':' || (x) == '.' \
|
||||||
|
)
|
||||||
|
int parse_ip_to_sockaddr(struct sockaddr* out, char* src)
|
||||||
|
{
|
||||||
|
char temp[64];
|
||||||
|
struct sockaddr_in *v4 = (struct sockaddr_in *) out;
|
||||||
|
struct sockaddr_in6 *v6 = (struct sockaddr_in6 *) out;
|
||||||
|
|
||||||
|
/* allow user to start with [ and end with any other invalid char */
|
||||||
|
{
|
||||||
|
int i=0, j=0;
|
||||||
|
if (src[i] == '[')
|
||||||
|
i++;
|
||||||
|
for (; i<64 && IS_IP_VALID_CHAR(src[i]); i++)
|
||||||
|
temp[j++] = src[i];
|
||||||
|
temp[j] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (temp[0] == '0' && temp[1] == '\0') {
|
||||||
|
v4->sin_family = AF_INET;
|
||||||
|
v4->sin_addr.s_addr = INADDR_ANY;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inet_pton(AF_INET, temp, &v4->sin_addr) == 1) {
|
||||||
|
out->sa_family = AF_INET;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inet_pton(AF_INET6, temp, &v6->sin6_addr) == 1) {
|
||||||
|
out->sa_family = AF_INET6;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parse_acl(struct ip_and_mask *out[], int max, char **entries)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (max == 0) {
|
||||||
|
*out = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*out = xmalloc(max * sizeof(struct ip_and_mask));
|
||||||
|
debug("acl alloc: %p", *out);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < max; i++) {
|
||||||
|
# define MAX_MASK_BITS (outentry->ip.family == AF_INET ? 32 : 128)
|
||||||
|
int j;
|
||||||
|
struct ip_and_mask* outentry = *out+i;
|
||||||
|
|
||||||
|
if (parse_ip_to_sockaddr(&outentry->ip.generic, entries[i]) == 0)
|
||||||
|
return i;
|
||||||
|
|
||||||
|
for (j=0; entries[i][j] && entries[i][j] != '/'; j++)
|
||||||
|
;
|
||||||
|
if (entries[i][j] == '/') {
|
||||||
|
outentry->mask = atoi(entries[i]+j+1);
|
||||||
|
if (outentry->mask < 1 || outentry->mask > MAX_MASK_BITS)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
outentry->mask = MAX_MASK_BITS;
|
||||||
|
# undef MAX_MASK_BITS
|
||||||
|
debug("acl ptr[%d]: %p %d",i, outentry, outentry->mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i=0; i < max; i++) {
|
||||||
|
struct ip_and_mask* entry = *out+i;
|
||||||
|
debug("acl entry %d @ %p has mask %d", i, entry, entry->mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
24
parse.h
Normal file
24
parse.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#ifndef __PARSE_H
|
||||||
|
#define __PARSE_H
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
union mysockaddr {
|
||||||
|
unsigned short family;
|
||||||
|
struct sockaddr generic;
|
||||||
|
struct sockaddr_in v4;
|
||||||
|
struct sockaddr_in6 v6;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ip_and_mask {
|
||||||
|
union mysockaddr ip;
|
||||||
|
int mask;
|
||||||
|
};
|
||||||
|
|
||||||
|
int parse_ip_to_sockaddr(struct sockaddr* out, char* src);
|
||||||
|
int parse_acl(struct ip_and_mask *out[], int max, char **entries);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
127
serve.c
127
serve.c
@@ -3,6 +3,7 @@
|
|||||||
#include "ioutil.h"
|
#include "ioutil.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "bitset.h"
|
#include "bitset.h"
|
||||||
|
#include "parse.h"
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
@@ -264,6 +265,89 @@ void* client_serve(void* client_uncast)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void control_acl(struct control_params* client)
|
||||||
|
{
|
||||||
|
int acl_entries = 0, parsed;
|
||||||
|
char** s_acl_entry = NULL;
|
||||||
|
struct ip_and_mask** acl, **old_acl;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
char entry[64];
|
||||||
|
int result = read_until_newline(client->socket, entry, 64);
|
||||||
|
if (result == -1 || result == 64)
|
||||||
|
goto done;
|
||||||
|
if (result == 1) /* blank line terminates */
|
||||||
|
break;
|
||||||
|
s_acl_entry = xrealloc(
|
||||||
|
s_acl_entry,
|
||||||
|
++acl_entries * sizeof(struct s_acl_entry*)
|
||||||
|
);
|
||||||
|
s_acl_entry[acl_entries-1] = strdup(entry);
|
||||||
|
debug("acl_entry = '%s'", s_acl_entry[acl_entries-1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
parsed = parse_acl(&acl, acl_entries, s_acl_entry);
|
||||||
|
if (parsed != acl_entries) {
|
||||||
|
write(client->socket, "error: ", 7);
|
||||||
|
write(client->socket, s_acl_entry[parsed],
|
||||||
|
strlen(s_acl_entry[parsed]));
|
||||||
|
write(client->socket, "\n", 1);
|
||||||
|
free(acl);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
old_acl = client->serve->acl;
|
||||||
|
client->serve->acl = acl;
|
||||||
|
client->serve->acl_entries = acl_entries;
|
||||||
|
free(old_acl);
|
||||||
|
write(client->socket, "ok\n", 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
done: if (acl_entries > 0) {
|
||||||
|
int i;
|
||||||
|
for (i=0; i<acl_entries; i++)
|
||||||
|
free(s_acl_entry[i]);
|
||||||
|
free(s_acl_entry);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
void control_mirror(struct control_params* client)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void control_status(struct control_params* client)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void* control_serve(void* client_uncast)
|
||||||
|
{
|
||||||
|
const int max = 256;
|
||||||
|
char command[max];
|
||||||
|
struct control_params* client = (struct control_params*) client_uncast;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
CLIENT_ERROR_ON_FAILURE(
|
||||||
|
read_until_newline(client->socket, command, max),
|
||||||
|
"Error reading command"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (strcmp(command, "acl") == 0)
|
||||||
|
control_acl(client);
|
||||||
|
else if (strcmp(command, "mirror") == 0)
|
||||||
|
control_mirror(client);
|
||||||
|
else if (strcmp(command, "status") == 0)
|
||||||
|
control_status(client);
|
||||||
|
else {
|
||||||
|
write(client->socket, "error: unknown command\n", 23);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close(client->socket);
|
||||||
|
free(client);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static int testmasks[9] = { 0,128,192,224,240,248,252,254,255 };
|
static int testmasks[9] = { 0,128,192,224,240,248,252,254,255 };
|
||||||
|
|
||||||
int is_included_in_acl(int list_length, struct ip_and_mask** list, struct sockaddr* test)
|
int is_included_in_acl(int list_length, struct ip_and_mask** list, struct sockaddr* test)
|
||||||
@@ -271,26 +355,30 @@ int is_included_in_acl(int list_length, struct ip_and_mask** list, struct sockad
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i=0; i < list_length; i++) {
|
for (i=0; i < list_length; i++) {
|
||||||
struct ip_and_mask *entry = list[i];
|
struct ip_and_mask *entry = list+i;
|
||||||
int testbits;
|
int testbits;
|
||||||
char *raw_address1, *raw_address2;
|
char *raw_address1, *raw_address2;
|
||||||
|
|
||||||
debug("checking acl entry %d", i);
|
debug("checking acl entry %d (%d/%d)", i, test->sa_family, entry->ip.family);
|
||||||
|
|
||||||
if (test->sa_family != entry->ip.family)
|
if (test->sa_family != entry->ip.family)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (test->sa_family == AF_INET) {
|
if (test->sa_family == AF_INET) {
|
||||||
|
debug("it's an AF_INET");
|
||||||
raw_address1 = (char*)
|
raw_address1 = (char*)
|
||||||
&((struct sockaddr_in*) test)->sin_addr;
|
&((struct sockaddr_in*) test)->sin_addr;
|
||||||
raw_address2 = (char*) &entry->ip.v4.sin_addr;
|
raw_address2 = (char*) &entry->ip.v4.sin_addr;
|
||||||
}
|
}
|
||||||
else if (test->sa_family == AF_INET6) {
|
else if (test->sa_family == AF_INET6) {
|
||||||
|
debug("it's an AF_INET6");
|
||||||
raw_address1 = (char*)
|
raw_address1 = (char*)
|
||||||
&((struct sockaddr_in6*) test)->sin6_addr;
|
&((struct sockaddr_in6*) test)->sin6_addr;
|
||||||
raw_address2 = (char*) &entry->ip.v6.sin6_addr;
|
raw_address2 = (char*) &entry->ip.v6.sin6_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug("testbits=%d", entry->mask);
|
||||||
|
|
||||||
for (testbits = entry->mask; testbits > 0; testbits -= 8) {
|
for (testbits = entry->mask; testbits > 0; testbits -= 8) {
|
||||||
debug("testbits=%d, c1=%d, c2=%d", testbits, raw_address1[0], raw_address2[0]);
|
debug("testbits=%d, c1=%d, c2=%d", testbits, raw_address1[0], raw_address2[0]);
|
||||||
if (testbits >= 8) {
|
if (testbits >= 8) {
|
||||||
@@ -366,7 +454,7 @@ void serve_open_control_socket(struct mode_serve_params* params)
|
|||||||
|
|
||||||
void accept_nbd_client(struct mode_serve_params* params, int client_fd, struct sockaddr* client_address)
|
void accept_nbd_client(struct mode_serve_params* params, int client_fd, struct sockaddr* client_address)
|
||||||
{
|
{
|
||||||
pthread_t client_thread;
|
pthread_t client_thread;
|
||||||
struct client_params* client_params;
|
struct client_params* client_params;
|
||||||
|
|
||||||
if (params->acl &&
|
if (params->acl &&
|
||||||
@@ -382,18 +470,37 @@ void accept_nbd_client(struct mode_serve_params* params, int client_fd, struct s
|
|||||||
client_params->block_allocation_map =
|
client_params->block_allocation_map =
|
||||||
params->block_allocation_map;
|
params->block_allocation_map;
|
||||||
|
|
||||||
client_thread = pthread_create(&client_thread, NULL,
|
SERVER_ERROR_ON_FAILURE(
|
||||||
client_serve, client_params);
|
pthread_create(
|
||||||
SERVER_ERROR_ON_FAILURE(client_thread,
|
&client_thread,
|
||||||
"Failed to create client thread");
|
NULL,
|
||||||
|
client_serve,
|
||||||
|
client_params
|
||||||
|
),
|
||||||
|
"Failed to create client thread"
|
||||||
|
);
|
||||||
/* FIXME: keep track of them? */
|
/* FIXME: keep track of them? */
|
||||||
/* FIXME: maybe shouldn't be fatal? */
|
/* FIXME: maybe shouldn't be fatal? */
|
||||||
}
|
}
|
||||||
|
|
||||||
void accept_control_connection(struct mode_serve_params* params, int client_fd, struct sockaddr* client_address)
|
void accept_control_connection(struct mode_serve_params* params, int client_fd, struct sockaddr* client_address)
|
||||||
{
|
{
|
||||||
write(client_fd, "hello", 5);
|
pthread_t control_thread;
|
||||||
close(client_fd);
|
struct control_params* control_params;
|
||||||
|
|
||||||
|
control_params = xmalloc(sizeof(struct control_params));
|
||||||
|
control_params->socket = client_fd;
|
||||||
|
control_params->serve = params;
|
||||||
|
|
||||||
|
SERVER_ERROR_ON_FAILURE(
|
||||||
|
pthread_create(
|
||||||
|
&control_thread,
|
||||||
|
NULL,
|
||||||
|
control_serve,
|
||||||
|
control_params
|
||||||
|
),
|
||||||
|
"Failed to create client thread"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void serve_accept_loop(struct mode_serve_params* params)
|
void serve_accept_loop(struct mode_serve_params* params)
|
||||||
@@ -402,7 +509,7 @@ void serve_accept_loop(struct mode_serve_params* params)
|
|||||||
int activity_fd, client_fd;
|
int activity_fd, client_fd;
|
||||||
struct sockaddr client_address;
|
struct sockaddr client_address;
|
||||||
fd_set fds;
|
fd_set fds;
|
||||||
socklen_t socklen=0;
|
socklen_t socklen=sizeof(client_address);
|
||||||
|
|
||||||
FD_ZERO(&fds);
|
FD_ZERO(&fds);
|
||||||
FD_SET(params->server, &fds);
|
FD_SET(params->server, &fds);
|
||||||
|
Reference in New Issue
Block a user