Last active
November 9, 2015 04:32
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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); | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "udp_sockets.h" | |
#ifndef UDP_CLIENT_H | |
#define UDP_CLIENT_H | |
int create_client_socket(char* hostname, char* port, host* server); | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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); | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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