Skip to content

Instantly share code, notes, and snippets.

@jsuwo
Last active November 9, 2015 04:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jsuwo/68a182f7f7cc20398973 to your computer and use it in GitHub Desktop.
Save jsuwo/68a182f7f7cc20398973 to your computer and use it in GitHub Desktop.
Code samples from Computer Networks I Lab Manual, Chapter 6 - More Advanced Socket Programming
#include <stdint.h>
#ifndef CALC_MESSAGE_H
#define CALC_MESSAGE_H
typedef struct
{
int length;
uint8_t operand_count;
uint8_t reserved[3];
uint32_t sum;
uint16_t operands[32763];
uint8_t padding;
} calc_message;
#endif
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <string.h>
#include <unistd.h>
#include "udp_sockets.h"
#include "udp_client.h"
uint8_t* create_calc_request(uint16_t op1, uint16_t op2, uint16_t op3, uint16_t op4)
{
// Create a 16-byte message
uint8_t* message = (uint8_t*)malloc(16 * sizeof(uint8_t));
// Store the operand count in the first byte of the message
message[0] = 4;
// Copy the operands into the array, starting at byte 8,
// since we need to skip the Reserved and Sum fields
memcpy(message + 8, &op1, sizeof(uint16_t));
memcpy(message + 10, &op2, sizeof(uint16_t));
memcpy(message + 12, &op3, sizeof(uint16_t));
memcpy(message + 14, &op4, sizeof(uint16_t));
// Return the dynamically-allocated message
return message;
}
int main()
{
host server; // Address of the server
uint8_t response[8]; // Response returned by the server
uint32_t result; // Result returned in server's response
// Create a socket to listen on port 5000
int sockfd = create_client_socket("localhost", "5000", &server);
// Encode the message to be sent
uint8_t* request = create_calc_request(10, 20, 30, 40);
// Send the 16-byte request to the server and free its memory
sendto(sockfd, request, 16, 0, (struct sockaddr*)&server.addr, server.addr_len);
free(request);
// Read the response from the server
recvfrom(sockfd, response, sizeof(response), 0, NULL, NULL);
// Extract the result from the response (starting at byte 4)
memcpy(&result, response + 4, sizeof(uint32_t));
// Print the result and close the socket
printf("Result: %d\n", result);
close(sockfd);
exit(EXIT_SUCCESS);
}
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <string.h>
#include <unistd.h>
#include "calc_message.h"
#include "udp_sockets.h"
#include "udp_client.h"
message* create_calc_request(uint16_t op1, uint16_t op2, uint16_t op3, uint16_t op4)
{
// Create a 16-byte message
calc_message* msg = (calc_message*)create_message();
// Store the operand count in the first byte of the message
msg->operand_count = 4;
// Store the operands in the message
msg->operands[0] = op1;
msg->operands[1] = op2;
msg->operands[2] = op3;
msg->operands[3] = op4;
// The message is 16 bytes long (8 bytes of headers + 8 bytes of operands)
msg->length = 16;
// Return the dynamically-allocated message
return (message*)msg;
}
int main()
{
host server; // Address of the server
calc_message* response; // Response returned by the server
// Create a socket to listen on port 5000
int sockfd = create_client_socket("localhost", "5000", &server);
// Encode the message to be sent
message* request = create_calc_request(10, 20, 30, 40);
// Send it and free its memory
send_message(sockfd, request, &server);
free(request);
// Read the response from the server
response = (calc_message*)receive_message(sockfd, &server);
// Print the result and close the socket
printf("Result: %d\n", response->sum);
free(response);
close(sockfd);
exit(EXIT_SUCCESS);
}
#include <arpa/inet.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <string.h>
#include <unistd.h>
#include "calc_message.h"
#include "udp_sockets.h"
#include "udp_client.h"
message* create_calc_request(uint16_t op1, uint16_t op2, uint16_t op3, uint16_t op4)
{
// Create a 16-byte message
calc_message* msg = (calc_message*)create_message();
// Store the operand count in the first byte of the message
msg->operand_count = 4;
// Convert the operands to network order and store them in the message
msg->operands[0] = htons(op1);
msg->operands[1] = htons(op2);
msg->operands[2] = htons(op3);
msg->operands[3] = htons(op4);
// The message is 16 bytes long (8 bytes of headers + 8 bytes of operands)
msg->length = 16;
// Return the dynamically-allocated message
return (message*)msg;
}
int main()
{
host server; // Address of the server
calc_message* response; // Response returned by the server
// Create a socket to listen on port 5000
int sockfd = create_client_socket("localhost", "5000", &server);
// Encode the message to be sent
message* request = create_calc_request(10, 20, 30, 40);
// Send it and free its memory
send_message(sockfd, request, &server);
free(request);
// Read the response from the server and convert its sum to
// host order
response = (calc_message*)receive_message(sockfd, &server);
response->sum = ntohl(response->sum);
// Print the result and close the socket
printf("Result: %d\n", response->sum);
free(response);
close(sockfd);
exit(EXIT_SUCCESS);
}
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
union endian_tester
{
int integer;
uint8_t bytes[4];
};
int main()
{
union endian_tester t = { .integer = 0xA0B1C2D3 };
int i;
for (i = 0; i < 4; ++i)
printf("%x ", t.bytes[i]);
puts("");
if (t.bytes[0] == 0xA0)
printf("This system is big-endian\n");
else
printf("This system is little-endian\n");
exit(EXIT_SUCCESS);
}
CC=gcc
CFLAGS=-Wall -Werror -g -c
LFLAGS=-Wall -Werror -g
all: client1 client2 client3 server1 server2 server3 endian poll
client%: client%.o udp_sockets.o udp_client.o
$(CC) $(LFLAGS) -o $@ $^
server%: server%.o udp_sockets.o udp_server.o
$(CC) $(LFLAGS) -o $@ $^
endian: endian.c
$(CC) $(LFLAGS) -o $@ $^
poll: poll.o udp_sockets.o udp_server.o
$(CC) $(LFLAGS) -o $@ $^
client%.o: client%.c udp_client.h udp_sockets.h
$(CC) $(CFLAGS) -o $@ $<
server%.o: server%.c udp_server.h udp_sockets.h
$(CC) $(CFLAGS) -o $@ $<
poll.o: poll.c udp_server.h udp_sockets.h
$(CC) $(CFLAGS) -o $@ $<
udp_sockets.o: udp_sockets.c udp_sockets.h
$(CC) $(CFLAGS) -o $@ $<
udp_server.o: udp_server.c udp_server.h udp_sockets.h
$(CC) $(CFLAGS) -o $@ $<
udp_client.o: udp_client.c udp_client.h udp_sockets.h
$(CC) $(CFLAGS) -o $@ $<
clean:
rm -f *.o client[1-3] server[1-3] endian poll
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "udp_sockets.h"
#include "udp_server.h"
int main()
{
message* msg; // Message read from the client
host client; // Client's address
int retval; // Return value from poll
// Create a socket to listen on port 5000
int sockfd = create_server_socket("5000");
// We will poll sockfd for the POLLIN event
struct pollfd fd = {
.fd = sockfd,
.events = POLLIN
};
// Poll the socket for 10 seconds
retval = poll(&fd, 1, 10000);
if (retval == 1 && fd.revents == POLLIN)
{
// Read the waiting message
msg = receive_message(sockfd, &client);
// Add NULL terminator and print the message
msg->buffer[msg->length] = '\0';
printf("Message received from %s: %s\n", client.friendly_ip, msg->buffer);
free(msg);
}
else
{
puts("No message received in 10s. Exiting.");
}
// Close the socket
close(sockfd);
exit(EXIT_SUCCESS);
}
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <string.h>
#include <unistd.h>
#include "udp_sockets.h"
#include "udp_server.h"
uint32_t calculate_sum(uint8_t* message)
{
uint8_t operand_count = message[0]; // Read operand count from message
uint8_t* ptr = message + 8; // Pointer to start of operands
uint16_t next_operand; // Next operand
uint32_t sum = 0; // Computed sum
int i;
// Iterate over the operands
for (i = 0; i < operand_count; ++i, ptr += sizeof(uint16_t))
{
// Copy each 16-bit operand from the message and add it to the sum
memcpy(&next_operand, ptr, sizeof(uint16_t));
sum += next_operand;
}
// Return the computed sum
return sum;
}
uint8_t* create_response_message(uint32_t result)
{
// Create an 8-byte message
uint8_t* message = (uint8_t*)malloc(8 * sizeof(uint8_t));
// The message contains no operands
message[0] = 0;
// Copy the result into the array, starting at byte 4,
// since we need to skip the Reserved field
memcpy(message + 4, &result, sizeof(uint32_t));
// Return the dynamically-allocated message
return message;
}
int main()
{
uint32_t result; // Result to be returned to the client
struct sockaddr_in addr; // Source address and port
socklen_t addr_len = sizeof(struct sockaddr_in); // Length of the addr structure
uint8_t request[1024]; // Buffer to store client's request
uint8_t* response;
// Create a socket to listen on port 5000
int sockfd = create_server_socket("5000");
// Read the next message into buffer, storing the source address in addr
recvfrom(sockfd, request, sizeof(request), 0, (struct sockaddr*)&addr, &addr_len);
// Compute the sum from the client's request
result = calculate_sum(request);
response = create_response_message(result);
// Send the 8-byte result to the client
sendto(sockfd, response, 8, 0, (struct sockaddr*)&addr, addr_len);
free(response);
// Close the socket
close(sockfd);
exit(EXIT_SUCCESS);
}
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <string.h>
#include <unistd.h>
#include "calc_message.h"
#include "udp_sockets.h"
#include "udp_server.h"
message* create_response_message(calc_message* request)
{
int i;
// Create a response message and initialize it
calc_message* response = (calc_message*)create_message();
response->operand_count = 0;
response->sum = 0;
// Compute the sum from the client's request
for (i = 0; i < request->operand_count; ++i)
response->sum += request->operands[i];
// Set the length of the message (8 bytes of headers; no operands)
response->length = 8;
// Return the dynamically-allocated message
return (message*)response;
}
int main()
{
calc_message* request; // Client's request message
message* response; // Server response message
host client; // Client's address
// Create a socket to listen on port 5000
int sockfd = create_server_socket("5000");
// Read the request message and generate the response
request = (calc_message*)receive_message(sockfd, &client);
response = create_response_message(request);
// Send the response and free the memory allocated to the messages
send_message(sockfd, response, &client);
free(request);
free(response);
// Close the socket
close(sockfd);
exit(EXIT_SUCCESS);
}
#include <arpa/inet.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <string.h>
#include <unistd.h>
#include "calc_message.h"
#include "udp_sockets.h"
#include "udp_server.h"
message* create_response_message(calc_message* request)
{
int i;
// Create a response message and initialize it
calc_message* response = (calc_message*)create_message();
response->operand_count = 0;
response->sum = 0;
// Compute the sum from the client's request
for (i = 0; i < request->operand_count; ++i)
response->sum += ntohs(request->operands[i]);
// Convert the sum to network order
response->sum = htonl(response->sum);
// Set the length of the message (8 bytes of headers; no operands)
response->length = 8;
// Return the dynamically-allocated message
return (message*)response;
}
int main()
{
calc_message* request; // Client's request message
message* response; // Server response message
host client; // Client's address
// Create a socket to listen on port 5000
int sockfd = create_server_socket("5000");
// Read the request message and generate the response
request = (calc_message*)receive_message(sockfd, &client);
response = create_response_message(request);
// Send the response and free the memory allocated to the messages
send_message(sockfd, response, &client);
free(request);
free(response);
// Close the socket
close(sockfd);
exit(EXIT_SUCCESS);
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "udp_client.h"
int create_client_socket(char* hostname, char* port, host* server)
{
int sockfd;
struct addrinfo* addr;
struct addrinfo* results = get_udp_sockaddr(hostname, port, 0);
// Iterate through each addrinfo in the list;
// stop when we successfully create a socket
for (addr = results; addr != NULL; addr = addr->ai_next)
{
// Open a socket
sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
// Try the next address if we couldn't open a socket
if (sockfd == -1)
continue;
// Copy server address and length to the out parameter 'server'
memcpy(&server->addr, addr->ai_addr, addr->ai_addrlen);
memcpy(&server->addr_len, &addr->ai_addrlen, sizeof(addr->ai_addrlen));
// We've successfully created a socket; stop iterating
break;
}
// Free the memory allocated to the addrinfo list
freeaddrinfo(results);
// If we tried every addrinfo and failed to create a socket
if (addr == NULL)
{
perror("Unable to create socket");
exit(EXIT_FAILURE);
}
else
{
// Otherwise, return the socket descriptor
return sockfd;
}
}
#include "udp_sockets.h"
#ifndef UDP_CLIENT_H
#define UDP_CLIENT_H
int create_client_socket(char* hostname, char* port, host* server);
#endif
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <unistd.h>
#include "udp_server.h"
#include "udp_sockets.h"
int bind_socket(struct addrinfo* addr_list)
{
struct addrinfo* addr;
int sockfd;
// Iterate through each addrinfo in the list; stop when we successfully bind
// to one
for (addr = addr_list; addr != NULL; addr = addr->ai_next)
{
// Open a socket
sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
// Try the next address if we couldn't open a socket
if (sockfd == -1)
continue;
// Try to bind the socket to the address/port
if (bind(sockfd, addr->ai_addr, addr->ai_addrlen) == -1)
{
// If binding fails, close the socket, and try the next address
close(sockfd);
continue;
}
else
{
// Otherwise, we've bound the address/port to the socket, so stop
// processing
break;
}
}
// Free the memory allocated to the addrinfo list
freeaddrinfo(addr_list);
// If addr is NULL, we tried every addrinfo and weren't able to bind to any
if (addr == NULL)
{
perror("Unable to bind");
exit(EXIT_FAILURE);
}
else
{
// Otherwise, return the socket descriptor
return sockfd;
}
}
int create_server_socket(char* port)
{
struct addrinfo* results = get_udp_sockaddr(NULL, port, AI_PASSIVE);
int sockfd = bind_socket(results);
return sockfd;
}
#include <netdb.h>
#ifndef UDP_SERVER_H
#define UDP_SERVER_H
int bind_socket(struct addrinfo* addr_list);
int create_server_socket(char* port);
#endif
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "udp_sockets.h"
struct addrinfo* get_udp_sockaddr(const char* node, const char* port, int flags)
{
struct addrinfo hints;
struct addrinfo* results;
int retval;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET; // Return socket addresses for our local IPv4 addresses
hints.ai_socktype = SOCK_DGRAM; // Return UDP socket addresses
hints.ai_flags = flags; // Socket addresses should be listening sockets
retval = getaddrinfo(node, port, &hints, &results);
if (retval != 0)
{
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(retval));
exit(EXIT_FAILURE);
}
return results;
}
message* create_message()
{
return (message*)malloc(sizeof(message));
}
message* receive_message(int sockfd, host* source)
{
message* msg = create_message();
// Length of the remote IP structure
source->addr_len = sizeof(source->addr);
// Read message, storing its contents in msg->buffer, and
// the source address in source->addr
msg->length = recvfrom(sockfd, msg->buffer, sizeof(msg->buffer), 0,
(struct sockaddr*)&source->addr,
&source->addr_len);
// If a message was read
if (msg->length > 0)
{
// Convert the source address to a human-readable form,
// storing it in source->friendly_ip
inet_ntop(source->addr.sin_family, &source->addr.sin_addr,
source->friendly_ip, sizeof(source->friendly_ip));
// Return the message received
return msg;
}
else
{
// Otherwise, free the allocated memory and return NULL
free(msg);
return NULL;
}
}
int send_message(int sockfd, message* msg, host* dest)
{
return sendto(sockfd, msg->buffer, msg->length, 0,
(struct sockaddr*)&dest->addr, dest->addr_len);
}
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#ifndef UDP_SOCKETS_H
#define UDP_SOCKETS_H
#define UDP_MSS 65535
typedef struct
{
int length;
uint8_t buffer[UDP_MSS];
} message;
typedef struct
{
struct sockaddr_in addr;
socklen_t addr_len;
char friendly_ip[INET_ADDRSTRLEN];
} host;
struct addrinfo* get_udp_sockaddr(const char* node, const char* port, int flags);
message* create_message();
message* receive_message(int sockfd, host* source);
int send_message(int sockfd, message* msg, host* dest);
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment