Skip to content

Instantly share code, notes, and snippets.

@en-em
Created September 25, 2016 12:04
Show Gist options
  • Save en-em/e8889248644723b0fc28ce2dd5d50701 to your computer and use it in GitHub Desktop.
Save en-em/e8889248644723b0fc28ce2dd5d50701 to your computer and use it in GitHub Desktop.
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <netdb.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <stdint.h>
#ifndef __USE_POSIX
#define __USE_POSIX
#endif
#include <limits.h>
static void my_exit (int code)
{
rl_callback_handler_remove();
printf ("Bye!\n");
exit (code);
}
static void handle_error (const char* s)
{
perror (s);
my_exit (EXIT_FAILURE);
}
static int socket_to_write;
void my_write (int fd, void* data, size_t size)
{
char* d = data;
int n_written;
while ((n_written = write (fd, d, size)) < size)
{
if (n_written < 0)
handle_error ("write");
size -= n_written;
d += n_written;
}
}
static void my_read (int fd, void* data, size_t size)
{
char* d = data;
int n_read;
while ((n_read = read (fd, d, size)) < size)
{
if (n_read == 0)
my_exit (EXIT_SUCCESS);
if (n_read < 0)
handle_error ("read");
size -= n_read;
d += n_read;
}
}
static void my_rlhandler(char* line)
{
if (line == NULL)
my_exit (EXIT_SUCCESS);
size_t len = strlen(line);
if (*line != 0)
{
add_history(line);
uint32_t wlen = htonl(len);
my_write (socket_to_write, &wlen, sizeof(wlen));
my_write (socket_to_write, line, len);
}
free (line);
}
static char* readdata (int fd)
{
uint32_t sz;
my_read (fd, &sz, sizeof(sz));
size_t size = ntohl(sz);
char* s = malloc(size+1);
my_read (fd, s, size);
s[size] = 0;
return s;
}
static void communicate(int sock)
{
fd_set fds;
socket_to_write = sock;
rl_callback_handler_install("> ", (rl_vcpfunc_t*) &my_rlhandler);
while (1)
{
FD_ZERO(&fds);
FD_SET(sock, &fds);
FD_SET(0, &fds);
while (select (sock+1, &fds, 0, 0, 0) < 0)
{
if (errno != EINTR && errno != EAGAIN)
handle_error("select");
}
if (FD_ISSET(0, &fds))
{
rl_callback_read_char();
}
if (FD_ISSET(sock, &fds))
{
char* message = readdata (sock);
int saved_point = rl_point;
char *saved_line = rl_copy_text(0, rl_end);
rl_save_prompt();
rl_replace_line("", 0);
rl_redisplay();
printf("] %s\n", message);
free(message);
rl_restore_prompt();
rl_replace_line(saved_line, 0);
rl_point = saved_point;
rl_redisplay();
free(saved_line);
}
}
}
static void usage (const char* pgm)
{
fprintf (stderr, "Usage: %s [-p port] [hostname]\n", pgm);
exit (EXIT_FAILURE);
}
int main (int argc, char* argv[])
{
int ls, cs;
struct sockaddr_in addr;
int port = 9999;
if (argc > 1)
{
if (strcmp(argv[1], "-p") == 0)
{
if (argc > 2)
{
port = atoi(argv[2]);
argv += 2;
argc -= 2;
}
else
usage(argv[0]);
}
}
if (argc == 1)
{
struct sockaddr_in peer;
// we are server
ls = socket(AF_INET, SOCK_STREAM, 0);
if (ls < 0)
handle_error("socket");
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(9999);
if (bind(ls, (struct sockaddr *) &addr,
sizeof(struct sockaddr_in)) < 0)
handle_error("bind");
if (listen (ls, 1) < 0)
handle_error ("listen");
printf ("Waiting for a connection...");
fflush(stdout);
socklen_t addrlen=sizeof(peer);
if ((cs = accept(ls, (struct sockaddr*)&peer, &addrlen)) >= 0)
{
char hostname[HOST_NAME_MAX+1];
getnameinfo ((struct sockaddr*)&peer, addrlen, hostname, HOST_NAME_MAX+1, 0, 0, 0);
printf ("Connected to %s\n", hostname);
communicate (cs);
}
handle_error ("accept");
}
else if (argc == 2)
{
struct hostent *server;
server = gethostbyname(argv[1]);
if (!server)
handle_error("gethostbyname");
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
memcpy (&addr.sin_addr.s_addr, server->h_addr, sizeof(addr.sin_addr.s_addr));
addr.sin_port = htons(9999);
cs = socket(AF_INET, SOCK_STREAM, 0);
if (cs < 0)
handle_error("socket");
if (connect (cs, (struct sockaddr *) &addr,
sizeof(struct sockaddr_in)) < 0)
handle_error("connect");
communicate (cs);
}
else
usage(argv[0]);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment