1 /**************************************************************************
3 * Copyright 2013-2014 RAD Game Tools and Valve Software
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 **************************************************************************/
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include <arpa/inet.h>
36 #include <sys/types.h>
37 #include <netinet/tcp.h>
45 int hostname_to_ip(char *hostname, char *ip);
46 void print_time(const char *szDesc, struct timespec *ptspec);
48 #if defined(_DEBUG) || defined(DEBUG)
49 #define DEBUG_PRINT(fmt, args...) fprintf( stderr, fmt, ## args )
51 #define DEBUG_PRINT(...) /* Don't do anything in release builds */
54 using namespace network;
57 /**********************************************************/
59 // Class Channel implementation
62 channel::channel(void *pbFixedBuffer, size_t cbFixedBuffer)
64 Initialize(pbFixedBuffer, cbFixedBuffer);
73 channel::Initialize(void *pbFixedBuffer, size_t cbFixedBuffer)
79 // fixed buffer to use for packets
80 m_cbFixedBuffer = cbFixedBuffer;
81 m_pbFixedBuffer = pbFixedBuffer;
84 memset(m_szServer, 0, sizeof(m_szServer));
96 shutdown(m_listenSocket, SHUT_RDWR);
97 close(m_listenSocket);
102 shutdown(m_socket, SHUT_RDWR);
108 channel::Connect(char *szServer, int port, int nRetries, unsigned int waitMS)
117 strncpy(m_szServer, szServer, sizeof(m_szServer));
120 for (int iTry = 0; iTry < nRetries; iTry++)
122 ec = channelConnect();
123 if (EC_TIMEOUT != ec)
128 usleep(waitMS * 1000); // 1000 microseconds = 1 milisecond
135 channel::Connect(int port, int backlog, bool fLocal)
144 ec = channelConnect();
150 channel::channelConnect()
154 if (false == m_fServer)
156 ec = connectConnection();
160 ec = acceptConnection();
167 channel::acceptConnection()
171 int noNagle = 1; // Turn off nagle
172 int reuseaddress = 1; // Do not reuse addresses
173 struct sockaddr_in serv_addr;
174 bool fFirstTime = false;
176 if (0 == m_listenSocket)
179 m_listenSocket = socket(AF_INET, SOCK_STREAM, 0);
180 if (-1 == m_listenSocket)
183 DEBUG_PRINT("%s %d: %s socket() failed with %d\n", __FILE__, __LINE__, __func__, errno);
188 // setsockopt(listenfd, IPPROTO_TCP, TCP_NODELAY, &noNagle, sizeof(noNagle));
189 rv = setsockopt(m_listenSocket, SOL_SOCKET, SO_REUSEADDR, (void *)&reuseaddress, sizeof(reuseaddress));
192 close(m_listenSocket);
194 DEBUG_PRINT("%s %d: %s setsockopt() failed with %d\n", __FILE__, __LINE__, __func__, errno);
199 rv = setsockopt(m_listenSocket, IPPROTO_TCP, TCP_NODELAY, (void *)&noNagle, sizeof(noNagle));
202 close(m_listenSocket);
204 DEBUG_PRINT("%s %d: %s setsockopt() failed with %d\n", __FILE__, __LINE__, __func__, errno);
209 memset(&serv_addr, '0', sizeof(serv_addr));
210 serv_addr.sin_family = AF_INET;
211 if (true == m_fLocal)
213 serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
217 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
219 serv_addr.sin_port = htons(m_port);
221 rv = bind(m_listenSocket, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
224 close(m_listenSocket);
226 DEBUG_PRINT("%s %d: %s bind() failed with %d\n", __FILE__, __LINE__, __func__, errno);
231 rv = listen(m_listenSocket, m_backlog);
234 close(m_listenSocket);
236 DEBUG_PRINT("%s %d: %s listen() failed with %d\n", __FILE__, __LINE__, __func__, errno);
250 if (true != fFirstTime)
252 // Non-blocking see if there's any connections awaiting us
253 flags = fcntl(m_listenSocket, F_GETFL, 0);
254 if (-1 == flags) flags = 0;
256 ret = fcntl(m_listenSocket, F_SETFL, flags);
259 DEBUG_PRINT("%s %d: %s accept() attempt on port %d\n", __FILE__, __LINE__, __func__, m_port);
260 m_socket = accept(m_listenSocket, (struct sockaddr *)NULL, NULL);
266 DEBUG_PRINT("%s %d: %s accept() failed with %d\n", __FILE__, __LINE__, __func__, errno);
268 //if (EAGAIN == errno || EWOULDBLOCK == errno)
274 // setsockopt(listenfd, IPPROTO_TCP, TCP_NODELAY, &noNagle, sizeof(noNagle));
275 rv = setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, (void *)&reuseaddress, sizeof(reuseaddress));
280 DEBUG_PRINT("%s %d: %s setsockopt() failed with %d\n", __FILE__, __LINE__, __func__, errno);
286 rv = setsockopt(m_socket, IPPROTO_TCP, TCP_NODELAY, (void *)&noNagle, sizeof(noNagle));
291 DEBUG_PRINT("%s %d: %s setsockopt() failed with %d\n", __FILE__, __LINE__, __func__, errno);
296 DEBUG_PRINT("%s %d: %s accept() succeeded to socket %d on port %d\n", __FILE__, __LINE__, __func__, m_socket, m_port);
304 channel::connectConnection()
308 int noNagle = 1; // Turn off nagle
309 int reuseaddress = 1; // Do not reuse addresses
310 struct sockaddr_in serv_addr;
311 char ip[1024] = { 0 };
313 m_socket = socket(AF_INET, SOCK_STREAM, 0);
317 DEBUG_PRINT("\n %s %d: %s Error : Could not create socket \n", __FILE__, __LINE__, __func__);
324 // setsockopt(listenfd, IPPROTO_TCP, TCP_NODELAY, &noNagle, sizeof(noNagle));
325 rv = setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, (void *)&reuseaddress, sizeof(reuseaddress));
330 DEBUG_PRINT("%s %d: %s setsockopt() failed with %d\n", __FILE__, __LINE__, __func__, errno);
335 rv = setsockopt(m_socket, IPPROTO_TCP, TCP_NODELAY, (void *)&noNagle, sizeof(noNagle));
340 DEBUG_PRINT("%s %d: %s setsockopt() failed with %d\n", __FILE__, __LINE__, __func__, errno);
346 hostname_to_ip(m_szServer, ip);
348 DEBUG_PRINT("%s has the ip of: %s\n", m_szServer, ip);
350 memset(&serv_addr, '0', sizeof(serv_addr));
352 serv_addr.sin_family = AF_INET;
353 serv_addr.sin_port = htons(m_port);
355 rv = inet_pton(AF_INET, ip, &serv_addr.sin_addr);
358 DEBUG_PRINT("%s %d: %s inet_pton() failed with %d\n", __FILE__, __LINE__, __func__, errno);
365 DEBUG_PRINT("%s %d: %s inet_pton() \"%s\" does not contain a character string representing a valid network address in the AF_INET address family.", __FILE__, __LINE__, __func__, ip);
371 rv = connect(m_socket, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
376 DEBUG_PRINT("%s %d: %s connect() failed on port %d with %d\n", __FILE__, __LINE__, __func__, m_port, tErrno);
377 if (ECONNREFUSED == tErrno)
385 DEBUG_PRINT("%s %d: %s connect() to socket %d on port %d\n", __FILE__, __LINE__, __func__, m_socket, m_port);
392 channel::Disconnect()
396 DEBUG_PRINT("%s %d: %s closing down socket %d on port %d\n", __FILE__, __LINE__, __func__, m_socket, m_port);
397 shutdown(m_socket, SHUT_RDWR);
410 // Returns the size and data of a message read from the network socket. Lifetime of the data returned is owned by the
411 // caller and should be cleaned up by using free().
413 // This method is the one that loops through the retries.
416 channel::ReadMsg(unsigned int *pcbBufOut, char **ppBufOut, int nRetries, int timeoutMS)
420 for (int iTry = 0; iTry < nRetries; iTry++)
422 ec = readMsgLoop(pcbBufOut, ppBufOut, timeoutMS);
423 if (EC_TIMEOUT == ec)
430 //if (EC_TIMEOUT == ec)
439 // The inner loop of the ReadMsg() that deals with reconnection and message size.
442 channel::readMsgLoop(unsigned int *pcbBufOut, char **ppBufOut, int timeoutMS)
445 char *pRecBuff = NULL;
446 //int bToRead = 1024;
448 u_int64_t cbSize64 = 0;
452 ec = channelConnect();
457 // A buffer is defined as having a size (int64_t) followed by the data of that size.
459 // First, read the size of the buffer:
461 ec = readMsgTimeout(sizeof(int64_t), (char *)&cbSize64, timeoutMS);
467 // malloc up some space
468 pRecBuff = (char *)my_malloc((size_t)cbSize64);
469 if (NULL == pRecBuff)
475 // Now read the data buffer
476 ec = readMsgTimeout(cbSize64, pRecBuff, timeoutMS);
480 DEBUG_PRINT("%s %d: %s Error from read(data) = %d (%d).", __FILE__, __LINE__, __func__, ec, errno);
485 DEBUG_PRINT("Debug: client buffer read %zd bytes\n", cbSize64);
487 *ppBufOut = pRecBuff;
488 *pcbBufOut = cbSize64; // MIN(bToRead, bRead)?
492 if (EC_NONE != ec && EC_TIMEOUT != ec)
494 DEBUG_PRINT(" Disconnecting.\n");
496 // Try to reconnect right away.
497 ec = channelConnect();
508 // The inner read of the readMsgLoop(). This one deals with timeouts explicitly.
511 channel::readMsgTimeout(unsigned int cbSize, char *pBuff, int timeoutMS)
514 double timeElapsedMS = 0;
515 unsigned int bRead = 0; // How many bytes read so far
516 char *pRecBuff = pBuff;
517 struct timespec tspecBefore, tspecNow;
520 clock_gettime(CLOCK_MONOTONIC, &tspecBefore);
522 //DEBUG_PRINT("channel::InternalRead: Timeout specified as %dms.\n", timeoutMS);
523 while (cbSize > bRead)
527 //bReadT = read(m_socket, pRecBuff+bRead, cbSize - bRead );
528 bReadT = recv(m_socket, pRecBuff + bRead, cbSize - bRead, MSG_NOSIGNAL | (m_fServer ? 0: MSG_DONTWAIT));
532 // Check to see if the error is actually just a timeout
534 if (EWOULDBLOCK != errno && EAGAIN != errno)
537 DEBUG_PRINT("%s %d: %s Error from read() on port %d = %d. \n", __FILE__, __LINE__, __func__, m_port, errno);
541 // See if we've gone past the timeout requested
542 clock_gettime(CLOCK_MONOTONIC, &tspecNow);
544 timeElapsedMS = ((double)(tspecNow.tv_sec - tspecBefore.tv_sec) * 1000) + ((double)(tspecNow.tv_nsec - tspecBefore.tv_nsec) / 1.0e6);
546 if (timeoutMS && (timeoutMS <= timeElapsedMS))
550 //DEBUG_PRINT("channel::InternalRead: Timing out %f\n", timeElapsedMS);
555 //DEBUG_PRINT("channel::InternalRead: Still time left %f\n", timeElapsedMS);
559 bRead += (unsigned int) bReadT; // Add the bytes we've read up to this point.
564 DEBUG_PRINT("%s %d: %s recv'd(%d bytes) on port %d\n", __FILE__, __LINE__, __func__, bRead, m_port);
572 // Writes a buffer out to a socket. In order to do so, it needs to prepend the buffer with the
573 // size in order for the readMsg to know how much data to get.
577 channel::WriteMsg(unsigned int cbBufIn, const char *pbBufIn, int nRetries, int timeoutMS)
581 for (int iTry = 0; iTry < nRetries; iTry++)
583 ec = writeMsgLoop(cbBufIn, pbBufIn, timeoutMS);
584 if (EC_TIMEOUT == ec)
591 //if (EC_TIMEOUT == ec)
598 channel::writeMsgLoop(unsigned int cbBufIn, const char *pbBufIn, int timeoutMS)
602 u_int64_t cbToWrite = cbBufIn; // Number of bytes to write if this write is to succeed
606 ec = channelConnect();
611 ec = writeMsgTimeout(sizeof(u_int64_t), (char *)&cbToWrite, timeoutMS);
614 DEBUG_PRINT("%s %d: %s Error from write(buffersize) = %d (%d) on port %d.", __FILE__, __LINE__, __func__, ec, errno, m_port);
618 ec = writeMsgTimeout(cbBufIn, pbBufIn, timeoutMS);
621 DEBUG_PRINT("%s %d: %s Error from write(data) = %d (%d) on port %d.", __FILE__, __LINE__, __func__, ec, errno, m_port);
625 DEBUG_PRINT("Debug: client buffer wrote %zd bytes on port %d\n", cbToWrite, m_port);
628 if (EC_NONE != ec && EC_TIMEOUT != ec)
630 DEBUG_PRINT(" Disconnecting.\n");
632 // Try to reconnect right away.
633 ec = channelConnect();
642 channel::writeMsgTimeout(unsigned int cbSize, const char *pBuff, int timeoutMS)
646 unsigned int bWritten = 0; // How many bytes sent so far
647 struct timespec tspecBefore, tspecNow;
650 clock_gettime(CLOCK_MONOTONIC, &tspecBefore);
652 DEBUG_PRINT("%s %d: %s attempting to send (%d bytes) to socket %d on port %d\n", __FILE__, __LINE__, __func__, cbSize, m_socket, m_port);
653 while (bWritten < cbSize)
657 bWrote = send(m_socket, pBuff + bWritten, cbSize - bWritten, MSG_NOSIGNAL | (timeoutMS ? MSG_DONTWAIT : 0));
660 // Check to see if the error is actually just a timeout
662 if (EWOULDBLOCK != errno && EAGAIN != errno)
665 DEBUG_PRINT("%s %d: %s Error %d from write() to socket %d on port %d.\n", __FILE__, __LINE__, __func__, errno, m_socket, m_port);
669 // See if we've gone past the timeout requested
670 clock_gettime(CLOCK_MONOTONIC, &tspecNow);
672 timeMS = ((double)(tspecNow.tv_sec - tspecBefore.tv_sec) * 1.0e9 + (double)(tspecNow.tv_nsec - tspecBefore.tv_nsec)) / 1000;
674 if (timeoutMS && (timeoutMS <= timeMS))
685 bWritten += (unsigned int) bWrote;
690 DEBUG_PRINT("%s %d: %s sent (%d bytes) to socket %d on port %d\n", __FILE__, __LINE__, __func__, bWritten, m_socket, m_port);
692 DEBUG_PRINT("%s %d: %s error (%d) sending (%d bytes) to socket %d on port %d\n", __FILE__, __LINE__, __func__, errno, cbSize, m_socket, m_port);
698 channel::my_malloc(size_t cbSize)
700 if (NULL == m_pbFixedBuffer)
701 return malloc(cbSize);
703 if (cbSize > m_cbFixedBuffer)
706 return m_pbFixedBuffer;
710 channel::my_free(void *pBuff)
713 if (pBuff == m_pbFixedBuffer)
722 // Internal helper functions
726 hostname_to_ip(char *hostname, char *ip)
728 struct addrinfo hints, *servinfo, *p;
729 struct sockaddr_in *h;
732 memset(&hints, 0, sizeof hints);
733 hints.ai_family = AF_UNSPEC; // use AF_INET6 to force IPv6
734 hints.ai_socktype = SOCK_STREAM;
736 if ((rv = getaddrinfo(hostname, "http", &hints, &servinfo)) != 0)
738 fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
742 // loop through all the results and connect to the first we can
743 for (p = servinfo; p != NULL; p = p->ai_next)
745 h = (struct sockaddr_in *)p->ai_addr;
746 strcpy(ip, inet_ntoa(h->sin_addr));
749 freeaddrinfo(servinfo); // all done with this structure
753 void print_time(const char *szDesc, struct timespec *ptspec)
755 printf("\t%s time:\n", szDesc);
756 printf("\t\t%ld seconds\n", ptspec->tv_sec);
757 printf("\t\t%ld nanoseconds\n", ptspec->tv_nsec);