socket.c
5.32 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
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
/***************************************************************************
*
* socket.c: some basic berkley socket stuff....far from beeing complete
*
* Copyright (C) 2009 Georg Steffers <georg@steffers.org>
* This file is part of gameserver
*
* gameserver is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Author: Georg Steffers (gst), georg@steffers.org
*
* Version: 0.0
* Created: 16.08.2009 19:59:33
* Revision: none
*
***************************************************************************/
#define USE_STRUCT_SCOT_SOCKET // set for include behaviour
/* #### HEADER FILE INCLUDES ######################################### */
#include <string.h>
#include <scot/exception.h>
#include <scot/memory.h>
#include <scot/stream.h>
#include <scot/socket.h>
#include <scot/socket_in.h>
#ifndef WIN32
# include <scot/socket_un.h>
#endif /* WIN32 */
#include <scot_common.h>
/* #### MACROS - LOCAL TO THIS SOURCE FILE ######################### */
#define SCOT_SOCKET_NEW_FAIL 0
#define SCOT_SOCKET_LISTEN_FAIL 1
#define SCOT_SOCKET_ACCEPT_FAIL 2
#define SCOT_SOCKET_CONNECT_FAIL 3
#define SCOT_SOCKET_NO_VALID_HOST 4
#define SCOT_SOCKET_AF_NOT_IMPLEMENTED 5
/* #### VARIABLES - LOCAL TO THIS SOURCE FILE ###################### */
const char * scot_socket_errmsg[] =
{
"[SOCKET]failed to create new socket",
"[SOCKET]failed to listen on port specified with socket",
"[SOCKET]failed to accept connections on socket",
"[SOCKET]failed to connect with socket",
"[SOCKET]invalid hostname",
"[SOCKET]address family not implemented"
};
const char * scot_socket_wrnmsg[] =
{
"[SOCKET]there was already an existent socket file.\n"
" i removed that file to let the new instance of the program\n"
" work, but notice that there might be another instance of this\n"
" program running, that is unusable hence now."
};
/* #### FUNCTION DEFINITIONS - EXPORTED FUNCTIONS ################## */
void
scot_socket_init (uint16_t major, uint16_t minor)
{
#ifdef WIN32
WORD version = MAKEWORD (major,minor);
WSADATA wsa_data;
WSAStartup (version, &wsa_data);
#endif
}
void
scot_socket_fini (void)
{
int a;
#ifdef WIN32
WSACleanup ();
#endif
}
/*
* actualy i found no good reason to bind a socken if one
* dont wants to listen to it too. If i find one i will change this.
*/
void
scot_socket_listen (const struct scot_socket* s)
{
excenv_t *ee;
TRY
{
if (bind (s->socket.handle.sock, s->sa, s->addr_len) == -1)
THROW (EXC (EXC_ERROR, SCOT_ERRNO, strerror (SCOT_ERRNO)));
if (listen (s->socket.handle.sock, SCOT_SOCKET_BACKLOG) == -1)
THROW (EXC (EXC_ERROR, SCOT_ERRNO, strerror (SCOT_ERRNO)));
}
CATCH (ee)
{
/*
* if we got an Address already in use error on a unix domain
* socket it is most likely because there is a stale socket file
* around. Then we can try to unlink it and retry the listen.
*/
exception_t * e;
while (e = retrive_exception (ee))
{
#ifndef WIN32
if (exc_errnum_get (e) == EADDRINUSE && s->sa->sa_family == AF_UNIX)
{
if (unlink (((struct sockaddr_un *) s->sa)->sun_path) == -1)
{
THROW (e);
THROW (EXC (EXC_ERROR,
SCOT_SOCKET_LISTEN_FAIL,
scot_socket_errmsg [SCOT_SOCKET_LISTEN_FAIL]));
}
else
{
THROW (EXC (EXC_WARNING,
SCOT_SOCKET_UN_FILE_EXISTS,
scot_socket_wrnmsg [SCOT_SOCKET_UN_FILE_EXISTS]));
free_exception (e);
scot_socket_listen (s);
}
}
else
#endif
{
THROW (e);
THROW (EXC (EXC_ERROR,
SCOT_SOCKET_LISTEN_FAIL,
scot_socket_errmsg [SCOT_SOCKET_LISTEN_FAIL]));
}
}
free_catched (ee);
}
}
struct scot_socket *
scot_socket_accept (const struct scot_socket* s)
{
switch (s->sa->sa_family)
{
#ifndef WIN32
case AF_UNIX: return scot_socket_un_accept (s);
#endif /* WIN32 */
case AF_INET: return scot_socket_in_accept (s);
}
}
void
scot_socket_connect (const struct scot_socket * s, const char * adr)
{
excenv_t * ee;
TRY
{
switch (s->sa->sa_family)
{
#ifndef WIN32
case AF_UNIX:
scot_socket_un_prep_con (s, adr); break;
#endif /* WIN32 */
case AF_INET:
scot_socket_in_prep_con (s, adr); break;
default:
THROW (EXC (EXC_ERROR,
SCOT_SOCKET_AF_NOT_IMPLEMENTED,
scot_socket_errmsg [SCOT_SOCKET_AF_NOT_IMPLEMENTED]));
}
if ((connect (s->socket.handle.sock, s->sa, s->addr_len)) == -1)
THROW (EXC (EXC_ERROR, SCOT_ERRNO, strerror (SCOT_ERRNO)));
}
CATCH (ee)
{
forward_all_exceptions (ee);
THROW (EXC (EXC_ERROR,
SCOT_SOCKET_CONNECT_FAIL,
scot_socket_errmsg [SCOT_SOCKET_CONNECT_FAIL]));
}
}
void
scot_socket_free (struct scot_socket * s)
{
if (s)
{
if (s->sa)
SCOT_MEM_FREE (s->sa);
SCOT_SOCK_CLOSE (s->socket.handle.sock);
SCOT_MEM_FREE (s);
}
}