Reputation: 401
I am doing a very simple application using TCP client-server protocol. First I set up the socket for server and start listening to the client requests. After the connection is established the client sends me a file and I read the file but after I close the connection another accept() call happen on the server-side and it fails. I am only doing connect() once on the client side. And I see the socket descriptor value on the second accept is different from the first one.
Thank you.
EDIT: It seems like I'm overwriting the value of the socket descriptor with the call to Readline() function in utility.c. My guess is that some lin in function might have overwritten the value above its stack.
server.c
#include <sys/socket.h> /* socket definitions */
#include <sys/types.h> /* socket types */
#include <arpa/inet.h> /* inet (3) funtions */
#include <errno.h>
#include <unistd.h> /* misc. UNIX functions */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include "utility.h" /* our own utility functions */
/* Global constants */
#define ECHO_PORT (2002)
#define MAX_LINE (1000)
int main(int argc, char *argv[]) {
int list_s; /* listening socket */
int conn_s; /* connection socket */
short int port; /* port number */
struct sockaddr_in servaddr; /* socket address structure */
struct sockaddr_in incoming_addr;
char* endptr; /* for strtol() */
/* Get port number from the command line, and
set to default port if no arguments were supplied */
if ( argc == 2 ) {
port = strtol(argv[1], &endptr, 0);
if ( *endptr ) {
fprintf(stderr, "ECHOSERV: Invalid port number.\n");
exit(EXIT_FAILURE);
}
}
else if ( argc < 2 ) {
port = ECHO_PORT;
}
else {
fprintf(stderr, "ECHOSERV: Invalid arguments.\n");
exit(EXIT_FAILURE);
}
/* Create the listening socket */
list_s = socket(AF_INET, SOCK_STREAM, 0);
if (list_s < 0) {
fprintf(stderr, "ECHOSERV: Error creating listening socket.\n");
exit(EXIT_FAILURE);
}
else {
fprintf(stdout, "Socket successfully created.\n");
}
/* Set all bytes in socket address structure to
zero, and fill in the relevant data members */
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(port);
/* Bind the socket descriptor "list_s" to the servaddr which defines the port number. */
if ( bind(list_s, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0 ) {
fprintf(stderr, "ECHOSERV: Error calling bind()\n");
exit(EXIT_FAILURE);
}
else {
fprintf(stdout, "Socket successfully binded to port no %d.\n", port);
}
if ( listen(list_s, 1) < 0 ) {
fprintf(stderr, "ECHOSERV: Error calling listen()\n");
exit(EXIT_FAILURE);
}
else {
fprintf(stdout, "Now listening to port: %d.\n", port);
}
/* Enter an infinite loop to respond
to client requests and echo input */
while (1) {
/* Wait for a connection, then accept() it */
socklen_t incoming_addr_len = sizeof(incoming_addr);
int server_socket = list_s;
printf("The value of list_s is: %d.\n", list_s);
conn_s = accept(server_socket, (struct sockaddr*)(&incoming_addr), &incoming_addr_len);
if ( conn_s < 0 ) {
fprintf(stderr, "ECHOSERV: Error calling accept(): %s.\n", strerror(errno));
exit(EXIT_FAILURE);
}
/* Read the data from the socket descriptor which in this case */
/* is the size of the file that is to be received. */
int data_size;
Readline(conn_s, &data_size, sizeof(data_size));
/* Read data from the given socket descriptor conn_s and then
* write the same data to the descriptor again to be sent as
* a response. */
char buffer[data_size];
Readline(conn_s, buffer, data_size);
printFile(buffer, data_size);
/* Close the connected socket */
if ( close(conn_s) < 0 ) {
fprintf(stderr, "ECHOSERV: Error calling close()\n");
exit(EXIT_FAILURE);
}
}
}
Client.c
#include <sys/socket.h> /* socket definitions */
#include <sys/types.h> /* socket types */
#include <arpa/inet.h> /* inet (3) funtions */
#include <unistd.h> /* misc. UNIX functions */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "utility.h" /* Our own utility functions */
/* Global constants */
#define MAX_LINE (1000)
#define DATA_IN_FILE (4)
static const char* const kFileName = "/home/pb/Desktop/workspace/Networking/practice_project/practice_project_test_file_1";
/* Function declarations */
int ParseCmdLine(int argc, char *argv[], char **szAddress, char **szPort);
/* main() */
int main(int argc, char *argv[]) {
int conn_s; /* connection socket */
short int port; /* port number */
struct sockaddr_in servaddr; /* socket address structure */
char buffer[MAX_LINE]; /* character buffer */
char *szAddress; /* Holds remote IP address */
char *szPort; /* Holds remote port */
char *endptr; /* for strtol() */
/* Get command line arguments */
ParseCmdLine(argc, argv, &szAddress, &szPort);
/* Set the remote port */
port = strtol(szPort, &endptr, 0);
if ( *endptr ) {
printf("ECHOCLNT: Invalid port supplied.\n");
exit(EXIT_FAILURE);
}
/* Create the listening socket */
if ( (conn_s = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
fprintf(stderr, "ECHOCLNT: Error creating listening socket.\n");
exit(EXIT_FAILURE);
}
/* Set all bytes in socket address structure to
zero, and fill in the relevant data members */
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(port);
/* Set the remote IP address */
if ( inet_aton(szAddress, &servaddr.sin_addr) <= 0 ) {
printf("ECHOCLNT: Invalid remote IP address.\n");
exit(EXIT_FAILURE);
}
/* connect() to the remote echo server */
if ( connect(conn_s, (struct sockaddr *) &servaddr, sizeof(servaddr) ) < 0 ) {
printf("ECHOCLNT: Error calling connect()\n");
exit(EXIT_FAILURE);
}
FILE* f = fopen(kFileName, "rb");
if (f == NULL) {
perror("Error ");
return -1;
}
fseek(f, 0, SEEK_END);
int size_of_file = ftell(f);
rewind(f);
char file_buffer[size_of_file];
int items_read = fread(file_buffer, 1, size_of_file, f);
if (items_read != size_of_file) {
printf("Read the rest.\n");
}
/* First sending to the server the size of the data in the */
/* file in bytes as an integer. */
sendData(conn_s, &size_of_file, sizeof(int));
/* This is the actual file now that we have let the server */
/* know the size of the file to be send. */
sendData(conn_s, file_buffer, size_of_file);
return EXIT_SUCCESS;
}
int ParseCmdLine(int argc, char *argv[], char **szAddress, char **szPort) {
int n = 1;
while ( n < argc ) {
if ( !strncmp(argv[n], "-a", 2) || !strncmp(argv[n], "-A", 2) ) {
*szAddress = argv[++n];
}
else if ( !strncmp(argv[n], "-p", 2) || !strncmp(argv[n], "-P", 2) ) {
*szPort = argv[++n];
}
else if ( !strncmp(argv[n], "-h", 2) || !strncmp(argv[n], "-H", 2) ) {
printf("Usage:\n\n");
printf(" timeclnt -a (remote IP) -p (remote port)\n\n");
exit(EXIT_SUCCESS);
}
++n;
}
return 0;
}
utility.c
#include "utility.h"
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <unistd.h>
#include <errno.h>
int printFile(char *binary_buffer, int buffer_size) {
int current_position = 0;
while (current_position < buffer_size) {
if(binary_buffer[current_position] == 0) {
printf("\n");
printf("Type 1.\n");
current_position = read_first_type(binary_buffer, current_position);
}
else if(binary_buffer[current_position] == 1) {
printf("\n");
printf("Type 2.\n");
current_position = read_second_type(binary_buffer, current_position);
}
}
return 0;
}
int read_first_type(const char* binary, const int offset) {
int size_of_units = 2;
int no_of_units;
short unit_buffer[1];
// current position is always Type and no_of_units is amount which is a byte off of Type.
no_of_units = binary[offset+1];
printf("No of units is %d.\n", no_of_units);
for (int i=0; i<no_of_units; ++i) {
// This is a Big-endian system so the values will bit off.
memcpy(unit_buffer, (binary+offset+2)+i*size_of_units, 2);
printf("Type 1 unit has number: %d.\n", unit_buffer[0]);
}
return (offset + no_of_units*size_of_units + 2);
}
int read_second_type(const char* binary, const int offset) {
int no_of_units;
int current_position = 4;
char amount[4];
memcpy(amount, binary+offset+1, 3);
amount[3] = '\0';
no_of_units = atoi(amount);
printf("No of units is %d.\n", no_of_units);
char unit_buffer[5];
int count;
for(int i=0; i<no_of_units; ++i) {
count = 0;
while(1) {
memcpy(unit_buffer+count, binary+offset+current_position+count, 1);
if (unit_buffer[count] == 44) {
unit_buffer[count] = '\0';
current_position += count+1;
break;
}
if (unit_buffer[count] == 0 || unit_buffer[count] == 1) {
unit_buffer[count] = '\0';
printf("Type 2 unit has number: %d.\n",atoi(unit_buffer));
return (offset+current_position+count);
}
count++;
}
printf("Type 2 unit has number: %d.\n",atoi(unit_buffer));
}
return offset+current_position+count;
}
/* Read a line from a socket */
ssize_t Readline(int sockd, void *vptr, size_t maxlen) {
ssize_t n, rc;
char c, *buffer;
buffer = vptr;
for ( n = 0; n < maxlen; n++ ) {
if ( (rc = read(sockd, &c, 1)) == 1 ) {
*buffer++ = c;
if ( c == '\n' )
break;
}
else if ( rc == 0 ) {
if ( n == 0 )
return 0;
else
break;
}
else {
if ( errno == EINTR )
continue;
return -1;
}
}
*buffer = 0;
return n;
}
/* Write a line to a socket */
ssize_t sendData(int sockd, const void *vptr, size_t n) {
size_t nleft;
ssize_t nwritten;
const char *buffer;
buffer = vptr;
nleft = n;
while ( nleft > 0 ) {
if ( (nwritten = write(sockd, buffer, nleft)) <= 0 ) {
if ( errno == EINTR )
nwritten = 0;
else
return -1;
}
nleft -= nwritten;
buffer += nwritten;
}
return n;
}
Upvotes: 0
Views: 222
Reputation: 123260
If the full buffer was read in ReadLine
(i.e. maxlen
reached in loop) then you will still write a 0x0 after the last character read, thus causing an out of buffer:
ssize_t Readline(int sockd, void *vptr, size_t maxlen) {
...
for ( n = 0; n < maxlen; n++ ) {
if ( (rc = read(sockd, &c, 1)) == 1 ) {
*buffer++ = c;
...
*buffer = 0; <<<<<<<<<<<< might be vptr[maxlen+1], i.e. buffer overflow
return n;
And this will almost always occur when doing
Readline(conn_s, &data_size, sizeof(data_size));
Only if the
octets making up data_size
contain an \n
before the end of the buffer it will not occur but then you will read the wrong number.
This buffer overflow might cause a corruption of adjacent memory which might lead to the problem you see.
Upvotes: 2