OpenCores
URL https://opencores.org/ocsvn/openrisc_2011-10-31/openrisc_2011-10-31/trunk

Subversion Repositories openrisc_2011-10-31

[/] [openrisc/] [trunk/] [or1ksim/] [peripheral/] [channels/] [tcp.c] - Blame information for rev 509

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 19 jeremybenn
/* tcp.c -- Definition of functions for peripheral to
2
 * communicate with host via a tcp socket.
3
 
4
   Copyright (C) 2002 Richard Prescott <rip@step.polymtl.ca>
5
   Copyright (C) 2008 Embecosm Limited
6
 
7
   Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
8
 
9
   This file is part of Or1ksim, the OpenRISC 1000 Architectural Simulator.
10
 
11
   This program is free software; you can redistribute it and/or modify it
12
   under the terms of the GNU General Public License as published by the Free
13
   Software Foundation; either version 3 of the License, or (at your option)
14
   any later version.
15
 
16
   This program is distributed in the hope that it will be useful, but WITHOUT
17
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
19
   more details.
20
 
21
   You should have received a copy of the GNU General Public License along
22
   with this program.  If not, see <http://www.gnu.org/licenses/>.  */
23
 
24
/* This program is commented throughout in a fashion suitable for processing
25
   with Doxygen. */
26
 
27
 
28
/* Autoconf and/or portability configuration */
29
#include "config.h"
30
#include "port.h"
31
 
32
/* System includes */
33
#include <stdlib.h>
34
#include <unistd.h>
35
#include <stdio.h>
36
#include <sys/types.h>
37
#include <sys/socket.h>
38
#include <netinet/in.h>
39
#include <fcntl.h>
40
#include <errno.h>
41
 
42
/* Package includes */
43
#include "channel.h"
44
#include "generic.h"
45
#include "fd.h"
46
 
47
/*! Structure to represent a TCP/IP channel */
48
struct tcp_channel
49
{
50
  struct fd_channel fds;
51
  int               socket_fd;    /* Socket to listen to */
52
  int               port_number;  /* TCP port number */
53
  int               connected;    /* If 0, no remote endpoint yet */
54
  int               nonblocking;  /* If 0, read/write will block until
55
                                     remote client connects */
56
};
57
 
58
/* Forward declarations of static functions */
59
static void *tcp_init (const char *input);
60
static int   tcp_open (void *data);
61
static int   tcp_read (void *data,
62
                       char *buffer,
63
                       int   size);
64
static int   tcp_write (void       *data,
65
                        const char *buffer,
66
                        int         size);
67
 
68
/*! Data structure holding all the operations for a TCP/IP channel */
69
struct channel_ops  tcp_channel_ops = {
70
        .init  = tcp_init,
71
        .open  = tcp_open,
72
        .close = generic_close,
73
        .read  = tcp_read,
74
        .write = tcp_write,
75
        .free  = generic_free,
76
};
77
 
78
static void *
79
tcp_init (const char *input)
80
{
81
  int port_number, fd, flags;
82
  struct sockaddr_in local_ip;
83
  struct tcp_channel *channel =
84
    (struct tcp_channel *) malloc (sizeof (struct tcp_channel));
85
  if (!channel)
86
    return NULL;
87
 
88
  fd = 0;
89
  channel->nonblocking = 1;
90
  channel->fds.fdin = -1;
91
  channel->fds.fdout = -1;
92
  channel->socket_fd = -1;
93
  channel->port_number = -1;
94
 
95
  port_number = atoi (input);
96
  if (port_number == 0)
97
    goto error;
98
 
99
  fd = socket (AF_INET, SOCK_STREAM, 0);
100
  if (fd < 0)
101
    goto error;
102
 
103
  flags = 1;
104
  if (setsockopt
105
      (fd, SOL_SOCKET, SO_REUSEADDR, (const char *) &flags, sizeof (int)) < 0)
106
    {
107
      perror ("Can not set SO_REUSEADDR option on channel socket");
108
      goto error;
109
    }
110
 
111
  memset (&local_ip, 0, sizeof (local_ip));
112
  local_ip.sin_family = AF_INET;
113
  local_ip.sin_addr.s_addr = htonl (INADDR_ANY);
114
  local_ip.sin_port = htons (port_number);
115
  if (bind (fd, (struct sockaddr *) &local_ip, sizeof (local_ip)) < 0)
116
    {
117
      perror ("Can't bind local address");
118
      goto error;
119
    }
120
 
121
  if (channel->nonblocking)
122
    {
123
      if (fcntl (fd, F_SETFL, O_NONBLOCK) < 0)
124
        {
125
          perror ("Can not make channel socket non-blocking");
126
          goto error;
127
        }
128
    }
129
 
130
  if (listen (fd, 1) < 0)
131
    goto error;
132
 
133
  channel->socket_fd = fd;
134
  channel->port_number = port_number;
135
  channel->connected = 0;
136
  return (void *) channel;
137
 
138
error:
139
  if (fd)
140
    close (fd);
141
  free (channel);
142
  return NULL;
143
}
144
 
145
static int
146
tcp_open (void *data)
147
{
148
  /* Socket is opened lazily, upon first read or write, so do nothing here */
149
  return 0;
150
}
151
 
152
 
153
static int
154
wait_for_tcp_connect (struct tcp_channel *channel)
155
{
156
  int fd;
157
  socklen_t sizeof_remote_ip;
158
  struct sockaddr_in remote_ip;
159
 
160
  sizeof_remote_ip = sizeof (remote_ip);
161
  fd =
162
    accept (channel->socket_fd, (struct sockaddr *) &remote_ip,
163
            &sizeof_remote_ip);
164
  if (fd < 0)
165
    {
166
      if (channel->nonblocking)
167
        {
168
          /* Not an error if there is not yet a remote connection - try again later */
169
          if (errno == EAGAIN)
170
            return 0;
171
        }
172
      perror ("Couldn't accept connection");
173
      return -1;
174
    }
175
 
176
  channel->fds.fdin = channel->fds.fdout = fd;
177
  close (channel->socket_fd);
178
  channel->socket_fd = -1;
179
  channel->connected = 1;
180
  return 1;
181
}
182
 
183
static int
184
tcp_read (void *data, char *buffer, int size)
185
{
186
  struct tcp_channel *channel = data;
187
 
188
  /* Lazily connect to tcp partner on read/write */
189
  if (!channel->connected)
190
    {
191
      int retval = wait_for_tcp_connect (data);
192
      if (retval <= 0)
193
        return retval;
194
    }
195
  return fd_read (data, buffer, size);
196
}
197
 
198
static int
199
tcp_write (void *data, const char *buffer, int size)
200
{
201
  struct tcp_channel *channel = data;
202
 
203
  /* Lazily connect to tcp partner on read/write */
204
  if (!channel->connected)
205
    {
206
      int retval = wait_for_tcp_connect (data);
207
      if (retval < 0)
208
        return retval;
209
    }
210
  return fd_write (data, buffer, size);
211
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.