int socket(int domain, int type, int protocol);creates a socket (the return value is a file descriptor)
int shutdown(int sockfd, int how);shuts down reading from a socket (how == SHUT_RD), writing to a socket (how == SHUT_WR), or both
int close(int sockfd);closes a socket (or any other file descriptor).
int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);binds the given socket to the given address, found in the first addrlen of memory pointed to by my_addr. See ip(7) for details.
int listen(int sockfd, int backlog);specifies willingness to accept connections, and how many can be queued.
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);waits for an actual connection, returns a new socket and the address of the peer.
int connect(int sockfd, struct sockaddr *serv_addr, socklen_t addrlen);requests a connection. The address is in the same format as for bind(2).
int gethostname(char *name, int len);if len is greater than the length of the domain name of the local host, fills in name.
struct hostent *gethostbyname(const char *n);given a null-terminated name (domain name or dotted IP address), returns a host entry, if possible. See gethostbyname(3) for details of the hostent structure.
struct protoent *getprotobyname(const char *n);given the name of a protocol, returns the corresponding number.
int send(int s, const void *buf, int len, int flags); int sendto(int s, const void *msg, int len, unsigned int flags, const struct sockaddr *to, socklen_t tolen); int write(int fd, const void *buf, int count);send and write are equivalent (for sockets), and are be used when the sockets are connected. This includes all TCP sockets, and those UDP sockets on which connect has been used. sendto is used for those UDP sockets that are not connected, and allows send-time decision of where to send. In other words, we can send to many different destinations on a single UDP socket.
All three return the length sent.
int recv(int s, void *buf, int len, int flags); int recvfrom(int s, void *buf, int len, unsigned int flags, struct sockaddr *from, socklen_t *fromlen); int read(int fd, void *buf, int count);correspond to the sending operations, returning the length received, 0 if (the OS knows that) the socket has been closed, or -1 if there was an error.
int WSAStartup(int version, WSADATA *implementation); int WSACleanup();
char buffer [BUFFER_SIZE]; int num_bytes, new_bytes, socket;num_bytes = 0; do { new_bytes = recv (socket, buffer + num_bytes, BUFFER_SIZE - num_bytes, 0); if (new_bytes < 0) { perror ("read"); /* then do something appropriate */ /* e.g. break out of loop, return from function, or exit program */ } num_bytes += new_bytes; } while ((num_bytes < BUFFER_SIZE) && expecting_more (buffer, num_bytes));
expecting_more(char * buffer, int num_bytes) { if ( more data is needed ) return 1; else return 0; }
/* this is a macro so the return statement returns from write_slip_data */ #define WRITE_BYTE(fd, c) \ if (write_tty_data (fd, c) != 1) { \ pthread_mutex_unlock (&(send_mutex [fd])); \ printf ("slip: error writing tty data\n"); \ return -1; \ } int write_slip_data (int fd, char * data, int numbytes) { int byte; if ((numbytes <= 0) || (numbytes > MAX_SLIP_SEND)) { printf ("slip: bad size %d\n", numbytes); return -1; } #ifdef DEBUG printf ("acquiring send lock for tty %d\n", fd); #endif /* DEBUG */ pthread_mutex_lock (&(send_mutex [fd])); #ifdef DEBUG print_packet ("sending packet", data, numbytes); #endif /* DEBUG */ /* send the start byte, which of course is called END :-) */ WRITE_BYTE (fd, END); for (byte = 0; byte < numbytes; byte++) { unsigned char c = (data [byte]) & 0xff; if (c == END) { WRITE_BYTE (fd, ESC); WRITE_BYTE (fd, ESC_END); } else if (c == ESC) { WRITE_BYTE (fd, ESC); WRITE_BYTE (fd, ESC_ESC); } else { /* normal byte */ WRITE_BYTE (fd, c); } } WRITE_BYTE (fd, END); /* signal the end of the frame */ pthread_mutex_unlock (&(send_mutex [fd])); return numbytes; }
This code has highlighted the "normal" parts of the code, which are not dedicated to initialization, error handling or debugging. This is only a fraction of the total code.
static void data_handler_for_tty (int tty, unsigned char c) { #ifdef DEBUG printf (" received character %x/%o on port %d\n", c, c, tty); #endif /* DEBUG */ /* make sure we have been initialized */ pthread_mutex_lock (&global_mutex); /* we have been initialized, so proceed */ pthread_mutex_unlock (&global_mutex); /* acquire the lock for the receive buffer */ pthread_mutex_lock (&(receive_mutex [tty])); if (error_frame [tty]) { if (c == END) { error_frame [tty] = 0; receive_position [tty] = 0; escaped [tty] = 0; } } else { if (escaped [tty]) { /* last character was an escape */ escaped [tty] = 0; if (c == ESC_END) { put_char_in_buffer (tty, END); } else if (c == ESC_ESC) { put_char_in_buffer (tty, ESC); } else { /* this may be a legitimate oversight in the sender */ printf ("warning: accepting illegal character %x after ESC\n", c & 0xff); put_char_in_buffer (tty, c); } } else { /* last character was not ESC */ if (c == END) { /* done, give packet to data handler. */ if (receive_position [tty] > 0) { /* packet is not empty */ if (slip_data_handler [tty] == NULL) { printf ("error: received packet, but no slip data handler\n"); print_packet ("received packet", receive_buffer [tty], receive_position [tty]); receive_position [tty] = 0; } else { #ifdef DEBUG printf ("received %d bytes\n", receive_position [tty]); print_packet ("received packet", receive_buffer [tty], receive_position [tty]); #endif /* DEBUG */ /* note the receive buffer remains locked while we call the slip data handler. If the slip data handler never returns, slip will deadlock, i.e., be unable to ever again receive data. This would also block the receive thread in ttynet. */ slip_data_handler [tty] (tty, receive_buffer [tty], receive_position [tty]); } /* get ready to start receiving a new packet */ receive_position [tty] = 0; } /* else: silently ignore packets of size 0 */ } else if (c == ESC) { /* signal for the next character */ escaped [tty] = 1; } else { /* 'normal' character */ put_char_in_buffer (tty, c); } } } /* finally make the buffer available to other threads. */ pthread_mutex_unlock (&(receive_mutex [tty])); }