I have another issue: I'm trying to handle connections made by local socket along with data from serial port. Here is my concept:
- Serial port is opened and monitored by select
- Local socket is opened and put in Listen state
- inside loop I call my function accept_connection periodically
- When new connection arrives I allocate new array of struct to handle connections data
- I'm adding socket to &input with FD_SET(socket,&input), and this is what select is monitoring
- I'm checking with FD_ISSET (after select returns) if there is data from some client
- If there is data I'm reading it with process_client
It appears that it is working so far.
My questions are:
- I'm doing this the first time. Are there some obvious mistakes?
- How do I know that client has disconnected, and socket should be cleared, and removed from clients array?
- Should I move some variables like *clients pointer
clients_num
outside themain
function to have easier access to them from other functions, otherwise next functions can have a really long parameter list?
main.c
struct client_struct {
int socket;
char cmd_type;
};
void main {
int loop_num=250;
int local_socket;
int serial_fd;
int max_fd;
int tmp_socket;
fd_set input;
fd_set tmp_input;
char *serial_output_buffer;
struct timeval timeout;
struct client_struct *clients;
int clients_num=0;
serial_output_buffer=malloc(INPUT_BYTES_NUM * sizeof(char));
serial_fd=open_port();
local_socket=open_local_socket();
FD_ZERO(&input);
FD_SET(serial_fd, &input);
max_fd = serial_fd+1;
while(TRUE) {
loop_num++;
if(loop_num>250) {
pool_from_serial(serial_fd);
loop_num=0;
}
tmp_socket=accept_connection();
if(tmp_socket) {
clients=alloc_client(clients,clients_num);
clients[clients_num].socket=tmp_socket;
clients_num++;
FD_SET(tmp_socket, &input);
max_fd = getMaxFd(serial_fd,clients,clients_num);
}
tmp_input=input;
n = select(max_fd,&tmp_input,NULL,NULL,&timeout);
/* See if there was an error */
if (n<0)
perror("select failed");
else if (n == 0)
;//puts("TIMEOUT");
else {
/* We have input */
if (FD_ISSET(serial_fd, &input)) {
if(process_serial(serial_fd,serial_output_buffer)) {
process_serial_data(serial_output_buffer);
}
}
for(i=0;i<clients_num;i++) {
if(FD_ISSET(clients[i].socket, &input)) {
process_client(clients,i);
}
}
}
fflush(stdout);
usleep(10000);
}
return 0;
}
int getMaxFd(int serial_fd,struct client_struct *clients,int client_num) {
int i;
int res=serial_fd;
for(i=0;i<client_num;i++) {
res=(res > clients[i].socket ? res : clients[i].socket);
}
return (res+1);
}
struct client_struct* alloc_client(struct client_struct *clients,int num) {
int i;
if(num==0) {
clients=(struct client_struct*)malloc(sizeof(struct client_struct));
} else {
struct client_struct *new_array=(struct client_struct*)malloc((num+1)*sizeof(struct client_struct));
if(!new_array) {
error_exit("alloc_client malloc failed");
}
for(i=0;i<num;i++) {
new_array[i]=clients[i];
}
free(clients);
clients=new_array;
}
return clients;
}
local_socket.c
int sck_unix; /* Listen Socket */
struct sockaddr_un adr_unix;/* AF_UNIX */
int len_unix; /* length */
void process_client(struct client_struct *clients,int num) {
char buf[256];
int nread=0;
int socket=clients[num].socket;
int bytes=0;
ioctl(socket, FIONREAD, &bytes);
if(!bytes)
return;
nread = recv(socket, buf, sizeof(buf), 0);
/* If error or eof, terminate. */
if(nread < 1 && errno!=EAGAIN){
close(socket);
error_exit("read client");
}
buf[nread]='\0';
printf("client read:%s\n",buf);
}
int accept_connection() {
int ns=0;
ns = accept(sck_unix, (struct sockaddr *) &adr_unix, &len_unix);
if(ns<0) {
if(errno==EAGAIN)
return 0;
else
error_exit("accept connection failed");
} else {
int flagss = fcntl(ns,F_GETFL,0);
flagss |= O_NONBLOCK;
fcntl(ns,F_SETFL,flagss);
printf("ns:%d\n",ns);
return ns;
}
}
int open_local_socket() {
int z; /* Status return code */
const char pth_unix[]="/tmp/my_sock"; /* pathname */
sck_unix = socket(AF_UNIX,SOCK_STREAM,0);
if ( sck_unix == -1 )
error_exit("Creation of local socket failed");
unlink(pth_unix);
memset(&adr_unix,0,sizeof adr_unix);
adr_unix.sun_family = AF_UNIX;
strncpy(adr_unix.sun_path,pth_unix,
sizeof adr_unix.sun_path-1)
[sizeof adr_unix.sun_path-1] = 0;
len_unix = SUN_LEN(&adr_unix);
z = bind(sck_unix,
(struct sockaddr *)&adr_unix,
len_unix);
if ( z == -1 )
error_exit("Bind to local socket failed");
if (listen(sck_unix, 5) == -1) {
error_exit("listen error");
}
int flagss = fcntl(sck_unix,F_GETFL,0);
flagss |= O_NONBLOCK;
fcntl(sck_unix,F_SETFL,flagss);
return sck_unix;
}