Yesterday I posted a request for a code review. After reviewing the code and the reviews, and after some sleep, I decided I can do better. In fact I logged on with the intent of deleting the question just as the first review was posted; so I was stuck with it.
This is pretty much the same program, but it is the result of much more effort. It even includes a thing I've never used before: select
. To use the program, and the previous program, the user provides two arguments: the target IP and the target port. Contrary to the last program, this program terminates with ctrlc.
#include <signal.h>
#include <arpa/inet.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#define BUFLEN 1024
#define STDIN 0
#define STDOUT 1
void sigint_handle(int dummy);
int connect_to(char *host, int port);
int transfer(int fd_in, char *buf, int buf_len, int fd_out);
// boolean flag for program continuation
volatile int run = 1;
// entry point of linux ELF
int main(int args, char **argv) {
int sd, ret_val = 0;
fd_set fds;
struct timeval tv;
char buffer[BUFLEN];
assert(args == 3);
signal(SIGINT, sigint_handle);
sd = connect_to(argv[1], atoi(argv[2]));
FD_ZERO(&fds);
tv.tv_sec = 0;
tv.tv_usec = 10000;
while (run) {
FD_SET(STDIN, &fds);
FD_SET(sd, &fds);
ret_val = select(sd + 1, &fds, NULL, NULL, &tv);
if (FD_ISSET(STDIN, &fds))
ret_val = transfer(STDIN, buffer, BUFLEN, sd);
else if (FD_ISSET(sd, &fds))
ret_val = transfer(sd, buffer, BUFLEN, STDOUT);
assert(ret_val == 0);
}
close(sd);
return 0;
}
// SIGINT handler
void sigint_handle(int dummy) {
run = 0;
}
// a very picky connect to tcp host function
int connect_to(char *host, int port) {
struct sockaddr_in addr;
int sd = socket(AF_INET, SOCK_STREAM, 0);
memset(&addr, 0, sizeof(addr));
assert(sd > -1);
addr.sin_family = AF_INET;
assert(inet_pton(AF_INET, host, &addr.sin_addr) > 0);
addr.sin_port = htons(port);
assert(connect(sd, (struct sockaddr *)&addr, sizeof(addr)) > -1);
return sd;
}
// transfer function - basically a one time pipe
int transfer(int fd_in, char *buf, int buf_len, int fd_out) {
int len = read(fd_in, buf, buf_len);
return len - write(fd_out, buf, len);
}
I should note it's not really meant to be user friendly. It's meant to do one specific task as a subprocess, and panics otherwise; again using ctrlc to quit.
import subprocess
import signal
import os
import socket
def dostuff():
host = socket.gethostbyname("google.com")
proc = subprocess.Popen(["./client " + host + " 80"],
stdout=subprocess.PIPE, shell=True,
stdin=subprocess.PIPE)
global pid
pid = proc.pid
proc.stdin.write("GET /\n\n")
while proc.poll() is None:
print proc.stdout.readline()
if __name__ == "__main__":
try: dostuff()
except: os.kill(pid, signal.SIGINT)
STDIN
andSTDOUT
? – Jamal♦ Jun 26 '15 at 0:34stdin
andstdout
already have the same file descriptor values. – Jamal♦ Jun 26 '15 at 0:37