YAP 7.1.0
sockets.c
1/*************************************************************************
2* *
3* YAP Prolog *
4* *
5* Yap Prolog was developed at NCCUP - Universidade do Porto *
6* *
7* Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997 *
8* *
9**************************************************************************
10* *
11* File: sockets.c *
12* Last rev: 5/2/88 *
13* mods: *
14* comments: Input/Output C implemented predicates *
15* *
16*************************************************************************/
17#ifdef SCCS
18static char SccsId[] = "%W% %G%";
19#endif
20
21/*
22 * This file includes the definition of a socket related IO.
23 *
24 */
25
26#include "Yap.h"
27#include "Yatom.h"
28#include "YapHeap.h"
29#include "yapio.h"
30#include <stdlib.h>
31#if HAVE_UNISTD_H
32#include <unistd.h>
33#endif
34#if HAVE_STDARG_H
35#include <stdarg.h>
36#endif
37#ifdef _WIN32
38#if HAVE_IO_H
39/* Windows */
40#include <io.h>
41#endif
42#if HAVE_SOCKET
43#include <winsock2.h>
44#endif
45#include <windows.h>
46#ifndef S_ISDIR
47#define S_ISDIR(x) (((x)&_S_IFDIR)==_S_IFDIR)
48#endif
49#endif
50#include "iopreds.h"
51
52#if HAVE_SOCKET
53static int SocketPutc( int, int);
54static int ConsoleSocketPutc( int, int);
55static int SocketGetc( int);
56static int ConsoleSocketGetc( int);
57
58void
59Yap_SocketOps( StreamDesc *st )
60{
61 st->stream_putc = SocketPutc;
62 st->stream_getc = SocketGetc;
63}
64
65void
66Yap_ConsoleSocketOps( StreamDesc *st )
67{
68 st->stream_putc = ConsoleSocketPutc;
69 st->stream_getc = ConsoleSocketGetc;
70}
71
72void
73Yap_socketStream( StreamDesc *s )
74{
75 CACHE_REGS
76 if (LOCAL_sockets_io &&
77 s->file == NULL)
78 {
79 s->status |= Socket_Stream_f;
80 s->u.socket.domain = af_inet;
81 s->u.socket.flags = client_socket;
82 s->u.socket.fd = 0;
83 return;
84 }
85}
86
87/*
88 sockets cannot use standard FILE *, we have to go through fds, and in the
89 case of VC++, we have to use the receive routines...
90*/
91static int
92SocketGetc(int sno)
93{
94 register StreamDesc *s = &GLOBAL_Stream[sno];
95 register Int ch;
96 char c;
97 int count;
98 /* should be able to use a buffer */
99#if _MSC_VER || defined(__MINGW32__)
100 count = recv(s->u.socket.fd, &c, sizeof(char), 0);
101#else
102 count = read(s->u.socket.fd, &c, sizeof(char));
103#endif
104 if (count == 0) {
105 s->u.socket.flags = closed_socket;
106 return EOF;
107 } else if (count > 0) {
108 ch = c;
109 } else {
110#if HAVE_STRERROR
111 Yap_Error(SYSTEM_ERROR_INTERNAL, TermNil,
112 "( socket_getc: %s)", strerror(errno));
113#else
114 Yap_Error(SYSTEM_ERROR_INTERNAL, TermNil,
115 "(socket_getc)");
116#endif
117 return EOF;
118 }
119 return ch;
120}
121
122/*
123 Basically, the same as console but also sends a prompt and takes care of
124 finding out whether we are at the start of a newline.
125*/
126static int
127ConsoleSocketGetc(int sno)
128{
129 CACHE_REGS
130 register StreamDesc *s = &GLOBAL_Stream[sno];
131 int ch;
132 Int c;
133 int count;
134
135 /* send the prompt away */
136 if (LOCAL_newline) {
137 char *cptr = LOCAL_Prompt, ch;
138 /* use the default routine */
139 while ((ch = *cptr++) != '\0') {
140 GLOBAL_Stream[StdErrStream].stream_putc(StdErrStream, ch);
141 }
142 strncpy(LOCAL_Prompt, RepAtom (LOCAL_AtPrompt)->StrOfAE, MAX_PROMPT);
143 LOCAL_newline = FALSE;
144 }
145 /* should be able to use a buffer */
146 LOCAL_PrologMode |= ConsoleGetcMode;
147#if _MSC_VER || defined(__MINGW32__)
148 count = recv(s->u.socket.fd, (void *)&c, sizeof(char), 0);
149#else
150 count = read(s->u.socket.fd, &c, sizeof(char));
151#endif
152 LOCAL_PrologMode &= ~ConsoleGetcMode;
153 if (count == 0) {
154 return console_post_process_eof(s);
155 } else if (count > 0) {
156 ch = c;
157 } else {
158 Yap_Error(SYSTEM_ERROR_INTERNAL, TermNil, "read");
159 return console_post_process_eof(s);
160 }
161 return ch;
162}
163
164/* static */
165static int
166ConsoleSocketPutc (int sno, int ch)
167{
168 StreamDesc *s = &GLOBAL_Stream[sno];
169 char c = ch;
170#if MAC || _MSC_VER
171 if (ch == 10)
172 {
173 ch = '\n';
174 }
175#endif
176#if _MSC_VER || defined(__MINGW32__)
177 send(s->u.socket.fd, &c, sizeof(c), 0);
178#else
179 if (write(s->u.socket.fd, &c, sizeof(c)) < 0) {
180#if HAVE_STRERROR
181 Yap_Error(SYSTEM_ERROR_FATAL, TermNil, "no access to console: %s", strerror(errno));
182#else
183 Yap_Error(SYSTEM_ERROR_FATAL, TermNil, "no access to console");
184#endif
185 }
186#endif
187 count_output_char(ch,s);
188 return ((int) ch);
189}
190
191static int
192SocketPutc (int sno, int ch)
193{
194 StreamDesc *s = &GLOBAL_Stream[sno];
195 char c = ch;
196#if MAC || _MSC_VER
197 if (ch == 10)
198 {
199 ch = '\n';
200 }
201#endif
202#if _MSC_VER || defined(__MINGW32__)
203 send(s->u.socket.fd, &c, sizeof(c), 0);
204#else
205 {
206 int out = 0;
207 while (!out) {
208 out = write(s->u.socket.fd, &c, sizeof(c));
209 if (out <0) {
210#if HAVE_STRERROR
211 Yap_Error(PERMISSION_ERROR_INPUT_STREAM, TermNil, "error writing stream socket: %s", strerror(errno));
212#else
213 Yap_Error(PERMISSION_ERROR_INPUT_STREAM, TermNil, "error writing stream socket");
214#endif
215 }
216 }
217 }
218#endif
219 return (int) ch;
220}
221
222
223/* given a socket file descriptor, get the corresponding stream descripor */
224int
225Yap_CheckIOStream(Term stream, char * error)
226{
227 int sno = Yap_CheckStream(stream, Input_Stream_f|Output_Stream_f|Socket_Stream_f, error);
228 UNLOCK(GLOBAL_Stream[sno].streamlock);
229 return(sno);
230}
231
232Term
233Yap_InitSocketStream(int fd, socket_info flags, socket_domain domain) {
234 StreamDesc *st;
235 int sno;
236
237 sno = GetFreeStreamD();
238 if (sno < 0) {
239 PlIOError (SYSTEM_ERROR_INTERNAL,TermNil, "new stream not available for socket/4");
240 return(TermNil);
241 }
242 st = &GLOBAL_Stream[sno];
243 st->u.socket.domain = domain;
244 st->u.socket.flags = flags;
245 st->vfs = NULL;
246 if (flags & (client_socket|server_session_socket)) {
247 /* I can read and write from these sockets */
248 st->status = (Socket_Stream_f|Input_Stream_f|Output_Stream_f);
249 } else {
250 /* oops, I cannot */
251 st->status = Socket_Stream_f;
252 }
253 st->u.socket.fd = fd;
254 // use dup and have two streams?
255 st->file = fdopen( fd, "rw");
256 st->charcount = 0;
257 st->linecount = 1;
258 st->linestart = 0;
259 st->vfs = NULL;
260 st->buf.on = false;
261 st->stream_putc = SocketPutc;
262 st->stream_getc = SocketGetc;
263 Yap_DefaultStreamOps( st );
264 UNLOCK(st->streamlock);
265 return(Yap_MkStream(sno));
266}
267
268/* given a socket file descriptor, get the corresponding stream descripor */
269int
270Yap_CheckSocketStream(Term stream, const char * error)
271{
272 int sno = Yap_CheckStream(stream, Socket_Stream_f, error);
273 UNLOCK(GLOBAL_Stream[sno].streamlock);
274 return sno;
275}
276
277/* given a stream index, get the corresponding domain */
278socket_domain
279Yap_GetSocketDomain(int sno)
280{
281 return(GLOBAL_Stream[sno].u.socket.domain);
282}
283
284/* given a stream index, get the corresponding status */
285socket_info
286Yap_GetSocketStatus(int sno)
287{
288 return(GLOBAL_Stream[sno].u.socket.flags);
289}
290
291/* update info on a socket, eg, new->server or new->client */
292void
293Yap_UpdateSocketStream(int sno, socket_info flags, socket_domain domain) {
294 StreamDesc *st;
295
296 st = &GLOBAL_Stream[sno];
297 st->u.socket.domain = domain;
298 st->u.socket.flags = flags;
299 if (flags & (client_socket|server_session_socket)) {
300 /* I can read and write from these sockets */
301 st->status = (Socket_Stream_f|Input_Stream_f|Output_Stream_f);
302 } else {
303 /* oops, I cannot */
304 st->status = Socket_Stream_f;
305 }
306}
307
308
309void
310Yap_InitSockets( void )
311{
312 Yap_InitSocketLayer( );
313}
314
315
316#endif
Main definitions.
int(* stream_getc)(int)
function the stream uses for writing a character
Definition: YapStreams.h:256
struct vfs * vfs
function the stream uses for reading a character
Definition: YapStreams.h:259