Commit | Line | Data |
---|---|---|
196ba1fc PH |
1 | /* sim_sock.c: OS-dependent socket routines\r |
2 | \r | |
3 | Copyright (c) 2001-2005, Robert M Supnik\r | |
4 | \r | |
5 | Permission is hereby granted, free of charge, to any person obtaining a\r | |
6 | copy of this software and associated documentation files (the "Software"),\r | |
7 | to deal in the Software without restriction, including without limitation\r | |
8 | the rights to use, copy, modify, merge, publish, distribute, sublicense,\r | |
9 | and/or sell copies of the Software, and to permit persons to whom the\r | |
10 | Software is furnished to do so, subject to the following conditions:\r | |
11 | \r | |
12 | The above copyright notice and this permission notice shall be included in\r | |
13 | all copies or substantial portions of the Software.\r | |
14 | \r | |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r | |
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r | |
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r | |
18 | ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r | |
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r | |
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r | |
21 | \r | |
22 | Except as contained in this notice, the name of Robert M Supnik shall not be\r | |
23 | used in advertising or otherwise to promote the sale, use or other dealings\r | |
24 | in this Software without prior written authorization from Robert M Supnik.\r | |
25 | \r | |
26 | 19-Nov-05 RMS Added conditional for OpenBSD (from Federico G. Schwindt)\r | |
27 | 16-Aug-05 RMS Fixed spurious SIGPIPE signal error in Unix\r | |
28 | 14-Apr-05 RMS Added WSAEINPROGRESS test (from Tim Riker)\r | |
29 | 09-Jan-04 RMS Fixed typing problem in Alpha Unix (found by Tim Chapman)\r | |
30 | 17-Apr-03 RMS Fixed non-implemented version of sim_close_sock\r | |
31 | (found by Mark Pizzolato)\r | |
32 | 17-Dec-02 RMS Added sim_connect_socket, sim_create_socket\r | |
33 | 08-Oct-02 RMS Revised for .NET compatibility\r | |
34 | 22-Aug-02 RMS Changed calling sequence for sim_accept_conn\r | |
35 | 22-May-02 RMS Added OS2 EMX support from Holger Veit\r | |
36 | 06-Feb-02 RMS Added VMS support from Robert Alan Byer\r | |
37 | 16-Sep-01 RMS Added Macintosh support from Peter Schorn\r | |
38 | 02-Sep-01 RMS Fixed UNIX bugs found by Mirian Lennox and Tom Markson\r | |
39 | */\r | |
40 | \r | |
41 | #include "sim_defs.h"\r | |
42 | #include "sim_sock.h"\r | |
43 | #include <signal.h>\r | |
44 | \r | |
45 | /* OS dependent routines\r | |
46 | \r | |
47 | sim_master_sock create master socket\r | |
48 | sim_accept_conn accept connection\r | |
49 | sim_read_sock read from socket\r | |
50 | sim_write_sock write from socket\r | |
51 | sim_close_sock close socket\r | |
52 | sim_setnonblock set socket non-blocking\r | |
53 | sim_msg_sock send message to socket\r | |
54 | */\r | |
55 | \r | |
56 | int32 sim_sock_cnt = 0;\r | |
57 | \r | |
58 | /* First, all the non-implemented versions */\r | |
59 | \r | |
60 | #if defined (__OS2__) && !defined (__EMX__)\r | |
61 | \r | |
62 | SOCKET sim_master_sock (int32 port)\r | |
63 | {\r | |
64 | return INVALID_SOCKET;\r | |
65 | }\r | |
66 | \r | |
67 | SOCKET sim_connect_sock (int32 ip, int32 port)\r | |
68 | {\r | |
69 | return INVALID_SOCKET;\r | |
70 | }\r | |
71 | \r | |
72 | SOCKET sim_accept_conn (SOCKET master, uint32 *ipaddr)\r | |
73 | {\r | |
74 | return INVALID_SOCKET;\r | |
75 | }\r | |
76 | \r | |
77 | int32 sim_read_sock (SOCKET sock, char *buf, int32 nbytes)\r | |
78 | {\r | |
79 | return -1;\r | |
80 | }\r | |
81 | \r | |
82 | int32 sim_write_sock (SOCKET sock, char *msg, int32 nbytes)\r | |
83 | {\r | |
84 | return 0;\r | |
85 | }\r | |
86 | \r | |
87 | void sim_close_sock (SOCKET sock, t_bool master)\r | |
88 | {\r | |
89 | return;\r | |
90 | }\r | |
91 | \r | |
92 | SOCKET sim_setnonblock (SOCKET sock)\r | |
93 | {\r | |
94 | return SOCKET_ERROR;\r | |
95 | }\r | |
96 | \r | |
97 | #else /* endif unimpl */\r | |
98 | \r | |
99 | /* UNIX, Win32, Macintosh, VMS, OS2 (Berkeley socket) routines */\r | |
100 | \r | |
101 | SOCKET sim_err_sock (SOCKET s, char *emsg, int32 flg)\r | |
102 | {\r | |
103 | int32 err = WSAGetLastError ();\r | |
104 | \r | |
105 | printf ("Sockets: %s error %d\n", emsg, err);\r | |
106 | sim_close_sock (s, flg);\r | |
107 | return INVALID_SOCKET;\r | |
108 | }\r | |
109 | \r | |
110 | SOCKET sim_create_sock (void)\r | |
111 | {\r | |
112 | SOCKET newsock;\r | |
113 | int32 err;\r | |
114 | \r | |
115 | #if defined (_WIN32)\r | |
116 | WORD wVersionRequested; \r | |
117 | WSADATA wsaData; \r | |
118 | wVersionRequested = MAKEWORD (1, 1); \r | |
119 | \r | |
120 | if (sim_sock_cnt == 0) {\r | |
121 | err = WSAStartup (wVersionRequested, &wsaData); /* start Winsock */ \r | |
122 | if (err != 0) {\r | |
123 | printf ("Winsock: startup error %d\n", err);\r | |
124 | return INVALID_SOCKET;\r | |
125 | }\r | |
126 | }\r | |
127 | sim_sock_cnt = sim_sock_cnt + 1;\r | |
128 | #endif /* endif Win32 */\r | |
129 | #if defined (SIGPIPE)\r | |
130 | signal (SIGPIPE, SIG_IGN); /* no pipe signals */\r | |
131 | #endif\r | |
132 | \r | |
133 | newsock = socket (AF_INET, SOCK_STREAM, 0); /* create socket */\r | |
134 | if (newsock == INVALID_SOCKET) { /* socket error? */\r | |
135 | err = WSAGetLastError ();\r | |
136 | printf ("Sockets: socket error %d\n", err);\r | |
137 | return INVALID_SOCKET;\r | |
138 | }\r | |
139 | return newsock;\r | |
140 | }\r | |
141 | \r | |
142 | SOCKET sim_master_sock (int32 port)\r | |
143 | {\r | |
144 | SOCKET newsock;\r | |
145 | struct sockaddr_in name;\r | |
146 | int32 sta;\r | |
147 | \r | |
148 | newsock = sim_create_sock (); /* create socket */\r | |
149 | if (newsock == INVALID_SOCKET) return newsock; /* socket error? */\r | |
150 | \r | |
151 | name.sin_family = AF_INET; /* name socket */\r | |
152 | name.sin_port = htons ((unsigned short) port); /* insert port */\r | |
153 | name.sin_addr.s_addr = htonl (INADDR_ANY); /* insert addr */\r | |
154 | \r | |
155 | sta = bind (newsock, (struct sockaddr *) &name, sizeof (name));\r | |
156 | if (sta == SOCKET_ERROR) /* bind error? */\r | |
157 | return sim_err_sock (newsock, "bind", 1);\r | |
158 | sta = sim_setnonblock (newsock); /* set nonblocking */\r | |
159 | if (sta == SOCKET_ERROR) /* fcntl error? */\r | |
160 | return sim_err_sock (newsock, "fcntl", 1);\r | |
161 | sta = listen (newsock, 1); /* listen on socket */\r | |
162 | if (sta == SOCKET_ERROR) /* listen error? */\r | |
163 | return sim_err_sock (newsock, "listen", 1);\r | |
164 | return newsock; /* got it! */\r | |
165 | }\r | |
166 | \r | |
167 | SOCKET sim_connect_sock (int32 ip, int32 port)\r | |
168 | {\r | |
169 | SOCKET newsock;\r | |
170 | struct sockaddr_in name;\r | |
171 | int32 sta;\r | |
172 | \r | |
173 | newsock = sim_create_sock (); /* create socket */\r | |
174 | if (newsock == INVALID_SOCKET) return newsock; /* socket error? */\r | |
175 | \r | |
176 | name.sin_family = AF_INET; /* name socket */\r | |
177 | name.sin_port = htons ((unsigned short) port); /* insert port */\r | |
178 | name.sin_addr.s_addr = htonl (ip); /* insert addr */\r | |
179 | \r | |
180 | sta = sim_setnonblock (newsock); /* set nonblocking */\r | |
181 | if (sta == SOCKET_ERROR) /* fcntl error? */\r | |
182 | return sim_err_sock (newsock, "fcntl", 1);\r | |
183 | sta = connect (newsock, (struct sockaddr *) &name, sizeof (name));\r | |
184 | if ((sta == SOCKET_ERROR) && \r | |
185 | (WSAGetLastError () != WSAEWOULDBLOCK) &&\r | |
186 | (WSAGetLastError () != WSAEINPROGRESS))\r | |
187 | return sim_err_sock (newsock, "connect", 1);\r | |
188 | \r | |
189 | return newsock; /* got it! */\r | |
190 | }\r | |
191 | \r | |
192 | SOCKET sim_accept_conn (SOCKET master, uint32 *ipaddr)\r | |
193 | {\r | |
194 | int32 sta, err;\r | |
195 | #if defined (macintosh) || defined (__linux) || \\r | |
196 | defined (__APPLE__) || defined (__OpenBSD__)\r | |
197 | socklen_t size;\r | |
198 | #elif defined (_WIN32) || defined (__EMX__) ||\\r | |
199 | (defined (__ALPHA) && defined (__unix__))\r | |
200 | int size;\r | |
201 | #else \r | |
202 | size_t size; \r | |
203 | #endif\r | |
204 | SOCKET newsock;\r | |
205 | struct sockaddr_in clientname;\r | |
206 | \r | |
207 | if (master == 0) return INVALID_SOCKET; /* not attached? */\r | |
208 | size = sizeof (clientname);\r | |
209 | newsock = accept (master, (struct sockaddr *) &clientname, &size);\r | |
210 | if (newsock == INVALID_SOCKET) { /* error? */\r | |
211 | err = WSAGetLastError ();\r | |
212 | if (err != WSAEWOULDBLOCK)\r | |
213 | printf ("Sockets: accept error %d\n", err);\r | |
214 | return INVALID_SOCKET;\r | |
215 | }\r | |
216 | if (ipaddr != NULL) *ipaddr = ntohl (clientname.sin_addr.s_addr);\r | |
217 | \r | |
218 | sta = sim_setnonblock (newsock); /* set nonblocking */\r | |
219 | if (sta == SOCKET_ERROR) /* fcntl error? */\r | |
220 | return sim_err_sock (newsock, "fcntl", 0);\r | |
221 | return newsock;\r | |
222 | }\r | |
223 | \r | |
224 | int32 sim_check_conn (SOCKET sock, t_bool rd)\r | |
225 | {\r | |
226 | fd_set rw_set, er_set;\r | |
227 | fd_set *rw_p = &rw_set;\r | |
228 | fd_set *er_p = &er_set;\r | |
229 | struct timeval tz;\r | |
230 | \r | |
231 | timerclear (&tz);\r | |
232 | FD_ZERO (rw_p);\r | |
233 | FD_ZERO (er_p);\r | |
234 | FD_SET (sock, rw_p);\r | |
235 | FD_SET (sock, er_p);\r | |
236 | if (rd) select ((int) sock + 1, rw_p, NULL, er_p, &tz);\r | |
237 | else select ((int) sock + 1, NULL, rw_p, er_p, &tz);\r | |
238 | if (FD_ISSET (sock, rw_p)) return 1;\r | |
239 | if (FD_ISSET (sock, er_p)) return -1;\r | |
240 | return 0;\r | |
241 | }\r | |
242 | \r | |
243 | int32 sim_read_sock (SOCKET sock, char *buf, int32 nbytes)\r | |
244 | {\r | |
245 | int32 rbytes, err;\r | |
246 | \r | |
247 | rbytes = recv (sock, buf, nbytes, 0);\r | |
248 | if (rbytes == 0) return -1; /* disconnect */\r | |
249 | if (rbytes == SOCKET_ERROR) {\r | |
250 | err = WSAGetLastError ();\r | |
251 | if (err == WSAEWOULDBLOCK) return 0; /* no data */\r | |
252 | printf ("Sockets: read error %d\n", err);\r | |
253 | return -1;\r | |
254 | }\r | |
255 | return rbytes;\r | |
256 | }\r | |
257 | \r | |
258 | int32 sim_write_sock (SOCKET sock, char *msg, int32 nbytes)\r | |
259 | {\r | |
260 | return send (sock, msg, nbytes, 0);\r | |
261 | }\r | |
262 | \r | |
263 | void sim_close_sock (SOCKET sock, t_bool master)\r | |
264 | {\r | |
265 | #if defined (_WIN32)\r | |
266 | closesocket (sock);\r | |
267 | if (master) {\r | |
268 | sim_sock_cnt = sim_sock_cnt - 1;\r | |
269 | if (sim_sock_cnt <= 0) {\r | |
270 | WSACleanup ();\r | |
271 | sim_sock_cnt = 0;\r | |
272 | }\r | |
273 | }\r | |
274 | #else\r | |
275 | close (sock);\r | |
276 | #endif\r | |
277 | return;\r | |
278 | }\r | |
279 | \r | |
280 | #if defined (_WIN32) /* Windows */\r | |
281 | SOCKET sim_setnonblock (SOCKET sock)\r | |
282 | {\r | |
283 | unsigned long non_block = 1;\r | |
284 | \r | |
285 | return ioctlsocket (sock, FIONBIO, &non_block); /* set nonblocking */\r | |
286 | }\r | |
287 | \r | |
288 | #elif defined (VMS) /* VMS */\r | |
289 | SOCKET sim_setnonblock (SOCKET sock)\r | |
290 | {\r | |
291 | int non_block = 1;\r | |
292 | \r | |
293 | return ioctl (sock, FIONBIO, &non_block); /* set nonblocking */\r | |
294 | }\r | |
295 | \r | |
296 | #else /* Mac, Unix, OS/2 */\r | |
297 | int32 sim_setnonblock (SOCKET sock)\r | |
298 | {\r | |
299 | int32 fl, sta;\r | |
300 | \r | |
301 | fl = fcntl (sock, F_GETFL,0); /* get flags */\r | |
302 | if (fl == -1) return SOCKET_ERROR;\r | |
303 | sta = fcntl (sock, F_SETFL, fl | O_NONBLOCK); /* set nonblock */\r | |
304 | if (sta == -1) return SOCKET_ERROR;\r | |
305 | #if !defined (macintosh) && !defined (__EMX__) /* Unix only */\r | |
306 | sta = fcntl (sock, F_SETOWN, getpid()); /* set ownership */\r | |
307 | if (sta == -1) return SOCKET_ERROR;\r | |
308 | #endif\r | |
309 | return 0;\r | |
310 | }\r | |
311 | \r | |
312 | #endif /* endif !Win32 && !VMS */\r | |
313 | \r | |
314 | #endif /* end else !implemented */\r |