This repository has been archived by the owner on Jul 9, 2021. It is now read-only.
forked from zappala/socket-programming-examples-c
/
socket.cc
238 lines (207 loc) · 6.4 KB
/
socket.cc
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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
#include "socket.h"
// for buffering
#include <sstream>
// for the socket (copied from Zappala's code)
#include <arpa/inet.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
// for making client sockets
#include <netdb.h>
// for debugging
#include "logger.h"
// make a new server
Socket::Socket(int srvPort, int maxConns)
{
bufLen = DEFAULT_BUFFER_LENGTH;
buf = new char[bufLen+1];
LOG("Successfully allocated new buffer!\n");
LOG("Creating new server/listening socket\n");
sockFd = 0;
struct sockaddr_in server_addr;
// setup socket address structure
memset(&server_addr,0,sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(srvPort);
server_addr.sin_addr.s_addr = INADDR_ANY;
// create socket
sockFd = socket(PF_INET,SOCK_STREAM,0);
if (!sockFd) {
perror("socket");
exit(-1);
}
// set socket to immediately reuse port when the application closes
int reuse = 1;
if (setsockopt(sockFd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) {
perror("setsockopt");
exit(-1);
}
// call bind to associate the socket with our local address and
// port
if (bind(sockFd,(const struct sockaddr *)&server_addr,sizeof(server_addr)) < 0) {
perror("bind");
exit(-1);
}
// convert the socket to listen for incoming connections
if (listen(sockFd,SOMAXCONN) < 0) {
perror("listen");
exit(-1);
}
}
Socket::Socket(string host_, int port_)
{
bufLen = DEFAULT_BUFFER_LENGTH;
buf = new char[bufLen+1];
LOG("Successfully allocated new buffer!\n");
LOG("Starting to create client socket...\n");
struct sockaddr_in server_addr;
// use DNS to get IP address
struct hostent *hostEntry;
hostEntry = gethostbyname(host_.c_str());
if (!hostEntry) {
LOG("No such host name: %s\n", host_.c_str());
exit(-1);
}
// setup socket address structure
memset(&server_addr,0,sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port_);
memcpy(&server_addr.sin_addr, hostEntry->h_addr_list[0], hostEntry->h_length);
// create socket
int server_ = socket(PF_INET,SOCK_STREAM,0);
if (!server_) {
perror("socket");
exit(-1);
}
// connect to server
if (connect(server_,(const struct sockaddr *)&server_addr,sizeof(server_addr)) < 0) {
perror("connect");
exit(-1);
}
sockFd = server_;
}
Socket::Socket(int fd)
{
bufLen = DEFAULT_BUFFER_LENGTH;
buf = new char[bufLen+1];
LOG("Successfully allocated new buffer!\n");
LOG("wrapping extant socket #%d\n", fd);
sockFd = fd;
}
Socket::~Socket()
{
if (sockFd > 0) {
close(sockFd);
}
delete buf;
}
int Socket::readToSentinel(const char *sentinel, string &targ)
{
int idx, nread;
while ((idx = cache.find(sentinel, 0)) == string::npos) {
LOG("Trying to read off of socket\n");
nread = recv(sockFd, buf, bufLen, 0);
if (nread < 0) {
if (errno == EINTR) {
// the socket call was interrupted -- try again
LOG("Socket call interrupted\n");
continue;
} else {
perror("while scanning for sentinel");
LOG("saw error on recv: %d\n", errno);
// an error occurred, stop trying to recv()
return nread;
}
} else if (nread == 0) {
// socket closed, stop trying to recv()
LOG("Child socket closed during sentinel search loop\n");
return nread;
} else {
LOG("got data");
// the socket gave a strictly positive return; use it
cache.append(buf, 0, nread);
}
}
// idx contains the index of the sentinel
//copy out the useful data
targ = cache.substr(0, idx);
// remove it from the cache, preserving any extra data (except the delimiter/sentinel)
cache.erase(0, idx+1);
LOG("Using delim '%s' I found '%s'\n", sentinel, targ.c_str());
return nread;
}
int Socket::readNBytes(int n, string &targ)
{
int nread;
while (cache.length() < n) {
LOG("Trying to read off of socket\n");
nread = recv(sockFd, buf, bufLen, 0);
if (nread < 0) {
if (errno == EINTR) {
// the socket call was interrupted -- try again
LOG("Socket call interrupted\n");
continue;
} else {
perror("while scanning for sentinel");
LOG("saw error on recv: %d\n", errno);
// an error occurred, stop trying to recv()
return nread;
}
} else if (nread == 0) {
// socket closed, stop trying to recv()
LOG("Child socket closed during sentinel search loop\n");
return nread;
} else {
// the socket gave a strictly positive return; use it
cache.append(buf, 0, nread);
}
}
// idx contains the index of the sentinel
//copy out the useful data
targ = cache.substr(0, n);
// remove it from the cache, preserving any extra data
cache.erase(0, n);
LOG("Using count '%d' I found '%s'\n", n, targ.c_str());
return nread;
}
int Socket::sendString(string &response)
{
// prepare to send response
const char* ptr = response.c_str();
int nleft = response.length();
int nwritten;
LOG("Sending response: '%s'\n", response.c_str());
// loop to be sure it is all sent
while (nleft) {
if ((nwritten = send(sockFd, ptr, nleft, 0)) < 0) {
if (errno == EINTR) {
// the socket call was interrupted -- try again
continue;
} else {
// an error occurred, so break out
perror("write");
return -1;
}
} else if (nwritten == 0) {
// the socket is closed
return 0;
}
nleft -= nwritten;
ptr += nwritten;
}
LOG("response sent.\n");
return 1;
}
int Socket::acceptClient()
{
// setup client
int client;
struct sockaddr_in client_addr;
socklen_t clientlen = sizeof(client_addr);
client = accept(sockFd, (struct sockaddr *)&client_addr, &clientlen);
return client;
}