Tag Archives: C/C++

A Simple Telnet Client

This is a simple telnet client written in C. In the negotiation phase of the connection it will respond with WONT to any DO coming from the server, and it will encourage the server to DO anything it offers with WILL. The only exception is the screen size setting, advertised as 24 x 80 by the client.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <termios.h>
#include <fcntl.h>

#define DO 0xfd
#define WONT 0xfc
#define WILL 0xfb
#define DONT 0xfe
#define CMD 0xff
#define CMD_ECHO 1
#define CMD_WINDOW_SIZE 31

void negotiate(int sock, unsigned char *buf, int len) {
	int i;
	
	if (buf[1] == DO && buf[2] == CMD_WINDOW_SIZE) {
		unsigned char tmp1[10] = {255, 251, 31};
		if (send(sock, tmp1, 3 , 0) < 0)
			exit(1);
		
		unsigned char tmp2[10] = {255, 250, 31, 0, 80, 0, 24, 255, 240};
		if (send(sock, tmp2, 9, 0) < 0)
			exit(1);
		return;
	}
	
	for (i = 0; i < len; i++) {
		if (buf[i] == DO)
			buf[i] = WONT;
		else if (buf[i] == WILL)
			buf[i] = DO;
	}

	if (send(sock, buf, len , 0) < 0)
		exit(1);
}

static struct termios tin;

static void terminal_set(void) {
	// save terminal configuration
	tcgetattr(STDIN_FILENO, &tin);
	
	static struct termios tlocal;
	memcpy(&tlocal, &tin, sizeof(tin));
	cfmakeraw(&tlocal);
	tcsetattr(STDIN_FILENO,TCSANOW,&tlocal);
}

static void terminal_reset(void) {
	// restore terminal upon exit
	tcsetattr(STDIN_FILENO,TCSANOW,&tin);
}

#define BUFLEN 20
int main(int argc , char *argv[]) {
	int sock;
	struct sockaddr_in server;
	unsigned char buf[BUFLEN + 1];
	int len;
	int i;

	if (argc != 2) {
		printf("Usage: %s address [port]\n", argv[0]);
		return 1;
	}
	int port = 23;
	if (argc == 3)
		port = atoi(argv[2]);

	//Create socket
	sock = socket(AF_INET , SOCK_STREAM , 0);
	if (sock == -1) {
		perror("Could not create socket. Error");
		return 1;
	}

	server.sin_addr.s_addr = inet_addr(argv[1]);
	server.sin_family = AF_INET;
	server.sin_port = htons(23);

	//Connect to remote server
	if (connect(sock , (struct sockaddr *)&server , sizeof(server)) < 0) {
		perror("connect failed. Error");
		return 1;
	}
	puts("Connected...\n");

	// set terminal
	terminal_set();
	atexit(terminal_reset);
	
	struct timeval ts;
	ts.tv_sec = 1; // 1 second
	ts.tv_usec = 0;

	while (1) {
		// select setup
		fd_set fds;
		FD_ZERO(&fds);
		if (sock != 0)
			FD_SET(sock, &fds);
		FD_SET(0, &fds);

		// wait for data
		int nready = select(sock + 1, &fds, (fd_set *) 0, (fd_set *) 0, &ts);
		if (nready < 0) {
			perror("select. Error");
			return 1;
		}
		else if (nready == 0) {
			ts.tv_sec = 1; // 1 second
			ts.tv_usec = 0;
		}
		else if (sock != 0 && FD_ISSET(sock, &fds)) {
			// start by reading a single byte
			int rv;
			if ((rv = recv(sock , buf , 1 , 0)) < 0)
				return 1;
			else if (rv == 0) {
				printf("Connection closed by the remote end\n\r");
				return 0;
			}

			if (buf[0] == CMD) {
				// read 2 more bytes
				len = recv(sock , buf + 1 , 2 , 0);
				if (len  < 0)
					return 1;
				else if (len == 0) {
					printf("Connection closed by the remote end\n\r");
					return 0;
				}
				negotiate(sock, buf, 3);
			}
			else {
				len = 1;
				buf[len] = '\0';
				printf("%s", buf);
				fflush(0);
			}
		}
		
		else if (FD_ISSET(0, &fds)) {
			buf[0] = getc(stdin); //fgets(buf, 1, stdin);
			if (send(sock, buf, 1, 0) < 0)
				return 1;
			if (buf[0] == '\n') // with the terminal in raw mode we need to force a LF
				putchar('\r');
		}
	}
	close(sock);
	return 0;
}

C Cheat Sheet

Array initialization

int a[4] = {[2] = 6, [3] = 7};
int grid[100][100] = [0][0] = 8, [50][25] = 7};

Structure initialization

struct address {
                 int street_no;
                 char *street_name;
                 char *city;
                 char *prov;
                 char *postal_code;
};
struct address temp_address = { .city = "Hamilton", .prov = "Ontario" };

struct a {
         struct b {
              int c;
              int d;
          } e;
         float f;
} g = {.e.c = 3 };

Union initialization

union {
      char birthday[9];
      int age;
      float weight;
} people = { .age = 14 };

printf format

%[flags][min field width][precision][length]conversion specifier

where:

flags:   
   #	Alternate
   0	zero pad
   -	left align
   +	explicit + - sign
     	space for + sign
   '	locale thousands grouping
   I	Use locale's alt digits  

min field width: #,*

precision: .#, .*

length:
   hh	char
   h	short
   l	long
   ll	long long
   j	[u]intmax_t
   z	size_t
   t	ptrdiff_t
   L	long double

conversion specifier:
   c	unsigned char
   d	signed int
   u	unsigned int
   x	unsigned hex int
   X	unsigned HEX int
   e	[-]d.ddde±dd double,
   E	[-]d.dddE±dd double

Examples:

printf("%08X", var);		00001234
printf("%20s","string");	string (right aligned)
printf("%*s", 20, "string");	string (right aligned, the alignment is specified as an argument)
printf("%-20s", "string");	string (left aligned)
printf("%-20.20s", "string");	string (the string is truncated if it is too long)