Files
lcdproc/server/sock.c
T

278 lines
6.6 KiB
C
Raw Normal View History

1999-12-09 23:15:14 +00:00
#include <unistd.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
1999-12-09 23:15:14 +00:00
#include <errno.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/time.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <string.h>
1999-12-09 23:15:14 +00:00
#include "shared/sockets.h"
1999-12-09 23:15:14 +00:00
#include "sock.h"
#include "clients.h"
2001-11-29 14:09:13 +00:00
#include "shared/report.h"
extern char bind_addr[64];
extern int lcd_port;
1999-12-09 23:15:14 +00:00
/**************************************************
LCDproc sockets code...
This is messy, and needs to be finished.
**************************************************/
fd_set active_fd_set, read_fd_set;
int orig_sock;
// Length of longest transmission allowed at once...
#define MAXMSG 8192
int read_from_client (int filedes);
// Creates a socket in internet space
int
sock_create_inet_socket (char * addr, unsigned int port)
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
struct sockaddr_in name;
int sock, sockopt=1;
2001-11-29 14:09:13 +00:00
report (RPT_INFO, "sock_create_inet_socket(%i)", port);
2000-04-03 22:13:57 +00:00
/* Create the socket. */
2001-11-29 14:09:13 +00:00
//debug(RPT_DEBUG, "Creating Inet Socket");
2000-04-03 22:13:57 +00:00
sock = socket (PF_INET, SOCK_STREAM, 0);
if (sock < 0) {
2001-11-29 14:09:13 +00:00
report(RPT_ERR, "Could not create socket");
2000-04-03 22:13:57 +00:00
return -1;
}
/* Set the socket so we can re-use it*/
if(setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&sockopt,sizeof(sockopt)) < 0) {
2001-11-29 14:09:13 +00:00
report(RPT_ERR, "Error setting socket option SO_REUSEADDR");
return -1;
}
2001-11-29 14:09:13 +00:00
2000-04-03 22:13:57 +00:00
/* Give the socket a name. */
2001-11-29 14:09:13 +00:00
//debug(RPT_DEBUG, "Binding Inet Socket");
memset (&name, 0, sizeof (name));
2000-04-03 22:13:57 +00:00
name.sin_family = AF_INET;
name.sin_port = htons (port);
inet_aton(addr, &name.sin_addr);
2000-04-03 22:13:57 +00:00
if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) {
2001-11-29 14:09:13 +00:00
report(RPT_ERR, "Could not bind to port %d", port);
2000-04-03 22:13:57 +00:00
return -1;
} else {
2001-11-29 14:09:13 +00:00
report(RPT_NOTICE, "listening for queries on port %d", port);
2000-04-03 22:13:57 +00:00
}
2000-04-03 22:13:57 +00:00
return sock;
1999-12-09 23:15:14 +00:00
}
//int StartSocketServer()
int
sock_create_server (char *bind_addr, int lcd_port)
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
int sock;
1999-12-09 23:15:14 +00:00
2001-11-29 14:09:13 +00:00
report (RPT_INFO, "sock_create_server()");
2000-04-03 22:13:57 +00:00
/* Create the socket and set it up to accept connections. */
sock = sock_create_inet_socket (bind_addr, lcd_port);
2000-04-03 22:13:57 +00:00
if (sock < 0) {
2001-11-29 14:09:13 +00:00
report (RPT_ERR, "sock_create_server: Error creating socket");
2000-04-03 22:13:57 +00:00
return -1;
}
2000-04-03 22:13:57 +00:00
if (listen (sock, 1) < 0) {
2001-11-29 14:09:13 +00:00
report(RPT_ERR, "error in attempting to listen to port");
2000-04-03 22:13:57 +00:00
return -1;
}
2000-04-03 22:13:57 +00:00
/* Initialize the set of active sockets. */
FD_ZERO (&active_fd_set);
FD_SET (sock, &active_fd_set);
2000-04-03 22:13:57 +00:00
orig_sock = sock;
1999-12-09 23:15:14 +00:00
/*
{
int val, len, sock;
sock = new;
2001-11-29 14:09:13 +00:00
1999-12-09 23:15:14 +00:00
len = sizeof(int);
getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &val, &len);
2001-11-29 14:09:13 +00:00
debug(RPT_DEBUG, "SEND buffer: %i bytes", val);
1999-12-09 23:15:14 +00:00
len = sizeof(int);
getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &val, &len);
2001-11-29 14:09:13 +00:00
debug(RPT_DEBUG, "RECV buffer: %i bytes", val);
1999-12-09 23:15:14 +00:00
}
*/
2000-04-03 22:13:57 +00:00
return sock;
1999-12-09 23:15:14 +00:00
}
// Service all clients with input pending...
int
sock_poll_clients ()
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
int i;
int err;
struct sockaddr_in clientname;
size_t size;
struct timeval t;
client *c;
2001-11-29 14:09:13 +00:00
debug(RPT_INFO, "sock_poll_clients()");
2000-04-03 22:13:57 +00:00
t.tv_sec = 0;
t.tv_usec = 0;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
/* Block until input arrives on one or more active sockets. */
read_fd_set = active_fd_set;
2000-04-03 22:13:57 +00:00
if (select (FD_SETSIZE, &read_fd_set, NULL, NULL, &t) < 0) {
2001-11-29 14:09:13 +00:00
report (RPT_ERR, "sock_poll_clients: Select error");
2000-04-03 22:13:57 +00:00
return -1;
}
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
/* Service all the sockets with input pending. */
for (i = 0; i < FD_SETSIZE; ++i) {
if (FD_ISSET (i, &read_fd_set)) {
if (i == orig_sock) {
/* Connection request on original socket. */
int new;
size = sizeof (clientname);
new = accept (orig_sock, (struct sockaddr *) &clientname, &size);
if (new < 0) {
2001-11-29 14:09:13 +00:00
report (RPT_ERR, "sock_poll_clients: Accept error");
2000-04-03 22:13:57 +00:00
return -1;
}
2001-11-29 14:09:13 +00:00
report (RPT_INFO, "sock_poll_clients: Connect from host %s:%hd on #%d",
inet_ntoa (clientname.sin_addr), ntohs (clientname.sin_port), new);
2000-04-03 22:13:57 +00:00
FD_SET (new, &active_fd_set);
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
fcntl (new, F_SETFL, O_NONBLOCK);
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
// TODO: Create new "client" here... (done?)
if (client_create (new) == NULL) {
2001-11-29 14:09:13 +00:00
report( RPT_ERR, "sock_poll_clients: error creating client %i", i);
2000-04-03 22:13:57 +00:00
return -1;
}
} else {
/* Data arriving on an already-connected socket. */
err = 0;
do {
2001-11-29 14:09:13 +00:00
debug (RPT_DEBUG, "sock_poll_clients: reading...");
2000-04-03 22:13:57 +00:00
err = read_from_client (i);
2001-11-29 14:09:13 +00:00
debug (RPT_DEBUG, "sock_poll_clients: ...done");
2000-04-03 22:13:57 +00:00
if (err < 0) {
// TODO: Destroy a "client" here... (done?)
c = client_find_sock (i);
if (c) {
//sock_send_string(i, "bye\n");
client_destroy (c);
close (i);
FD_CLR (i, &active_fd_set);
2001-11-29 14:09:13 +00:00
report (RPT_INFO, "sock_poll_clients: Closed connection %i", i);
2000-04-03 22:13:57 +00:00
} else
2001-11-29 14:09:13 +00:00
report (RPT_ERR, "sock_poll_clients: Can't find client %i", i);
2000-04-03 22:13:57 +00:00
}
} while (err > 0);
2000-04-03 22:13:57 +00:00
}
}
}
return 0;
1999-12-09 23:15:14 +00:00
}
int
read_from_client (int filedes)
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
char buffer[MAXMSG];
int nbytes, i;
client *c;
2001-11-29 14:09:13 +00:00
report(RPT_DEBUG, "read_from_client()" );
//nbytes = read (filedes, buffer, MAXMSG);
2001-11-29 14:09:13 +00:00
//debug(RPT_DEBUG, "read_from_client(%i): reading...", filedes);
//nbytes = sock_recv (filedes, buffer, MAXMSG);
2001-11-29 14:09:13 +00:00
//debug(RPT_DEBUG, "read_from_client(%i): ...done", filedes);
//debug (RPT_DEBUG, "read_from_client(%i): %i bytes", filedes, nbytes);
errno = 0;
if ((nbytes = sock_recv (filedes, buffer, MAXMSG)) < 0) {
if (errno != EAGAIN)
2001-11-29 14:09:13 +00:00
report (RPT_DEBUG, "read_from_client: (fd %d) %s", filedes, strerror(errno));
2000-04-03 22:13:57 +00:00
return 0;
} else if (nbytes == 0) // EOF
return -1;
else if (nbytes > (MAXMSG - (MAXMSG / 8))) // Very noisy client...
{
sock_send_string (filedes, "huh? Too much data received... quiet down!\n");
2000-04-03 22:13:57 +00:00
return -1;
} else // Data Read
{
buffer[nbytes] = 0;
// Now, replace zeros with linefeeds...
for (i = 0; i < nbytes; i++)
if (buffer[i] == 0)
buffer[i] = '\n';
// Enqueue a "client message" here...
c = client_find_sock (filedes);
if (c) {
client_add_message (c, buffer);
} else
2001-11-29 14:09:13 +00:00
report (RPT_DEBUG, "read_from_client: Can't find client %i", filedes);
2001-11-29 14:09:13 +00:00
debug (RPT_DEBUG, "read_from_client: got message: `%s'", buffer);
2000-04-03 22:13:57 +00:00
return nbytes;
}
return nbytes;
1999-12-09 23:15:14 +00:00
}
// FIXME: This talks to all open files, including
// stdin, stdout, stderr, the LCD, etc...
// BUT it should only talk to sockets!
int
sock_close_all ()
1999-12-09 23:15:14 +00:00
{
int fd;
1999-12-09 23:15:14 +00:00
2001-11-29 14:09:13 +00:00
report (RPT_INFO, "sock_close_all()");
for (fd = 0; fd < FD_SETSIZE; fd++) {
2000-04-03 22:13:57 +00:00
// TODO: Destroy a "client" here...? Nope.
// Instead of using STDIN_FILENO, STDOUT_FILENO,
// and STDERR_FILENO, one could use "fd = 4" in the
// for() call - but this would probably not be good
// practice...
if ( fd == STDIN_FILENO ||
fd == STDOUT_FILENO ||
fd == STDERR_FILENO)
continue;
else {
//sock_send_string (fd, "bye\n");
close (fd);
FD_CLR (fd, &active_fd_set);
2001-11-29 14:09:13 +00:00
debug (RPT_DEBUG, "sock_close_all: Closed connection %i", fd);
}
2000-04-03 22:13:57 +00:00
}
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
return 0;
1999-12-09 23:15:14 +00:00
}