summaryrefslogtreecommitdiffstats
path: root/vpp-api/lua/cough.c
blob: 4251c73220263b08718281dc5d28585886ee08bc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
/*
 * Copyright (c) 2016 Cisco and/or its affiliates.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* 
 * This is a temporary helper library to seamlessly run against
 * the current API as exposed by libpneum.
 * In the future once the sync API is exposed as well as
 * a way to free the received data, this can go away.
 */

#include <dlfcn.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <pthread.h>

pthread_mutex_t mut;
pthread_mutex_t *cb_lock = &mut;

void *pneum_handle = NULL;

typedef void* (*arbitrary)();

int (*orig_pneum_connect)(char *name, char *chroot_prefix) = NULL;
int (*orig_pneum_connect_sync)(char *name, char *chroot_prefix) = NULL;
int (*orig_pneum_disconnect)(void) = NULL;
int (*orig_pneum_read)(char **data, int *l) = NULL;
int (*orig_pneum_write)(char *data, int len) = NULL;
int (*orig_pneum_has_data)(void) = NULL;
int (*orig_pneum_data_free)(char *data) = NULL;

arbitrary my_function = NULL;

typedef uint8_t u8;
typedef uint32_t u32;

u8 *cough_read_buffer;
u32 cough_read_buffer_size = 1000000;
u32 cough_read_head = 0;
u32 cough_read_lock_start = 0; /* lock_start till head is busy memory */
u32 cough_read_tail = 0;


int wrap_pneum_callback(char *data, int len) {
  // printf("Cough callback! with %d bytes\n", len);
  pthread_mutex_lock(cb_lock);
  if(cough_read_lock_start == cough_read_head) {
    // printf("Reset read head!\n");
    cough_read_head = 0;
    cough_read_tail = 0;
    cough_read_lock_start = 0;
  }
  u32 store_len = len;
  memcpy(cough_read_buffer + cough_read_head, &store_len, sizeof(u32));
  cough_read_head += sizeof(u32);
  memcpy(cough_read_buffer + cough_read_head, data, len);
  cough_read_head += len;
  pthread_mutex_unlock(cb_lock);
  return len;
}

int cough_pneum_attach(char *pneum_fname, char *cough_fname) {
  /* this is needed to make the pneum aware of the wrap_pneum_callback */
  pneum_handle = dlopen(cough_fname, RTLD_NOW|RTLD_GLOBAL);
  /* now let's try to load pneum itself */
  pneum_handle = dlopen(pneum_fname, RTLD_NOW|RTLD_GLOBAL);
  if (pneum_handle) {
    *(void**)(&orig_pneum_connect) = dlsym(pneum_handle,"pneum_connect");
    *(void**)(&orig_pneum_connect_sync) = dlsym(pneum_handle,"pneum_connect_sync");
    *(void**)(&orig_pneum_disconnect) = dlsym(pneum_handle,"pneum_disconnect");
    *(void**)(&orig_pneum_read) = dlsym(pneum_handle,"pneum_read");
    *(void**)(&orig_pneum_write) = dlsym(pneum_handle,"pneum_write");
    *(void**)(&orig_pneum_has_data) = dlsym(pneum_handle,"pneum_has_data");
    *(void**)(&orig_pneum_data_free) = dlsym(pneum_handle,"pneum_data_free");
    // If you uncomment the below line we pretend we have an async-only libpneum
    orig_pneum_connect_sync = NULL;
    cough_read_buffer = malloc(cough_read_buffer_size);
  } else {
    printf("Could not get cough handle\n");
    printf("Error: %s", dlerror());
    return -1;
  }

  *(void**)(&my_function) = dlsym(pneum_handle,"something");
}


int pneum_connect(char *name, char *chroot_prefix) {
  if(orig_pneum_connect) {
    return(orig_pneum_connect(name, chroot_prefix));
  } else {
    printf("COUGH: pneum_connect\n");
    return -1;
  }
}
int pneum_connect_sync(char *name, char *chroot_prefix) {
  if(orig_pneum_connect_sync) {
    int ret = (orig_pneum_connect_sync(name, chroot_prefix));
    return ret;
  } else {
    return(orig_pneum_connect(name, chroot_prefix));
  }
}


int pneum_disconnect(void) {
  if(orig_pneum_disconnect) {
    return orig_pneum_disconnect();
  } else {
    printf("COUGH: pneum_disconnect\n");
    return -1;
  }
}

int pneum_has_data(void) {
  if (orig_pneum_connect_sync) {
    /* always return 1 in a pass-through case */
    return 1;
  } else {
    // printf("COUGH: pneum_has_data\n");
    return (cough_read_head != cough_read_tail);
  }
}


int pneum_read(char **data, int *l) {
  if(orig_pneum_connect_sync) {
    return orig_pneum_read(data, l);
  } else { 
    while(!pneum_has_data());
    u32 n_bytes;
    pthread_mutex_lock(cb_lock);
    memcpy(&n_bytes, cough_read_buffer + cough_read_tail, sizeof(u32));
    cough_read_tail += sizeof(u32);
    void * dataptr = (void *) (cough_read_buffer + cough_read_tail);
    *data = dataptr;
    cough_read_tail += n_bytes;
    *l = n_bytes;
    pthread_mutex_unlock(cb_lock);
    return n_bytes; 
  }
}

int pneum_write(char *data, int len) {
  if(orig_pneum_write) {
    return(orig_pneum_write(data, len));
  } else {
    printf("COUGH: pneum_write\n");
    return -1;
  }
}

void pneum_data_free(char *data) {
  if (orig_pneum_connect_sync) {
    if(orig_pneum_data_free) {
      orig_pneum_data_free(data);
    } else {
      printf("COUGH: pneum_data_free\n");
    }
  } else {
    u32 *len;
    uint32_t index = ((u8*)data) - cough_read_buffer;
    pthread_mutex_lock(cb_lock);
    if ((index < cough_read_head) && (index > cough_read_lock_start)) {
      len = (void *)(data - sizeof(u32));
      cough_read_lock_start = index + *len;
    }
    pthread_mutex_unlock(cb_lock);
  }
}