Files
lcdproc/shared/sockets.c
T

339 lines
7.2 KiB
C
Raw Normal View History

#include "config.h"
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/types.h>
#ifndef WINSOCK2
1999-12-09 23:15:14 +00:00
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#else
#include <winsock2.h>
#endif
#include <stdarg.h>
1999-12-09 23:15:14 +00:00
#include <fcntl.h>
2001-11-29 14:09:13 +00:00
#include "report.h"
1999-12-09 23:15:14 +00:00
#include "sockets.h"
/**************************************************
LCDproc client sockets code...
Feel free to use this in your own clients... :)
**************************************************/
// Length of longest transmission allowed at once...
#define MAXMSG 8192
typedef struct sockaddr_in sockaddr_in;
static int
sock_init_sockaddr (sockaddr_in *name, const char *hostname, unsigned short int port)
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
struct hostent *hostinfo;
memset (name, '\0', sizeof (*name));
2000-04-03 22:13:57 +00:00
name->sin_family = AF_INET;
name->sin_port = htons (port);
hostinfo = gethostbyname (hostname);
if (hostinfo == NULL) {
2001-11-29 14:09:13 +00:00
report (RPT_ERR, "sock_init_sockaddr: Unknown host %s.", hostname);
2000-04-03 22:13:57 +00:00
return -1;
}
name->sin_addr = *(struct in_addr *) hostinfo->h_addr;
2000-04-03 22:13:57 +00:00
return 0;
1999-12-09 23:15:14 +00:00
}
// Client functions...
int
sock_connect (char *host, unsigned short int port)
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
struct sockaddr_in servername;
int sock;
int err = 0;
1999-12-09 23:15:14 +00:00
2001-11-29 14:09:13 +00:00
report (RPT_DEBUG, "sock_connect: Creating socket");
2000-04-03 22:13:57 +00:00
sock = socket (PF_INET, SOCK_STREAM, 0);
#ifdef WINSOCK2
if (sock == INVALID_SOCKET) {
#else
2000-04-03 22:13:57 +00:00
if (sock < 0) {
#endif
2001-11-29 14:09:13 +00:00
report (RPT_ERR, "sock_connect: Error creating socket");
2000-04-03 22:13:57 +00:00
return sock;
}
2001-11-29 14:09:13 +00:00
debug (RPT_DEBUG, "sock_connect: Created socket (%i)", sock);
if (sock_init_sockaddr (&servername, host, port) < 0)
return -1;
2000-04-03 22:13:57 +00:00
err = connect (sock, (struct sockaddr *) &servername, sizeof (servername));
#ifdef WINSOCK2
if (err == INVALID_SOCKET) {
#else
2000-04-03 22:13:57 +00:00
if (err < 0) {
#endif
2001-11-29 14:09:13 +00:00
report (RPT_ERR, "sock_connect: connect failed");
shutdown (sock, SHUT_RDWR);
2000-04-03 22:13:57 +00:00
return 0; // Normal exit if server doesn't exist...
}
#ifndef WINSOCK2
2000-04-03 22:13:57 +00:00
fcntl (sock, F_SETFL, O_NONBLOCK);
#else
{
unsigned long tmp = 1;
if (ioctlsocket(sock, FIONBIO, &tmp) == SOCKET_ERROR)
report(RPT_ERR, "sock_connect: Error setting socket to non-blocking");
}
#endif
2000-04-03 22:13:57 +00:00
return sock;
1999-12-09 23:15:14 +00:00
}
int
sock_close (int fd)
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
int err;
err = shutdown (fd, SHUT_RDWR);
2000-04-03 22:13:57 +00:00
if (!err)
close (fd);
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
return err;
1999-12-09 23:15:14 +00:00
}
/** send printf-like formatted output */
int
sock_printf(int fd, const char *format, .../*args*/ )
{
char buf[MAXMSG];
va_list ap;
int size = 0;
va_start(ap, format);
size = vsnprintf(buf, sizeof(buf), format, ap);
va_end(ap);
if (size < 0) {
report(RPT_ERR, "sock_printf: vsnprintf failed");
return -1;
}
if (size > sizeof(buf))
report(RPT_WARNING, "sock_printf: vsnprintf truncated message");
return sock_send_string(fd, buf);
}
1999-12-09 23:15:14 +00:00
// Send/receive lines of text
int
sock_send_string (int fd, char *string)
1999-12-09 23:15:14 +00:00
{
return sock_send(fd, string, strlen(string));
1999-12-09 23:15:14 +00:00
}
// Recv gives only one line per call...
int
sock_recv_string (int fd, char *dest, size_t maxlen)
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
char *ptr = dest;
int recvBytes = 0;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
if (!dest)
return -1;
if (maxlen <= 0)
return 0;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
while (1) {
#ifndef WINSOCK2
2000-04-03 22:13:57 +00:00
int err = read (fd, ptr, 1);
#else
int err = recv(fd, ptr, 1, 0);
#endif
2000-04-03 22:13:57 +00:00
if (err == -1) {
if (errno == EAGAIN) {
if (recvBytes) {
2000-04-03 22:13:57 +00:00
// We've begun to read a string, but no bytes are
// available. Loop.
continue;
}
return 0;
} else {
2001-11-29 14:09:13 +00:00
report (RPT_ERR, "sock_recv_string: socket read error");
2000-04-03 22:13:57 +00:00
return err;
}
} else if (err == 0) {
return recvBytes;
2000-04-03 22:13:57 +00:00
}
2000-02-14 13:38:39 +00:00
recvBytes++;
2000-02-14 13:38:39 +00:00
// stop at max. bytes allowed, at NUL or at LF
if (recvBytes == maxlen || *ptr == '\0' || *ptr == '\n') {
*ptr = '\0';
2000-04-03 22:13:57 +00:00
break;
}
ptr++;
}
2000-02-14 13:38:39 +00:00
// Don't return an empty string
if (recvBytes == 1 && dest[0] == '\0')
2000-04-03 22:13:57 +00:00
return 0;
2000-02-14 13:38:39 +00:00
if (recvBytes < maxlen - 1)
dest[recvBytes] = '\0';
2000-02-14 13:38:39 +00:00
return recvBytes;
1999-12-09 23:15:14 +00:00
}
// Send/receive raw data
int
sock_send (int fd, void *src, size_t size)
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
int offset = 0;
1999-12-09 23:15:14 +00:00
2000-04-03 22:13:57 +00:00
if (!src)
return -1;
2000-02-14 13:38:39 +00:00
2000-04-03 22:13:57 +00:00
while (offset != size) {
// write isn't guaranteed to send the entire string at once,
// so we have to sent it in a loop like this
#ifndef WINSOCK2
int sent = write (fd, ((char *) src) + offset, size - offset);
#else
int sent = send(fd, ((char *) src) + offset, size - offset, 0);
#endif
2000-04-03 22:13:57 +00:00
if (sent == -1) {
if (errno != EAGAIN) {
2001-11-29 14:09:13 +00:00
report (RPT_ERR, "sock_send: socket write error");
report (RPT_DEBUG, "Message was: '%.*s'", size-offset, (char *) src);
//shutdown(fd, SHUT_RDWR);
2000-04-03 22:13:57 +00:00
return sent;
}
continue;
} else if (sent == 0) {
// when this returns zero, it generally means
// we got disconnected
return sent + offset;
}
2000-02-14 13:38:39 +00:00
2000-04-03 22:13:57 +00:00
offset += sent;
}
2000-02-14 13:38:39 +00:00
2000-04-03 22:13:57 +00:00
return offset;
1999-12-09 23:15:14 +00:00
}
int
sock_recv (int fd, void *dest, size_t maxlen)
1999-12-09 23:15:14 +00:00
{
2000-04-03 22:13:57 +00:00
int err;
2000-04-03 22:13:57 +00:00
if (!dest)
return -1;
if (maxlen <= 0)
return 0;
#ifndef WINSOCK2
2000-04-03 22:13:57 +00:00
err = read (fd, dest, maxlen);
#else
err = recv(fd, dest, maxlen, 0);
#endif
2000-04-03 22:13:57 +00:00
if (err < 0) {
2001-11-29 14:09:13 +00:00
//report (RPT_DEBUG,"sock_recv: socket read error");
//shutdown(fd, SHUT_RDWR);
2000-04-03 22:13:57 +00:00
return err;
}
2001-11-29 14:09:13 +00:00
//debug(RPT_DEBUG, "sock_recv: Got message \"%s\"", (char *)dest);
2000-04-03 22:13:57 +00:00
return err;
1999-12-09 23:15:14 +00:00
}
/*****************************************************************************/
char*
sock_geterror(void)
{
#ifndef WINSOCK2
return strerror(errno);
#else
2005-04-05 07:28:18 +00:00
static char retString[256];
long err;
char* tmp;
err = WSAGetLastError();
sprintf(retString, "Error code %ld: ", err);
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
err,
0, /* Default language */
(LPTSTR) &tmp,
0,
NULL);
/* append the message text after the error code and ensure a terminating
character ends the string */
strncpy(retString + strlen(retString), tmp,
sizeof(retString) - strlen(retString) - 1);
retString[sizeof(retString) - 1] = '\0';
return retString;
#endif
}
2005-07-17 16:14:07 +00:00
/** prints error to logfile and sends it to the client.
* @param fd socket
* @param message the message to send (without the "huh? ") */
int sock_send_error(int fd, char* message)
{
// simple: performance penalty isn't worth more work...
return sock_printf_error(fd, message);
}
/** prints printf-like formatted output to logfile and sends it to the
* client.
* @param fd socket
* @param message the message to send (without the "huh? ") */
int
sock_printf_error(int fd, const char *format, .../*args*/ )
{
char buf[MAXMSG];
static const int huhsize = sizeof("huh? ") - 1;
char *p = buf + huhsize;
va_list ap;
int size = 0;
va_start(ap, format);
size = vsnprintf(buf, sizeof(buf), format, ap);
va_end(ap);
if (size < 0) {
report(RPT_ERR, "sock_printf_error: vsnprintf failed");
return -1;
}
if (size > sizeof(buf))
report(RPT_WARNING, "sock_printf_error: vsnprintf truncated message");
/* prepend the "huh? " */
if (size > sizeof(buf) - huhsize)
size = sizeof(buf) - huhsize;
memmove(p, buf, size);
memcpy(buf, "huh? ", huhsize);
report(RPT_ERR, "error: %s", buf);
return sock_send_string(fd, buf);
}