wmii/libixp/socket.c

205 lines
4.3 KiB
C
Raw Normal View History

2005-11-18 18:54:58 +03:00
/*
2006-01-20 17:20:24 +03:00
* (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com>
2005-11-18 18:54:58 +03:00
* See LICENSE file for license details.
*/
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/types.h>
2006-01-21 22:04:29 +03:00
#include <netinet/in.h>
#include <netdb.h>
2005-11-18 18:54:58 +03:00
#include <sys/un.h>
#include <unistd.h>
#include "cext.h"
#include "ixp.h"
static int
2006-01-21 22:04:29 +03:00
connect_unix_sock(char *address)
2005-11-18 18:54:58 +03:00
{
2005-12-21 18:18:11 +03:00
int fd = 0;
struct sockaddr_un addr = { 0 };
socklen_t su_len;
2005-11-18 18:54:58 +03:00
2005-12-21 18:18:11 +03:00
/* init */
addr.sun_family = AF_UNIX;
2006-01-21 22:04:29 +03:00
strncpy(addr.sun_path, address, sizeof(addr.sun_path));
2005-12-21 18:18:11 +03:00
su_len = sizeof(struct sockaddr) + strlen(addr.sun_path);
2005-11-18 18:54:58 +03:00
2005-12-21 18:18:11 +03:00
if((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
return -1;
if(connect(fd, (struct sockaddr *) &addr, su_len)) {
close(fd);
return -1;
}
return fd;
2005-11-18 18:54:58 +03:00
}
2006-01-21 22:04:29 +03:00
static int
2006-01-23 16:25:15 +03:00
connect_inet_sock(char *host)
2006-01-21 22:04:29 +03:00
{
int fd = 0;
struct sockaddr_in addr = { 0 };
struct hostent *hp;
char *port = strrchr(host, '!');
const char *errstr = nil;
unsigned int prt;
2006-01-21 22:04:29 +03:00
*port = 0;
port++;
prt = cext_strtonum(port, 1024, 65535, &errstr);
2006-01-21 22:04:29 +03:00
if(errstr)
return -1;
/* init */
if((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
return -1;
hp = gethostbyname(host);
addr.sin_family = AF_INET;
addr.sin_port = htons(prt);
2006-01-21 22:04:29 +03:00
bcopy(hp->h_addr, &addr.sin_addr, hp->h_length);
if(connect(fd, (struct sockaddr *) &addr, sizeof(struct sockaddr_in))) {
close(fd);
return -1;
}
return fd;
}
int
2006-01-21 22:04:29 +03:00
ixp_connect_sock(char *address)
{
2006-01-21 22:04:29 +03:00
char *p = strchr(address, '!');
char *addr, *type;
if(!p)
return -1;
*p = 0;
2006-01-21 22:04:29 +03:00
addr = &p[1];
2006-01-23 16:25:15 +03:00
type = address; /* unix, inet */
if(!strncmp(type, "unix", 5))
2006-01-21 22:04:29 +03:00
return connect_unix_sock(addr);
else if(!strncmp(type, "tcp", 4))
2006-01-23 16:25:15 +03:00
return connect_inet_sock(addr);
return -1;
}
2005-12-21 18:18:11 +03:00
int
ixp_accept_sock(int fd)
2005-11-18 18:54:58 +03:00
{
2005-12-21 18:18:11 +03:00
socklen_t su_len;
struct sockaddr_un addr = { 0 };
2005-11-18 18:54:58 +03:00
2005-12-21 18:18:11 +03:00
su_len = sizeof(struct sockaddr);
return accept(fd, (struct sockaddr *) &addr, &su_len);
2005-11-18 18:54:58 +03:00
}
static int
2006-01-23 16:25:15 +03:00
create_inet_sock(char *host, char **errstr)
2006-01-21 22:04:29 +03:00
{
int fd;
struct sockaddr_in addr = { 0 };
char *port = strrchr(host, '!');
unsigned int prt;
2006-01-21 22:04:29 +03:00
if(!port) {
*errstr = "no port provided in address";
return -1;
}
*port = 0;
port++;
prt = cext_strtonum(port, 1024, 65535, (const char **)errstr);
2006-01-21 22:04:29 +03:00
if(*errstr)
return -1;
signal(SIGPIPE, SIG_IGN);
if((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
*errstr = "cannot open socket";
return -1;
}
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(prt);
2006-01-21 22:04:29 +03:00
if(bind(fd, (struct sockaddr *) &addr, sizeof(struct sockaddr_in)) < 0) {
*errstr = "cannot bind socket";
close(fd);
return -1;
}
if(listen(fd, IXP_MAX_CACHE) < 0) {
2006-01-21 22:04:29 +03:00
*errstr = "cannot listen on socket";
close(fd);
return -1;
}
return fd;
}
static int
create_unix_sock(char *file, char **errstr)
2005-11-18 18:54:58 +03:00
{
2005-12-21 18:18:11 +03:00
int fd;
int yes = 1;
struct sockaddr_un addr = { 0 };
socklen_t su_len;
2005-11-18 18:54:58 +03:00
2005-12-21 18:18:11 +03:00
signal(SIGPIPE, SIG_IGN);
if((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
*errstr = "cannot open socket";
return -1;
}
if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
(char *) &yes, sizeof(yes)) < 0) {
*errstr = "cannot set socket options";
close(fd);
return -1;
}
addr.sun_family = AF_UNIX;
2006-01-21 22:04:29 +03:00
strncpy(addr.sun_path, file, sizeof(addr.sun_path));
2005-12-21 18:18:11 +03:00
su_len = sizeof(struct sockaddr) + strlen(addr.sun_path);
2005-11-18 18:54:58 +03:00
unlink(file); /* remove old socket, if any */
2005-12-21 18:18:11 +03:00
if(bind(fd, (struct sockaddr *) &addr, su_len) < 0) {
*errstr = "cannot bind socket";
close(fd);
return -1;
}
2006-01-21 22:04:29 +03:00
chmod(file, S_IRWXU);
2005-11-18 18:54:58 +03:00
if(listen(fd, IXP_MAX_CACHE) < 0) {
2005-12-21 18:18:11 +03:00
*errstr = "cannot listen on socket";
close(fd);
return -1;
}
return fd;
2005-11-18 18:54:58 +03:00
}
int
2006-01-21 22:04:29 +03:00
ixp_create_sock(char *address, char **errstr)
{
2006-01-21 22:04:29 +03:00
char *p = strchr(address, '!');
char *addr, *type;
if(!p) {
*errstr = "no socket type defined";
return -1;
}
*p = 0;
2006-01-21 22:04:29 +03:00
addr = &p[1];
2006-01-23 16:25:15 +03:00
type = address; /* unix, inet */
if(!strncmp(type, "unix", 5))
2006-01-21 22:04:29 +03:00
return create_unix_sock(addr, errstr);
else if(!strncmp(type, "tcp", 4))
2006-01-23 16:25:15 +03:00
return create_inet_sock(addr, errstr);
2006-01-21 22:04:29 +03:00
else
*errstr = "unkown socket type";
return -1;
}