summaryrefslogtreecommitdiffstats
path: root/src/osd/sdl/sdlsocket.c
blob: e7e294a92c54e33ff044fa485db3d0c55a4b51e8 (plain) (blame)
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
//============================================================
//
//  sdlsocket.c - SDL socket (inet) access functions
//
//  Copyright (c) 1996-2013, Nicola Salmoria and the MAME Team.
//  Visit http://mamedev.org for licensing and usage restrictions.
//
//  SDLMAME by Olivier Galibert and R. Belmont
//
//============================================================

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#ifndef SDLMAME_WIN32
#include <sys/select.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#endif
#include <errno.h>

#define NO_MEM_TRACKING
#include "emu.h"
#include "sdlfile.h"

const char *sdlfile_socket_identifier  = "socket.";

/*
    Checks whether the path is a socket specification. A valid socket
    specification has the format "socket." host ":" port. Host may be simple
    or fully qualified. Port must be between 1 and 65535.
*/
bool sdl_check_socket_path(const char *path)
{
#ifndef SDLMAME_WIN32
	if (strlen(sdlfile_socket_identifier) > 0 &&
		strncmp(path, sdlfile_socket_identifier, strlen(sdlfile_socket_identifier)) == 0 &&
		strchr(path, ':') != NULL) return true;
#endif
	return false;
}

file_error sdl_open_socket(const char *path, UINT32 openflags, osd_file **file, UINT64 *filesize)
{
#ifndef SDLMAME_WIN32
	char hostname[256];
	struct hostent *localhost;
	struct sockaddr_in sai;
	int flag = 1;
	int port;

	sscanf( path+strlen(sdlfile_socket_identifier), "%255[^:]:%d", hostname, &port );

//  printf("Connecting to server '%s' on port '%d'\n", hostname, port);

	if (((*file)->socket = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	{
		return FILERR_ACCESS_DENIED;
	}

	if (setsockopt((*file)->socket, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag)) == -1)
	{
		return FILERR_ACCESS_DENIED;
	}

	localhost = gethostbyname(hostname);

	memset(&sai, 0, sizeof(sai));
	sai.sin_family = AF_INET;
	sai.sin_port = htons(port);
	sai.sin_addr = *((struct in_addr *)localhost->h_addr);

	// listening socket support
	if (openflags & OPEN_FLAG_CREATE)
	{
//      printf("Listening for client at '%s' on port '%d'\n", hostname, port);
		// bind socket...
		if (bind((*file)->socket, (struct sockaddr *)&sai, sizeof(struct sockaddr)) == -1)
		{
			return FILERR_ACCESS_DENIED;
		}

		// start to listen...
		if (listen((*file)->socket, 1) == -1) {
			return FILERR_ACCESS_DENIED;
		}

		// mark socket as "listening"
		(*file)->handle = 0;
		*filesize = 0;
		return FILERR_NONE;
	}

//  printf("Connecting to server '%s' on port '%d'\n", hostname, port);
	if (connect((*file)->socket, (struct sockaddr *)&sai, sizeof(struct sockaddr)) == -1)
	{
		return FILERR_ACCESS_DENIED;
	}

	*filesize = 0;
	(*file)->handle = -1;
#endif
	return FILERR_NONE;
}

file_error sdl_read_socket(osd_file *file, void *buffer, UINT64 offset, UINT32 count, UINT32 *actual)
{
#ifndef SDLMAME_WIN32
	ssize_t result;
	char line[80];
	struct timeval timeout;
	fd_set readfds;

	FD_ZERO(&readfds);
	FD_SET(file->socket, &readfds);
	timeout.tv_sec = timeout.tv_usec = 0;

	if (select(file->socket + 1, &readfds, NULL, NULL, &timeout) < 0)
	{
		sprintf(line, "%s : %s : %d ", __func__, __FILE__,  __LINE__);
		perror(line);
		return error_to_file_error(errno);
	}
	else if (FD_ISSET(file->socket, &readfds))
	{
		if (file->handle == -1)
		{
			// connected socket
			result = read(file->socket, buffer, count);
		}
		else
		{
			// listening socket
			int AcceptSocket;
			AcceptSocket = accept(file->socket, NULL, NULL);
			if (AcceptSocket < 0)
			{
				return FILERR_FAILURE;
			}
			close(file->socket);
			file->socket = AcceptSocket;
			file->handle = -1;
			if (actual != NULL )
			{
				*actual = 0;
			}

			return FILERR_NONE;
		}
	}
	else
	{
		return FILERR_FAILURE;
	}

	if (result < 0)
	{
		return error_to_file_error(errno);
	}

	if (actual != NULL )
	{
		*actual = result;
	}
#endif
	return FILERR_NONE;
}

file_error sdl_write_socket(osd_file *file, const void *buffer, UINT64 offset, UINT32 count, UINT32 *actual)
{
#ifndef SDLMAME_WIN32
	ssize_t result;

	result = write(file->socket, buffer, count);

	if (result < 0)
	{
		return error_to_file_error(errno);
	}

	if (actual != NULL )
	{
		*actual = result;
	}
#endif
	return FILERR_NONE;
}

file_error sdl_close_socket(osd_file *file)
{
#ifndef SDLMAME_WIN32
	close(file->socket);
	osd_free(file);
#endif
	return FILERR_NONE;
}