Created
July 11, 2012 18:56
-
-
Save yitznewton/3092365 to your computer and use it in GitHub Desktop.
Knock-knock telnet server
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <string.h> | |
#include <errno.h> | |
#include <stdlib.h> | |
#include <sys/socket.h> | |
#include <arpa/inet.h> | |
#include <unistd.h> | |
#include <signal.h> | |
int listener_global; | |
void error(char *msg) | |
{ | |
fprintf(stderr, "Error: %s\n", msg); | |
} | |
void error_fatal(char *msg) | |
{ | |
error(msg); | |
exit(1); | |
} | |
void handle_shutdown(int sig) | |
{ | |
if (listener_global) { | |
close(listener_global); | |
} | |
fprintf(stderr, "Toodles!\n"); | |
exit(0); | |
} | |
int register_handler(int sig, void (*handler)(int)) | |
{ | |
struct sigaction action; | |
action.sa_handler = handler; | |
sigemptyset(&action.sa_mask); | |
action.sa_flags = 0; | |
return sigaction(sig, &action, NULL); | |
} | |
void assert_ok(int code, char *msg) | |
{ | |
if (code == -1) { | |
error_fatal(msg); | |
} | |
} | |
int initialize_listener() | |
{ | |
int listener = listener_global = socket(PF_INET, SOCK_STREAM, 0); | |
int reuse = 1; | |
assert_ok(setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, | |
(char *) &reuse, sizeof(int)), "Can't open socket"); | |
struct sockaddr_in name; | |
name.sin_family = PF_INET; | |
name.sin_port = (in_port_t) htons(30000); | |
name.sin_addr.s_addr = htonl(INADDR_ANY); | |
assert_ok(bind(listener, (struct sockaddr *) &name, sizeof(name)), | |
"Can't bind"); | |
assert_ok(listen(listener, 10), "Can't start listening"); | |
return listener; | |
} | |
int accept_on_demand(int listener) | |
{ | |
struct sockaddr_storage client_addr; | |
unsigned int address_size = sizeof(client_addr); | |
return accept(listener, (struct sockaddr *) &client_addr, | |
&address_size); | |
} | |
void send_to(int connection, char *msg) | |
{ | |
assert_ok(send(connection, msg, strlen(msg), 0), "Can't send"); | |
} | |
int expect_from(int connection, char *msg) | |
{ | |
char input[255]; | |
assert_ok(read_in(connection, input, sizeof(input)), | |
"Can't read in"); | |
return strncasecmp(msg, input, strlen(msg)) == 0; | |
} | |
int read_in(int connection, char *buf, int len) | |
{ | |
char *s = buf; // copy the pointer to shuttle through it | |
int slen = len; | |
int c = recv(connection, s, slen, 0); | |
while ((c > 0) && (s[c-1] != '\n')) { | |
s += c; | |
slen -= c; | |
c = recv(connection, s, slen, 0); | |
fprintf(stderr, "Beep\n"); | |
} | |
if (c < 0) { | |
// error | |
return c; | |
} | |
else if (c == 0) { | |
// empty | |
buf[0] = '\0'; // set buffer to start with null char | |
} | |
else { | |
buf[c-1] = '\0'; // replace \r with \0 | |
} | |
return len - slen; | |
} | |
int main() | |
{ | |
register_handler(SIGINT, handle_shutdown); | |
int listener = initialize_listener(); | |
puts("Waiting for connection..."); | |
while(1) { | |
int connect_d = accept_on_demand(listener); | |
send_to(connect_d, "Knock! Knock!\n"); | |
if (!expect_from(connect_d, "Who's there?")) { | |
send_to(connect_d, "Shoulda said \"Who's there?\". Bye!\n"); | |
assert_ok(close(connect_d), "Can't close connection"); | |
continue; | |
} | |
send_to(connect_d, "Oscar\n"); | |
if (!expect_from(connect_d, "Oscar who?")) { | |
send_to(connect_d, "Shoulda said \"Oscar who?\". Bye!\n"); | |
assert_ok(close(connect_d), "Can't close connection"); | |
continue; | |
} | |
send_to(connect_d, "Oscar silly question, get a silly answer!\n"); | |
assert_ok(close(connect_d), "Can't close connection"); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment