Include the version information in the usage output.
[tetrinet.git] / sockets.c
blob9c979cb84fa8613f8a0a4835e7b619c555b13908
1 /* Tetrinet for Linux, by Andrew Church <achurch@achurch.org>
2 * This program is public domain.
4 * Socket routines.
5 */
7 #include <stdarg.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <errno.h>
11 #include <sys/types.h>
12 #include <netdb.h>
13 #include <netinet/in.h>
14 #include <sys/socket.h>
15 #include <sys/time.h>
16 #include "sockets.h"
17 #include "tetrinet.h"
19 static FILE *logfile;
21 /*************************************************************************/
23 static int lastchar = EOF;
25 int sgetc(int s)
27 int c;
28 char ch;
30 if (lastchar != EOF) {
31 c = lastchar;
32 lastchar = EOF;
33 return c;
35 if (read(s, &ch, 1) != 1)
36 return EOF;
37 c = ch & 0xFF;
38 return c;
41 int sungetc(int c, int s)
43 return lastchar = c;
46 /*************************************************************************/
48 /* Read a string, stopping with (and discarding) 0xFF as line terminator.
49 * If connection was broken, return NULL.
52 char *sgets(char *buf, int len, int s)
54 int c;
55 unsigned char *ptr = (unsigned char *) buf;
57 if (len == 0)
58 return NULL;
59 c = sgetc(s);
60 while (--len && (*ptr++ = c) != 0xFF && (c = sgetc(s)) >= 0)
62 if (c < 0)
63 return NULL;
64 if (c == 0xFF)
65 ptr--;
66 *ptr = 0;
67 if (log) {
68 if (!logfile)
69 logfile = fopen(logname, "a");
70 if (logfile) {
71 struct timeval tv;
72 gettimeofday(&tv, NULL);
73 fprintf(logfile, "[%d.%03d] <<< %s\n",
74 tv.tv_sec, tv.tv_usec/1000, buf);
75 fflush(logfile);
78 return buf;
81 /*************************************************************************/
83 /* Adds a 0xFF line terminator. */
85 int sputs(const char *str, int s)
87 unsigned char c = 0xFF;
88 int n = 0;
90 if (log) {
91 if (!logfile)
92 logfile = fopen(logname, "a");
93 if (logfile) {
94 struct timeval tv;
95 gettimeofday(&tv, NULL);
96 fprintf(logfile, "[%d.%03d] >>> %s\n",
97 tv.tv_sec, tv.tv_usec/1000, str);
100 if (*str != 0) {
101 n = write(s, str, strlen(str));
102 if (n <= 0)
103 return n;
105 if (write(s, &c, 1) <= 0)
106 return n;
107 return n+1;
110 /*************************************************************************/
112 /* Adds a 0xFF line terminator. */
114 int sockprintf(int s, const char *fmt, ...)
116 va_list args;
117 char buf[16384]; /* Really huge, to try and avoid truncation */
119 va_start(args, fmt);
120 vsnprintf(buf, sizeof(buf), fmt, args);
121 return sputs(buf, s);
124 /*************************************************************************/
125 /*************************************************************************/
127 int conn(const char *host, int port, char ipbuf[4])
129 #ifdef HAVE_IPV6
130 char hbuf[NI_MAXHOST];
131 struct addrinfo hints, *res, *res0;
132 char service[11];
133 #else
134 struct hostent *hp;
135 struct sockaddr_in sa;
136 #endif
137 int sock;
139 #ifdef HAVE_IPV6
140 snprintf(service, sizeof(service), "%d", port);
141 memset(&hints, 0, sizeof(hints));
142 hints.ai_family = AF_UNSPEC;
143 hints.ai_socktype = SOCK_STREAM;
144 if (getaddrinfo(host, service, &hints, &res0))
145 return -1;
146 for (res = res0; res; res = res->ai_next) {
147 int errno_save;
148 sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
149 if (sock < 0)
150 continue;
151 getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf),
152 NULL, 0, 0);
153 if (connect(sock, res->ai_addr, res->ai_addrlen) == 0) {
154 if (ipbuf) {
155 if (res->ai_family == AF_INET6) {
156 struct sockaddr_in6 *sin6 =
157 (struct sockaddr_in6 *)(res->ai_addr);
158 memcpy(ipbuf, (char *)(&sin6->sin6_addr) + 12, 4);
159 } else {
160 struct sockaddr_in *sin =
161 (struct sockaddr_in *)(res->ai_addr);
162 memcpy(ipbuf, &sin->sin_addr, 4);
165 break;
167 errno_save = errno;
168 close(sock);
169 sock = -1;
170 errno = errno_save;
172 freeaddrinfo(res0);
173 #else /* !HAVE_IPV6 */
174 memset(&sa, 0, sizeof(sa));
175 if (!(hp = gethostbyname(host)))
176 return -1;
177 memcpy((char *)&sa.sin_addr, hp->h_addr, hp->h_length);
178 sa.sin_family = hp->h_addrtype;
179 sa.sin_port = htons((unsigned short)port);
180 if ((sock = socket(sa.sin_family, SOCK_STREAM, 0)) < 0)
181 return -1;
182 if (connect(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
183 int errno_save = errno;
184 close(sock);
185 errno = errno_save;
186 return -1;
188 if (ipbuf)
189 memcpy(retbuf, &sa.sin_addr, 4);
190 #endif
192 return sock;
195 /*************************************************************************/
197 void disconn(int s)
199 shutdown(s, 2);
200 close(s);
203 /*************************************************************************/