Skip to content

Instantly share code, notes, and snippets.

@yitznewton
Created July 11, 2012 18:56
Show Gist options
  • Save yitznewton/3092365 to your computer and use it in GitHub Desktop.
Save yitznewton/3092365 to your computer and use it in GitHub Desktop.
Knock-knock telnet server
#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