Capturing Input/Output of Another Process in C

In my travels in C programming, I periodically need to run another process and redirect its standard output back to the first process. While it is straight forward to perform, it is not always obvious. This article will explain the process of how this is done in three sections.

In my travels in C programming, I periodically need to run another process and redirect its standard output back to the first process. While it is straight forward to perform, it is not always obvious. This article will explain the process of how this is done in three sections.

  • High Level Overview
  • Explanation of each line
  • Code Sample

High Level Overview

  • Create a three pipe(2)s for standard input, output and error
  • fork(2) the process
  • The child process runs dup2(2) to over the pipes to redirect the new processes’s standard
  • input, output and error to the pipe.
  • The parent process reads from the pipe(2) descriptors as needed.


A pipe(2) is a Unix system call API that creates two file descriptors. Data written to one end of the pipe can be read by the other. It provides simple FIFO functionality without the need to maintain an associated data structure. The process should initially create three pipe(2) file descriptor pairs for standard input, output and error. For our purposes, it will be used to bridge communication between the parent and second process.

Next, our program will run a standard Unix fork(2), which creates a copy of the running processes, the stack and machine code, except with a different process ID. The return value for the parent is the process ID (pid) of the child, while the child returns 0.

dup2(2)‘s documentation says it “duplicates” a file descriptor, but I found this to be a misleading misnomer. In layman’s terms, dup2(2) cause any reads or writes to the newfd to be redirected (pointed) to the oldfd descriptor while the original newfd is closed. For our uses, the child process will use dup2(2) to redirect its standard input, output and error to the pipe(2) descriptors.

At this point, the child process will run execl(2), which will replace the current process with a new process. This is different than spawning a new process, such as through system(3), thought the effect would be the same. Now, because of the dup(2) calls, any reads or writes to standard input, output or error will be redirected to the respective pipe(2)‘s.

On the other end, the parent process will use the other end of the pipe(2) to read or write to the child process, thus accomplishing our objective.

Example Code

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define SAMPLE_STRING	"Bismillah"

