1219820Sjeff/*
2219820Sjeff  This software is available to you under a choice of one of two
3219820Sjeff  licenses.  You may choose to be licensed under the terms of the GNU
4219820Sjeff  General Public License (GPL) Version 2, available at
5219820Sjeff  <http://www.fsf.org/copyleft/gpl.html>, or the OpenIB.org BSD
6219820Sjeff  license, available in the LICENSE.TXT file accompanying this
7219820Sjeff  software.  These details are also available at
8219820Sjeff  <http://openib.org/license.html>.
9219820Sjeff
10219820Sjeff  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
11219820Sjeff  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12219820Sjeff  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
13219820Sjeff  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
14219820Sjeff  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
15219820Sjeff  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
16219820Sjeff  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
17219820Sjeff  SOFTWARE.
18219820Sjeff
19219820Sjeff  Copyright (c) 2004 Topspin Communications.  All rights reserved.
20219820Sjeff  Copyright (c) 2005 Mellanox Technologies Ltd.  All rights reserved.
21219820Sjeff
22219820Sjeff  $Id$
23219820Sjeff*/
24219820Sjeff
25219820Sjeff/*
26219820Sjeff * system includes
27219820Sjeff */
28219820Sjeff#if HAVE_CONFIG_H
29219820Sjeff#  include <config.h>
30219820Sjeff#endif /* HAVE_CONFIG_H */
31219820Sjeff
32219820Sjeff/*
33219820Sjeff  For non-i386 systems, we pass socket() through to library code using
34219820Sjeff  dlsym() instead of trying to make the system call directly.  This
35219820Sjeff  may cause problems if this library is LD_PRELOADed before the real C
36219820Sjeff  library is available.  Eventually we may want to add the same type
37219820Sjeff  of system call assembly code as i386 has for IA64 and AMD64, but for
38219820Sjeff  now....
39219820Sjeff*/
40219820Sjeff#ifndef i386
41219820Sjeff#define _GNU_SOURCE /* Get RTLD_NEXT */
42219820Sjeff#include <dlfcn.h>
43219820Sjeff#else
44219820Sjeff#include <sys/syscall.h>
45219820Sjeff#endif
46219820Sjeff
47219820Sjeff#include <errno.h>
48219820Sjeff#include <stdio.h>
49219820Sjeff#include <stdlib.h>
50219820Sjeff#include <sys/socket.h>
51219820Sjeff#include <string.h>
52219820Sjeff/*
53219820Sjeff * SDP specific includes
54219820Sjeff */
55219820Sjeff#include "linux/sdp_inet.h"
56219820Sjeff
57219820Sjeff#if 0
58219820Sjeff#define _SDP_VERBOSE_PRELOAD
59219820Sjeff#endif
60219820Sjeff
61219820Sjeff#define SOCKOP_socket           1
62219820Sjeff#define SOCKOP_bind             2
63219820Sjeff#define SOCKOP_connect          3
64219820Sjeff#define SOCKOP_listen           4
65219820Sjeff#define SOCKOP_accept           5
66219820Sjeff#define SOCKOP_getsockname      6
67219820Sjeff#define SOCKOP_getpeername      7
68219820Sjeff#define SOCKOP_socketpair       8
69219820Sjeff#define SOCKOP_send             9
70219820Sjeff#define SOCKOP_recv             10
71219820Sjeff#define SOCKOP_sendto           11
72219820Sjeff#define SOCKOP_recvfrom         12
73219820Sjeff#define SOCKOP_shutdown         13
74219820Sjeff#define SOCKOP_setsockopt       14
75219820Sjeff#define SOCKOP_getsockopt       15
76219820Sjeff#define SOCKOP_sendmsg          16
77219820Sjeff#define SOCKOP_recvmsg          17
78219820Sjeff
79219820Sjeffextern char * program_invocation_name;
80219820Sjeffextern char * program_invocation_short_name;
81219820Sjeffextern char ** const environ;
82219820Sjeff
83219820Sjeff/* ========================================================================= */
84219820Sjeff/*..socket -- replacment socket call. */
85219820Sjeffint socket
86219820Sjeff(
87219820Sjeff int domain,
88219820Sjeff int type,
89219820Sjeff int protocol
90219820Sjeff)
91219820Sjeff{
92219820Sjeff#ifdef i386
93219820Sjeff  long  __ret;
94219820Sjeff  void *__scratch;
95219820Sjeff  int   call[3];
96219820Sjeff#endif
97219820Sjeff  char *test;
98219820Sjeff  char *inet;
99219820Sjeff  char **tenviron;
100219820Sjeff
101219820Sjeff#ifdef _SDP_VERBOSE_PRELOAD
102219820Sjeff  FILE *fd;
103219820Sjeff#endif
104219820Sjeff  /*
105219820Sjeff   * check for magic enviroment variable
106219820Sjeff   */
107219820Sjeff  if ((AF_INET == domain || AF_INET6 == domain) &&
108219820Sjeff      SOCK_STREAM == type) {
109219820Sjeff
110219820Sjeff    if (environ) {
111219820Sjeff      tenviron = environ;
112219820Sjeff      for (test = *tenviron; NULL != test; test = *++tenviron) {
113219820Sjeff
114219820Sjeff        inet = AF_INET_STR;
115219820Sjeff
116219820Sjeff        while (*inet == *test && '\0' != *inet) {
117219820Sjeff
118219820Sjeff          inet++;
119219820Sjeff	  test++;
120219820Sjeff        } /* while */
121219820Sjeff
122219820Sjeff        if ('\0' == *inet && '=' == *test) {
123219820Sjeff
124219820Sjeff          domain = AF_INET_SDP;
125219820Sjeff          break;
126219820Sjeff        } /* if */
127219820Sjeff      } /* for */
128219820Sjeff    } /* if */
129219820Sjeff  } /* if */
130219820Sjeff
131219820Sjeff#ifdef _SDP_VERBOSE_PRELOAD
132219820Sjeff  fd = fopen("/tmp/libsdp.log.txt", "a+");
133219820Sjeff
134219820Sjeff  fprintf(fd, "SOCKET: <%s> domain <%d> type <%d> protocol <%d>\n",
135219820Sjeff	  program_invocation_short_name, domain, type, protocol);
136219820Sjeff
137219820Sjeff  fclose(fd);
138219820Sjeff#endif
139219820Sjeff
140219820Sjeff#ifdef i386
141219820Sjeff  /* Make the socket() system call directly, as described above */
142219820Sjeff  call[0] = domain;
143219820Sjeff  call[1] = type;
144219820Sjeff  call[2] = protocol;
145219820Sjeff
146219820Sjeff  __asm__ __volatile__("movl %%ebx, %1\n" /* save %ebx */
147219820Sjeff                       "movl %3, %%ebx\n" /* put sockopt in %ebx as arg */
148219820Sjeff                       "int $0x80\n"      /* do syscall */
149219820Sjeff                       "movl %1, %%ebx\n" /* restore %ebx */
150219820Sjeff                       : "=a" (__ret), "=r" (__scratch)
151219820Sjeff                       : "0" (__NR_socketcall),
152219820Sjeff		       "g" (SOCKOP_socket),
153219820Sjeff		       "c" (call));
154219820Sjeff  return __ret;
155219820Sjeff#else /* i386 */
156219820Sjeff  /* Use the standard library socket() to pass through the call */
157219820Sjeff  {
158219820Sjeff    static int (*orig_socket)(int, int, int);
159219820Sjeff
160219820Sjeff    if (!orig_socket) {
161219820Sjeff      orig_socket = dlsym(RTLD_NEXT, "socket");
162219820Sjeff    }
163219820Sjeff
164219820Sjeff    return orig_socket(domain, type, protocol);
165219820Sjeff  }
166219820Sjeff#endif /* i386 */
167219820Sjeff} /* socket */
168