C - simple encrypting socket with tcp connections fail to encrypt big files - c

Its using a blocking queue for encrypting files with XOR.
The buffers are set to be very big, but still when i encrypt the encryption of big files (1000 chars and more) I should receive the same file, but I am receiving only the beginning. Anyone knows how to fix this?
thanks.
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <time.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include <signal.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/select.h>
#include <netinet/tcp.h>
#include "os_queue.c"
#define BACKLOGGED_CONNECTIONS 10
queue_t new_queue;
int i=0;
void *worker_thread(void* key_path) {
int j = i;
i++;
printf("worker %d stssssart\n",j);
int rc;
int sockfd;
int key_fd;
if ((key_fd = open(key_path, O_RDONLY)) < 0) {
printf("ERROR: open key file failed: %s\n",strerror(errno));
exit(1);
}
while (1) {
rc = queue_dequeue(&new_queue,&sockfd);
if (rc != 0) {
printf("error! dequeue of a client's sockfd from the shared queue failed: %d\n",rc);
}
if(cipher(sockfd,key_fd)!=0){
printf("chipher did not work");
exit(1);
}
}
printf("worker %d finish\n",j);
close(key_fd);
pthread_exit((void*) &key_fd);
}
int cipher(int sockfd,int key_fd){
int keyFileFD, numberOfBytes,loop,n,key_num,totalsent,nsent,i;
char inputBuffer[262144], keyBuffer[262144],outputBuffer[262144];
if(lseek(key_fd,0,SEEK_SET) == -1){
printf("lseek function failed %s\n", strerror(errno));
return errno;
}
while (1) {
n = read(sockfd, inputBuffer, sizeof(inputBuffer));
if(n < 0){
if(errno ==EPIPE || errno == ENOTCONN || errno == ECONNRESET) {
printf("111");
close(sockfd);
return 0;
}
else{
printf("Read error: %s\n", strerror(errno));
close(sockfd);
return 0;
}
}
key_num=read(key_fd, keyBuffer, n);
if (key_num < 0) {
printf("Error reading file: %s\n", strerror(errno));
return errno;
}
while (key_num<n) {
if(lseek(key_fd,0,SEEK_SET) == -1) {
/*
*error
*/
printf("lseek function failed %s\n", strerror(errno));
return errno;
}
int cont=read(key_fd, keyBuffer+key_num, n-key_num);
if (cont == -1) {
printf("Error reading file: %s\n", strerror(errno));
return errno;
}
key_num=key_num+cont;
}
for(i=0;i<n;i++){
outputBuffer[i] = (inputBuffer[i] ^ keyBuffer[i]);
}
if(write(sockfd, outputBuffer,n)<0) {
if(errno ==EPIPE || errno == ENOTCONN || errno == ECONNRESET) {
close(sockfd);
return 0;
} else{
printf("Read error: %s\n", strerror(errno));
close(sockfd);
return 0;
}
}
close(sockfd);
}
return 0;
}
int main(int argc, char *argv[]) {
int base_sockfd, new_sockfd,i, rc, keyFileFD, num_of_workers,addrsize_1,addrsize_2;
struct sockaddr_in serv_addr, client_addr;
char* key_path = argv[3];
addrsize_1 = sizeof(struct sockaddr);
num_of_workers = atoi(argv[1]);
if(argc!=4){
printf("number of args is not 4: %s\n",strerror(errno));
return errno;
}
if(access(key_path, R_OK)<0){
printf("Key file does not exist or the file is not accessible: %s\n",strerror(errno));
return errno;
}
/*init data structures*/
rc = init_queue(&new_queue,2*num_of_workers);
if (rc!=0) {
printf("error! shared queue init failed\n");
return 1;
}
pthread_t threads[num_of_workers];
/*create workers*/
for (i = 0; i < num_of_workers; i++) {
rc = pthread_create(&threads[i], NULL, worker_thread, (void*) key_path);
if (rc != 0) {
printf("error! pthread_create() failed: %d\n", rc);
return 1;
}
}
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(atoi(argv[2])); // short, network byte order
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");//INADDR_ANY;
if ((base_sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
printf("error! socket() failed: %s\n", strerror(errno));
return errno;
}
if (bind(base_sockfd, (struct sockaddr *)&serv_addr, addrsize_1) < 0) {
printf("error! bind() failed: %s\n", strerror(errno));
close(base_sockfd);
return errno;
}
addrsize_2 = sizeof(struct sockaddr_in);
if (listen(base_sockfd,SOMAXCONN) < 0) {
printf("error! listen() failed: %s\n", strerror(errno));
return errno;
}
while(1){
if ( (new_sockfd = accept(base_sockfd, (struct sockaddr*)&client_addr, &addrsize_2)) <= 0) {
printf("error! accept() failed: %s\n", strerror(errno));
close(base_sockfd);
return errno;
}
/*we have a new valid client sockfd, so enqueue it*/
rc = queue_enqueue(&new_queue, new_sockfd);
if (rc!= 0) {
printf("error! enqueue to shared queue failed withe value:%d\n",rc);
return 1;
}
}
/*clean up and close resources*/
rc=free_queue(&new_queue);
if(rc!=0)
printf("error! free queue failed with value:%d\n",rc);
return 1;
//close(base_sockfd);
/*exit gracefully*/
}
queue:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
typedef struct queue {
int *arr;
int capacity;
int size;
int in;
int out;
pthread_mutex_t mutex;
pthread_cond_t cond_full;
pthread_cond_t cond_empty;
} queue_t;
int queue_enqueue(queue_t *queue, int value) {
int rc;
rc = pthread_mutex_lock(&(queue->mutex));
if(rc!=0){
return rc;
}
while (queue->size == queue->capacity) {
pthread_cond_wait(&(queue->cond_full), &(queue->mutex));
}
queue->arr[queue->in] = value;
++ queue->size;
++ queue->in;
queue->in %= queue->capacity;
rc = pthread_mutex_unlock(&(queue->mutex));
if(rc!=0){
return rc;
}
rc = pthread_cond_signal(&(queue->cond_empty));
if(rc!=0){
return rc;
}
}
int queue_dequeue(queue_t *queue,int *value){
int rc;
rc = pthread_mutex_lock(&(queue->mutex));
if(rc!=0){
return rc;
}
while (queue->size == 0){
pthread_cond_wait(&(queue->cond_empty), &(queue->mutex));
}
*value = queue->arr[queue->out];
-- queue->size;
++ queue->out;
queue->out %= queue->capacity;
rc = pthread_mutex_unlock(&(queue->mutex));
if(rc!=0){
return rc;
}
rc = pthread_cond_signal(&(queue->cond_full));
return rc;
}
int init_queue(queue_t *new_queue,int cnt) {
int rc;
new_queue->capacity = cnt;
new_queue->arr = malloc(sizeof(cnt)*sizeof(int));
if (new_queue->arr== NULL) {
return -1;
}
new_queue->size = 0;
new_queue->in = 0;
new_queue->out = 0;
//init shared queue lock (mutex)
rc = pthread_mutex_init(&(new_queue->mutex), NULL);
if (rc != 0) {
return rc;
}
//init shared queue conditions variable
rc = pthread_cond_init(&(new_queue->cond_full), NULL);
if (rc != 0) {
return rc;
}
rc = pthread_cond_init(&(new_queue->cond_empty), NULL);
if (rc != 0) {
return rc;
}
}
int free_queue(queue_t *queue_to_kill) {
int rc;
rc = pthread_mutex_destroy(&(queue_to_kill->mutex));
if (rc) {
return rc;
}
rc = pthread_cond_destroy(&(queue_to_kill->cond_empty));
if (rc) {
return rc;
}
rc = pthread_cond_destroy(&(queue_to_kill->cond_full));
if (rc) {
return rc;
}
}
client:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <pthread.h>
int connectToHostname(int sock, char* hostname, char* port);
int main(int argc, char* argv[]){
int sock;
char* hostname;
char* port;
/* place default port if required*/
if(argc < 3)
{
port = "42666";
}
else
{
port = argv[2];
}
/* place default hostname if required*/
if(argc == 1)
{
hostname = "localhost";
}
else
{
hostname = argv[1];
}
/* open TCP socket with IPv4*/
if((sock = socket(PF_INET, SOCK_STREAM, 0))<0)
{
perror("Could not open socket");
exit(errno);
}
int fd = -1;
int fd2 = -1;
if(argc >= 4)
{
fd = open(argv[3], O_WRONLY|O_CREAT|O_TRUNC, 0666);
}
if(argc >= 5)
{
fd2 = open(argv[4], O_RDONLY, 0);
}
connectToHostname(sock, hostname, port);
char buf[100];
while(1)
{
if(fd2 <0)
{
scanf("%99s",buf);
send(sock, buf, strlen(buf), 0);
}
else
{
int stupid = read(fd2, buf, 99);
if(stupid == 0)
{
close(sock);
exit(0);
}
send(sock, buf, stupid, 0);
}
int sz = recv(sock, buf, 99, 0);
buf[100] = '\0';
if(fd< 0)
{
printf("%s\n", buf);
}
else
{
write(fd, buf, sz);
}
}
}
int connectToHostname(int sock, char* hostname, char* port)
{
int rv;
struct addrinfo hints, *servinfo, *p;
struct sockaddr_in *h;
struct sockaddr_in dest_addr;
/* server addr is IPv4*/
dest_addr.sin_family = AF_INET;
/* write server port*/
dest_addr.sin_port = htons((short)strtol(port, NULL,10));
/* zero out hints (since garbage is bad)*/
memset(&hints, 0, sizeof(hints));
/* we want IPv4 address and TCP*/
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
/* try get address info*/
if((rv = getaddrinfo(hostname, port, &hints, &servinfo)) != 0)
{
fprintf(stderr, "Error getting address info: %s\n", gai_strerror(rv));
exit(1);
}
p = servinfo;
while(p!= NULL)
{
/* put last address into sent pointer*/
h = (struct sockaddr_in *)p->ai_addr;
dest_addr.sin_addr = h->sin_addr;
if(connect(sock, (struct sockaddr*)(&dest_addr), sizeof(struct sockaddr)) == 0)
break;/* if connection succesfull*/
p = p->ai_next;
}
freeaddrinfo(servinfo);
if(p == NULL)
{
/*We didnt find a host*/
perror("Could not connect to server");
exit(errno);
}
return 0;
}
i used this script to test it:
echo niv > key_file
echo is > read_file_b
echo thethethethethethethethethethe > read_file_c
echo se > read_file_d
echo rse > read_file_e
echo rse > read_file_f
echo aaaaaaa > write_file_a
echo bbbbbbb > write_file_b
echo ccccccc > write_file_c
echo ddddddd > write_file_d
echo ddddddd > write_file_e
echo ddddddd > write_file_f
gcc setos_server.c -pthread -o setos_server
./setos_server 3 2 key_file &
sleep 0.1
#printf "\n\n"
gcc client.c -pthread -o client
./client 127.0.0.1 2 write_file_a read_file_a &
./client 127.0.0.1 2 write_file_b read_file_b &
./client 127.0.0.1 2 write_file_c read_file_c &
./client 127.0.0.1 2 write_file_d read_file_d &
./client 127.0.0.1 2 write_file_e read_file_e &
./client 127.0.0.1 2 write_file_f read_file_f &
./client 127.0.0.1 2 final_file_a write_file_a &
./client 127.0.0.1 2 final_file_b write_file_b &
./client 127.0.0.1 2 final_file_c write_file_c &
./client 127.0.0.1 2 final_file_d write_file_d &
./client 127.0.0.1 2 final_file_e write_file_e &
./client 127.0.0.1 2 final_file_f write_file_f &
sleep 2
pkill setos_server
when read_file_a is a big file (more then 10000 chars).
thank you for your help.

One too many close()
while (1) {
n = read(sockfd, inputBuffer, sizeof(inputBuffer));
if(n < 0){
....
}
close(sockfd);
}
kills the socket after the very first read().
PS: shorter functions and correct formatting makes it very easy to spot.

Related

TCP server can not accept client connect beyond 1000?

I met a strange question, When I run a TCP program manually(./tcpServDemo),Tcp Server program Can receive more than 5000 client connections, But When I running tcpServerDemo in the background(systemctl start tcpServDemo.service),It can only receive more than 900 client connections,
when I debugging, I found TCP recv-Q queue is full. I modified the TCP parameters(net.core.somaxconn = 65500 net.ipv4.tcp_max_syn_backlog = 409600),But it didn't work
I've been debugging for several days. I really don't know where the problem is?Who can help me,
thanks for everyone!
OS: CentOS 7.9
tcpClient.c:
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <netdb.h>
#include <netinet/in.h>
#include <pthread.h>
//#define SERVPORT 8088
int ServPort;
char ServerIP[32];
pthread_mutex_t lock;
int count;
void *cTcpConn(void *arg) {
usleep(2000);
int sockfd,sendbytes;
struct sockaddr_in serv_addr;//需要连接的服务器地址信息
memset(&serv_addr, 0, sizeof(struct sockaddr_in));
//1.创建socket
//AF_INET 表示IPV4
//SOCK_STREAM 表示TCP
if((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0) {
printf("socket create failed.");
return NULL;
}
//填充服务器地址信息
serv_addr.sin_family = AF_INET; //网络层的IP协议: IPV4
serv_addr.sin_port = htons(ServPort); //传输层的端口号
serv_addr.sin_addr.s_addr = inet_addr(ServerIP); //网络层的IP地址: 实际的服务器IP地址
//2.发起对服务器的连接信息
//三次握手,需要将sockaddr_in类型的数据结构强制转换为sockaddr
if((connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(struct sockaddr))) < 0) {
printf("connect failed!\n");
close(sockfd);
return NULL;
} else {
pthread_mutex_lock(&lock);
count++;
pthread_mutex_unlock(&lock);
printf("connect successful! count:%d\n", count);
}
#if 0
//3.发送消息给服务器端
if((sendbytes = send(sockfd,"hello",5,0)) < 0) {
perror("send");
exit(1);
}
#endif
while(1) {
sleep(10);
}
//4.关闭
close(sockfd);
return NULL;
}
int main(int argc, char **argv) {
if (argc != 3) {
printf("Usage: %s ServerIP ServerPort\n", argv[0]);
return 0;
}
strncpy(ServerIP, argv[1], sizeof(ServerIP) - 1);
ServPort = atoi(argv[2]);
int i;
pthread_t pid;
for (i = 0; i < 8000; i++) {
usleep(10000);
if(0 != pthread_create(&pid, NULL, cTcpConn, NULL)) {
printf("thread create failed.\n");
}
}
while (1) {
sleep(10);
}
return 0;
}
tcpServDemo.c:
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/epoll.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
int main() {
const int EVENTS_SIZE = 4096;
char buff[1024];
int eNum;
int socketFd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in sockAddr;
sockAddr.sin_port = htons(8088);
sockAddr.sin_family = AF_INET;
sockAddr.sin_addr.s_addr = htons(INADDR_ANY);
if (bind(socketFd, (struct sockaddr *) &sockAddr, sizeof(sockAddr)) == -1) {
return -1;
}
if (listen(socketFd, 10) == -1) {
return -1;
}
int eFd = epoll_create(1);
struct epoll_event epev;
epev.events = EPOLLIN;
epev.data.fd = socketFd;
epoll_ctl(eFd, EPOLL_CTL_ADD, socketFd, &epev);
int i;
int count = 0;
struct epoll_event events[EVENTS_SIZE];
while (1) {
eNum = epoll_wait(eFd, events, EVENTS_SIZE, -1);
if (eNum == -1) {
return -1;
}
for (i = 0; i < eNum; i++) {
if (events[i].data.fd == socketFd) {
if (events[i].events & EPOLLIN) {
struct sockaddr_in cli_addr;
socklen_t length = sizeof(cli_addr);
int fd = accept(socketFd, (struct sockaddr *) &cli_addr, &length);
if (fd > 0) {
count++;
epev.events = EPOLLIN | EPOLLET;
epev.data.fd = fd;
int flags = fcntl(fd, F_GETFL, 0);
if (flags < 0) {
continue;
}
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
continue;
}
epoll_ctl(eFd, EPOLL_CTL_ADD, fd, &epev);
printf("client on line fd:%d-count:%d\n", fd, count);
} else {
printf("accept failed.\n, fd:%d-errno:%d-strerror:%s\n", fd, errno, strerror(errno));
}
}
} else {
if (events[i].events & EPOLLERR || events[i].events & EPOLLHUP) {
epoll_ctl(eFd, EPOLL_CTL_DEL, events[i].data.fd, NULL);
close(events[i].data.fd);
}
}
}
}
}
/usr/lib/systemd/system/tcpServDemo.service:
[Unit]
Description= application service monitor daemon
After=network.target
[Service]
User=root
Type=forking
ExecStart=/var/workstation/testcode/C-Code/tcpServDemo
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartSec=1s
[Install]
WantedBy=multi-user.target graphic.target
You were running out of file descriptors. accept() would have returned -1 and set errno to EMFILE. It would have been helpful to share that error message with us. You raise the (soft) file descriptor limit by either
setting LimitNOFILESoft your service file to suitable higher value (see systemd.exec(5)), or
calling setrlimit(RLIMIT_NOFILE, ...) with a higher value for rlim_cur less than rlimit_max. It's pretty normal for servers to set their rlimit_cur to the rlimit_max retrieved from getrlimit(RLIMIT_NOFILE, ...) so you can tweak resource usage (in this case number of file descriptors) externally.