int main() {
	int fdstdin[2];
	int fdstdout[2];
	int fdstderr[2];
	int pid;


	pid = fork();

	if (pid == 0) { /* Child process */
		int ret;
		 * Have the 2nd argument (oldd) point to
		 * the first argument, (newd)
		dup2(fdstdin[0], STDIN_FILENO);
		dup2(fdstdout[1], STDOUT_FILENO);
		dup2(fdstderr[1], STDERR_FILENO);


		/* This simulates a simple writing to stderr */
		system("printf Hi > /dev/stderr");

		/* Simulates writing from stdin to a test file */
		system("cat > `mktemp`");

		/* Typical method is to run execl(2). Here just using printf */
		ret = execl("/usr/bin/printf", "printf", "Hello World!", NULL); 

		if (ret == -1) {
			 * execl(2) returns -1 if an error occurs. Any
			 * debugging messages to the console would be
			 * interpreted as output of the process. Therefore,
			 * we will simply exit.
			 * The parent process's read attempts will return -1
	else { /* Parent process */
		char buf[1000];

		/* Close the other end of the pipe */

		/* Read from the stderr */
		read(fdstderr[0], buf, 1000);
		printf("Stderr message from child, simulated by a "
		    "system(): %s\n", buf);

		/* Sending data to the stdin of the child process */
		printf("Sending string '%s' to stdin, written to mktemp file.\n"

		write(fdstdin[1], SAMPLE_STRING, strlen(SAMPLE_STRING));
		/* Closing the stdin pipe */

		/* Read from the stdout */
		read(fdstdout[0], buf, 1000);
		printf("Stdout message from child, run with an execl(): %s\n",

Compiling and running this code should give you the following output.

$ ./redirect
Stderr message from child, simulated by a system(): Hi
Sending string 'Bismillah' to stdin, written to mktemp file.
Stdout message from child, run with an execl(): Hello World!

I hope this helps someone going forward! Thoughts?

This work is heavily based off of Cameron Zwarich’s excellent 1998 article Pipes in Unix from C-Scene, issue #4. I have it in hard-copy from 2001 and periodically refer back to it.

Avoiding Redundancy with Function Pointers

I am currently writing OpenGit, a BSD-licensed re-implementation of Linus Torvald’s Git (lower-cased going forward). This frequently involves reviewing git’s source code to understand how it works under the hood. One of the things I consistently encounter is git performing similar and sizable tasks in multiple different ways and places, resulting in redundancy and a higher maintenance cost.

In this brief entry, I will discuss a classic problem and how I solve it: When minor variants of a routine result in multiple implementations.

Example Pseudo-Code Problem

Git makes heavy use of zlib deflation, a library used to decompress arbitrary data. In the process, git will perform different subroutines, such as calculating an object’s cyclic redundancy check (CRC) or SHA1 value, both on deflated and inflated data, consuming the data in different ways. Rather than having a single deflation function, git re-implemented the deflation code in numerous different ways.

To help understand the problem, lets use this sample pseudo-code, which are decompression routines. The primary difference between the two functions is that one executes additional_routine_one() on the decompressed data, while the other executes additional_routine_two() on the uncompressed data.

decompress_routine_one(int fd, char *data, uint8_t *bin)
   int size;
   char compressed_data[1000];
   char *decompressed_data;

   do {
      size = read(fd, compressed_data, 1000);

      ... decompress the data ...

      additional_routine_one(decompressed_data, bin);
   } while(size <= 0);

decompress_routine_two(int fd, char *var)
   int size;
   char compressed_data[1000];
   char *decompressed_data;

   do {
      size = read(fd, compressed_data, 1000);
      additional_routine_two(compressed_data, var);

      ... decompress the data ...

   } while(size <= 0);

decompress_routine_one(fd, data, bin);
decompress_routine_two(fd, data, var);

In this example, both will decompress the data in the do-while loop, but perform different tasks and require different arguments for the routine.

  • The first executes additional_routine_one(), which uses two arguments: The decompressed_data and uses the bin variable.
  • The second executes additional_routine_two(), which utilizes the raw compressed data, and the variables var and size.

In other words, not only does the additional task change, the location of the task changes. This could be further complicated by the number of arguments that the additional routine utilizes.

Possible Solution

The best approach I have concluded with is to implement handler function pointers at the appropriate points in the primary routine. The application should verify if the handler is not necessary by checking if the pointer is set to NULL. This is, of course, not my own creation, but based on reviewing Linux and BSD (oh, and Windows) kernel implementations. Consider the following alternative.

typedef void datahandler(char *, int, void *);

additional_routine_one(char *data, int size, void *arg)
   char *x = arg;
   ... do something ...

additional_routine_two(char *data, int size, void *arg)
   int *x = arg;
   ... do something ...

decompress_routine(int fd, datahandler decompressed_handler, void *darg,
    datahandler compressed_handler, void *iarg)
   int size;
   char buf[1000];

   do {
      size = read(fd, buf, 1000);
      if (decompressed_handler)

      ... decompress the data ...

      if (compressed_handler)
   } while(size <= 0);

decompress_routine(fd, additional_routine_one, bin, NULL, NULL);
decompress_routine(fd, NULL, NULL, additional_routine_two, var);

In this example, the decompress_routine performs the same complex decompression algorithm, but rather than having two separate functions, at the appropriate points in each function they verify if a function pointer was passed, If so, it passes the respective argument.

Additionally, if the program must run both additional_routine_one and additional_routine_two the program can run:

decompress_routine(fd, additional_routine_one, bin, additional_routine_two, var);

Finally, if in cases where I require more than one argument, I typically pass a pointer to a structure with the data I need.

Potential Tradeoffs

  • Performance: There is a trivial cost to verifying if the function pointer is set to NULL or not. This may be irrelevant for general-purpose applications, but could be something to consider for extremely high-performing systems, where memory or disk utilization is not a concern.
  • Code clarity: Having a series of NULLs is “ugly” code. However, this can be trivially resolved by using macros to hide away the NULL references.

Thoughts? Comments? Threats?

Passing by Reference: C’s Garbage Collection

The C programming language has no built-in garbage-collection mechanism – and it very likely never will. This can (and does) lead to memory leaks by even the best programmers. It is also an imputes for the Rust language. However, depending on your use-case, it is still possible to structure your code to use the stack as a sort of zero-cost “garbage collector”.

Lets jump directly into the code!

This is how many applications instantiate and utilize a structure or arbitrary object.

struct resource *instance;
instance = malloc(sizeof(struct resource));
get_resource(instance); ... free(instance);

While this is a perfectly fine snippet of code, it requires the program to explicitly free(3) instance when it is no longer needed or risk a memory leak. There is also a slight performance loss from the malloc(3) and free(3).

Therefore, lately I have been using another method.

struct resource instance;

Rather than allocating memory, this uses the stack. When the variable is “destroyed” immediately after falling out of scope without the need for a free(3).

The downside, of course, is losing the ability to pass the pointer elsewhere after the initial allocating function closes. But, this can be overcome by creating the variable in the parent function to all those that need it.


SHA1 on FreeBSD Snippet

I needed some code that produces SHA1 digests for a project I am working on. I hunted through the FreeBSD’s sha1(1) code and produced this minimal snippet. Hopefully this helps someone else in the future.

Compile and run as follows:

$ cc shatest.c -o shatest -lmd
$ ./shatest
$ printf "bismillah" | sha1

Thanks to FreeBSD for maintaining such clean code!

Tracing ifconfig commands from userspace to device driver

I am currently working on expanding FreeBSD’s rtwn(4) wireless device driver. I have the basics down, such as initialization, powering on and off, loading the firmware, etc, and am now trying to fill in specific ifconfig(8) methods. This requires having an in depth knowledge of how ifconfig(8) commands pass are ultimately delivered to the driver. I could not find concise documentation that outlines each stage of the process. So I wrote one! 🙂

This article is specific to FreeBSD 12.0-CURRENT, but it should apply to any future version and other operating systems that utilizes net80211(4), such as OpenBSD, NetBSD, DragonFlyBSD and illumos. I hope it serves to help the FreeBSD community continue to develop WiFi and other device drivers.  This is not an exhaustive guide as there is far too many code, but it should provide you with the basic order of operations.

In this example, I will walk through changing the channel on your WiFi card and placing it in monitor mode as follows:

# ifconfig wlan0 channel 6 wlanmode monitor

High Level Summary

FreeBSD’s ifconfig(8) utilizes the lib80211(3) userspace library which functions as an API to populate kernel data structures and issue ioctl(2) syscall. The kernel receives the ioctl(2) syscall in a new thread, interprets the structure and routes the command to the appropriate stack. In our case this is net80211(4). The kernel then creates a new queued task and terminates the thread. Later on, a different kernel thread receives the queued task and runs the associated net80211(4) handler which immediately delivers execution to the device driver.

To summarize again:

Lets begin!

Userspace: ifconfig(8) + lib80211(3) library

Starting: ifconfig(8) executable

Startnig early in ifconfig(8), it opens a SOCK_DGRAM socket in /usr/src/sbin/ifconfig/ifconfig.c as follows:

s = socket(AF_LOCAL, SOCK_DGRAM, 0)

This socket functions as the interface for userspace to kernel communication. Rather than tracing from the if-else maze in main()1, I grepped for the string “channel” and found it in ieee80211_cmd[] defined at the end of /usr/src/sbin/ifconfig/ifieee80211.c. This table enumerates all ieee80211 ifconfig(8) commands. The “channel” command is defined as follows:

DEF_CMD_ARG("channel", set80211channel)

Note the second argument. I looked up DEF_CMD_ARG and found that it was a pre-processor macro that defines what function is run when the user sends ifconfig(8) a command. A quick grep search shows set80211channel is defined in /usr/src/sbin/ifconfig/ifieee80211.c. The parameters are fairly easy to identify: val is the new channel number (1 through 14) and s is the socket we opened earlier. This executes ifconfig(8)‘s set80211 function whose sole purpose is to cleanly transfer execution into the lib80211(3) library.

Userspace: lib80211(3) library

lib80211(3) is an 802.11 wireless network management library to formally communicate with the kernel. Its worth noting that neither OpenBSD nor NetBSD have this library and instead opt to communicate directly to the kernel.

As mentioned, ifconfig(8)‘s set80211 function calls lib80211_set80211, located in /usr/src/lib/lib80211/lib80211_ioctl.c. The lib80211_set80211 function populates an ieee80211req data structure, used for user-to-kernel ieee80211 communication. In the below example, this is the ireq variable, which contains the WiFi interface name and intended channel. The library then calls the ioctl(2), as follows:

ioctl(s, SIOCS80211, &ireq)

This runs the syscall to formally enter kernel-space execution. In essence, ifconfig(8) is nothing more than a fancy ioctl(2) controller. You could write your own interface configuration tool that directly calls the ioctl(2) syscall and get the same result. Now on to the kernel!

The Kernel: Kernel Command Routing to net80211(4)

There are two brief explanations before we proceed.

First, at a high-level the BSD kernel operates like an IP router in that it routes execution through the kernel, populating relevant data values along the way, until the execution reaches its destination handling functions. The following explanation shows how the kernel will identify the syscall type, determine that it is for an interface card, determine the type of interface card and finally queue a task for future execution.

Second, the BSD kernel utilizes a common pattern of using template methods that call a series of function pointers. The exact function pointers are conditionally populated, allowing the code to maintain a consistent structure while the exact implementation may differ. It works very well but can make tracing execution paths difficult if you are just reading the code straight through. When I had trouble, I typically used illumos’s OpenGrok or dtrace(1) .

Brief Dtrace Detour

Solaris’s dtrace(1) is a dynamic tracing tool imported to FreeBSD that is used to monitor a kernel or process in real time. It is useful in understanding what the operating system is doing and saves you the trouble of using printf(3)-style debugging. I used dtrace(1) in writing this guide identify what the kernel was executing, function arguments, and the stack trace at any given moment.

For example, if I wanted to monitor the ifioctl function, I might run this:

# dtrace -n '
> fbt:kernel:ifioctl:entry {
> self->cmd = args[1];
> stack(10);
> }
> fbt:kernel:ifioctl:return {
> printf("ifioctl(cmd=%x) = %x", self->cmd, arg1);
> exit(0);
> } '

This dtrace(1) one-line command sets up handlers for ifioctl‘s entry and return probes. On entry, dtrace(1) records the value of the 2nd argument cmd, and displays the last 10 elements of the stack. On return, it displays the function argument and return value. I used variations of this basic command template throughout my research, especially when I was confused in tracing the code or could not identify a function’s arguments.

Syscall Interception

The first non-assembly function is the amd64-specific syscall handler amd64_syscall that receives a new thread structure and identifies the type as a syscall. In our case it is for an ioctl(2) so amd64_syscall calls sys_ioctl located in /usr/src/sys/kern/sys_generic.c.

On FreeBSD sys_ioctl performs input validation and formats the data it receives. It then calls kern_ioctl which determines what type of file descriptor the ioctl(2) is working with, what the capabilities for the socket are and assigns the function pointer fo_ioctl accordingly. (NetBSD and OpenBSD do not have kern_ioctl. For them sys_ioctl directly calls fo_ioctl.) Our file descriptor corresponds to an interface, so FreeBSD assigns fo_ioctl as a function pointer to ifioctl, which handles interface-layer ioctl(2) calls. This function is located in /usr/src/sys/net/if.c.

Network IOCTL

The function ifioctl is responsible for all sorts of interfaces: Ethernet, WiFi, epair(4), etc. ifioctl starts with a switch-condition based on the cmd argument. This checks if the command can be handled by net80211(4) without needing to jump into the driver, such as creating a clone interface or updating the MTU. A quick dtrace(2) probe reveals that the cmd argument is SIOCS80211, which fails to meet any switch-conditions, so execution jumps to the bottom. The function continues and calls ifp->if_ioctl, which in the case of WiFi is a function pointer to ieee80211_ioctl, located in /usr/src/sys/net80211/ieee80211_ioctl.c.


ieee80211_ioctl contains another switch-case. With cmd set to SIOCS80211, execution matches the associated case and calls ieee80211_ioctl_set80211, located in /usr/src/sys/net80211/ieee80211_ioctl.c.

ieee80211_ioctl_set80211 has yet another switch-case with a few dozen conditions2. The ireq->i_type was set to IEEE80211_IOC_CHANNEL by lib80211(3) so it will match the associated case and execute ieee80211_ioctl_setchannel. The gist of this function is to determine if the input channel is valid or if the kernel needs to set any other values. It concludes by calling setcurchan, which does two things. First, it determines the validity of the channel and if any additional values must be set. Second, it runs ieee80211_runtask, that makes the final thread-level call to taskqueue_enqueue.

The Kernel: Task Execution

taskqueue_enqueue is not an ieee80211(9) function, but its worth a brief review. In a nutshell, the taskqueue(9) framework allows you to defer code execution into the future. For example, if you want to delay execution for 3 seconds, running the kernel equivalent of sleep(3) would cause the entire CPU core to halt for 3 seconds. This is unacceptable. Instead, taskqueue(9) allows you specify a function that the kernel will execute at a later time.

In our channel change example, the scheduled function is the net80211(4) function update_channel, located in /usr/src/sys/net80211/ieee80211_proto.c. When taskqueue(9) reaches our enqueued task, it will first initiate the update_channel handler to receive the task and immediately hand over execution to the driver code pointed to by ic_set_channel.

To summarize, up to this point the kernel has routed the command to the network stack, which routed to the WiFi-specific stack, where it was scheduled as a task for future execution. When taskqueue(9) reaches the task, it immediately jumps to the driver-specific code. At last, we entered the driver!

The Driver

From here on, the code is driver-specific and I will not get into the implementation details, as each device has its own unique channel changing process. I am currently working on rtwn(9), which is located in /usr/src/sys/dev/rtwn. NetBSD and OpenBSD separate USB and PCI drivers, so the same driver is located in /usr/src/sys/dev/usb/if_urtwn.c and /usr/src/sys/dev/pci/if_rtwn.c, respectively.

Operating Systems need a standard way to communicate with device drivers. Typically, the driver provides a structure containing a series of function pointers to driver-specific code and the kernel uses this as an entry-point into the driver code. In the case of WiFi, this structure is ieee80211com, located in /usr/src/sys/net80211/ieee80211_var.h. By convention, all BSD-derived systems use the variable name ic to handle ieee80211(9) methods.

In our case, we are changing the channel, so the operating system will call ic->ic_set_channel, which is a pointer to the driver’s channel changing function. For rtwn(9), this is rtwn_set_channel, which itself is a function pointer to r92c_set_chanr92e_set_chan or r12a_set_chan, depending on which specific device you are using.

The specifics of rtwn(9) are outside of the scope of this article, but it is worth discussing how the driver communicates to the hardware.

The softc structure is a struct that maintains the device’s run-time variables, states, and method implementations. By convention, each driver’s softc instance is called sc. You might wonder why you need yet another method function pointer when ieee80211com provides that. This is because ieee80211com‘s methods point to command handlers, not necessarily to device routines. A device drivers may have their own internal methods that are not part of ieee80211com. Also, the softc structure can handle minor variations between device versions. rtwn(9)‘s softc struct is called rtwn_softc and located in /usr/src/sys/dev/rtwn/if_rtwnvar.h.

How does a driver send data to the driver? rtwn(9) uses the rtwn_write_[1|2|4] and rtwn_read_[1|2|4] methods to actually send or receive a byte, word or double-word3. rtwn_read_1 is a pointer to the sc_read_1 method.

The driver assigns the sc_read class of functions at initialization to either the rtwn_usb_read_* and rtwn_usb_write_* methods or rtwn_pci_read_* and rtwn_pci_write_*. The aforementioned class of functions are abstractions to the PCI and USB buses. In the case of PCI, these function calls will eventually call bus_space_read_* and bus_space_write_*, which are part of the PCI subsystem. In the case of USB, the driver will call usbd_do_request_flags, which is part of the USB subsystem. A well-written driver should abstract these bus-specific layers and provide you with clean read and write methods for various data sizes. As an aside, FreeBSD is long overdue for an SDIO stack and this is a major impediment for the Raspberry Pi, Chromebooks and other embedded devices. But I digress…

As an example, the driver uses the following line to enable hardware interrupts.

rtwn_write_4(sc, R92C_HIMR, R92C_INT_ENABLE);

This will write the value R92C_INT_ENABLE to the R92C_HIMR device register.

The End

To summarize this long journey, the ifconfig(8) opens a socket and passes it to the lib80211(3) library. lib80211(3) sends a userspace-to-kernel command structure to the kernel with an ioctl(2) syscall. The syscall triggers the kernel to run a new kernel thread. From here, the kernel determines that theioctl(2) command corresponds to a network card, specifies the type as a WiFi card, then identifies the exact command type. The ieee80211(9) tells taskqueue to create a new task to change the WiFi channel, then terminates. Later on, the taskqueue(9) runs the ieee80211(9) task handler that transfers execution to the driver. The driver communicates to the hardware using the PCI or USB buses to change the WiFi channel.

In conclusion, in my opinion, FreeBSD is technically superior to Linux, but lacks in several critical areas, among which is hardware support. I hope this article serves the FreeBSD community to continue to produce high-quality, faster device drivers.

Thank you


  1. Linux has a point when they argue that the classic ifconfig(8) is antiquated. Its syntax is inconsistent and this is reflected in the spaghetti-code of if-then conditions.
  2. Note: on my FreeBSD 11.1-RELEASE kernel this function was optimized out, so dtrace(1) probes failed. You should be able to add CFLAGS= -O0 -fno-inline to your /etc/make.conf, but that did not seem disable the optimization for me. Your mileage may vary.
  3. Lets use rtwn_read_1 for now, but the concepts apply to the others.

[This article was also published in the January/February 2018 edition of the FreeBSD Journal]

Why Numerous Programming Languages?

There are numerous programming languages out there, some of which have general purpose and some have specific purposes. Here are some of the languages I’ve come across.

  • Assembly Language – This is not so much a language, as a way to write raw CPU instructions in a way that’s more human readable. I’ve only seen it used to write simple libraries and low-level operating system functions.
  • BASIC – A business programming language used to perform simple tasks or games.
  • C/C++ – These are general purpose languages that run directly on the hardware, which means dealing directly with memory and operating system specifics. Their manipulation of the hardware can only be through the operating system.
  • C# – Uses C++, but calls upon a uniquely Microsoft .NET library.
  • Java – A general purpose language that does not run on the physical hardware. It was primarily built to make the binary executable portable across all physical platforms and OS’s
  • Perl – An interpreted scripting language. It was initially created as a “glue language” to perform simple tasks or fit into unique places (such as a robust CGI language).
  • PHP – A web scripting language that is interpreted through a PHP interpreter.
  • Python – Object-oriented, multi-platform, interpreted language (which means it requires an interpreter). Never used it, so here it is.
  • Ruby – I don’t know much about, so here’s a link.

This list could go on forever. I should also add Fortran and Pascal to this list (but I won’t).

There is no “best language”, there are just different languages for different purposes. But if you are going to learn a language for general purposes, I would suggest C++, one of those .NET languages or Java.

Found Old Chat Server Project

During my high school years, I used to be part of an “underground” IRC server. We would talk about security-related topics and the latest exploits, usually about some Unix variant. Even though no one would really care about our late-night computer conversations, I thought it best that we chat over an encrypted medium, and considering that I knew nothing about how SSL could serve to transparently encrypt IRC daemons and clients, I decided to write my own encrypted chat server. Below is the C code using the Unix API for the very simple framework. I planned on adding encryption for which I was learning the GMP library. I wrote the code below my junior year of HS.

I tried to re-create this project in undergrad, but kept failing and never figured out why. I randomly found a printout of this structure among some old papers.

Pretty certain there’s a memory leak here somewhere, but eh…

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <arpa/inet.h>

struct clientinfo {
   int fd;
   struct sockaddr_in info;

int rmfd(struct clientinfo *connects, int location, int numcon) {
   int count;
   struct clientinfo *temp;

      connects[count] = connects[count+1];

   temp = malloc(sizeof(struct clientinfo)*(numcon-1+(numcon-1==0)));

   for(count=0;countsizeof(struct clientinfo)*(numcon-1+(numcon-1==0)));
   for(count=0;countreturn numcon-1;

int addfd(struct clientinfo *connects, int numcon) {
   struct clientinfo *temp;
   int count;
   temp = malloc(sizeof(struct clientinfo) * (numcon+(numcon==0)));
   for(count=0;countsizeof(struct clientinfo)*(numcon+1));
   for(count=0;countreturn numcon+1;

int main(int argc, char **argv) {
   int check;
   int sin_size;
   int numcon;
   int maxfd;
   int readtest;
   int writecount;
   char rwbuf[1024];
   struct timeval timer;
   struct clientinfo *connects;
   fd_set sockrd;

   if (argc != 2) {
      fprintf(stderr, "usage: %s port\n", argv[0]);

   sin_size = sizeof(struct sockaddr);
   numcon = 0;
   connects = malloc(sizeof(struct clientinfo));
   connects[0].info.sin_family = AF_INET;
   connects[0].info.sin_port = htons(atoi(argv[1]));
   connects[0].info.sin_addr.s_addr = INADDR_ANY;

   connects[0].fd = socket(AF_INET, SOCK_STREAM, 0);
   check = bind(connects[0].fd, (struct sockaddr *)&connects[0].info, sizeof(struct sockaddr));
   if(check == -1) {
   check = listen(connects[0].fd, 1024);
   if (check == -1) {
   maxfd = connects[0].fd;
   for(;;) {
      FD_SET(connects[0].fd, &sockrd);
         FD_SET(connects[check].fd, &sockrd);
      timer.tv_sec = 60;
      timer.tv_usec = 0;

      select(maxfd+1, &sockrd, NULL, NULL, &timer);
      if (FD_ISSET(connects[0].fd, &sockrd)) {
         sin_size = sizeof(struct sockaddr_in);
         numcon = addfd(connects, numcon);
         connects[numcon].fd = accept(connects[0].fd, (struct sockaddr *)&connects[numcon].info, &sin_size);
         if (connects[numcon].fd > maxfd)
            maxfd = connects[numcon].fd;
      else {
         for(readtest=1;readtest<=numcon;readtest++) {
            if(FD_ISSET(connects[readtest].fd, &sockrd)) {
               memset(rwbuf, 0, 1024);
               check = read(connects[readtest].fd, rwbuf, 1024);
               if (check == 0) {
                  numcon = rmfd(connects, readtest, numcon);
               else {
                  for(writecount=1;writecount<=numcon;writecount++) {
                     if (writecount != readtest)
                        write(connects[writecount].fd, rwbuf, 1024);