Saturday, March 15, 2008

Netpipe

At least a year ago, I decided at random to write what is basically netcat, but with a server that defaults to broadcasting to all clients.

server.c

#include <signal.h>
#include "base.h"
typedef enum {
false = 0,
true = 1
} bool;
typedef struct {
bool running;
bool new;
int acceptfd;
char buff[MAX_LEN];
pthread_t id;
} process_info;
void * connect_thread(void * arg) {
process_info * info = (process_info *) arg;
info->running = true;
memset(info->buff, '\0', MAX_LEN);
usleep(200);
while(recv(info->acceptfd, info->buff, MAX_LEN - 1, 0) > 0) {
info->new = true;
while(info->new) {
usleep(200);
}
memset(info->buff, '\0', MAX_LEN);
}
info->running = false;
close(info->acceptfd);
pthread_exit(NULL);
}

int main(int argc, char ** argv) {
if(argc < 2)
return -1;
int sfd, acfd;
unsigned int size = sizeof(struct sockaddr_in);
unsigned int i, ct;
struct sockaddr_in addr, remote;
short port;
bool found;
process_info thread_info[MAX_CON];
signal(SIGKILL, exit);
if((port = atoi(argv[1])) == 0) {
fputs("Invalid port\n", stderr);
return -1;
}
if((sfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
return 1;
}
fcntl(sfd, F_SETFL, O_NONBLOCK);
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
memset(&(addr.sin_zero), '\0', 8);

if(bind(sfd, (struct sockaddr *) &addr, size) == -1) {
perror("bind");
return 2;
}

if(listen(sfd, MAX_CON) == -1) {
perror("listen");
return 3;
}
for(;;) {
if((acfd = accept(sfd, (struct sockaddr *) &remote, &size)) != -1) {
found = false;
for(i = 0; i < MAX_CON; i++) {
if(!thread_info[i].running) {
found = true;
break;
}
}
if(found) {
thread_info[i].acceptfd = acfd;
thread_info[i].running = true;
thread_info[i].new = false;
pthread_create(&(thread_info[i].id), NULL, connect_thread, &(thread_info[i]));
}
else
write(2, "Too many connections\n", 21);
}
for(ct = 0; ct < MAX_CON; ct++) {
if(thread_info[ct].running && thread_info[ct].new) {
write(1, thread_info[ct].buff, strlen(thread_info[ct].buff));
for(i = 0; i < MAX_CON; i++) {
if(thread_info[i].id != thread_info[ct].id && thread_info[i].running) {
send(thread_info[i].acceptfd, thread_info[ct].buff, strlen(thread_info[ct].buff), 0);
}
}
thread_info[ct].new = false;
}
}
}
}

client.c

#include "base.h"

void * recv_thread(void * arg) {
char buff[MAX_LEN];
memset(buff, '\0', MAX_LEN);
while(recv(*((int *) arg), buff, MAX_LEN, 0) > 0) {
write(1, buff, strlen(buff));
memset(buff, '\0', MAX_LEN);
}
pthread_exit(NULL);
}
int main(int argc, char ** argv) {
if(argc < 2)
return -1;
int sfd;
int size = sizeof(struct sockaddr_in);
short int port;
struct sockaddr_in remote;
char buff[MAX_LEN];
memset(buff, '\0', MAX_LEN);
char * ip_str = malloc(strlen(argv[1]) + 1);
struct hostent * host;
pthread_t child;
strcpy(ip_str, argv[1]);
port = get_port(ip_str);
rm_port(ip_str);

if((sfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
return 1;
}
host = gethostbyname(ip_str);
if(host == NULL) {
fprintf(stderr, "Unknown host: %s\n", ip_str);
return -2;
}

remote.sin_family = AF_INET;
remote.sin_port = htons(port);
memcpy(&(remote.sin_addr), *(host->h_addr_list), sizeof(remote.sin_addr));
memset(&(remote.sin_zero), '\0', 8);

if(connect(sfd, (struct sockaddr *) &remote, size) == -1) {
perror("connect");
return 2;
}
pthread_create(&child, NULL, recv_thread, &sfd);
while(read(0, buff, MAX_LEN - 1) > 0) {
send(sfd, buff, strlen(buff), 0);
memset(buff, '\0', MAX_LEN);
}
close(sfd);
free(ip_str);
}

base.h

#include <sys/types.h>
#include <netdb.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <unistd.h>
#include <wait.h>
#include <stdio.h>
#include <stdlib.h>
#define MAX_LEN 1024
short get_port(char * ip_str) {
char found = 0;
unsigned int i, len = strlen(ip_str);
for(i = 0; i < len; i++)
if(ip_str[i] == ':') {
found = 1;
break;
}
if(found > 0 && i < len - 1) {
return atoi(&(ip_str[i + 1]));
}
else
return -1;
}
void rm_port(char * ip_str) {
unsigned int i, len = strlen(ip_str);
for(i = 0; i < len; i++)
if(ip_str[i] == ':')
ip_str[i] = '\0';
}

No comments: