PageRenderTime 41ms CodeModel.GetById 2ms app.highlight 35ms RepoModel.GetById 1ms app.codeStats 0ms

/elements/userlevel/socket.cc

https://github.com/bhesmans/click
C++ | 543 lines | 416 code | 68 blank | 59 comment | 170 complexity | 036a4a8dbb62817a30c4b2da7d889e62 MD5 | raw file
  1// -*- mode: c++; c-basic-offset: 2 -*-
  2/*
  3 * socket.{cc,hh} -- transports packets via sockets
  4 * Mark Huang <mlhuang@cs.princeton.edu>
  5 *
  6 * Copyright (c) 2004  The Trustees of Princeton University (Trustees).
  7 * Copyright (c) 2006-2007 Regents of the University of California
  8 *
  9 * Permission is hereby granted, free of charge, to any person obtaining a
 10 * copy of this software and associated documentation files (the "Software"),
 11 * to deal in the Software without restriction, subject to the conditions
 12 * listed in the Click LICENSE file. These conditions include: you must
 13 * preserve this copyright notice, and you cannot mention the copyright
 14 * holders in advertising related to the Software without their permission.
 15 * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
 16 * notice is a summary of the Click LICENSE file; the license in that file is
 17 * legally binding.
 18 */
 19
 20#include <click/config.h>
 21#include <click/error.hh>
 22#include <click/args.hh>
 23#include <click/glue.hh>
 24#include <click/standard/scheduleinfo.hh>
 25#include <click/packet_anno.hh>
 26#include <click/packet.hh>
 27#include <unistd.h>
 28#include <sys/ioctl.h>
 29#include <sys/socket.h>
 30#include <sys/un.h>
 31#include <arpa/inet.h>
 32#include <netinet/tcp.h>
 33#include <fcntl.h>
 34#include "socket.hh"
 35
 36#ifdef HAVE_PROPER
 37#include <proper/prop.h>
 38#endif
 39
 40CLICK_DECLS
 41
 42Socket::Socket()
 43  : _task(this), _timer(this),
 44    _fd(-1), _active(-1), _rq(0), _wq(0),
 45    _local_port(0), _local_pathname(""),
 46    _timestamp(true), _sndbuf(-1), _rcvbuf(-1),
 47    _snaplen(2048), _headroom(Packet::default_headroom), _nodelay(1),
 48    _verbose(false), _client(false), _proper(false), _allow(0), _deny(0)
 49{
 50}
 51
 52Socket::~Socket()
 53{
 54}
 55
 56int
 57Socket::configure(Vector<String> &conf, ErrorHandler *errh)
 58{
 59  String socktype;
 60  _client = (noutputs() == 0);
 61  Args args = Args(this, errh).bind(conf);
 62  if (args.read_mp("TYPE", socktype).execute() < 0)
 63    return -1;
 64  socktype = socktype.upper();
 65
 66  // remove keyword arguments
 67  Element *allow = 0, *deny = 0;
 68  if (args.read("VERBOSE", _verbose)
 69      .read("SNAPLEN", _snaplen)
 70      .read("HEADROOM", _headroom)
 71      .read("TIMESTAMP", _timestamp)
 72      .read("RCVBUF", _rcvbuf)
 73      .read("SNDBUF", _sndbuf)
 74      .read("NODELAY", _nodelay)
 75      .read("CLIENT", _client)
 76      .read("PROPER", _proper)
 77      .read("ALLOW", allow)
 78      .read("DENY", deny)
 79      .consume() < 0)
 80    return -1;
 81
 82  if (allow && !(_allow = (IPRouteTable *)allow->cast("IPRouteTable")))
 83    return errh->error("%s is not an IPRouteTable", allow->name().c_str());
 84
 85  if (deny && !(_deny = (IPRouteTable *)deny->cast("IPRouteTable")))
 86    return errh->error("%s is not an IPRouteTable", deny->name().c_str());
 87
 88  if (socktype == "TCP" || socktype == "UDP") {
 89    _family = AF_INET;
 90    _socktype = socktype == "TCP" ? SOCK_STREAM : SOCK_DGRAM;
 91    _protocol = socktype == "TCP" ? IPPROTO_TCP : IPPROTO_UDP;
 92    if (args.read_mp("ADDR", _remote_ip)
 93	.read_mp("PORT", IPPortArg(_protocol), _remote_port)
 94	.read_p("LOCAL_ADDR", _local_ip)
 95	.read_p("LOCAL_PORT", IPPortArg(_protocol), _local_port)
 96	.complete() < 0)
 97      return -1;
 98  }
 99
100  else if (socktype == "UNIX" || socktype == "UNIX_DGRAM") {
101    _family = AF_UNIX;
102    _socktype = socktype == "UNIX" ? SOCK_STREAM : SOCK_DGRAM;
103    _protocol = 0;
104    if (args.read_mp("FILENAME", FilenameArg(), _remote_pathname)
105	.read_p("LOCAL_FILENAME", FilenameArg(), _local_pathname)
106	.complete() < 0)
107      return -1;
108    int max_path = (int)sizeof(((struct sockaddr_un *)0)->sun_path);
109    // if not in the abstract namespace (begins with zero byte),
110    // reserve room for trailing NUL
111    if ((_remote_pathname[0] && _remote_pathname.length() >= max_path) ||
112	(_remote_pathname[0] == 0 && _remote_pathname.length() > max_path))
113      return errh->error("remote filename '%s' too long", _remote_pathname.printable().c_str());
114    if ((_local_pathname[0] && _local_pathname.length() >= max_path) ||
115	(_local_pathname[0] == 0 && _local_pathname.length() > max_path))
116      return errh->error("local filename '%s' too long", _local_pathname.printable().c_str());
117  }
118
119  else
120    return errh->error("unknown socket type `%s'", socktype.c_str());
121
122  return 0;
123}
124
125
126int
127Socket::initialize_socket_error(ErrorHandler *errh, const char *syscall)
128{
129  int e = errno;		// preserve errno
130
131  if (_fd >= 0) {
132    remove_select(_fd, SELECT_READ | SELECT_WRITE);
133    close(_fd);
134    _fd = -1;
135  }
136
137  return errh->error("%s: %s", syscall, strerror(e));
138}
139
140int
141Socket::initialize(ErrorHandler *errh)
142{
143  // open socket, set options
144  _fd = socket(_family, _socktype, _protocol);
145  if (_fd < 0)
146    return initialize_socket_error(errh, "socket");
147
148  if (_family == AF_INET) {
149    _remote.in.sin_family = _family;
150    _remote.in.sin_port = htons(_remote_port);
151    _remote.in.sin_addr = _remote_ip.in_addr();
152    _remote_len = sizeof(_remote.in);
153    _local.in.sin_family = _family;
154    _local.in.sin_port = htons(_local_port);
155    _local.in.sin_addr = _local_ip.in_addr();
156    _local_len = sizeof(_local.in);
157  }
158  else {
159    _remote.un.sun_family = _family;
160    _remote_len = offsetof(struct sockaddr_un, sun_path) + _remote_pathname.length();
161    if (_remote_pathname[0]) {
162      strcpy(_remote.un.sun_path, _remote_pathname.c_str());
163      _remote_len++;
164    } else
165      memcpy(_remote.un.sun_path, _remote_pathname.c_str(), _remote_pathname.length());
166    _local.un.sun_family = _family;
167    _local_len = offsetof(struct sockaddr_un, sun_path) + _local_pathname.length();
168    if (_local_pathname[0]) {
169      strcpy(_local.un.sun_path, _local_pathname.c_str());
170      _local_len++;
171    } else
172      memcpy(_local.un.sun_path, _local_pathname.c_str(), _local_pathname.length());
173  }
174
175  // enable timestamps
176  if (_timestamp) {
177#ifdef SO_TIMESTAMP
178    int one = 1;
179    if (setsockopt(_fd, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one)) < 0)
180      return initialize_socket_error(errh, "setsockopt(SO_TIMESTAMP)");
181#else
182    return initialize_socket_error(errh, "TIMESTAMP not supported on this platform");
183#endif
184  }
185
186#ifdef TCP_NODELAY
187  // disable Nagle algorithm
188  if (_protocol == IPPROTO_TCP && _nodelay)
189    if (setsockopt(_fd, IP_PROTO_TCP, TCP_NODELAY, &_nodelay, sizeof(_nodelay)) < 0)
190      return initialize_socket_error(errh, "setsockopt(TCP_NODELAY)");
191#endif
192
193  // set socket send buffer size
194  if (_sndbuf >= 0)
195    if (setsockopt(_fd, SOL_SOCKET, SO_SNDBUF, &_sndbuf, sizeof(_sndbuf)) < 0)
196      return initialize_socket_error(errh, "setsockopt(SO_SNDBUF)");
197
198  // set socket receive buffer size
199  if (_rcvbuf >= 0)
200    if (setsockopt(_fd, SOL_SOCKET, SO_RCVBUF, &_rcvbuf, sizeof(_rcvbuf)) < 0)
201      return initialize_socket_error(errh, "setsockopt(SO_RCVBUF)");
202
203  // if a server, then the first arguments should be interpreted as
204  // the address/port/file to bind() to, not to connect() to
205  if (!_client) {
206    memcpy(&_local, &_remote, _remote_len);
207    _local_len = _remote_len;
208  }
209
210  // if a server, or if the optional local arguments have been
211  // specified, bind() to the specified address/port/file
212  if (!_client || _local_port != 0 || _local_pathname != "") {
213#ifdef HAVE_PROPER
214    int ret = -1;
215    if (_proper) {
216      ret = prop_bind_socket(_fd, (struct sockaddr *)&_local, _local_len);
217      if (ret < 0)
218	errh->warning("prop_bind_socket: %s", strerror(errno));
219    }
220    if (ret < 0)
221#endif
222    if (bind(_fd, (struct sockaddr *)&_local, _local_len) < 0)
223      return initialize_socket_error(errh, "bind");
224  }
225
226  if (_client) {
227    // connect
228    if (_socktype == SOCK_STREAM) {
229      if (connect(_fd, (struct sockaddr *)&_remote, _remote_len) < 0)
230	return initialize_socket_error(errh, "connect");
231      if (_verbose)
232	click_chatter("%s: opened connection %d to %s:%d", declaration().c_str(), _fd, IPAddress(_remote.in.sin_addr).unparse().c_str(), ntohs(_remote.in.sin_port));
233    }
234    _active = _fd;
235  } else {
236    // start listening
237    if (_socktype == SOCK_STREAM) {
238      if (listen(_fd, 2) < 0)
239	return initialize_socket_error(errh, "listen");
240      if (_verbose) {
241	if (_family == AF_INET)
242	  click_chatter("%s: listening for connections on %s:%d (%d)", declaration().c_str(), IPAddress(_local.in.sin_addr).unparse().c_str(), ntohs(_local.in.sin_port), _fd);
243	else
244	  click_chatter("%s: listening for connections on %s (%d)", declaration().c_str(), _local.un.sun_path, _fd);
245      }
246    } else {
247      _active = _fd;
248    }
249  }
250
251  // nonblocking I/O and close-on-exec for the socket
252  fcntl(_fd, F_SETFL, O_NONBLOCK);
253  fcntl(_fd, F_SETFD, FD_CLOEXEC);
254
255  if (noutputs())
256    add_select(_fd, SELECT_READ);
257
258  if (ninputs() && input_is_pull(0)) {
259    ScheduleInfo::join_scheduler(this, &_task, errh);
260    _signal = Notifier::upstream_empty_signal(this, 0, &_task);
261    add_select(_fd, SELECT_WRITE);
262    _timer.initialize(this);
263  }
264
265  return 0;
266}
267
268void
269Socket::cleanup(CleanupStage)
270{
271  if (_active >= 0 && _active != _fd) {
272    close(_active);
273    _active = -1;
274  }
275  if (_rq)
276    _rq->kill();
277  if (_wq)
278    _wq->kill();
279  if (_fd >= 0) {
280    // shut down the listening socket in case we forked
281#ifdef SHUT_RDWR
282    shutdown(_fd, SHUT_RDWR);
283#else
284    shutdown(_fd, 2);
285#endif
286    close(_fd);
287    if (_family == AF_UNIX)
288      unlink(_local_pathname.c_str());
289    _fd = -1;
290  }
291}
292
293bool
294Socket::allowed(IPAddress addr)
295{
296  IPAddress gw;
297
298  if (_allow && _allow->lookup_route(addr, gw) >= 0)
299    return true;
300  else if (_deny && _deny->lookup_route(addr, gw) >= 0)
301    return false;
302  else
303    return true;
304}
305
306void
307Socket::close_active(void)
308{
309  if (_active >= 0) {
310    remove_select(_active, SELECT_READ | SELECT_WRITE);
311    close(_active);
312    if (_verbose)
313      click_chatter("%s: closed connection %d", declaration().c_str(), _active);
314    _active = -1;
315  }
316}
317
318void
319Socket::selected(int fd, int)
320{
321  int len;
322  union { struct sockaddr_in in; struct sockaddr_un un; } from;
323  socklen_t from_len = sizeof(from);
324  bool allow;
325
326  if (noutputs()) {
327    // accept new connections
328    if (_socktype == SOCK_STREAM && !_client && _active < 0 && fd == _fd) {
329      _active = accept(_fd, (struct sockaddr *)&from, &from_len);
330
331      if (_active < 0) {
332	if (errno != EAGAIN)
333	  click_chatter("%s: accept: %s", declaration().c_str(), strerror(errno));
334	return;
335      }
336
337      if (_family == AF_INET) {
338	allow = allowed(IPAddress(from.in.sin_addr));
339
340	if (_verbose)
341	  click_chatter("%s: %s connection %d from %s:%d", declaration().c_str(),
342			allow ? "opened" : "denied",
343			_active, IPAddress(from.in.sin_addr).unparse().c_str(), ntohs(from.in.sin_port));
344
345	if (!allow) {
346	  close(_active);
347	  _active = -1;
348	  return;
349	}
350      } else {
351	if (_verbose)
352	  click_chatter("%s: opened connection %d from %s", declaration().c_str(), _active, from.un.sun_path);
353      }
354
355      fcntl(_active, F_SETFL, O_NONBLOCK);
356      fcntl(_active, F_SETFD, FD_CLOEXEC);
357
358      add_select(_active, SELECT_READ | SELECT_WRITE);
359      _events = SELECT_READ | SELECT_WRITE;
360    }
361
362    // read data from socket
363    if (!_rq)
364      _rq = Packet::make(_headroom, 0, _snaplen, 0);
365    if (_rq) {
366      if (_socktype == SOCK_STREAM)
367	len = read(_active, _rq->data(), _rq->length());
368      else if (_client)
369	len = recv(_active, _rq->data(), _rq->length(), MSG_TRUNC);
370      else {
371	// datagram server, find out who we are talking to
372	len = recvfrom(_active, _rq->data(), _rq->length(), MSG_TRUNC, (struct sockaddr *)&from, &from_len);
373
374	if (_family == AF_INET && !allowed(IPAddress(from.in.sin_addr))) {
375	  if (_verbose)
376	    click_chatter("%s: dropped datagram from %s:%d", declaration().c_str(),
377			  IPAddress(from.in.sin_addr).unparse().c_str(), ntohs(from.in.sin_port));
378	  len = -1;
379	  errno = EAGAIN;
380	} else if (len > 0) {
381	  memcpy(&_remote, &from, from_len);
382	  _remote_len = from_len;
383	}
384      }
385
386      // this segment OK
387      if (len > 0) {
388	if (len > _snaplen) {
389	  // truncate packet to max length (should never happen)
390	  assert(_rq->length() == (uint32_t)_snaplen);
391	  SET_EXTRA_LENGTH_ANNO(_rq, len - _snaplen);
392	} else {
393	  // trim packet to actual length
394	  _rq->take(_snaplen - len);
395	}
396
397	// set timestamp
398	if (_timestamp)
399	  _rq->timestamp_anno().assign_now();
400
401	// push packet
402	output(0).push(_rq);
403	_rq = 0;
404      }
405
406      // connection terminated or fatal error
407      else if (len == 0 || errno != EAGAIN) {
408	if (errno != EAGAIN && _verbose)
409	  click_chatter("%s: %s", declaration().c_str(), strerror(errno));
410	close_active();
411	return;
412      }
413    }
414  }
415
416  if (ninputs() && input_is_pull(0))
417    run_task(0);
418}
419
420int
421Socket::write_packet(Packet *p)
422{
423  int len;
424
425  assert(_active >= 0);
426
427  while (p->length()) {
428    if (!IPAddress(_remote_ip) && _client && _family == AF_INET && _socktype != SOCK_STREAM) {
429      // If the IP address specified when the element was created is 0.0.0.0,
430      // send the packet to its IP destination annotation address
431      _remote.in.sin_addr = p->dst_ip_anno();
432    }
433
434    // write segment
435    if (_socktype == SOCK_STREAM)
436      len = write(_active, p->data(), p->length());
437    else
438      len = sendto(_active, p->data(), p->length(), 0,
439		   (struct sockaddr *)&_remote, _remote_len);
440
441    // error
442    if (len < 0) {
443      // out of memory or would block
444      if (errno == ENOBUFS || errno == EAGAIN)
445	return -1;
446
447      // interrupted by signal, try again immediately
448      else if (errno == EINTR)
449	continue;
450
451      // connection probably terminated or other fatal error
452      else {
453	if (_verbose)
454	  click_chatter("%s: %s", declaration().c_str(), strerror(errno));
455	close_active();
456	break;
457      }
458    } else
459      // this segment OK
460      p->pull(len);
461  }
462
463  p->kill();
464  return 0;
465}
466
467void
468Socket::push(int, Packet *p)
469{
470  fd_set fds;
471  int err;
472
473  if (_active >= 0) {
474    // block
475    do {
476      FD_ZERO(&fds);
477      FD_SET(_active, &fds);
478      err = select(_active + 1, NULL, &fds, NULL, NULL);
479    } while (err < 0 && errno == EINTR);
480
481    if (err >= 0) {
482      // write
483      do {
484	err = write_packet(p);
485      } while (err < 0 && (errno == ENOBUFS || errno == EAGAIN));
486    }
487
488    if (err < 0) {
489      if (_verbose)
490	click_chatter("%s: %s, dropping packet", declaration().c_str(), strerror(err));
491      p->kill();
492    }
493  } else
494    p->kill();
495}
496
497bool
498Socket::run_task(Task *)
499{
500  assert(ninputs() && input_is_pull(0));
501  bool any = false;
502
503  if (_active >= 0) {
504    Packet *p = 0;
505    int err = 0;
506
507    // write as much as we can
508    do {
509      p = _wq ? _wq : input(0).pull();
510      _wq = 0;
511      if (p) {
512	any = true;
513	err = write_packet(p);
514      }
515    } while (p && err >= 0);
516
517    if (err < 0) {
518      // queue packet for writing when socket becomes available
519      _wq = p;
520      p = 0;
521      add_select(_active, SELECT_WRITE);
522    } else if (_signal)
523      // more pending
524      // (can't use fast_reschedule() cause selected() calls this)
525      _task.reschedule();
526    else
527      // wrote all we could and no more pending
528      remove_select(_active, SELECT_WRITE);
529  }
530
531  // true if we wrote at least one packet
532  return any;
533}
534
535void
536Socket::add_handlers()
537{
538  add_task_handlers(&_task);
539}
540
541CLICK_ENDDECLS
542ELEMENT_REQUIRES(userlevel IPRouteTable)
543EXPORT_ELEMENT(Socket)