Skip to content

Instantly share code, notes, and snippets.

@insipx
Last active June 15, 2016 20:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save insipx/b49080f77046ee1a332e97c69a302d4e to your computer and use it in GitHub Desktop.
Save insipx/b49080f77046ee1a332e97c69a302d4e to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#define TRUE 1
#define FALSE 0
#define PORT "3490" // le beautiful port
#define BACKLOG 10 // # of pending conn queue will hold
int opt = TRUE;
int master_socket, addrlen, new_socket, client_socket[30], max_clients = 30, activity,
i, valread, sd;
int max_sd;
struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage their_addr; // remotehost addr info
socklen_t sin_size;
int yes=1;
char s[INET6_ADDRSTRLEN];
int address_info;
char buffer[1025];
char *msg;
void setmsg(char *buf){
msg = buf;
}
void *get_in_addr(struct sockaddr *sa){
if (sa -> sa_family == AF_INET){ //if IPv4
return &(((struct sockaddr_in*)sa)->sin_addr);//return the addr of 'sin'
}
//else we have an IPv6 addr
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
uint16_t get_in_port(struct sockaddr *sa)
{
return (((struct sockaddr_in*)sa) ->sin_port);
}
int main(int argc, char *argv[])
{
memset(&hints, 0, sizeof(hints)); //zero the struct
hints.ai_family = AF_UNSPEC; //set the type of connection to IPv4/6
hints.ai_socktype = SOCK_STREAM; //TCP stream sockets
hints.ai_flags = AI_PASSIVE; //fill in IP for me
fd_set readfds;
char *message = "ECHO Daemon v1.0 \r\n";
//init client socket to 0 so not checked
for(i = 0; i < max_clients; i++){
client_socket[i] = 0;
}
//create master socket
if((master_socket = socket(AF_UNSPEC, SOCK_STREAM, 0)) == 0)
{
perror("[!!] socket failed");
exit(EXIT_FAILURE);
}
//set master socket to allow multiple connections
//(will work w/o this is a safegaurd
//get addr info
if((address_info = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0){
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(address_info));
return 1;
}
//loop through results and bind to first we can
for(p = servinfo; p != NULL; p = p -> ai_next){
if((master_socket = socket(p->ai_family, p->ai_socktype, //get a socket desc
p->ai_protocol)) == -1){
perror("[!ERROR!!] server: socket");
continue;
}
if(setsockopt(master_socket, SOL_SOCKET, SO_REUSEADDR, (char*)&opt,
sizeof(opt))<0)
{
perror("[!!] setsockopt");
exit(EXIT_FAILURE);
}
if(bind(master_socket, p->ai_addr,p->ai_addrlen) == -1){ //bind to it
close(master_socket);
perror("[!ERROR!] server bind failed");
continue;
}
break;
}
freeaddrinfo(servinfo);
//reached the end of the LL :'(
if (p == NULL){
fprintf(stderr, "[!!!] Server: failed to bind\n");
exit(1);
}
if(listen(master_socket, BACKLOG) == -1){
perror("listen");
exit(EXIT_FAILURE);
}
printf("[server] establishing connection...\n");
while(TRUE){
sin_size = sizeof their_addr;
FD_ZERO(&readfds);
FD_SET(master_socket, &readfds);
max_sd = master_socket;
//add child sockets to set
for(i = 0; i < max_clients; i++){
sd = client_socket[i];
//if valid socket desc add to read list
if(sd > 0) FD_SET(sd, &readfds);
//highest file desc #, need it for select func
if(sd > max_sd) max_sd = sd;
}
//wait for activity on one of the sockets, timeout NULL, so this will wait..foreverr 0.0
activity = select(max_sd + 1, &readfds, NULL, NULL, NULL);
if((activity < 0) && (errno!=EINTR)) printf("[!!] select error");
if(FD_ISSET(master_socket, &readfds))
{
new_socket = accept(master_socket, (struct sockaddr*)&their_addr,&sin_size);
if(new_socket == -1){
perror("[!!] Could not Accept");
continue;
}
printf("New Connection, socket fd is %d, ip is: %s, port: %d \n",new_socket,
inet_ntop(their_addr.ss_family,
get_in_addr((struct sockaddr *) &their_addr),
s,
sizeof s),
htons(get_in_port((struct sockaddr *)&their_addr)));
if(send(new_socket, message, strlen(message), 0) != strlen(message))
{
perror("[!!] send");
}
puts("Welcome message sent successfully");
for(i = 0; i < max_clients; i++)
{
if(client_socket[i] == 0)
{
client_socket[i] = new_socket;
printf("Adding to list of sockets as %d\n",i);
break;
}
}
}
for (i = 0; i < max_clients; i++)
{
sd = client_socket[i];
if(FD_ISSET(sd,&readfds))
{
//check if it was for closing, also read inc msg
if ((valread = read(sd, buffer, 1024)) == 0)
{
//somebody d/ced get deets and p
getpeername(sd,(struct sockaddr*)&their_addr, (&sin_size));
printf("Host disconnected, ip %s, port %d \n", inet_ntop(their_addr.ss_family,
get_in_addr((struct sockaddr *)&their_addr),
s,
sizeof(s)),
htons(get_in_port((struct sockaddr *)&their_addr)));
close (sd);
client_socket[i] = 0;
}else{
//set string terminating NULL byte on end of data read
buffer[valread] = '\0';
send(sd, buffer, strlen(buffer), 0);
}
}
}
}
return 0;
}
/* //play with these to send data to clients
*
* 'send all' b/c kernel may not send all bytes over the network
* that is out of our control, but we need to make s ure everything makes it over
*
//sometimes not all of the data sends >.< ....
int sendall(int s, char *buf, int *len){
int total = 0;
int bytesleft = *len;
int n;
while(total < *len){
n = send(s, buf+total, bytesleft, 0);
if(n==-1){
perror("[!!!] could not send");
break;} //means send failed
total += n; //tally up what was sent
bytesleft -= n; //bytes left to send
}
*len = total; //number actually sent
return n == -1? -1:0; //return -1 on failure, 0 on success
}
int sendmesg(){
int len = strlen(msg) + 1;
if (sendall(new_fd, msg, &len) == -1){
perror("[!!!] could not send");
return -1;
}
sleep(1);
return 0;
}
void *sendmesgptr(){
//could do an if-else error structure here, but it's covered in sendmesg() already
sendmesg(msg);
return NULL;
}
*/
//kill outgoing
void killout(){
close(master_socket);
//close client sockets here
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment