source: abuse/branches/pd/macabuse/imlib/port/unix/jnet.c @ 636

Last change on this file since 636 was 49, checked in by Sam Hocevar, 15 years ago
  • Imported original public domain release, for future reference.
  • Property svn:keywords set to Id
File size: 6.4 KB
Line 
1#include <stdio.h>
2#include <stdlib.h>
3#include <fcntl.h>
4#include <unistd.h>
5#include <sys/ioctl.h>
6#include <sys/stat.h>
7#include <sys/types.h>
8#include <sys/time.h>
9#include <string.h>
10#include <signal.h>
11#include <netinet/in.h>
12#include <sys/socket.h>
13
14#ifdef __sgi
15#include <bstring.h>
16#endif
17
18#ifdef _AIX
19#include <sys/select.h>
20#include <strings.h>
21extern "C" {
22#endif
23#include <netdb.h>
24
25#ifdef _AIX
26} ;
27#endif
28
29#include "jnet.hpp"
30#include "macs.hpp"
31#include "jmalloc.hpp"
32
33int net_init(int protocol)
34{
35  if (protocol==TCPIP_PROTOCOL)    // UNIX always has TCPIP!
36    return 1;
37  else return 0;
38}
39
40
41out_socket::~out_socket()
42{ ; }
43
44void net_uninit() { ; }
45
46char last_sock_err[200];
47int current_sock_err=0;
48
49void set_sock_err(int x) { current_sock_err=x; }
50
51
52#define PK_BUFFER_SIZE 2000
53
54
55
56class unix_out_socket : public out_socket
57{
58  int fd;
59  int type;      // SOCK_DGRAM, or SOCK_STREAM
60  public :
61  uchar pk_buffer[PK_BUFFER_SIZE];
62  long pk_buffer_ro,pk_buffer_last;
63  unix_out_socket(int FD) { fd=FD; pk_buffer_ro=pk_buffer_last=0; }
64  unix_out_socket();
65  void fill_buffer();
66  int get_fd() { return fd; }
67  virtual int try_connect(char *rhost, int port);
68  virtual int ready_to_read();
69  virtual int ready_to_write();
70  virtual int send(packet &pk);
71  virtual int get(packet &pk);
72  virtual ~unix_out_socket();
73} ;
74
75
76class unix_in_socket : public in_socket
77{
78  int fd;
79  sockaddr_in host;
80  int port;
81  public :
82  unix_in_socket(int Port);
83  virtual out_socket *check_for_connect();
84  virtual ~unix_in_socket();
85} ;
86
87
88int unix_out_socket::ready_to_read()
89{
90  if (pk_buffer_last>pk_buffer_ro) return 1;
91  struct timeval tv={0,0};
92  fd_set set,ex_set;
93  FD_ZERO(&set);
94  FD_SET(fd,&set);
95
96  FD_ZERO(&ex_set);
97  FD_SET(fd,&ex_set);
98  select(FD_SETSIZE,&set,NULL,&ex_set,&tv);                // check for exception
99  return (FD_ISSET(fd,&set) || FD_ISSET(fd,&ex_set));
100}
101
102int unix_out_socket::ready_to_write()
103{
104  struct timeval tv={0,0};
105  fd_set set,ex_set;
106  FD_ZERO(&set);
107  FD_SET(fd,&set);
108  select(FD_SETSIZE,NULL,&set,NULL,&tv);                // check for exception
109  return (FD_ISSET(fd,&set));
110}
111
112unix_in_socket::unix_in_socket(int Port)
113{
114  port=Port;
115  fd=socket(AF_INET,SOCK_STREAM,0);
116  memset( (char*) &host,0, sizeof(host));
117  host.sin_family = AF_INET;
118  host.sin_port = htons(port);
119  host.sin_addr.s_addr = htonl (INADDR_ANY);
120  if (bind(fd, (struct sockaddr *) &host, sizeof(sockaddr_in))==-1)
121  {
122    set_sock_err(SOCK_BIND_FAIL);
123    sprintf(last_sock_err,"Unable to bind to port %d",port);
124  }
125  else
126  {
127    if (listen(fd,1)==-1)
128    {
129      set_sock_err(SOCK_LISTEN_FAIL);
130      sprintf(last_sock_err,"Unable to listen to port %d",port);     
131    }
132  }
133
134}
135
136
137out_socket *unix_in_socket::check_for_connect()
138{
139  struct timeval tv={0,0};
140  fd_set set,ex_set;
141  FD_ZERO(&set);
142  FD_SET(fd,&set);
143
144
145  select(FD_SETSIZE,&set,NULL,NULL,&tv);                // check for exception
146
147  if (FD_ISSET(fd,&set))
148  {
149    int len=sizeof(sockaddr_in);
150    int new_fd=accept(fd, (struct sockaddr *) &host, &len);
151    if (new_fd<0)
152    {
153      set_sock_err(SOCK_ACCEPT_FAIL);
154      sprintf(last_sock_err,"Accept failure on port %d",port);     
155      return NULL;
156    }
157
158    unsigned long gaddr=ntohl(host.sin_addr.s_addr);
159    return new unix_out_socket(new_fd);
160  } else return NULL;
161}
162 
163
164unix_out_socket::unix_out_socket()
165{
166  pk_buffer_ro=pk_buffer_last=0;
167  fd=-1;
168}
169   
170
171int unix_out_socket::try_connect(char *rhost, int port)
172{
173  if (strlen(rhost)>5 &&
174      rhost[0]=='t' &&
175      rhost[1]=='c' &&
176      rhost[2]=='p' &&
177      rhost[1]=='/')
178    type=SOCK_STREAM;
179  else type=SOCK_DGRAM;
180
181  if (fd==-1)
182    fd=socket(AF_INET,type,0);
183  if (fd==-1)
184  {
185    set_sock_err(SOCK_CREATE_FAIL);
186    sprintf(last_sock_err,"Failed to create socket (too many file descriptors open?)");
187    return 0;
188  }
189
190  hostent *hp=gethostbyname(rhost);
191  if (!rhost)
192  {
193    set_sock_err(SOCK_NAMELOOKUP_FAIL);
194    sprintf(last_sock_err,"Unable to get address for name %s",rhost);     
195    return 0;
196  } else
197  {
198    sockaddr_in host;
199    memset( (char*) &host,0, sizeof(host));
200    host.sin_family = AF_INET;
201    host.sin_port = htons(port);
202    host.sin_addr.s_addr = htonl (INADDR_ANY);
203    memcpy(&host.sin_addr,hp->h_addr,hp->h_length);
204   
205    if (connect(fd, (struct sockaddr *) &host, sizeof(host))==-1)
206    {
207      set_sock_err(SOCK_CONNECT_FAIL);
208      sprintf(last_sock_err,"Unable to connect to address %s on port %d",rhost,port);
209      return 0;
210    }
211
212    return 1;
213  }
214}
215
216
217
218unix_out_socket::~unix_out_socket()
219{  close(fd); }
220
221unix_in_socket::~unix_in_socket()
222{  close(fd);  }
223
224
225void unix_out_socket::fill_buffer()
226{
227  while (!ready_to_read()) ;
228  pk_buffer_last=read(get_fd(),pk_buffer,PK_BUFFER_SIZE);
229  pk_buffer_ro=0;
230}
231
232int unix_out_socket::get(packet &pk)
233{
234  pk.ro=pk.wo=2;
235
236  ushort size=0;
237  if (pk_buffer_last==pk_buffer_ro)
238    fill_buffer();
239
240  if (pk_buffer_last-pk_buffer_ro<2)  // make sure the two byte for the size are in the same packet
241  {
242    uchar two[2];
243    two[0]=pk_buffer[pk_buffer_ro];
244    fill_buffer();
245    if (pk_buffer_last-pk_buffer_ro<2)  // if still not enough info, something is screwy
246    {
247      printf("Incomplete packet\n");
248      return 0;
249    }
250
251    two[1]=pk_buffer[pk_buffer_ro];
252    pk_buffer_ro++;
253    size=lstl((*((ushort *)two)));
254  } else
255  {
256    memcpy(&size,pk_buffer+pk_buffer_ro,2); pk_buffer_ro+=2;
257    size=lstl(size);
258  }
259  pk.rend=size+2;
260  pk.make_bigger(pk.rend);
261
262  uchar *pk_off=pk.buf+2;
263  int rs;
264  while (size)
265  {
266    if (pk_buffer_last==pk_buffer_ro)
267      fill_buffer();   
268    if (pk_buffer_last-pk_buffer_ro>size)
269      rs=size;
270    else
271      rs=pk_buffer_last-pk_buffer_ro;
272   
273    memcpy(pk_off,pk_buffer+pk_buffer_ro,rs);
274    pk_buffer_ro+=rs;
275    size-=rs;
276    pk_off+=rs;         
277  }
278 
279  return 1;
280}
281
282int unix_out_socket::send(packet &pk)
283
284  while (!ready_to_write()) ;
285  ushort size=lstl(pk.wo-2);
286  memcpy(pk.buf,&size,2);
287  return write(fd,pk.buf,pk.wo)==pk.wo;
288}
289
290in_socket *create_in_socket(int port)
291{ return new unix_in_socket(port); }
292
293out_socket *create_out_socket(char *name, int port)
294{ unix_out_socket *s=new unix_out_socket();
295  if (s->try_connect(name,port))
296    return s;
297  else   
298    delete s;
299  return NULL;
300}
301
302uchar *get_local_address()                             // same format as above (be sure to jfree this)
303{
304  char name[80];
305  uchar *ip=(uchar *)jmalloc(4,"IP address");
306
307  if (gethostname(name,80)!=0)
308  { ip[0]=127; ip[1]=ip[2]=0; ip[3]=1; }
309  else
310  {
311    struct hostent *me=gethostbyname(name);
312    memcpy(ip,me->h_addr,4);
313  }
314}
315
316
317
318
319
320
321
322
323
Note: See TracBrowser for help on using the repository browser.