Creation of sockets from scratch using TCP_REPAIR?

I'm using TCP_REPAIR to create a pair of already-connected sockets that talk to each other without actually going through the TCP connect flow.
I've tried to use the ideas in LWN for connection repair and their soccr library, but unfortunately, no matter what I do, I always get an ECONNRESET error the moment I try to write data to any of the sockets.
Here's an example of what I've tried:
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <linux/socket.h>
#include <netinet/tcp.h>
#include <string.h>
#include <fcntl.h>
#include <getopt.h>
#include <stdlib.h>
#include <errno.h>
struct tcp {
char *addr;
uint32_t port;
};
int createSocket(struct tcp src, struct tcp dst) {
int sk, yes = 1;
struct sockaddr_in addr;
sk = socket(AF_INET, SOCK_STREAM, 0);
if (sk < 0) {
printf("Cannot create socket\n");
return -1;
}
if (setsockopt(sk, SOL_TCP, TCP_REPAIR, &yes, sizeof(yes))) {
printf("Cannot set TCP_REPAIR\n");
return -1;
}
if (setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1) {
printf("Cannot set SO_REUSEADDR\n");
return -1;
}
memset(&addr,0,sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(src.port);
if (inet_pton(AF_INET, src.addr, &(addr.sin_addr)) < 0) {
printf("Error converting source host:port to binary\n");
return -1;
}
if (bind(sk, (struct sockaddr *) &addr, sizeof(addr))) {
printf("Cannot bind to source port\n");
return -1;
}
memset(&addr,0,sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(dst.port);
if (inet_pton(AF_INET, dst.addr, &(addr.sin_addr)) < 0) {
printf("Error converting destination host:port to binary\n");
return -1;
}
if (connect(sk, (struct sockaddr *) &addr, sizeof(addr))) {
printf("Cannot bind to remote port\n");
return -1;
}
int no = 0;
if (setsockopt(sk, SOL_TCP, TCP_REPAIR, &no, sizeof(no))) {
printf("Cannot set TCP_REPAIR\n");
return -1;
}
return sk;
}
int main(int argc, char **argv) {
struct tcp tcp[2] = {
{"127.0.0.1", 17000},
{"127.0.0.1", 34000}
};
int source_socket = createSocket(tcp[0], tcp[1]);
printf("Source socket created: %d \n",source_socket);
int dest_socket = createSocket(tcp[1], tcp[0]);
printf("Destination socket created: %d \n",dest_socket);
if (source_socket < 0 || dest_socket < 0)
return -1;
char* message = "Hello world";
ssize_t written = write(dest_socket, message, strlen(message)); // ECONNRESET error
if (written < 0) {
printf("Error writing to socket %d\n",errno);
return -1;
}
printf("%ld bytes written\n",written);
char buffer[1024];
ssize_t bytesRead = read(dest_socket, buffer, sizeof(buffer)-1);
printf("Bytes read %ld\n",bytesRead);
buffer[bytesRead] = 0;
printf("Message read: %s\n",buffer);
printf("Finished %d %d \n",source_socket,dest_socket);
return 0;
}
And the output is
Source socket created: 3
Destination socket created: 4
Error writing to socket 104
I get the same result (Connection reset by peer error) if I use the soccr library:
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <linux/socket.h>
#include <netinet/tcp.h>
#include <string.h>
#include <fcntl.h>
#include <getopt.h>
#include <stdlib.h>
#include <errno.h>
#include "./soccr.h"
struct tcp {
char *addr;
uint32_t port;
uint32_t seq;
uint16_t mss_clamp;
uint16_t wscale;
};
int createSocket(struct tcp src, struct tcp dst) {
int sk, yes = 1;
union libsoccr_addr src_addr, dst_addr;
struct libsoccr_sk_data data = {};
struct libsoccr_sk *so;
data.state = TCP_ESTABLISHED;
data.inq_seq = dst.seq;
data.outq_seq = src.seq;
sk = socket(AF_INET, SOCK_STREAM, 0);
if (sk < 0) {
printf("Cannot create socket. Errno %d\n",errno);
return -1;
}
so = libsoccr_pause(sk);
if (setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1) {
printf("Cannot set socket options. Errno %d\n",errno);
return -1;
}
src_addr.v4.sin_family = AF_INET;
src_addr.v4.sin_port = htons(src.port);
if (inet_pton(AF_INET, src.addr, &src_addr.v4.sin_addr) != 1) {
printf("Cannot convert source host:port to binary. Errno %d\n",errno);
return -1;
}
dst_addr.v4.sin_family = AF_INET;
dst_addr.v4.sin_port = htons(dst.port);
if (inet_pton(AF_INET, dst.addr, &(dst_addr.v4.sin_addr)) != 1) {
printf("Cannot convert destination host:port to binary. Errno %d\n",errno);
return -1;
}
libsoccr_set_addr(so, 1, &src_addr, 0);
libsoccr_set_addr(so, 0, &dst_addr, 0);
data.snd_wscale = src.wscale;
data.rcv_wscale = dst.wscale;
data.mss_clamp = src.mss_clamp;
data.opt_mask = TCPI_OPT_WSCALE | TCPOPT_MAXSEG;
if (libsoccr_restore(so, &data, sizeof(data)) < 0) {
printf("Cannot apply restore options. Errno %d\n",errno);
return -1;
}
libsoccr_resume(so);
return sk;
}
int main(int argc, char **argv) {
struct tcp tcp[2] = {
{"127.0.0.1", 17000, 5000000, 1460, 7},
{"127.0.0.1", 34000, 6000000, 1460, 7}
};
int source_socket = createSocket(tcp[0], tcp[1]);
printf("Source socket created: %d \n",source_socket);
int dest_socket = createSocket(tcp[1], tcp[0]);
printf("Destination socket created: %d \n",dest_socket);
if (source_socket < 0 || dest_socket < 0)
return -1;
char* message = "Hello world";
ssize_t written = write(source_socket, message, strlen(message));
if (written < 0) {
printf("Error writing to socket %d\n",errno);
return -1;
}
printf("%ld bytes written\n",written);
char buffer[1024];
ssize_t bytesRead = read(dest_socket, buffer, sizeof(buffer)-1);
printf("Bytes read %ld\n",bytesRead);
buffer[bytesRead] = 0;
printf("Message read: %s\n",buffer);
printf("Finished\n");
return 0;
}
Any ideas about what I might be doing wrong here?

C socket: recv jams the program if used twice

I'm trying to implement C code on a UNIX platform which sends all files data to the client, and uploading a file from the client to the server.
The first part is working but for the second part I've encountered an issue.
After some debugging I've found out that the server side jams the client when I'm using recv the second time in the code [I've marked it for your convenience].
I've tried to look up on guides or what I'm doing wrong but I couldn't find the issue for what causing the program to get stuck.
For de-bugging purposes I'm now trying to send an int from client to the server
server side
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <dirent.h>
#include <fcntl.h>
#define PORT 0x0da2
#define IP_ADDR 0x7f000001
#define QUEUE_LEN 20
int main(void)
{
//char directory[1024];
//chdir("server");
//getcwd(directory, sizeof(directory));
//printf("%s",directory);
DIR* directory;
struct dirent* ent;
int fd;
char buffer[1000] = {0};
char convert[100] = {0};
size_t array_size = 0;
struct stat fileStat;
if ((directory = opendir ("server")) == NULL)
{
perror ("Cannot open .");
return 1;
}
while ((ent = readdir(directory)) != NULL)
{
if (!( !strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) )
{
fd = openat(dirfd(directory), ent->d_name, 0);
if (fd == -1)
{
perror ("Can't get stats.");
return 1;
}
if(fstat(fd, &fileStat)== -1)
{
perror ("Can't get stats.");
return 1;
}
strcat(buffer,ent->d_name);
sprintf(convert,"%lld", (long long) fileStat.st_size);
strcat(buffer, " ");
strcat(buffer,convert);
strcat(buffer,"\n");
}
}
int listenS = socket(AF_INET, SOCK_STREAM, 0);
if (listenS < 0)
{
perror("socket");
return 1;
}
struct sockaddr_in s = {0};
s.sin_family = AF_INET;
s.sin_port = htons(PORT);
s.sin_addr.s_addr = htonl(IP_ADDR);
if (bind(listenS, (struct sockaddr*)&s, sizeof(s)) < 0)
{
perror("bind");
return 1;
}
if (listen(listenS, QUEUE_LEN) < 0)
{
perror("listen");
return 1;
}
struct sockaddr_in clientIn;
int clientInSize = sizeof clientIn;
while (1)
{
int newfd = accept(listenS, (struct sockaddr*)&clientIn, (socklen_t*)&clientInSize);
if (newfd < 0)
{
perror("accept");
return 1;
}
if (send(newfd, &buffer, strlen(buffer), 0) < 0)
{
perror("send");
return 1;
}
char namebuff[100] = {0};
char sizebuff[256] = {0};
//int size;
ssize_t nrecv;
int error = 0;
int fsize;
//int dataleft;
if ((nrecv = recv(newfd, &namebuff, sizeof(namebuff), 0)) < 0)
{
perror("recv");
return 1;
}
if((strstr(buffer,namebuff) != NULL))
{
error = -1;
if (send(newfd, &error, sizeof(int), 0) < 0)
{
perror("send");
return 1;
}
}
/*if ((nrecv = recv(newfd, &fsize, sizeof(int), 0)) < 0) //this line is what jams the program
{
perror("recv");
return 1;
}*/
if(error != -1) //
{
if ((nrecv = recv(newfd, &sizebuff, sizeof(sizebuff), 0)) < 0)
{
perror("recv");
return 1;
}
fsize = atoi(sizebuff);
}
printf("%s\n",namebuff);
printf("%d\n",fsize);
close(newfd);
}
close(listenS);
return 0;
}
client side
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <fcntl.h>
#define PORT 0x0da2
#define IP_ADDR 0x7f000001
int ctoi(char c) {
return c-'0';
}
int main(void)
{
int sock = socket(AF_INET, SOCK_STREAM, 0);
ssize_t nrecv;
struct sockaddr_in s = {0};
s.sin_family = AF_INET;
s.sin_port = htons(PORT);
s.sin_addr.s_addr = htonl(IP_ADDR);
if (connect(sock, (struct sockaddr*)&s, sizeof(s)) < 0)
{
perror("connect");
return 1;
}
printf("Successfully connected.\n");
char buffer[1000] = {0};
if ((nrecv = recv(sock, &buffer, sizeof(buffer), 0)) < 0)
{
perror("recv");
return 1;
}
printf("./client list-files\n%s\n", buffer); //nrcev gives the size of the data is recived
int fd;
//int i;
//ssize_t nwrite, nread;
char sizebuff[256];
struct stat file_stat;
int numcheck = 0;
//char buffer2[4096];
char namebuff[100] = "coolfile.txt";
fd=open("coolfile.txt",O_RDONLY);
if (send(sock, &namebuff, strlen(namebuff), 0) < 0)
{
perror("send");
return 1;
}
/*if ((nrecv = recv(sock, &numcheck, sizeof(int), 0)) < 0)
{
perror("recv");
return 1;
}*/
if (numcheck == -1)
{
printf("file already exists in the server\n");
return 1;
}
if (fstat(fd, &file_stat) < 0)
{
printf("error");
return 1;
}
sprintf(sizebuff, "%ld", file_stat.st_size);
//printf("%s\n",sizebuff);
/*int number = 5;
if(send(sock, &number, sizeof(int), 0) < 0)
{
printf("error");
return 1;
}*/
if(send(sock, &sizebuff, strlen(sizebuff), 0) < 0);
{
printf("error");
return 1;
}
/*
nread = read(fd, buffer2, 4096);
for (i = 0; i < nread; i += nwrite)
{
nwrite = write(sock, buffer2 + i, nread - i);
}
} while (nread != 0);*/
return 0;
}
Thanks for your help!

SSL:ERROR :0906D06C:PEM routines:PEM_read_bio:no start line:pem_lib.c:644:Expecting: CERTIFICATE

I'm writing a https proxy . And my program has two error.
15883:error:0906D06C:PEM routines:PEM_read_bio:no start line:pem_lib.c:644:Expecting: CERTIFICATE
15883:error:140AD009:SSL routines:SSL_CTX_use_certificate_file:PEM lib:ssl_rsa.c:491:
And this is my code,i don't know where is wrong.please help me 。
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <resolv.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#include <pthread.h>
#define SIZE 1024
#define PKEY "cacert.pem"
#define CERTT "privkey.pem"
pthread_mutex_t mut;
int counter = 0;
char url[400] = {0};
unsigned long GetIp(char domainname[250])
{
struct sockaddr_in sin;
struct hostent *phost;
if((phost = gethostbyname(domainname)) == NULL)
{
perror("gethostbyname error\n");
return 0;
}
sin.sin_addr = *((struct in_addr *)phost->h_addr_list[0]);
const char *ip = inet_ntoa(sin.sin_addr);
printf("ip is %s\n", ip);
return sin.sin_addr.s_addr;
}
void ShowCerts(SSL * ssl)
{
X509 *cert;
char *line;
cert = SSL_get_peer_certificate(ssl);
if (cert != NULL) {
printf("数字证书信息:\n");
line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
printf("证书: %s\n", line);
free(line);
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("颁发者: %s\n", line);
free(line);
X509_free(cert);
} else
printf("无证书信息!\n");
}
char *SendWeb(char buf[])
{
char *buffer1 ;
int sockfd;
int len;
struct sockaddr_in web;
SSL_CTX *ctx;
SSL *ssl;
if((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0)
{
perror("socket create failed!\n");
exit(errno);
}
bzero(&web,sizeof(web));
web.sin_family = AF_INET;
web.sin_port = htons(443);
// web.sin_addr.s_addr = inet_addr("110.75.146.111");
web.sin_addr.s_addr = GetIp(url);
if(connect(sockfd,(struct sockaddr *)&web,sizeof(web)) != 0 )
{
perror("connect error!\n");
exit(errno);
}
ssl = SSL_new(ctx);
SSL_set_fd(ssl,sockfd);
if(SSL_connect(ssl) == -1)
{
ERR_print_errors_fp(stderr);
}
ShowCerts(ssl);
bzero(buffer1,SIZE);
len = SSL_write(ssl,buf,SIZE);
if(len < 0)
{
printf("SendWeb error!\n");
}
else
{
printf("Send sucess is %s\n", buf);
}
len = SSL_read(ssl,buffer1,SIZE);
if(len > 0)
{
printf("Recv Web : %s\n", buffer1);
}
else
{
printf("Recv Web Error!错误代码:%d,错误信息:%s.\n", errno,strerror(errno));
}
return buffer1;
}
char RecvBro()
{
//char url[400] = {0};
int i, sockfd , client_fd,new_fd;
struct sockaddr_in mim_ser,brow;
int len;
char *index_start,*index_end,*buf;
SSL_CTX *ctx;
ctx = SSL_CTX_new(SSLv23_server_method());//以ssl v2 v3 标准敬爱内容方式产生一个SSL_CTX
if(ctx == NULL)
{
ERR_print_errors_fp(stdout);
exit(1);
}
//载入用户数字证书,发给客户端,包含公钥
if(!SSL_CTX_use_certificate_file(ctx,CERTT,SSL_FILETYPE_PEM))
{
ERR_print_errors_fp(stdout);
exit(1);
}
//载入用户私钥
if(SSL_CTX_use_PrivateKey_file(ctx,PKEY,SSL_FILETYPE_PEM))
{
ERR_print_errors_fp(stdout);
exit(1);
}
if(!SSL_CTX_check_private_key(ctx))
{
ERR_print_errors_fp(stdout);
exit(1);
}
if((sockfd=socket(PF_INET,SOCK_STREAM,0))== -1)
{
perror("socket create failed");
exit(1);
}
bzero(&mim_ser,sizeof(mim_ser));
mim_ser.sin_family = PF_INET;
mim_ser.sin_port = htons(443);
mim_ser.sin_addr.s_addr = INADDR_ANY;
if((bind(sockfd,(struct sockaddr *)&mim_ser,sizeof(struct sockaddr))) == -1)
{
perror("bind failed");
exit(1);
}
if(listen(sockfd,10) == -1)
{
perror("listen error");
exit(1);
}
SSL *ssl;
int len2 = sizeof (struct sockaddr);
if((new_fd = accept(sockfd,(struct sockaddr *)&brow,&len2)) == -1)
{
perror("accept error");
exit(1);
}
//基于ctx产生一个新的ssl
ssl = SSL_new(ctx);
SSL_set_fd(ssl,new_fd);//将连接用户的socket加入SSL
if(SSL_accept(ssl) == -1)
{
perror("accept");
close(new_fd);
}
buf = (char *)malloc(SIZE);
// char buf[SIZE]= {0};
bzero(buf,SIZE);
len = SSL_read(ssl,buf,SIZE);
if(len > 0)
{
printf("recv from browser is %s\n",buf);
}
else
{
printf("RECV ERROR!错误代码:%s,错误信息:%s\n",errno,strerror);
}
index_start = strstr(buf,"Host:");
index_end = strstr(index_end,"\r\n");
if(index_start == NULL ||index_end == NULL)
{
perror("index_start or index_end is NULL\n");
}
if((i = (int)(index_start - index_end )) <= 0)
{
perror("index_start - index_end <= 0 \n");
}
bzero(url,400);
strncpy(url,index_start + 6, i-6);
buf = SendWeb(buf);
len = SSL_write(ssl,buf,SIZE);
if(len <= 0)
{
printf("\nSend sucess!\n");
}
}
int main ()
{
ERR_load_BIO_strings();
SSL_library_init();//ssl库初始化
OpenSSL_add_all_algorithms();//载入所有ssl算法
SSL_load_error_strings();//载入所有ssl从错误消息
pthread_mutex_init(&mut,NULL);
while(1)
{
pthread_t work_thread;
if(pthread_create(&work_thread,NULL,(void *)&RecvBro,NULL))
{
perror("create thread error\n");
}
else
{
pthread_mutex_lock(&mut);
counter++;
pthread_mutex_unlock(&mut);
pthread_detach(work_thread);
}
}
pthread_mutex_destroy(&mut);
}
First of all, it seems like you have a typo and these two lines:
#define PKEY "cacert.pem"
#define CERTT "privkey.pem"
probably should be changed to
#define CERTT "cacert.pem"
#define PKEY "privkey.pem"
And even that is not enough. Check the items listed below
1) SSL_CTX_use_certificate_file() is used to load the certificate that corresponds to the private key, and not a CA certificate (like the name of your file "cacert.pem" suggests). You may find the following answer useful to quickly understand all of this: Starting to use OpenSSL
You should use SSL_CTX_load_verify_locations() to specify the file with CA certificate(s) like this:
SSL_CTX_load_verify_locations(ctx, "cacert.pem", NULL);
See the documentation for this API.
2) Certificate files of PEM type (both for SSL_CTX_use_certificate_file() with SSL_FILETYPE_PEM and for SSL_CTX_load_verify_locations()) should have dash header and footer, like this:
-----BEGIN CERTIFICATE-----
... (certificate in base64 encoding) ...
-----END CERTIFICATE-----
The error 9478:error:0906D06C:PEM routines:PEM_read_bio:no start line:pem_lib.c:644:Expecting: CERTIFICATE suggests that you don't have those dash header/footer lines in your file.

Processes not terminating

There are some strange things happening in my client-server application. Please, look at these simple fork client/server:
CLIENT:
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/wait.h>
#define IP_SERVER "192.168.1.89"
#define PORT_SERVER 65000
#define BUFFERSIZE 1024
#define NUMFILES 3
double timeElapsed(struct timeval* before, struct timeval* after) {
return after->tv_sec - before->tv_sec + (double) (after->tv_usec - before->tv_usec)/1000000;
}
void getFile(char *request, struct sockaddr_in server) {
char buffer[1024];
int sockProc, res;
int file;
int sizeServ = sizeof(server);
int writeFile;
sockProc = socket(AF_INET, SOCK_STREAM, 0);
if (sockProc < 0) {
printf("Error on creating socket client\n");
perror("");
exit(1);
}
file = open(request, O_CREAT | O_WRONLY, S_IRWXU);
res = connect(sockProc, (struct sockaddr*)&server, (socklen_t)sizeServ);
if (res < 0) {
printf("Error on connecting to server!\n");
perror("");
exit(1);
}
res = send(sockProc, (void*)request, strlen(request), 0);
memset(buffer, 0, sizeof(buffer));
while((res = recv(sockProc, (void*)buffer, sizeof(buffer), 0)) > 0) {
write(file, (void*)buffer, strlen(buffer));
memset(buffer, 0, sizeof(buffer));
}
close(sockProc);
close(file);
return;
}
int main(int argc, char** argv) {
int sockCli, res, i;
struct sockaddr_in server;
int sizeServ = sizeof(server);
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
inet_pton(AF_INET, IP_SERVER, &server.sin_addr);
server.sin_port = htons(PORT_SERVER);
char files[NUMFILES][32];
char nameFile[32];
char command[32] = "rm *.txt";
system(command);
struct timeval begin;
struct timeval end;
pid_t processes[NUMFILES];
for(i = 0; i<NUMFILES; i++) {
memset(nameFile, 0, sizeof(nameFile));
printf("Inserisci nome file (con estensione) da ricevere:\n");
scanf("%s", nameFile);
strcpy(files[i], nameFile);
}
gettimeofday(&begin, NULL);
for(i=0; i<NUMFILES; i++) {
pid_t child = fork();
if(child == 0) {
getFile(files[i], server);
exit(0);
}
else {
processes[i] = child;
continue;
}
}
/*for(i=0; i<NUMFILES; i++) {
waitpid(processes[i], NULL, 0);
}*/
wait(NULL);
gettimeofday(&end, NULL);
printf("Time elapsed on TCP is %f seconds\n", timeElapsed(&begin, &end));
return 0;
}
and the SERVER:
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#define IP_SERVER "192.168.1.89"
#define PORT_SERVER 65000
#define BUFFERSIZE 1024
void execRequest(int* sockCli, struct sockaddr_in* client) {
char buffer[BUFFERSIZE];
char request[BUFFERSIZE];
int res;
memset(request, 0, sizeof(request));
res = recv(*sockCli, (void*)request, sizeof(request), 0);
if(res < 0) {
printf("Error on recv()\n");
perror("");
exit(1);
}
printf("Requested file %s\n", request);
char resource[32] = "files/";
strcat(resource, request);
int file = open(resource, O_RDONLY);
if (file < 0) {
printf("File %s does not exist\n", request);
exit(1);
}
memset(buffer, 0, sizeof(buffer));
while((res = read(file, (void*)buffer, sizeof(buffer))) > 0) {
send(*sockCli, (void*)buffer, strlen(buffer), 0);
memset(buffer, 0, sizeof(buffer));
}
close((*sockCli));
close(file);
free(sockCli);
free(client);
return;
}
int main(int argc, char** argv) {
int sockServ, i, res;
int *sockCli;
struct sockaddr_in server;
struct sockaddr_in* client;
sockServ = socket(AF_INET, SOCK_STREAM, 0);
if(sockServ < 0) {
printf("Error in creating socket\n");
perror("");
exit(1);
}
memset(&server, 0, sizeof(server));
server.sin_addr.s_addr = inet_addr(IP_SERVER);
server.sin_port = htons(PORT_SERVER);
server.sin_family = AF_INET;
int reuse = 1;
res = setsockopt(sockServ, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int));
if (res < 0) {
printf("setsockopt() REUSEADDR failed\n");
perror("");
exit(1);
}
res = bind(sockServ, (struct sockaddr*)&server, sizeof(server));
if (res < 0) {
printf("Error on bindind TCP server!\n");
perror("");
exit(1);
}
res = listen(sockServ, 5);
if (res < 0) {
printf("Error on listening TCP server!\n");
perror("");
exit(1);
}
while(1) {
sockCli = (int*)malloc(sizeof(int));
client = (struct sockaddr_in*)malloc(sizeof(struct sockaddr_in));
int sizeClient = sizeof(struct sockaddr_in);
*sockCli = accept(sockServ, (struct sockaddr*)client, &sizeClient);
if ((*sockCli) < 0) {
printf("accept() failed\n");
perror("");
continue;
}
printf("Connected to %s:%d\n", inet_ntoa(client->sin_addr), client->sin_port);
if( !fork() ) {
execRequest(sockCli, client);
exit(0);
}
else
continue;
}
return 0;
}
This is very strange. The processes created by the client don't terminate even if the server closes the sockets and so recv() should return 0 and let client processes exit from the loop. Moreover there's something strange about reading files:
the server simply reads files.txt but in doing this it includes the string ".txt" in the read characters and sends all this mixture to the client...why?
they are simple file mono character like
aaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaa
but the server reads and and sends:
aaaaaaaaaaaaaaaaaa.txt
aaaaaaaaaaaaaaaaaa
can I solve all this?
You can't use strlen(buffer), just because you're loading characters from a text file doesn't mean that buffer will be a valid string unless you take steps to ensure it is. And you don't; there's no termination since you can fill all of buffer with data from the file.
How many times must we play the broken record here on Stack Overflow? Don't cast malloc!
I chalk this error to failure to read the manual(s), to find out what header to include, what a string is (and hence what strlen/strcat/str*{anything}* expects of its input, what printf expects of arguments that correspond to a %s format specifier, etc.) and what read/recv produces.
res = recv(*sockCli, (void*)request, sizeof(request), 0);
if(res < 0) {
printf("Error on recv()\n");
perror("");
exit(1);
}
printf("Requested file %.*s\n", res, request); // NOTE the field width provided by 'res'
By the manual, examples such as res = read(file, (void*)buffer, sizeof(buffer)) supposedly store either an error or a length. The condition ensures that the send code will only execute when it's a length value, so why not use it as one? send(*sockCli, (void*)buffer, res, 0);?
The presense of these problems seems to indicate that your method of learning isn't working. Which book are you reading? Learning C without a book is a bit like learning which berries are poisonous without communication.

Resources