-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.c
More file actions
160 lines (143 loc) · 4.18 KB
/
server.c
File metadata and controls
160 lines (143 loc) · 4.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/*
** server.c -- a stream socket server demo
*/
#include <stdio.h>
#include <stdint.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 <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#include <pthread.h>
#include "thpool.h"
#define PORT "3490" // the port users will be connecting to
#define BACKLOG 10 // how many pending connections queue will hold
#define MAXCONNECT 2 // max number of concurrent connections allowed
#define BUFFER_SIZE 1024 // size of buffer
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
// echo function for each thread
void echo(void *newfd_ptr) {
printf("starting echo\n");
int new_fd = *(int*) newfd_ptr;
// create buffer to receive incoming msgs
char buf[BUFFER_SIZE];
// echo back incoming msgs
while (1) {
int read = recv(new_fd, buf, BUFFER_SIZE, 0);
if (read == 0) {
printf("Remote side closed\n");
close(new_fd);
break;
} else if (read == -1) {
perror("recv");
continue;
}
// echo back received msg
if (send(new_fd, buf, read, 0) == -1) {
perror("send");
}
}
printf("exiting thread\n");
pthread_exit(NULL);
}
int main(void)
{
int sockfd, new_fd; // listen on sock_fd, new connection on new_fd
struct addrinfo hints, *servinfo, *p; // used for prepping sockaddr structs
struct sockaddr_storage their_addr; // connector's address information
socklen_t sin_size;
int rc; // return code
int numConn; // current number of connections
threadpool thr_pool; // thread pool
int yes=1;
char s[INET6_ADDRSTRLEN]; // used to contain IP address
int rv; // return value for error checking
memset(&hints, 0, sizeof hints); // clear hints struct
hints.ai_family = AF_UNSPEC; // dont care IPv4 or v6
hints.ai_socktype = SOCK_STREAM; // TCP
hints.ai_flags = AI_PASSIVE; // use my IP
// fills out servinfo as linked list of posible socket address structures
if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and bind to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) {
// get socket file descriptor
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("server: socket");
continue;
}
// allows reuse of local addresses
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
// bind port number to socket
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("server: bind");
continue;
}
break;
}
freeaddrinfo(servinfo); // all done with this structure
// if none of the results resulted in bind
if (p == NULL) {
fprintf(stderr, "server: failed to bind\n");
exit(1);
}
// wait for incoming connections with queue size of BACKLOG
if (listen(sockfd, BACKLOG) == -1) {
perror("listen");
exit(1);
}
printf("server: waiting for connections...\n");
if (!(thr_pool = thpool_init(MAXCONNECT))) { // initialize thread pool
printf("error creating thread pool");
exit(1);
}
while(1) { // main accept() loop
sin_size = sizeof their_addr;
printf("num current connections: %d\n", thpool_num_threads_working(thr_pool));
// put incoming connection info into their_addr
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
if (new_fd == -1) {
perror("accept");
continue;
}
// print out incoming address
inet_ntop(their_addr.ss_family,
get_in_addr((struct sockaddr *)&their_addr),
s, sizeof s);
printf("server: got connection from %s\n", s);
// create new thread for the connection
if (thpool_num_threads_working(thr_pool) > MAXCONNECT) {
printf("max connections reached, adding to queue\n");
}
rc = thpool_add_work(thr_pool, &echo, &new_fd);
printf("adding work to pool\n");
if (rc == -1) {
printf("ERROR; adding work to thread pool");
exit(-1);
}
sleep(1);
}
thpool_destroy(thr_pool); // destroy thread pool
return 0;
}